X-Git-Url: https://git.saurik.com/apple/ipsec.git/blobdiff_plain/fd507379c886424c32550ce6b5ad547bb6db5d70..e627a751fc4d26304657fc20440abb72632b1e6e:/ipsec-tools/racoon/session.c?ds=sidebyside diff --git a/ipsec-tools/racoon/session.c b/ipsec-tools/racoon/session.c index 2f9f557..208ff5d 100644 --- a/ipsec-tools/racoon/session.c +++ b/ipsec-tools/racoon/session.c @@ -1,3 +1,5 @@ +/* $NetBSD: session.c,v 1.7.6.2 2007/08/01 11:52:22 vanhu Exp $ */ + /* $KAME: session.c,v 1.32 2003/09/24 02:01:17 jinmei Exp $ */ /* @@ -62,6 +64,15 @@ #include #include +#include +#include +#include + +#include +#include +#include +#include + #include "libpfkey.h" #include "var.h" @@ -69,99 +80,211 @@ #include "vmbuf.h" #include "plog.h" #include "debug.h" +#include "plog.h" #include "schedule.h" #include "session.h" #include "grabmyaddr.h" -#include "evt.h" #include "cfparse_proto.h" #include "isakmp_var.h" -#include "admin_var.h" -#include "admin.h" -#include "privsep.h" +#include "isakmp_xauth.h" +#include "isakmp_cfg.h" #include "oakley.h" #include "pfkey.h" #include "handler.h" #include "localconf.h" #include "remoteconf.h" -#include "backupsa.h" #ifdef ENABLE_NATT #include "nattraversal.h" #endif #include "vpn_control_var.h" #include "policy.h" +#include "algorithm.h" /* XXX ??? */ + +#include "sainfo.h" +#include "power_mgmt.h" + +#include +#include +#include + extern pid_t racoon_pid; -static void close_session __P((void)); -static void check_rtsock __P((void *)); -static void initfds __P((void)); -static void init_signal __P((void)); -static int set_signal __P((int sig, RETSIGTYPE (*func) __P((int)))); -static void check_sigreq __P((void)); -static void check_flushsa_stub __P((void *)); -static void check_flushsa __P((void)); -static void auto_exit_do __P((void *)); -static int close_sockets __P((void)); - -static fd_set mask0; -static fd_set maskdying; -static int nfds = 0; +extern int launchdlaunched; +static void close_session (int); +static int init_signal (void); +static int set_signal (int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *)); +static void check_flushsa_stub (void *); +static void check_flushsa (void); +static void auto_exit_do (void *); +static int close_sockets (void); + static volatile sig_atomic_t sigreq[NSIG + 1]; -static int dying = 0; -static struct sched *check_rtsock_sched = NULL; +int terminated = 0; +int pending_signal_handle = 0; + +static int64_t racoon_keepalive = -1; + +dispatch_queue_t main_queue; + +static NEPolicySessionRef policySession = NULL; + +/* + * This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly) + * launched on demand and for requires a keepalive on dirty/failure exits. + * The launchd plist can't be used for this because RunOnLoad is required to have keepalive on a failure exit. + */ +int64_t +launchd_update_racoon_keepalive (Boolean enabled) +{ + if (launchdlaunched) { + int64_t val = (__typeof__(val))enabled; + /* Set our own KEEPALIVE value */ + if (vproc_swap_integer(NULL, + VPROC_GSK_BASIC_KEEPALIVE, + &val, + &racoon_keepalive)) { + plog(ASL_LEVEL_ERR, + "failed to swap launchd keepalive integer %d\n", enabled); + } + } + return racoon_keepalive; +} + +static CFUUIDRef +copy_racoon_proc_uuid(void) +{ + struct proc_uniqidentifierinfo procu; + CFUUIDBytes uuidBytes; + int size = 0; + + memset(&procu, 0, sizeof(procu)); + size = proc_pidinfo(getpid(), PROC_PIDUNIQIDENTIFIERINFO, 1, &procu, PROC_PIDUNIQIDENTIFIERINFO_SIZE); + if (size != PROC_PIDUNIQIDENTIFIERINFO_SIZE) { + return (NULL); + } + + memcpy(&uuidBytes, procu.p_uuid, sizeof(CFUUIDBytes)); + return CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, uuidBytes); +} + +static bool +policy_session_init(void) +{ + bool success = true; + policySession = NEPolicyCreateSession(kCFAllocatorDefault, CFSTR("racoon"), NULL, NULL); + if (policySession == NULL) { + return false; + } + + CFUUIDRef proc_uuid = copy_racoon_proc_uuid(); + if (proc_uuid == NULL) { + return false; + } + + CFMutableArrayRef conditions = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + if (conditions) { + CFMutableDictionaryRef uuidCondition = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (uuidCondition) { + CFDictionarySetValue(uuidCondition, kNEPolicyConditionType, kNEPolicyValPolicyConditionTypeApplication); + CFDictionarySetValue(uuidCondition, kNEPolicyApplicationUUID, proc_uuid); + CFArrayAppendValue(conditions, uuidCondition); + CFRelease(uuidCondition); + } else { + success = false; + } + + CFMutableDictionaryRef interfacesCondition = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (interfacesCondition) { + CFDictionarySetValue(interfacesCondition, kNEPolicyConditionType, kNEPolicyValPolicyConditionTypeAllInterfaces); + CFArrayAppendValue(conditions, interfacesCondition); + CFRelease(interfacesCondition); + } else { + success = false; + } + } else { + success = false; + } + + CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (result) { + CFDictionaryAddValue(result, kNEPolicyResult, kNEPolicyValPolicyResultPass); + } else { + success = false; + } + + if (success) { + success = (NEPolicyAdd(policySession, 0, conditions, result, NULL) != kNEPolicyIDInvalid); + } + + if (result) { + CFRelease(result); + } + if (conditions) { + CFRelease(conditions); + } + if (proc_uuid) { + CFRelease(proc_uuid); + } + + return (success && NEPolicyApply(policySession)); +} -int +// +// Session +// +// Initialize listening sockets, timers, vpn control etc., +// write the PID file and call dispatch_main. +// +void session(void) { - fd_set rfds; - struct timeval *timeout; - int error; - struct myaddrs *p; char pid_file[MAXPATHLEN]; FILE *fp; - int i, update_fds; + int i; + + main_queue = dispatch_get_main_queue(); /* initialize schedular */ sched_init(); - initmyaddr(); - - if (isakmp_init() < 0) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to initialize isakmp"); + /* needs to be called after schedular */ + if (init_power_mgmt() < 0) { + plog(ASL_LEVEL_ERR, + "failed to initialize power-mgmt."); exit(1); } -#ifdef ENABLE_ADMINPORT - if (admin_init() < 0) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to initialize admin port"); - exit(1); + if (lcconf->autograbaddr == 1) + if (pfroute_init()) { + plog(ASL_LEVEL_ERR, "failed to initialize route socket.\n"); + exit(1); + } + + if (!policy_session_init()) { + plog(ASL_LEVEL_ERR, "failed to initialize NEPolicy session.\n"); } -#endif -#ifdef ENABLE_VPNCONTROL_PORT - if (vpncontrol_init() < 0) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to initialize vpn control port"); + + if (initmyaddr()) { + plog(ASL_LEVEL_ERR, "failed to initialize listening addresses.\n"); + exit(1); + } + if (isakmp_init()) { + plog(ASL_LEVEL_ERR, "failed to initialize isakmp"); exit(1); + } +#ifdef ENABLE_VPNCONTROL_PORT + if (vpncontrol_init()) { + plog(ASL_LEVEL_ERR, "failed to initialize vpn control port"); + //exit(1); } #endif - init_signal(); - initfds(); - -#ifndef __APPLE__ -#ifdef ENABLE_NATT - natt_keepalive_init (); -#endif -#endif - - if (privsep_init() != 0) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to initialize privsep"); - exit(1); - } - + if (init_signal()) { + plog(ASL_LEVEL_ERR, "failed to initialize signals.\n"); + exit(1); + } + for (i = 0; i <= NSIG; i++) sigreq[i] = 0; @@ -169,342 +292,67 @@ session(void) if (!f_foreground) { racoon_pid = getpid(); if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE] == NULL) - strlcpy(pid_file, _PATH_VARRUN "racoon.pid", MAXPATHLEN); + strlcpy(pid_file, _PATH_VARRUN "racoon.pid", sizeof(pid_file)); else if (lcconf->pathinfo[LC_PATHTYPE_PIDFILE][0] == '/') - strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN); + strlcpy(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); else { - strlcat(pid_file, _PATH_VARRUN, MAXPATHLEN); - strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], MAXPATHLEN); + strlcat(pid_file, _PATH_VARRUN, sizeof(pid_file)); + strlcat(pid_file, lcconf->pathinfo[LC_PATHTYPE_PIDFILE], sizeof(pid_file)); } fp = fopen(pid_file, "w"); if (fp) { if (fchmod(fileno(fp), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { - syslog(LOG_ERR, "%s", strerror(errno)); + plog(ASL_LEVEL_ERR, "%s", strerror(errno)); fclose(fp); exit(1); } fprintf(fp, "%ld\n", (long)racoon_pid); fclose(fp); } else { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "cannot open %s", pid_file); } } - - while (1) { - if (!TAILQ_EMPTY(&lcconf->saved_msg_queue)) - pfkey_post_handler(); - update_fds = 0; - /* - * asynchronous requests via signal. - * make sure to reset sigreq to 0. - */ - check_sigreq(); - - /* scheduling */ - timeout = schedular(); - - if (dying) - rfds = maskdying; - else - rfds = mask0; - error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout); - if (error < 0) { - switch (errno) { - case EINTR: - continue; - default: - plog(LLV_ERROR2, LOCATION, NULL, - "failed select (%s)\n", - strerror(errno)); - exit(1); - } - /*NOTREACHED*/ - } - -#ifdef ENABLE_ADMINPORT - if ((lcconf->sock_admin != -1) && - (FD_ISSET(lcconf->sock_admin, &rfds))) - admin_handler(); -#endif -#ifdef ENABLE_VPNCONTROL_PORT - { - struct vpnctl_socket_elem *elem; - struct vpnctl_socket_elem *t_elem; - - if ((lcconf->sock_vpncontrol != -1) && - (FD_ISSET(lcconf->sock_vpncontrol, &rfds))) { - vpncontrol_handler(); - update_fds = 1; // in case new socket created - update mask - } - /* The handler may close and remove the list element - * so we can't rely on it being valid after calling - * the handler. - */ - LIST_FOREACH_SAFE(elem, &lcconf->vpnctl_comm_socks, chain, t_elem) { - if ((elem->sock != -1) && - (FD_ISSET(elem->sock, &rfds))) - if (vpncontrol_comm_handler(elem)) - update_fds = 1; // socket closed by peer - update mask - } - } -#endif - - for (p = lcconf->myaddrs; p; p = p->next) { - if (!p->addr) - continue; - if (FD_ISSET(p->sock, &rfds)) - if ((error = isakmp_handler(p->sock)) == -2) - break; - } - if (error == -2) { - if (lcconf->autograbaddr) { - /* serious socket problem - close all listening sockets and re-open */ - isakmp_close(); - initfds(); - sched_new(5, check_rtsock, NULL); - continue; - } else { - isakmp_close_sockets(); - isakmp_open(); - initfds(); - continue; - } - } - - if (FD_ISSET(lcconf->sock_pfkey, &rfds)) - pfkey_handler(); - - if (lcconf->rtsock >= 0 && FD_ISSET(lcconf->rtsock, &rfds)) { - if (update_myaddrs() && lcconf->autograbaddr) - if (check_rtsock_sched == NULL) /* only schedule if not already done */ - check_rtsock_sched = sched_new(5, check_rtsock, NULL); - // initfds(); //%%% BUG FIX - not needed here - } - if (update_fds) { - initfds(); - update_fds = 0; - } - } + + xpc_transaction_begin(); + +#if !TARGET_OS_EMBEDDED + // enable keepalive for recovery (from crashes and bad exits... after init) + (void)launchd_update_racoon_keepalive(true); +#endif // !TARGET_OS_EMBEDDED + + // Off to the races! + if (!terminated) { + dispatch_main(); + } + + exit(1); // should not be reached!!! } /* clear all status and exit program. */ static void -close_session() +close_session(int error) { - flushph1(); + sched_killall(); + cleanup_power_mgmt(); + if ( terminated ) + ike_session_flush_all_phase2(false); + ike_session_flush_all_phase1(false); close_sockets(); - backupsa_clean(); - - plog(LLV_INFO, LOCATION, NULL, "racoon shutdown\n"); - exit(0); -} - -static void -check_rtsock(p) - void *p; -{ - - check_rtsock_sched = NULL; - grab_myaddrs(); - isakmp_close_unused(); - - autoconf_myaddrsport(); - isakmp_open(); - - /* initialize socket list again */ - initfds(); -} - -static void -initfds() -{ - struct myaddrs *p; - - nfds = 0; - - FD_ZERO(&mask0); - FD_ZERO(&maskdying); - -#ifdef ENABLE_ADMINPORT - if (lcconf->sock_admin != -1) { - if (lcconf->sock_admin >= FD_SETSIZE) { - plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - admin socket\n"); - exit(1); - } - FD_SET(lcconf->sock_admin, &mask0); - /* XXX should we listen on admin socket when dying ? - */ -#if 0 - FD_SET(lcconf->sock_admin, &maskdying); -#endif - nfds = (nfds > lcconf->sock_admin ? nfds : lcconf->sock_admin); - } -#endif -#ifdef ENABLE_VPNCONTROL_PORT - { - struct vpnctl_socket_elem *elem; - - if (lcconf->sock_vpncontrol != -1) { - if (lcconf->sock_vpncontrol >= FD_SETSIZE) { - plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - vpncontrol socket\n"); - exit(1); - } - FD_SET(lcconf->sock_vpncontrol, &mask0); - nfds = (nfds > lcconf->sock_vpncontrol ? nfds : lcconf->sock_vpncontrol); - } - - LIST_FOREACH(elem, &lcconf->vpnctl_comm_socks, chain) { - if (elem->sock != -1) { - if (elem->sock >= FD_SETSIZE) { - plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun vpnctl_comm socket\n"); - exit(1); - } - FD_SET(elem->sock, &mask0); - nfds = (nfds > elem->sock ? nfds : elem->sock); - } - } - } - -#endif - - if (lcconf->sock_pfkey >= FD_SETSIZE) { - plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - pfkey socket\n"); - exit(1); - } - FD_SET(lcconf->sock_pfkey, &mask0); - FD_SET(lcconf->sock_pfkey, &maskdying); - nfds = (nfds > lcconf->sock_pfkey ? nfds : lcconf->sock_pfkey); - if (lcconf->rtsock >= 0) { - if (lcconf->rtsock >= FD_SETSIZE) { - plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - rt socket\n"); - exit(1); - } - FD_SET(lcconf->rtsock, &mask0); - nfds = (nfds > lcconf->rtsock ? nfds : lcconf->rtsock); - } - - for (p = lcconf->myaddrs; p; p = p->next) { - if (!p->addr) - continue; - if (p->sock < 0) - continue; - if (p->sock >= FD_SETSIZE) { - plog(LLV_ERROR2, LOCATION, NULL, "fd_set overrun - isakmp socket\n"); - exit(1); - } - FD_SET(p->sock, &mask0); - nfds = (nfds > p->sock ? nfds : p->sock); - } - nfds++; -} -static int signals[] = { - SIGHUP, - SIGINT, - SIGTERM, - SIGUSR1, - SIGUSR2, - SIGCHLD, - SIGPIPE, - 0 -}; + xpc_transaction_end(); + +#if !TARGET_OS_EMBEDDED + // a clean exit, so disable launchd keepalive + (void)launchd_update_racoon_keepalive(false); +#endif // !TARGET_OS_EMBEDDED -/* - * asynchronous requests will actually dispatched in the - * main loop in session(). - */ -RETSIGTYPE -signal_handler(sig) - int sig; -{ - /* Do not just set it to 1, because we may miss some signals by just setting - * values to 0/1 - */ - sigreq[sig]++; + plog(ASL_LEVEL_NOTICE, "racoon shutdown\n"); + exit(0); } -static void -check_sigreq() -{ - int sig; - - /* - * XXX We are not able to tell if we got - * several time the same signal. This is - * not a problem for the current code, - * but we shall remember this limitation. - */ - for (sig = 0; sig <= NSIG; sig++) { - if (sigreq[sig] == 0) - continue; - - sigreq[sig]--; - switch(sig) { - case 0: - return; - - /* Catch up childs, mainly scripts. - */ - case SIGCHLD: - { - pid_t pid; - int s; - - pid = wait(&s); - } - break; - -#ifdef DEBUG_RECORD_MALLOCATION - /* - * XXX This operation is signal handler unsafe and may lead to - * crashes and security breaches: See Henning Brauer talk at - * EuroBSDCon 2005. Do not run in production with this option - * enabled. - */ - case SIGUSR2: - DRM_dump(); - break; -#endif - - case SIGHUP: - /* Save old configuration, load new one... */ - isakmp_close(); - close(lcconf->rtsock); - if (cfreparse()) { - plog(LLV_ERROR2, LOCATION, NULL, - "configuration read failed\n"); - exit(1); - } - if (lcconf->logfile_param == NULL) - plogreset(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]); - - initmyaddr(); - isakmp_cleanup(); - isakmp_init(); - initfds(); - break; - - case SIGINT: - case SIGTERM: - plog(LLV_INFO, LOCATION, NULL, - "caught signal %d\n", sig); - EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL); - pfkey_send_flush(lcconf->sock_pfkey, - SADB_SATYPE_UNSPEC); - sched_new(1, check_flushsa_stub, NULL); - dying = 1; - break; - - default: - plog(LLV_INFO, LOCATION, NULL, - "caught signal %d\n", sig); - break; - } - } -} /* * waiting the termination of processing until sending DELETE message @@ -514,7 +362,6 @@ static void check_flushsa_stub(p) void *p; { - check_flushsa(); } @@ -529,33 +376,33 @@ check_flushsa() buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); if (buf == NULL) { - plog(LLV_DEBUG, LOCATION, NULL, + plog(ASL_LEVEL_DEBUG, "pfkey_dump_sadb: returned nothing.\n"); return; } - msg = (struct sadb_msg *)buf->v; - end = (struct sadb_msg *)(buf->v + buf->l); + msg = ALIGNED_CAST(struct sadb_msg *)buf->v; + end = ALIGNED_CAST(struct sadb_msg *)(buf->v + buf->l); /* counting SA except of dead one. */ n = 0; while (msg < end) { if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg)) break; - next = (struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len)); + next = ALIGNED_CAST(struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len)); // Wcast-align fix (void*) - aligned buffer + multiple of 64 if (msg->sadb_msg_type != SADB_DUMP) { msg = next; continue; } if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { - plog(LLV_ERROR, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "pfkey_check (%s)\n", ipsec_strerror()); msg = next; continue; } - sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]); + sa = ALIGNED_CAST(struct sadb_sa *)(mhp[SADB_EXT_SA]); // Wcast-align fix (void*) - mhp contains pointers to aligned structs if (!sa) { msg = next; continue; @@ -578,63 +425,219 @@ check_flushsa() return; } - close_session(); +#if !TARGET_OS_EMBEDDED + if (lcconf->vt) + vproc_transaction_end(NULL, lcconf->vt); +#endif + close_session(0); } void auto_exit_do(void *p) { - EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL); + plog(ASL_LEVEL_NOTICE, + "performing auto exit\n"); +#if ENABLE_NO_SA_FLUSH + close_session(0); +#else pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); sched_new(1, check_flushsa_stub, NULL); - dying = 1; + dying(); +#endif /* ENABLE_NO_SA_FLUSH */ } void check_auto_exit(void) { - - if (lcconf->auto_exit_sched != NULL) { /* exit scheduled? */ + if (lcconf->auto_exit_sched) { /* exit scheduled? */ if (lcconf->auto_exit_state != LC_AUTOEXITSTATE_ENABLED - || vpn_control_connected() /* vpn control connected */ - || policies_installed()) /* policies installed in kernel */ + || vpn_control_connected() /* vpn control connected */ + || policies_installed() /* policies installed in kernel */ + || !no_remote_configs(FALSE)) { /* remote or anonymous configs */ SCHED_KILL(lcconf->auto_exit_sched); + } } else { /* exit not scheduled */ if (lcconf->auto_exit_state == LC_AUTOEXITSTATE_ENABLED - && !vpn_control_connected() - && !policies_installed()) - if (lcconf->auto_exit_delay == 0) - auto_exit_do(NULL); /* immediate exit */ - else - lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL); + && !vpn_control_connected() + && !policies_installed() + && no_remote_configs(FALSE)) { + if (lcconf->auto_exit_delay == 0) { + auto_exit_do(NULL); /* immediate exit */ + } else { + lcconf->auto_exit_sched = sched_new(lcconf->auto_exit_delay, auto_exit_do, NULL); + } + } } } +static int signals[] = { + SIGHUP, + SIGINT, + SIGTERM, + SIGUSR1, + SIGUSR2, + SIGPIPE, + 0 +}; -static void + +void +check_sigreq() +{ + int sig; + + /* + * XXX We are not able to tell if we got + * several time the same signal. This is + * not a problem for the current code, + * but we shall remember this limitation. + */ + for (sig = 0; sig <= NSIG; sig++) { + if (sigreq[sig] == 0) + continue; + + sigreq[sig]--; + switch(sig) { + case 0: + return; + + /* Catch up childs, mainly scripts. + */ + + case SIGUSR1: + case SIGHUP: +#ifdef ENABLE_HYBRID + if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) { + plog(ASL_LEVEL_ERR, + "ISAKMP mode config structure reset failed, " + "not reloading\n"); + return; + } +#endif + if ( terminated ) + break; + + /* + * if we got a HUP... try graceful teardown of sessions before we close and reopen sockets... + * so that info-deletes notifications can make it to the peer. + */ + if (sig == SIGHUP) { + ike_session_flush_all_phase2(true); + ike_session_flush_all_phase1(true); + } + + /* Save old configuration, load new one... */ + if (cfreparse(sig)) { + plog(ASL_LEVEL_ERR, + "configuration read failed\n"); + exit(1); + } + if (lcconf->logfile_param == NULL && logFileStr[0] == 0) + plogresetfile(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]); + +#if TARGET_OS_EMBEDDED + if (no_remote_configs(TRUE)) { +#if ENABLE_NO_SA_FLUSH + close_session(0); +#else + pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); +#ifdef ENABLE_FASTQUIT + close_session(0); +#else + sched_new(1, check_flushsa_stub, NULL); +#endif /* ENABLE_FASTQUIT */ + dying(); +#endif /* ENABLE_NO_SA_FLUSH */ + } +#endif + + break; + + case SIGINT: + case SIGTERM: + plog(ASL_LEVEL_NOTICE, + "caught signal %d\n", sig); +#if ENABLE_NO_SA_FLUSH + close_session(0); +#else + pfkey_send_flush(lcconf->sock_pfkey, + SADB_SATYPE_UNSPEC); + if ( sig == SIGTERM ){ + terminated = 1; /* in case if it hasn't been set yet */ + close_session(0); + } + else + sched_new(1, check_flushsa_stub, NULL); + + dying(); +#endif /* ENABLE_NO_SA_FLUSH */ + break; + + default: + plog(ASL_LEVEL_NOTICE, + "caught signal %d\n", sig); + break; + } + } +} + + +/* + * asynchronous requests will actually dispatched in the + * main loop in session(). + */ +RETSIGTYPE +signal_handler(int sig, siginfo_t *sigi, void *ctx) +{ +#if 0 + plog(ASL_LEVEL_NOTICE, + "%s received signal %d from pid %d uid %d\n\n", + __FUNCTION__, sig, sigi->si_pid, sigi->si_uid); +#endif + + /* Do not just set it to 1, because we may miss some signals by just setting + * values to 0/1 + */ + sigreq[sig]++; + if ( sig == SIGTERM ){ + terminated = 1; + } + + pending_signal_handle = 1; + dispatch_async(main_queue, + ^{ + if (pending_signal_handle) { + check_sigreq(); + pending_signal_handle = 0; + } + }); +} + + +static int init_signal() { int i; - for (i = 0; signals[i] != 0; i++) + for (i = 0; signals[i] != 0; i++) { if (set_signal(signals[i], signal_handler) < 0) { - plog(LLV_ERROR2, LOCATION, NULL, + plog(ASL_LEVEL_ERR, "failed to set_signal (%s)\n", strerror(errno)); - exit(1); + return (1); } + } + return 0; } static int -set_signal(sig, func) - int sig; - RETSIGTYPE (*func) __P((int)); +set_signal(int sig, RETSIGTYPE (*func) (int, siginfo_t *, void *)) { struct sigaction sa; memset((caddr_t)&sa, 0, sizeof(sa)); - sa.sa_handler = func; - sa.sa_flags = SA_RESTART; + sa.sa_sigaction = func; + sa.sa_flags = SA_RESTART | SA_SIGINFO; if (sigemptyset(&sa.sa_mask) < 0) return -1; @@ -645,17 +648,34 @@ set_signal(sig, func) return 0; } +void +fatal_error(int error) +{ + close_session(error == 0 ? -1 : error); +} + +/* suspend all socket sources except pf_key */ +void +dying(void) +{ + if (lcconf->rt_source) + dispatch_suspend(lcconf->rt_source); + if (lcconf->vpncontrol_source) + dispatch_suspend(lcconf->vpncontrol_source); + isakmp_suspend_sockets(); +} + static int close_sockets() { + pfroute_close(); isakmp_close(); - pfkey_close(lcconf->sock_pfkey); -#ifdef ENABLE_ADMINPORT - (void)admin_close(); -#endif + pfkey_close(); #ifdef ENABLE_VPNCONTROL_PORT vpncontrol_close(); #endif + return 0; } +