X-Git-Url: https://git.saurik.com/apple/ipsec.git/blobdiff_plain/e8d9021d008d9729f3dfcdc16bb03a990513b007..e627a751fc4d26304657fc20440abb72632b1e6e:/ipsec-tools/racoon/session.c diff --git a/ipsec-tools/racoon/session.c b/ipsec-tools/racoon/session.c index 8f15109..208ff5d 100644 --- a/ipsec-tools/racoon/session.c +++ b/ipsec-tools/racoon/session.c @@ -68,9 +68,10 @@ #include #include -#include #include #include +#include +#include #include "libpfkey.h" @@ -79,24 +80,20 @@ #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 "isakmp_xauth.h" #include "isakmp_cfg.h" -#include "admin_var.h" -#include "admin.h" -#include "privsep.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 @@ -107,58 +104,30 @@ #include "sainfo.h" #include "power_mgmt.h" +#include +#include +#include extern pid_t racoon_pid; -extern char logFileStr[]; -extern int launchedbylaunchd(void); -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, siginfo_t *, void *)))); -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; -#define HANDLE_TENTATIVE_INTF_FAILURES() do { \ - if (tentative_failures) { \ - plog(LLV_ERROR, LOCATION, NULL, \ - "detected tentative interface/address issues: will retry later.\n"); \ - if (check_rtsock_sched == NULL) { \ - /* only schedule if not already done */ \ - check_rtsock_sched = sched_new(5, check_rtsock, NULL); \ - } \ - } \ - } while(0) +static int64_t racoon_keepalive = -1; -static void -reinit_socks (void) -{ - int tentative_failures; - - isakmp_close(); - close(lcconf->rtsock); - initmyaddr(); - if (isakmp_open(&tentative_failures) < 0) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to reopen isakmp sockets\n"); - } - initfds(); - HANDLE_TENTATIVE_INTF_FAILURES(); -} +dispatch_queue_t main_queue; -static int64_t racoon_keepalive = -1; +static NEPolicySessionRef policySession = NULL; /* * This is used to (manually) update racoon's launchd keepalive, which is needed because racoon is (mostly) @@ -168,79 +137,154 @@ static int64_t racoon_keepalive = -1; int64_t launchd_update_racoon_keepalive (Boolean enabled) { - if (launchedbylaunchd()) { - vproc_t vp = vprocmgr_lookup_vproc("com.apple.racoon"); - if (vp) { - int64_t val = (__typeof__(val))enabled; - if (vproc_swap_integer(vp, - VPROC_GSK_BASIC_KEEPALIVE, - &val, - &racoon_keepalive)) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to swap launchd keepalive integer %d\n", enabled); - } - vproc_release(vp); + 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; } -int +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)); +} + +// +// 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 tentative_failures; + int i; + + main_queue = dispatch_get_main_queue(); /* initialize schedular */ sched_init(); /* needs to be called after schedular */ if (init_power_mgmt() < 0) { - errx(1, "failed to initialize power-mgmt."); + plog(ASL_LEVEL_ERR, + "failed to initialize power-mgmt."); + exit(1); } - initmyaddr(); - - if (isakmp_init(false, &tentative_failures) < 0) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to initialize isakmp"); - 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"); } - HANDLE_TENTATIVE_INTF_FAILURES(); - -#ifdef ENABLE_ADMINPORT - if (admin_init() < 0) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to initialize admin 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); - } -#endif + } #ifdef ENABLE_VPNCONTROL_PORT - if (vpncontrol_init() < 0) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to initialize vpn control port"); - exit(1); + if (vpncontrol_init()) { + plog(ASL_LEVEL_ERR, "failed to initialize vpn control port"); + //exit(1); } - #endif - init_signal(); - initfds(); - -#ifdef HAVE_OPENSSL - if (privsep_init() != 0) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to initialize privsep"); - exit(1); - } -#endif - + if (init_signal()) { + plog(ASL_LEVEL_ERR, "failed to initialize signals.\n"); + exit(1); + } + for (i = 0; i <= NSIG; i++) sigreq[i] = 0; @@ -259,407 +303,56 @@ session(void) 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); } } - + + 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 - 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(); - - check_power_mgmt(); - - /* scheduling */ - timeout = schedular(); - // Workaround: make sure timeout is playing nice - if (timeout) { - if (timeout->tv_usec < 0 || timeout->tv_usec > SELECT_USEC_MAX ) { - timeout->tv_sec += ((__typeof__(timeout->tv_sec))timeout->tv_usec)/SELECT_USEC_MAX; - timeout->tv_usec %= SELECT_USEC_MAX; - } - if (timeout->tv_sec > SELECT_SEC_MAX /* tv_sec is unsigned */) { - timeout->tv_sec = SELECT_SEC_MAX; - } - if (!timeout->tv_sec && !timeout->tv_usec) { - timeout->tv_sec = 1; - } - } - - 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) nfds %d\n", - strerror(errno), nfds); - reinit_socks(); - update_fds = 0; - continue; - } - /*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 ((p->sock != -1) && - (FD_ISSET(p->sock, &rfds))) - if ((error = isakmp_handler(p->sock)) == -2) - break; - } - if (error == -2) { - plog(LLV_ERROR2, LOCATION, NULL, - "failed to process isakmp port\n"); - reinit_socks(); - update_fds = 0; - 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(1, check_rtsock, NULL); - // initfds(); //%%% BUG FIX - not needed here - } - if (update_fds) { - initfds(); - update_fds = 0; - } - } + // 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) { + sched_killall(); + cleanup_power_mgmt(); if ( terminated ) - flushph2(false); - flushph1(false); + ike_session_flush_all_phase2(false); + ike_session_flush_all_phase1(false); close_sockets(); - backupsa_clean(); + xpc_transaction_end(); + #if !TARGET_OS_EMBEDDED // a clean exit, so disable launchd keepalive (void)launchd_update_racoon_keepalive(false); #endif // !TARGET_OS_EMBEDDED - plog(LLV_INFO, LOCATION, NULL, "racoon shutdown\n"); + plog(ASL_LEVEL_NOTICE, "racoon shutdown\n"); exit(0); } -static void -check_rtsock(p) - void *p; -{ - int tentative_failures; - - check_rtsock_sched = NULL; - grab_myaddrs(); - isakmp_close_unused(); - - autoconf_myaddrsport(); - isakmp_open(&tentative_failures); - - /* initialize socket list again */ - initfds(); - HANDLE_TENTATIVE_INTF_FAILURES(); -} - -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 -}; - -/* - * asynchronous requests will actually dispatched in the - * main loop in session(). - */ -RETSIGTYPE -signal_handler(sig, sigi, ctx) - int sig; - siginfo_t *sigi; - void *ctx; -{ -#if 0 - plog(LLV_DEBUG, LOCATION, NULL, - "%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; - } -} - -static void -check_sigreq() -{ - int sig; - int tentative_failures; - - /* - * 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 SIGUSR1: - case SIGHUP: -#ifdef ENABLE_HYBRID - if ((isakmp_cfg_init(ISAKMP_CFG_INIT_WARM)) != 0) { - plog(LLV_ERROR, LOCATION, NULL, - "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) { - flushph2(true); - flushph1(true); - } - /* Save old configuration, load new one... */ - isakmp_close(); - close(lcconf->rtsock); - if (cfreparse(sig)) { - plog(LLV_ERROR2, LOCATION, NULL, - "configuration read failed\n"); - exit(1); - } - if (lcconf->logfile_param == NULL && logFileStr[0] == 0) - plogreset(lcconf->pathinfo[LC_PATHTYPE_LOGFILE]); - - initmyaddr(); - isakmp_cleanup(); - isakmp_init(true, &tentative_failures); - HANDLE_TENTATIVE_INTF_FAILURES(); - initfds(); -#if TARGET_OS_EMBEDDED - if (no_remote_configs(TRUE)) { - EVT_PUSH(NULL, NULL, EVTT_RACOON_QUIT, NULL); - pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); -#ifdef ENABLE_FASTQUIT - close_session(); -#else - sched_new(1, check_flushsa_stub, NULL); -#endif - dying = 1; - } -#endif - 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); - if ( sig == SIGTERM ){ - terminated = 1; /* in case if it hasn't been set yet */ - close_session(); - } - else - 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 @@ -669,7 +362,6 @@ static void check_flushsa_stub(p) void *p; { - check_flushsa(); } @@ -684,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; @@ -733,69 +425,218 @@ 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(LLV_DEBUG, LOCATION, 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 */ - || !no_remote_configs(FALSE)) /* remote or anonymous configs */ + || 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() + && !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); + && 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, siginfo_t *, void *)); +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_sigaction = func; sa.sa_flags = SA_RESTART | SA_SIGINFO; if (sigemptyset(&sa.sa_mask) < 0) @@ -807,17 +648,33 @@ 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; }