1 /* $NetBSD: session.c,v 1.7.6.2 2007/08/01 11:52:22 vanhu Exp $ */
3 /* $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $ */
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
36 #include <sys/types.h>
37 #include <sys/param.h>
39 #include <sys/socket.h>
41 # include <sys/wait.h>
44 # define WEXITSTATUS(s) ((unsigned)(s) >> 8)
47 # define WIFEXITED(s) (((s) & 255) == 0)
50 #ifndef HAVE_NETINET6_IPSEC
51 #include <netinet/ipsec.h>
53 #include <netinet6/ipsec.h>
67 #include <netinet/in.h>
68 #include <netinet/ip.h>
69 #include <netinet/ip_icmp.h>
71 #include <TargetConditionals.h>
72 #include <vproc_priv.h>
73 #include <dispatch/dispatch.h>
75 #include <os/transaction_private.h>
88 #include "grabmyaddr.h"
89 #include "cfparse_proto.h"
90 #include "isakmp_var.h"
91 #include "isakmp_xauth.h"
92 #include "isakmp_cfg.h"
96 #include "localconf.h"
97 #include "remoteconf.h"
99 #include "nattraversal.h"
101 #include "vpn_control_var.h"
103 #include "algorithm.h" /* XXX ??? */
106 #include "power_mgmt.h"
108 #include <NetworkExtension/NEPolicy.h>
109 #include <sys/proc_info.h>
113 #define IKEv1_TRANSACTION "IKEv1_Transaction"
115 extern pid_t racoon_pid
;
116 extern int launchdlaunched
;
117 static void close_session (int);
118 static int init_signal (void);
119 static int set_signal (int sig
, RETSIGTYPE (*func
) (int, siginfo_t
*, void *));
120 static void check_flushsa_stub (void *);
121 static void check_flushsa (void);
122 static void auto_exit_do (void *);
123 static int close_sockets (void);
125 static volatile sig_atomic_t sigreq
[NSIG
+ 1];
127 int pending_signal_handle
= 0;
129 static int64_t racoon_keepalive
= -1;
131 dispatch_queue_t main_queue
;
133 static NEPolicySessionRef policySession
= NULL
;
135 static os_transaction_t g_ikev1_transaction
= NULL
;
138 * This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly)
139 * launched on demand and for <rdar://problem/8768510> requires a keepalive on dirty/failure exits.
140 * The launchd plist can't be used for this because RunOnLoad is required to have keepalive on a failure exit.
143 launchd_update_racoon_keepalive (Boolean enabled
)
145 if (launchdlaunched
) {
146 int64_t val
= (__typeof__(val
))enabled
;
147 /* Set our own KEEPALIVE value */
148 if (vproc_swap_integer(NULL
,
149 VPROC_GSK_BASIC_KEEPALIVE
,
151 &racoon_keepalive
)) {
153 "failed to swap launchd keepalive integer %d\n", enabled
);
156 return racoon_keepalive
;
160 copy_racoon_proc_uuid(void)
162 struct proc_uniqidentifierinfo procu
;
163 CFUUIDBytes uuidBytes
;
166 memset(&procu
, 0, sizeof(procu
));
167 size
= proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO
, 1, &procu
, PROC_PIDUNIQIDENTIFIERINFO_SIZE
);
168 if (size
!= PROC_PIDUNIQIDENTIFIERINFO_SIZE
) {
172 memcpy(&uuidBytes
, procu
.p_uuid
, sizeof(CFUUIDBytes
));
173 return CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault
, uuidBytes
);
177 policy_session_init(void)
180 policySession
= NEPolicyCreateSession(kCFAllocatorDefault
, CFSTR("racoon"), NULL
, NULL
);
181 if (policySession
== NULL
) {
185 CFUUIDRef proc_uuid
= copy_racoon_proc_uuid();
186 if (proc_uuid
== NULL
) {
190 CFMutableArrayRef conditions
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
192 CFMutableDictionaryRef uuidCondition
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
194 CFDictionarySetValue(uuidCondition
, kNEPolicyConditionType
, kNEPolicyValPolicyConditionTypeApplication
);
195 CFDictionarySetValue(uuidCondition
, kNEPolicyApplicationUUID
, proc_uuid
);
196 CFArrayAppendValue(conditions
, uuidCondition
);
197 CFRelease(uuidCondition
);
202 CFMutableDictionaryRef interfacesCondition
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
203 if (interfacesCondition
) {
204 CFDictionarySetValue(interfacesCondition
, kNEPolicyConditionType
, kNEPolicyValPolicyConditionTypeAllInterfaces
);
205 CFArrayAppendValue(conditions
, interfacesCondition
);
206 CFRelease(interfacesCondition
);
214 CFMutableDictionaryRef result
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
216 CFDictionaryAddValue(result
, kNEPolicyResult
, kNEPolicyValPolicyResultPass
);
222 success
= (NEPolicyAdd(policySession
, 0, conditions
, result
, NULL
) != kNEPolicyIDInvalid
);
229 CFRelease(conditions
);
232 CFRelease(proc_uuid
);
235 return (success
&& NEPolicyApply(policySession
));
241 // Initialize listening sockets, timers, vpn control etc.,
242 // write the PID file and call dispatch_main.
247 char pid_file
[MAXPATHLEN
];
251 main_queue
= dispatch_get_main_queue();
253 /* initialize schedular */
256 /* needs to be called after schedular */
257 if (init_power_mgmt() < 0) {
259 "failed to initialize power-mgmt.");
263 if (lcconf
->autograbaddr
== 1)
264 if (pfroute_init()) {
265 plog(ASL_LEVEL_ERR
, "failed to initialize route socket.\n");
269 if (!policy_session_init()) {
270 plog(ASL_LEVEL_ERR
, "failed to initialize NEPolicy session.\n");
274 plog(ASL_LEVEL_ERR
, "failed to initialize listening addresses.\n");
278 plog(ASL_LEVEL_ERR
, "failed to initialize isakmp");
281 #ifdef ENABLE_VPNCONTROL_PORT
282 if (vpncontrol_init()) {
283 plog(ASL_LEVEL_ERR
, "failed to initialize vpn control port");
289 plog(ASL_LEVEL_ERR
, "failed to initialize signals.\n");
293 for (i
= 0; i
<= NSIG
; i
++)
296 /* write .pid file */
298 racoon_pid
= getpid();
299 if (lcconf
->pathinfo
[LC_PATHTYPE_PIDFILE
] == NULL
)
300 strlcpy(pid_file
, _PATH_VARRUN
"racoon.pid", sizeof(pid_file
));
301 else if (lcconf
->pathinfo
[LC_PATHTYPE_PIDFILE
][0] == '/')
302 strlcpy(pid_file
, lcconf
->pathinfo
[LC_PATHTYPE_PIDFILE
], sizeof(pid_file
));
304 strlcat(pid_file
, _PATH_VARRUN
, sizeof(pid_file
));
305 strlcat(pid_file
, lcconf
->pathinfo
[LC_PATHTYPE_PIDFILE
], sizeof(pid_file
));
307 fp
= fopen(pid_file
, "w");
309 if (fchmod(fileno(fp
),
310 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
) == -1) {
311 plog(ASL_LEVEL_ERR
, "%s", strerror(errno
));
315 fprintf(fp
, "%ld\n", (long)racoon_pid
);
319 "cannot open %s", pid_file
);
323 if (g_ikev1_transaction
== NULL
) {
324 g_ikev1_transaction
= os_transaction_create(IKEv1_TRANSACTION
);
327 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
328 // enable keepalive for recovery (from crashes and bad exits... after init)
329 (void)launchd_update_racoon_keepalive(true);
330 #endif // !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
337 exit(1); // should not be reached!!!
341 /* clear all status and exit program. */
343 close_session(int error
)
346 cleanup_power_mgmt();
348 ike_session_flush_all_phase2(false);
349 ike_session_flush_all_phase1(false);
352 if (g_ikev1_transaction
!= NULL
) {
353 os_release(g_ikev1_transaction
);
354 g_ikev1_transaction
= NULL
;
357 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
358 // a clean exit, so disable launchd keepalive
359 (void)launchd_update_racoon_keepalive(false);
360 #endif // !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
362 plog(ASL_LEVEL_NOTICE
, "racoon shutdown\n");
368 * waiting the termination of processing until sending DELETE message
369 * for all inbound SA will complete.
372 check_flushsa_stub(p
)
382 struct sadb_msg
*msg
, *end
, *next
;
384 caddr_t mhp
[SADB_EXT_MAX
+ 1];
387 buf
= pfkey_dump_sadb(SADB_SATYPE_UNSPEC
);
389 plog(ASL_LEVEL_DEBUG
,
390 "pfkey_dump_sadb: returned nothing.\n");
394 msg
= ALIGNED_CAST(struct sadb_msg
*)buf
->v
;
395 end
= ALIGNED_CAST(struct sadb_msg
*)(buf
->v
+ buf
->l
);
397 /* counting SA except of dead one. */
400 if (PFKEY_UNUNIT64(msg
->sadb_msg_len
) < sizeof(*msg
))
402 next
= ALIGNED_CAST(struct sadb_msg
*)((caddr_t
)msg
+ PFKEY_UNUNIT64(msg
->sadb_msg_len
)); // Wcast-align fix (void*) - aligned buffer + multiple of 64
403 if (msg
->sadb_msg_type
!= SADB_DUMP
) {
408 if (pfkey_align(msg
, mhp
) || pfkey_check(mhp
)) {
410 "pfkey_check (%s)\n", ipsec_strerror());
415 sa
= ALIGNED_CAST(struct sadb_sa
*)(mhp
[SADB_EXT_SA
]); // Wcast-align fix (void*) - mhp contains pointers to aligned structs
421 if (sa
->sadb_sa_state
!= SADB_SASTATE_DEAD
) {
434 sched_new(1, check_flushsa_stub
, NULL
);
438 #if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
440 vproc_transaction_end(NULL
, lcconf
->vt
);
441 #endif // !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
446 auto_exit_do(void *p
)
448 plog(ASL_LEVEL_NOTICE
,
449 "performing auto exit\n");
450 #if ENABLE_NO_SA_FLUSH
453 pfkey_send_flush(lcconf
->sock_pfkey
, SADB_SATYPE_UNSPEC
);
454 sched_new(1, check_flushsa_stub
, NULL
);
456 #endif /* ENABLE_NO_SA_FLUSH */
460 check_auto_exit(void)
462 if (lcconf
->auto_exit_sched
) { /* exit scheduled? */
463 if (lcconf
->auto_exit_state
!= LC_AUTOEXITSTATE_ENABLED
464 || vpn_control_connected() /* vpn control connected */
465 || policies_installed() /* policies installed in kernel */
466 || !no_remote_configs(FALSE
)) { /* remote or anonymous configs */
467 SCHED_KILL(lcconf
->auto_exit_sched
);
469 } else { /* exit not scheduled */
470 if (lcconf
->auto_exit_state
== LC_AUTOEXITSTATE_ENABLED
471 && !vpn_control_connected()
472 && !policies_installed()
473 && no_remote_configs(FALSE
)) {
474 if (lcconf
->auto_exit_delay
== 0) {
475 auto_exit_do(NULL
); /* immediate exit */
477 lcconf
->auto_exit_sched
= sched_new(lcconf
->auto_exit_delay
, auto_exit_do
, NULL
);
483 static int signals
[] = {
500 * XXX We are not able to tell if we got
501 * several time the same signal. This is
502 * not a problem for the current code,
503 * but we shall remember this limitation.
505 for (sig
= 0; sig
<= NSIG
; sig
++) {
506 if (sigreq
[sig
] == 0)
514 /* Catch up childs, mainly scripts.
520 if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM
)) != 0) {
522 "ISAKMP mode config structure reset failed, "
531 * if we got a HUP... try graceful teardown of sessions before we close and reopen sockets...
532 * so that info-deletes notifications can make it to the peer.
535 ike_session_flush_all_phase2(true);
536 ike_session_flush_all_phase1(true);
539 /* Save old configuration, load new one... */
540 if (cfreparse(sig
)) {
542 "configuration read failed\n");
545 if (lcconf
->logfile_param
== NULL
&& logFileStr
[0] == 0)
546 plogresetfile(lcconf
->pathinfo
[LC_PATHTYPE_LOGFILE
]);
548 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
549 if (no_remote_configs(TRUE
)) {
550 #if ENABLE_NO_SA_FLUSH
553 pfkey_send_flush(lcconf
->sock_pfkey
, SADB_SATYPE_UNSPEC
);
554 #ifdef ENABLE_FASTQUIT
557 sched_new(1, check_flushsa_stub
, NULL
);
558 #endif /* ENABLE_FASTQUIT */
560 #endif /* ENABLE_NO_SA_FLUSH */
562 #endif // (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
568 plog(ASL_LEVEL_NOTICE
,
569 "caught signal %d\n", sig
);
570 #if ENABLE_NO_SA_FLUSH
573 pfkey_send_flush(lcconf
->sock_pfkey
,
575 if ( sig
== SIGTERM
){
576 terminated
= 1; /* in case if it hasn't been set yet */
580 sched_new(1, check_flushsa_stub
, NULL
);
583 #endif /* ENABLE_NO_SA_FLUSH */
587 plog(ASL_LEVEL_NOTICE
,
588 "caught signal %d\n", sig
);
596 * asynchronous requests will actually dispatched in the
597 * main loop in session().
600 signal_handler(int sig
, siginfo_t
*sigi
, void *ctx
)
603 plog(ASL_LEVEL_NOTICE
,
604 "%s received signal %d from pid %d uid %d\n\n",
605 __FUNCTION__
, sig
, sigi
->si_pid
, sigi
->si_uid
);
608 /* Do not just set it to 1, because we may miss some signals by just setting
612 if ( sig
== SIGTERM
){
616 pending_signal_handle
= 1;
617 dispatch_async(main_queue
,
619 if (pending_signal_handle
) {
621 pending_signal_handle
= 0;
632 for (i
= 0; signals
[i
] != 0; i
++) {
633 if (set_signal(signals
[i
], signal_handler
) < 0) {
635 "failed to set_signal (%s)\n",
644 set_signal(int sig
, RETSIGTYPE (*func
) (int, siginfo_t
*, void *))
648 memset((caddr_t
)&sa
, 0, sizeof(sa
));
649 sa
.sa_sigaction
= func
;
650 sa
.sa_flags
= SA_RESTART
| SA_SIGINFO
;
652 if (sigemptyset(&sa
.sa_mask
) < 0)
655 if (sigaction(sig
, &sa
, (struct sigaction
*)0) < 0)
662 fatal_error(int error
)
664 close_session(error
== 0 ? -1 : error
);
667 /* suspend all socket sources except pf_key */
671 if (lcconf
->rt_source
)
672 dispatch_suspend(lcconf
->rt_source
);
673 if (lcconf
->vpncontrol_source
)
674 dispatch_suspend(lcconf
->vpncontrol_source
);
675 isakmp_suspend_sockets();
684 #ifdef ENABLE_VPNCONTROL_PORT