]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/session.c
ipsec-317.220.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / session.c
1 /* $NetBSD: session.c,v 1.7.6.2 2007/08/01 11:52:22 vanhu Exp $ */
2
3 /* $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $ */
4
5 /*
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include "config.h"
35
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/time.h>
39 #include <sys/socket.h>
40 #if HAVE_SYS_WAIT_H
41 # include <sys/wait.h>
42 #endif
43 #ifndef WEXITSTATUS
44 # define WEXITSTATUS(s) ((unsigned)(s) >> 8)
45 #endif
46 #ifndef WIFEXITED
47 # define WIFEXITED(s) (((s) & 255) == 0)
48 #endif
49
50 #ifndef HAVE_NETINET6_IPSEC
51 #include <netinet/ipsec.h>
52 #else
53 #include <netinet6/ipsec.h>
54 #endif
55
56 #include <stdlib.h>
57 #include <stdio.h>
58 #include <string.h>
59 #include <errno.h>
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 #include <signal.h>
64 #include <sys/stat.h>
65 #include <paths.h>
66
67 #include <netinet/in.h>
68 #include <netinet/ip.h>
69 #include <netinet/ip_icmp.h>
70
71 #include <TargetConditionals.h>
72 #include <vproc_priv.h>
73 #include <dispatch/dispatch.h>
74 #include <xpc/xpc.h>
75
76 #include "libpfkey.h"
77
78 #include "var.h"
79 #include "misc.h"
80 #include "vmbuf.h"
81 #include "plog.h"
82 #include "debug.h"
83 #include "plog.h"
84
85 #include "schedule.h"
86 #include "session.h"
87 #include "grabmyaddr.h"
88 #include "cfparse_proto.h"
89 #include "isakmp_var.h"
90 #include "isakmp_xauth.h"
91 #include "isakmp_cfg.h"
92 #include "oakley.h"
93 #include "pfkey.h"
94 #include "handler.h"
95 #include "localconf.h"
96 #include "remoteconf.h"
97 #ifdef ENABLE_NATT
98 #include "nattraversal.h"
99 #endif
100 #include "vpn_control_var.h"
101 #include "policy.h"
102 #include "algorithm.h" /* XXX ??? */
103
104 #include "sainfo.h"
105 #include "power_mgmt.h"
106
107 #include <NetworkExtension/NEPolicy.h>
108 #include <sys/proc_info.h>
109 #include <libproc.h>
110
111
112 extern pid_t racoon_pid;
113 extern int launchdlaunched;
114 static void close_session (int);
115 static int init_signal (void);
116 static int set_signal (int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *));
117 static void check_flushsa_stub (void *);
118 static void check_flushsa (void);
119 static void auto_exit_do (void *);
120 static int close_sockets (void);
121
122 static volatile sig_atomic_t sigreq[NSIG + 1];
123 int terminated = 0;
124 int pending_signal_handle = 0;
125
126 static int64_t racoon_keepalive = -1;
127
128 dispatch_queue_t main_queue;
129
130 static NEPolicySessionRef policySession = NULL;
131
132 /*
133 * This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly)
134 * launched on demand and for <rdar://problem/8768510> requires a keepalive on dirty/failure exits.
135 * The launchd plist can't be used for this because RunOnLoad is required to have keepalive on a failure exit.
136 */
137 int64_t
138 launchd_update_racoon_keepalive (Boolean enabled)
139 {
140 if (launchdlaunched) {
141 int64_t val = (__typeof__(val))enabled;
142 /* Set our own KEEPALIVE value */
143 if (vproc_swap_integer(NULL,
144 VPROC_GSK_BASIC_KEEPALIVE,
145 &val,
146 &racoon_keepalive)) {
147 plog(ASL_LEVEL_ERR,
148 "failed to swap launchd keepalive integer %d\n", enabled);
149 }
150 }
151 return racoon_keepalive;
152 }
153
154 static CFUUIDRef
155 copy_racoon_proc_uuid(void)
156 {
157 struct proc_uniqidentifierinfo procu;
158 CFUUIDBytes uuidBytes;
159 int size = 0;
160
161 memset(&procu, 0, sizeof(procu));
162 size = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 1, &procu, PROC_PIDUNIQIDENTIFIERINFO_SIZE);
163 if (size != PROC_PIDUNIQIDENTIFIERINFO_SIZE) {
164 return (NULL);
165 }
166
167 memcpy(&uuidBytes, procu.p_uuid, sizeof(CFUUIDBytes));
168 return CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, uuidBytes);
169 }
170
171 static bool
172 policy_session_init(void)
173 {
174 bool success = true;
175 policySession = NEPolicyCreateSession(kCFAllocatorDefault, CFSTR("racoon"), NULL, NULL);
176 if (policySession == NULL) {
177 return false;
178 }
179
180 CFUUIDRef proc_uuid = copy_racoon_proc_uuid();
181 if (proc_uuid == NULL) {
182 return false;
183 }
184
185 CFMutableArrayRef conditions = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
186 if (conditions) {
187 CFMutableDictionaryRef uuidCondition = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
188 if (uuidCondition) {
189 CFDictionarySetValue(uuidCondition, kNEPolicyConditionType, kNEPolicyValPolicyConditionTypeApplication);
190 CFDictionarySetValue(uuidCondition, kNEPolicyApplicationUUID, proc_uuid);
191 CFArrayAppendValue(conditions, uuidCondition);
192 CFRelease(uuidCondition);
193 } else {
194 success = false;
195 }
196
197 CFMutableDictionaryRef interfacesCondition = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
198 if (interfacesCondition) {
199 CFDictionarySetValue(interfacesCondition, kNEPolicyConditionType, kNEPolicyValPolicyConditionTypeAllInterfaces);
200 CFArrayAppendValue(conditions, interfacesCondition);
201 CFRelease(interfacesCondition);
202 } else {
203 success = false;
204 }
205 } else {
206 success = false;
207 }
208
209 CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
210 if (result) {
211 CFDictionaryAddValue(result, kNEPolicyResult, kNEPolicyValPolicyResultPass);
212 } else {
213 success = false;
214 }
215
216 if (success) {
217 success = (NEPolicyAdd(policySession, 0, conditions, result, NULL) != kNEPolicyIDInvalid);
218 }
219
220 if (result) {
221 CFRelease(result);
222 }
223 if (conditions) {
224 CFRelease(conditions);
225 }
226 if (proc_uuid) {
227 CFRelease(proc_uuid);
228 }
229
230 return (success && NEPolicyApply(policySession));
231 }
232
233 //
234 // Session
235 //
236 // Initialize listening sockets, timers, vpn control etc.,
237 // write the PID file and call dispatch_main.
238 //
239 void
240 session(void)
241 {
242 char pid_file[MAXPATHLEN];
243 FILE *fp;
244 int i;
245
246 main_queue = dispatch_get_main_queue();
247
248 /* initialize schedular */
249 sched_init();
250
251 /* needs to be called after schedular */
252 if (init_power_mgmt() < 0) {
253 plog(ASL_LEVEL_ERR,
254 "failed to initialize power-mgmt.");
255 exit(1);
256 }
257
258 if (lcconf->autograbaddr == 1)
259 if (pfroute_init()) {
260 plog(ASL_LEVEL_ERR, "failed to initialize route socket.\n");
261 exit(1);
262 }
263
264 if (!policy_session_init()) {
265 plog(ASL_LEVEL_ERR, "failed to initialize NEPolicy session.\n");
266 }
267
268 if (initmyaddr()) {
269 plog(ASL_LEVEL_ERR, "failed to initialize listening addresses.\n");
270 exit(1);
271 }
272 if (isakmp_init()) {
273 plog(ASL_LEVEL_ERR, "failed to initialize isakmp");
274 exit(1);
275 }
276 #ifdef ENABLE_VPNCONTROL_PORT
277 if (vpncontrol_init()) {
278 plog(ASL_LEVEL_ERR, "failed to initialize vpn control port");
279 //exit(1);
280 }
281 #endif
282
283 if (init_signal()) {
284 plog(ASL_LEVEL_ERR, "failed to initialize signals.\n");
285 exit(1);
286 }
287
288 for (i = 0; i <= NSIG; i++)
289 sigreq[i] = 0;
290
291 /* write .pid file */
292 if (!f_foreground) {
293 racoon_pid = getpid();
294 if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL)
295 strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file));
296 else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/')
297 strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file));
298 else {
299 strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file));
300 strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file));
301 }
302 fp = fopen(pid_file, "w");
303 if (fp) {
304 if (fchmod(fileno(fp),
305 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
306 plog(ASL_LEVEL_ERR, "%s", strerror(errno));
307 fclose(fp);
308 exit(1);
309 }
310 fprintf(fp, "%ld\n", (long)racoon_pid);
311 fclose(fp);
312 } else {
313 plog(ASL_LEVEL_ERR,
314 "cannot open %s", pid_file);
315 }
316 }
317
318 xpc_transaction_begin();
319
320 #if !TARGET_OS_EMBEDDED
321 // enable keepalive for recovery (from crashes and bad exits... after init)
322 (void)launchd_update_racoon_keepalive(true);
323 #endif // !TARGET_OS_EMBEDDED
324
325 // Off to the races!
326 if (!terminated) {
327 dispatch_main();
328 }
329
330 exit(1); // should not be reached!!!
331 }
332
333
334 /* clear all status and exit program. */
335 static void
336 close_session(int error)
337 {
338 sched_killall();
339 cleanup_power_mgmt();
340 if ( terminated )
341 ike_session_flush_all_phase2(false);
342 ike_session_flush_all_phase1(false);
343 close_sockets();
344
345 xpc_transaction_end();
346
347 #if !TARGET_OS_EMBEDDED
348 // a clean exit, so disable launchd keepalive
349 (void)launchd_update_racoon_keepalive(false);
350 #endif // !TARGET_OS_EMBEDDED
351
352 plog(ASL_LEVEL_NOTICE, "racoon shutdown\n");
353 exit(0);
354 }
355
356
357 /*
358 * waiting the termination of processing until sending DELETE message
359 * for all inbound SA will complete.
360 */
361 static void
362 check_flushsa_stub(p)
363 void *p;
364 {
365 check_flushsa();
366 }
367
368 static void
369 check_flushsa()
370 {
371 vchar_t *buf;
372 struct sadb_msg *msg, *end, *next;
373 struct sadb_sa *sa;
374 caddr_t mhp[SADB_EXT_MAX + 1];
375 int n;
376
377 buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC);
378 if (buf == NULL) {
379 plog(ASL_LEVEL_DEBUG,
380 "pfkey_dump_sadb: returned nothing.\n");
381 return;
382 }
383
384 msg = ALIGNED_CAST(struct sadb_msg *)buf->v;
385 end = ALIGNED_CAST(struct sadb_msg *)(buf->v + buf->l);
386
387 /* counting SA except of dead one. */
388 n = 0;
389 while (msg < end) {
390 if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg))
391 break;
392 next = ALIGNED_CAST(struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len)); // Wcast-align fix (void*) - aligned buffer + multiple of 64
393 if (msg->sadb_msg_type != SADB_DUMP) {
394 msg = next;
395 continue;
396 }
397
398 if (pfkey_align(msg, mhp) || pfkey_check(mhp)) {
399 plog(ASL_LEVEL_ERR,
400 "pfkey_check (%s)\n", ipsec_strerror());
401 msg = next;
402 continue;
403 }
404
405 sa = ALIGNED_CAST(struct sadb_sa *)(mhp[SADB_EXT_SA]); // Wcast-align fix (void*) - mhp contains pointers to aligned structs
406 if (!sa) {
407 msg = next;
408 continue;
409 }
410
411 if (sa->sadb_sa_state != SADB_SASTATE_DEAD) {
412 n++;
413 msg = next;
414 continue;
415 }
416
417 msg = next;
418 }
419
420 if (buf != NULL)
421 vfree(buf);
422
423 if (n) {
424 sched_new(1, check_flushsa_stub, NULL);
425 return;
426 }
427
428 #if !TARGET_OS_EMBEDDED
429 if (lcconf->vt)
430 vproc_transaction_end(NULL, lcconf->vt);
431 #endif
432 close_session(0);
433 }
434
435 void
436 auto_exit_do(void *p)
437 {
438 plog(ASL_LEVEL_NOTICE,
439 "performing auto exit\n");
440 #if ENABLE_NO_SA_FLUSH
441 close_session(0);
442 #else
443 pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
444 sched_new(1, check_flushsa_stub, NULL);
445 dying();
446 #endif /* ENABLE_NO_SA_FLUSH */
447 }
448
449 void
450 check_auto_exit(void)
451 {
452 if (lcconf->auto_exit_sched) { /* exit scheduled? */
453 if (lcconf->auto_exit_state != LC_AUTOEXITSTATE_ENABLED
454 || vpn_control_connected() /* vpn control connected */
455 || policies_installed() /* policies installed in kernel */
456 || !no_remote_configs(FALSE)) { /* remote or anonymous configs */
457 SCHED_KILL(lcconf->auto_exit_sched);
458 }
459 } else { /* exit not scheduled */
460 if (lcconf->auto_exit_state == LC_AUTOEXITSTATE_ENABLED
461 && !vpn_control_connected()
462 && !policies_installed()
463 && no_remote_configs(FALSE)) {
464 if (lcconf->auto_exit_delay == 0) {
465 auto_exit_do(NULL); /* immediate exit */
466 } else {
467 lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL);
468 }
469 }
470 }
471 }
472
473 static int signals[] = {
474 SIGHUP,
475 SIGINT,
476 SIGTERM,
477 SIGUSR1,
478 SIGUSR2,
479 SIGPIPE,
480 0
481 };
482
483
484 void
485 check_sigreq()
486 {
487 int sig;
488
489 /*
490 * XXX We are not able to tell if we got
491 * several time the same signal. This is
492 * not a problem for the current code,
493 * but we shall remember this limitation.
494 */
495 for (sig = 0; sig <= NSIG; sig++) {
496 if (sigreq[sig] == 0)
497 continue;
498
499 sigreq[sig]--;
500 switch(sig) {
501 case 0:
502 return;
503
504 /* Catch up childs, mainly scripts.
505 */
506
507 case SIGUSR1:
508 case SIGHUP:
509 #ifdef ENABLE_HYBRID
510 if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) {
511 plog(ASL_LEVEL_ERR,
512 "ISAKMP mode config structure reset failed, "
513 "not reloading\n");
514 return;
515 }
516 #endif
517 if ( terminated )
518 break;
519
520 /*
521 * if we got a HUP... try graceful teardown of sessions before we close and reopen sockets...
522 * so that info-deletes notifications can make it to the peer.
523 */
524 if (sig == SIGHUP) {
525 ike_session_flush_all_phase2(true);
526 ike_session_flush_all_phase1(true);
527 }
528
529 /* Save old configuration, load new one... */
530 if (cfreparse(sig)) {
531 plog(ASL_LEVEL_ERR,
532 "configuration read failed\n");
533 exit(1);
534 }
535 if (lcconf->logfile_param == NULL && logFileStr[0] == 0)
536 plogresetfile(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]);
537
538 #if TARGET_OS_EMBEDDED
539 if (no_remote_configs(TRUE)) {
540 #if ENABLE_NO_SA_FLUSH
541 close_session(0);
542 #else
543 pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC);
544 #ifdef ENABLE_FASTQUIT
545 close_session(0);
546 #else
547 sched_new(1, check_flushsa_stub, NULL);
548 #endif /* ENABLE_FASTQUIT */
549 dying();
550 #endif /* ENABLE_NO_SA_FLUSH */
551 }
552 #endif
553
554 break;
555
556 case SIGINT:
557 case SIGTERM:
558 plog(ASL_LEVEL_NOTICE,
559 "caught signal %d\n", sig);
560 #if ENABLE_NO_SA_FLUSH
561 close_session(0);
562 #else
563 pfkey_send_flush(lcconf->sock_pfkey,
564 SADB_SATYPE_UNSPEC);
565 if ( sig == SIGTERM ){
566 terminated = 1; /* in case if it hasn't been set yet */
567 close_session(0);
568 }
569 else
570 sched_new(1, check_flushsa_stub, NULL);
571
572 dying();
573 #endif /* ENABLE_NO_SA_FLUSH */
574 break;
575
576 default:
577 plog(ASL_LEVEL_NOTICE,
578 "caught signal %d\n", sig);
579 break;
580 }
581 }
582 }
583
584
585 /*
586 * asynchronous requests will actually dispatched in the
587 * main loop in session().
588 */
589 RETSIGTYPE
590 signal_handler(int sig, siginfo_t *sigi, void *ctx)
591 {
592 #if 0
593 plog(ASL_LEVEL_NOTICE,
594 "%s received signal %d from pid %d uid %d\n\n",
595 __FUNCTION__, sig, sigi->si_pid, sigi->si_uid);
596 #endif
597
598 /* Do not just set it to 1, because we may miss some signals by just setting
599 * values to 0/1
600 */
601 sigreq[sig]++;
602 if ( sig == SIGTERM ){
603 terminated = 1;
604 }
605
606 pending_signal_handle = 1;
607 dispatch_async(main_queue,
608 ^{
609 if (pending_signal_handle) {
610 check_sigreq();
611 pending_signal_handle = 0;
612 }
613 });
614 }
615
616
617 static int
618 init_signal()
619 {
620 int i;
621
622 for (i = 0; signals[i] != 0; i++) {
623 if (set_signal(signals[i], signal_handler) < 0) {
624 plog(ASL_LEVEL_ERR,
625 "failed to set_signal (%s)\n",
626 strerror(errno));
627 return (1);
628 }
629 }
630 return 0;
631 }
632
633 static int
634 set_signal(int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *))
635 {
636 struct sigaction sa;
637
638 memset((caddr_t)&sa, 0, sizeof(sa));
639 sa.sa_sigaction = func;
640 sa.sa_flags = SA_RESTART | SA_SIGINFO;
641
642 if (sigemptyset(&sa.sa_mask) < 0)
643 return -1;
644
645 if (sigaction(sig, &sa, (struct sigaction *)0) < 0)
646 return(-1);
647
648 return 0;
649 }
650
651 void
652 fatal_error(int error)
653 {
654 close_session(error == 0 ? -1 : error);
655 }
656
657 /* suspend all socket sources except pf_key */
658 void
659 dying(void)
660 {
661 if (lcconf->rt_source)
662 dispatch_suspend(lcconf->rt_source);
663 if (lcconf->vpncontrol_source)
664 dispatch_suspend(lcconf->vpncontrol_source);
665 isakmp_suspend_sockets();
666 }
667
668 static int
669 close_sockets()
670 {
671 pfroute_close();
672 isakmp_close();
673 pfkey_close();
674 #ifdef ENABLE_VPNCONTROL_PORT
675 vpncontrol_close();
676 #endif
677
678 return 0;
679 }
680
681