]> git.saurik.com Git - apple/ipsec.git/blobdiff - ipsec-tools/racoon/session.c
ipsec-317.220.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / session.c
index f5610768bffb12243e52ed86140db37a003c5415..208ff5dcb110e78d81555a8ed83cd8b0a062dd4e 100644 (file)
 #include <netinet/ip.h>
 #include <netinet/ip_icmp.h>
 
-#include <resolv.h>
 #include <TargetConditionals.h>
 #include <vproc_priv.h>
 #include <dispatch/dispatch.h>
+#include <xpc/xpc.h>
 
 #include "libpfkey.h"
 
 #include "sainfo.h"
 #include "power_mgmt.h"
 
+#include <NetworkExtension/NEPolicy.h>
+#include <sys/proc_info.h>
+#include <libproc.h>
 
 
 extern pid_t racoon_pid;
@@ -111,7 +114,6 @@ 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_sigreq (void);
 static void check_flushsa_stub (void *);
 static void check_flushsa (void);
 static void auto_exit_do (void *);
@@ -119,11 +121,14 @@ static int close_sockets (void);
 
 static volatile sig_atomic_t sigreq[NSIG + 1];
 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.
@@ -146,6 +151,85 @@ launchd_update_racoon_keepalive (Boolean 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));
+}
+
 //
 // Session
 // 
@@ -176,6 +260,11 @@ session(void)
             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");
+       }
+       
     if (initmyaddr()) {
         plog(ASL_LEVEL_ERR, "failed to initialize listening addresses.\n");
         exit(1);
@@ -225,6 +314,9 @@ session(void)
                                "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);
@@ -250,12 +342,14 @@ close_session(int error)
        ike_session_flush_all_phase1(false);
        close_sockets();
 
+       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(ASL_LEVEL_INFO, "racoon shutdown\n");
+       plog(ASL_LEVEL_NOTICE, "racoon shutdown\n");
        exit(0);
 }
 
@@ -341,11 +435,15 @@ check_flushsa()
 void
 auto_exit_do(void *p)
 {
-       plog(ASL_LEVEL_DEBUG, 
+       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();
+#endif /* ENABLE_NO_SA_FLUSH */
 }
 
 void
@@ -383,7 +481,7 @@ static int signals[] = {
 };
 
 
-static void
+void
 check_sigreq()
 {
        int sig;
@@ -439,13 +537,17 @@ check_sigreq()
                                            
 #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
+#endif /* ENABLE_FASTQUIT */
                     dying();
+#endif /* ENABLE_NO_SA_FLUSH */
                 }
 #endif
 
@@ -453,9 +555,12 @@ check_sigreq()
                 
             case SIGINT:
             case SIGTERM:                      
-                plog(ASL_LEVEL_INFO
+                plog(ASL_LEVEL_NOTICE
                      "caught signal %d\n", sig);
-                pfkey_send_flush(lcconf->sock_pfkey, 
+#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 */
@@ -465,10 +570,11 @@ check_sigreq()
                     sched_new(1, check_flushsa_stub, NULL);
                 
                                dying();
+#endif /* ENABLE_NO_SA_FLUSH */
                 break;
                 
             default:
-                plog(ASL_LEVEL_INFO
+                plog(ASL_LEVEL_NOTICE
                      "caught signal %d\n", sig);
                 break;
                }
@@ -484,7 +590,7 @@ RETSIGTYPE
 signal_handler(int sig, siginfo_t *sigi, void *ctx)
 {
 #if 0
-    plog(ASL_LEVEL_DEBUG, 
+    plog(ASL_LEVEL_NOTICE,
          "%s received signal %d from pid %d uid %d\n\n",
          __FUNCTION__, sig, sigi->si_pid, sigi->si_uid);
 #endif
@@ -496,9 +602,14 @@ signal_handler(int sig, siginfo_t *sigi, void *ctx)
     if ( sig == SIGTERM ){
         terminated = 1;
     }
+
+       pending_signal_handle = 1;
     dispatch_async(main_queue, 
                    ^{
-                        check_sigreq(); 
+                                               if (pending_signal_handle) {
+                                                       check_sigreq();
+                                                       pending_signal_handle = 0;
+                                               }
                    });
 }