]> git.saurik.com Git - apple/configd.git/blobdiff - configd.tproj/session.c
configd-293.8.tar.gz
[apple/configd.git] / configd.tproj / session.c
index 88577cdebdc1480f1c17563b84f28b8f9288291c..bc25fe2afc53496486a7bde947ec0a8f8aa35612 100644 (file)
@@ -1,57 +1,70 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2005, 2007-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- *
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
  * @APPLE_LICENSE_HEADER_END@
  */
 
+/*
+ * Modification History
+ *
+ * June 1, 2001                        Allan Nathanson <ajn@apple.com>
+ * - public API conversion
+ *
+ * March 24, 2000              Allan Nathanson <ajn@apple.com>
+ * - initial revision
+ */
+
 #include "configd.h"
 #include "configd_server.h"
 #include "session.h"
 
+#include <unistd.h>
+#include <bsm/libbsm.h>
+
 /* information maintained for each active session */
 static serverSessionRef        *sessions = NULL;
 static int             nSessions = 0;
 
 
+__private_extern__
 serverSessionRef
 getSession(mach_port_t server)
 {
        int     i;
 
        if (server == MACH_PORT_NULL) {
-               SCDLog(LOG_NOTICE, CFSTR("Excuse me, why is getSession() being called with an invalid port?"));
+               SCLog(TRUE, LOG_ERR, CFSTR("Excuse me, why is getSession() being called with an invalid port?"));
                return NULL;
        }
 
-       if (nSessions > 0) {
-               for (i=0; i<nSessions; i++) {
-                       serverSessionRef        thisSession = sessions[i];
-
-                       if (thisSession == NULL) {
-                               /* found an empty slot, skip it */
-                               continue;
-                       } else if (thisSession->key == server) {
-                               return thisSession;     /* we've seen this server before */
-                       } else if ((thisSession->session != NULL) &&
-                                  (((SCDSessionPrivateRef)thisSession->session)->notifySignalTask == server)) {
-                                       return thisSession;
-                       }
+       for (i = 0; i < nSessions; i++) {
+               serverSessionRef        thisSession = sessions[i];
+
+               if (thisSession == NULL) {
+                       /* found an empty slot, skip it */
+                       continue;
+               } else if (thisSession->key == server) {
+                       return thisSession;     /* we've seen this server before */
+               } else if (thisSession->store &&
+                          (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) {
+                       return thisSession;
                }
        }
 
@@ -60,11 +73,13 @@ getSession(mach_port_t server)
 }
 
 
+__private_extern__
 serverSessionRef
-addSession(CFMachPortRef server)
+addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info))
 {
-       int     i;
-       int     n = -1;
+       CFMachPortContext       context = { 0, NULL, NULL, NULL, NULL };
+       mach_port_t             mp      = server;
+       int                     n = -1;
 
        if (nSessions <= 0) {
                /* new session (actually, the first) found */
@@ -72,33 +87,69 @@ addSession(CFMachPortRef server)
                n = 0;
                nSessions = 1;
        } else {
-               for (i=0; i<nSessions; i++) {
+               int     i;
+
+               for (i = 0; i < nSessions; i++) {
                        if (sessions[i] == NULL) {
                                /* found an empty slot, use it */
                                n = i;
+                               break;
                        }
                }
                /* new session identified */
                if (n < 0) {
                        /* no empty slots, add one to the list */
                        n = nSessions++;
-                       sessions = realloc(sessions, ((nSessions) * sizeof(serverSessionRef)));
+                       sessions = reallocf(sessions, ((nSessions) * sizeof(serverSessionRef)));
                }
        }
 
-       SCDLog(LOG_DEBUG, CFSTR("Allocating new session for port %d"), CFMachPortGetPort(server));
+       // allocate a new session for this server
        sessions[n] = malloc(sizeof(serverSession));
-       sessions[n]->key                 = CFMachPortGetPort(server);
-       sessions[n]->serverPort          = server;
-       sessions[n]->serverRunLoopSource = NULL;
-       sessions[n]->session             = NULL;
-       sessions[n]->callerEUID          = 1;           /* not "root" */
-       sessions[n]->callerEGID          = 1;           /* not "wheel" */
+       bzero(sessions[n], sizeof(serverSession));
+
+       // create server port
+       context.info            = sessions[n];
+       context.copyDescription = copyDescription;
+
+       if (server == MACH_PORT_NULL) {
+               // create mach port for SCDynamicStore client
+               (void) mach_port_allocate(mach_task_self(),
+                                         MACH_PORT_RIGHT_RECEIVE,
+                                         &mp);
+       }
+
+       //
+       // Note: we create the CFMachPort *before* we insert a send
+       //       right present to ensure that CF does not establish
+       //       its dead name notification.
+       //
+       sessions[n]->serverPort = CFMachPortCreateWithPort(NULL,
+                                                          mp,
+                                                          configdCallback,
+                                                          &context,
+                                                          NULL);
+
+       if (server == MACH_PORT_NULL) {
+               // insert send right that will be moved to the client
+               (void) mach_port_insert_right(mach_task_self(),
+                                             mp,
+                                             mp,
+                                             MACH_MSG_TYPE_MAKE_SEND);
+       }
+
+       sessions[n]->key                 = mp;
+//     sessions[n]->serverRunLoopSource = NULL;
+//     sessions[n]->store               = NULL;
+       sessions[n]->callerEUID          = 1;           /* not "root" */
+       sessions[n]->callerRootAccess    = UNKNOWN;
+       sessions[n]->callerWriteAccess   = UNKNOWN;
 
        return sessions[n];
 }
 
 
+__private_extern__
 void
 removeSession(mach_port_t server)
 {
@@ -106,7 +157,7 @@ removeSession(mach_port_t server)
        serverSessionRef        thisSession;
        CFStringRef             sessionKey;
 
-       for (i=0; i<nSessions; i++) {
+       for (i = 0; i < nSessions; i++) {
                thisSession = sessions[i];
 
                if (thisSession == NULL) {
@@ -135,12 +186,13 @@ removeSession(mach_port_t server)
 }
 
 
+__private_extern__
 void
 cleanupSession(mach_port_t server)
 {
        int             i;
 
-       for (i=0; i<nSessions; i++) {
+       for (i = 0; i < nSessions; i++) {
                serverSessionRef        thisSession = sessions[i];
 
                if ((thisSession != NULL) && (thisSession->key == server)) {
@@ -148,25 +200,36 @@ cleanupSession(mach_port_t server)
                         * session entry still exists.
                         */
 
+                       if (_configd_trace) {
+                               SCTrace(TRUE, _configd_trace, CFSTR("cleanup : %5d\n"), server);
+                       }
+
                        /*
                         * Ensure that any changes made while we held the "lock"
                         * are discarded.
                         */
-                       if (SCDOptionGet(NULL, kSCDOptionIsLocked) &&
-                           SCDOptionGet(thisSession->session, kSCDOptionIsLocked)) {
+                       if ((storeLocked > 0) &&
+                           ((SCDynamicStorePrivateRef)thisSession->store)->locked) {
                                /*
-                                * swap cache and associated data which, after
+                                * swap store and associated data which, after
                                 * being closed, will result in the restoration
                                 * of the original pre-"locked" data.
                                 */
-                               _swapLockedCacheData();
+                               _swapLockedStoreData();
                        }
 
                        /*
                         * Close any open connections including cancelling any outstanding
                         * notification requests and releasing any locks.
                         */
-                       (void) _SCDClose(&thisSession->session);
+                       __MACH_PORT_DEBUG(TRUE, "*** cleanupSession", server);
+                       (void) __SCDynamicStoreClose(&thisSession->store, TRUE);
+                       __MACH_PORT_DEBUG(TRUE, "*** cleanupSession (after __SCDynamicStoreClose)", server);
+
+                       /*
+                        * Our send right has already been removed. Remove our receive right.
+                        */
+                       (void) mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_RECEIVE, -1);
 
                        /*
                         * Lastly, remove the session entry.
@@ -176,33 +239,186 @@ cleanupSession(mach_port_t server)
                        return;
                }
        }
+
+       SCLog(TRUE, LOG_ERR, CFSTR("MACH_NOTIFY_NO_SENDERS w/no session, port = %d"), server);
+       __MACH_PORT_DEBUG(TRUE, "*** cleanupSession w/no session", server);
        return;
 }
 
 
+__private_extern__
 void
-listSessions()
+listSessions(FILE *f)
 {
        int     i;
 
-       fprintf(stderr, "Current sessions:");
-       for (i=0; i<nSessions; i++) {
+       SCPrint(TRUE, f, CFSTR("Current sessions :\n"));
+       for (i = 0; i < nSessions; i++) {
                serverSessionRef        thisSession = sessions[i];
 
                if (thisSession == NULL) {
                        continue;
                }
 
-               fprintf(stderr, " %d", thisSession->key);
+               SCPrint(TRUE, f, CFSTR("\t%d : port = 0x%x"), i, thisSession->key);
+
+               if (thisSession->store != NULL) {
+                       SCDynamicStorePrivateRef        storePrivate    = (SCDynamicStorePrivateRef)thisSession->store;
+
+                       if (storePrivate->notifySignalTask != TASK_NULL) {
+                              SCPrint(TRUE, f, CFSTR(", task = %d"), storePrivate->notifySignalTask);
+                       }
+               }
+
+               if (sessionData != NULL) {
+                       CFDictionaryRef info;
+                       CFStringRef     key;
 
-               if (thisSession->session != NULL) {
-                       task_t  task = ((SCDSessionPrivateRef)thisSession->session)->notifySignalTask;
+                       key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), thisSession->key);
+                       info = CFDictionaryGetValue(sessionData, key);
+                       CFRelease(key);
+                       if (info != NULL) {
+                               CFStringRef     name;
 
-                       if (task != TASK_NULL) {
-                              fprintf(stderr, "/%d", task);
+                               name = CFDictionaryGetValue(info, kSCDName);
+                               if (name != NULL) {
+                                       SCPrint(TRUE, f, CFSTR(", name = %@"), name);
+                               }
                        }
                }
+
+               if (thisSession->serverPort != NULL) {
+                       SCPrint(TRUE, f, CFSTR("\n\t\t%@"), thisSession->serverPort);
+               }
+
+               if (thisSession->serverRunLoopSource != NULL) {
+                       SCPrint(TRUE, f, CFSTR("\n\t\t%@"), thisSession->serverRunLoopSource);
+               }
+
+               SCPrint(TRUE, f, CFSTR("\n"));
+       }
+
+       SCPrint(TRUE, f, CFSTR("\n"));
+       return;
+}
+
+
+#if    TARGET_OS_IPHONE
+
+#include <Security/Security.h>
+#include <Security/SecTask.h>
+
+static CFStringRef
+sessionName(serverSessionRef session)
+{
+       CFDictionaryRef info;
+       CFStringRef     name    = NULL;
+       CFStringRef     sessionKey;
+
+       sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), session->key);
+       info = CFDictionaryGetValue(sessionData, sessionKey);
+       CFRelease(sessionKey);
+
+       if (info != NULL) {
+               name = CFDictionaryGetValue(info, kSCDName);
+       }
+
+       return (name != NULL) ? name : CFSTR("???");
+}
+
+
+static Boolean
+hasEntitlement(serverSessionRef session, CFStringRef entitlement)
+{
+       Boolean         hasEntitlement  = FALSE;
+       SecTaskRef      task;
+
+       /* Create the security task from the audit token. */
+       task = SecTaskCreateWithAuditToken(NULL, session->auditToken);
+       if (task != NULL) {
+               CFErrorRef      error   = NULL;
+               CFTypeRef       value;
+
+               /* Get the value for the entitlement. */
+               value = SecTaskCopyValueForEntitlement(task, kSCWriteEntitlementName, &error);
+               if (value != NULL) {
+                       if (isA_CFBoolean(value)) {
+                               if (CFBooleanGetValue(value)) {
+                                       /* if client DOES have entitlement */
+                                       hasEntitlement = YES;
+                               }
+                       } else {
+                               SCLog(TRUE, LOG_ERR,
+                                     CFSTR("hasEntitlement: entitlement not valid: %@"),
+                                     sessionName(session));
+                       }
+
+                       CFRelease(value);
+               } else if (error != NULL) {
+                       SCLog(TRUE, LOG_ERR,
+                             CFSTR("hasEntitlement SecTaskCopyValueForEntitlement() failed, error=%@: %@"),
+                             error,
+                             sessionName(session));
+                       CFRelease(error);
+               }
+
+               CFRelease(task);
+       } else {
+               SCLog(TRUE, LOG_ERR,
+                     CFSTR("hasEntitlement SecTaskCreateWithAuditToken() failed: %@"),
+                     sessionName(session));
+       }
+
+       return hasEntitlement;
+}
+
+#endif // TARGET_OS_IPHONE
+
+
+__private_extern__
+Boolean
+hasRootAccess(serverSessionRef session)
+{
+       if (session->callerRootAccess == UNKNOWN) {
+               /*
+                * get the credentials associated with the caller.
+                */
+               audit_token_to_au32(session->auditToken,
+                                   NULL,                       // auidp
+                                   &session->callerEUID,       // euid
+                                   NULL,                       // egid
+                                   NULL,                       // ruid
+                                   NULL,                       // rgid
+                                   NULL,                       // pid
+                                   NULL,                       // asid
+                                   NULL);                      // tid
+
+               session->callerRootAccess = (session->callerEUID == 0) ? YES : NO;
        }
-       fprintf(stderr, "\n");
+
+       return (session->callerRootAccess == YES) ? TRUE : FALSE;
 }
 
+
+__private_extern__
+Boolean
+hasWriteAccess(serverSessionRef session)
+{
+       if (session->callerWriteAccess == UNKNOWN) {
+               /* assume that the client DOES NOT have the entitlement */
+               session->callerWriteAccess = NO;
+
+               if (hasRootAccess(session)) {
+                       // grant write access to eUID==0 processes
+                       session->callerWriteAccess = YES;
+               }
+#if    TARGET_OS_IPHONE
+               else if (hasEntitlement(session, kSCWriteEntitlementName)) {
+                       // grant write access to "entitled" processes
+                       session->callerWriteAccess = YES;
+               }
+#endif // TARGET_OS_IPHONE
+       }
+
+       return (session->callerWriteAccess == YES) ? TRUE : FALSE;
+}