+/* $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 $ */
/*
#include <sys/stat.h>
#include <paths.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+#include <TargetConditionals.h>
+#include <vproc_priv.h>
+#include <dispatch/dispatch.h>
+#include <xpc/xpc.h>
+
#include "libpfkey.h"
#include "var.h"
#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 <NetworkExtension/NEPolicy.h>
+#include <sys/proc_info.h>
+#include <libproc.h>
+
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 <rdar://problem/8768510> 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;
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
check_flushsa_stub(p)
void *p;
{
-
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;
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;
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;
}
+