/*
- * Copyright (c) 2000, 2001, 2003-2005, 2007-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2005, 2007-2020 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
- *
+ *
* 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,
* 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@
*/
#include <unistd.h>
#include <bsm/libbsm.h>
+#include <os/state_private.h>
#include <sandbox.h>
-#if !TARGET_IPHONE_SIMULATOR || (defined(IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED) && (IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED >= 1090))
+#if !TARGET_OS_SIMULATOR || (defined(IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED) && (IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED >= 1090))
#define HAVE_MACHPORT_GUARDS
#endif
-/* information maintained for each active session */
-static serverSessionRef *sessions = NULL;
-static int nSessions = 0; /* # of allocated sessions */
-static int lastSession = -1; /* # of last used session */
-
-/* CFMachPortInvalidation runloop */
-static CFRunLoopRef sessionRunLoop = NULL;
+/* information maintained for the main listener */
+static serverSessionRef server_session = NULL;
-/* temp session */
-static serverSessionRef temp_session = NULL;
+/*
+ * information maintained for each active session
+ * Note: sync w/sessionQueue()
+ */
+static CFMutableDictionaryRef client_sessions = NULL;
+static CFIndex client_sessions_advise = 250; // when snapshot handler should detail sessions
-__private_extern__
-serverSessionRef
-getSession(mach_port_t server)
+static dispatch_queue_t
+sessionQueue(void)
{
- int i;
+ static dispatch_once_t once;
+ static dispatch_queue_t q;
- if (server == MACH_PORT_NULL) {
- SCLog(TRUE, LOG_ERR, CFSTR("Excuse me, why is getSession() being called with an invalid port?"));
- return NULL;
- }
+ dispatch_once(&once, ^{
+ // allocate mapping between [client] session mach port and session info
+ client_sessions = CFDictionaryCreateMutable(NULL,
+ 0,
+ NULL, // use the actual mach_port_t as the key
+ &kCFTypeDictionaryValueCallBacks);
+
+ // and a queue to synchronize access to the mapping
+ q = dispatch_queue_create("SCDynamicStore/sessions", NULL);
+ });
- /* look for matching session (note: slot 0 is the "server" port) */
- for (i = 1; i <= lastSession; i++) {
- serverSessionRef thisSession = sessions[i];
+ return q;
+}
- if (thisSession == NULL) {
- /* found an empty slot, skip it */
- continue;
- }
- if (thisSession->key == server) {
- /* we've seen this server before */
- return thisSession;
- }
+#pragma mark -
+#pragma mark __serverSession object
- if ((thisSession->store != NULL) &&
- (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) {
- /* we've seen this task port before */
- return thisSession;
- }
- }
+static CFStringRef __serverSessionCopyDescription (CFTypeRef cf);
+static void __serverSessionDeallocate (CFTypeRef cf);
- /* no sessions available */
- return NULL;
-}
+static const CFRuntimeClass __serverSessionClass = {
+ 0, // version
+ "serverSession", // className
+ NULL, // init
+ NULL, // copy
+ __serverSessionDeallocate, // dealloc
+ NULL, // equal
+ NULL, // hash
+ NULL, // copyFormattingDesc
+ __serverSessionCopyDescription // copyDebugDesc
+};
+static CFTypeID __serverSessionTypeID = _kCFRuntimeNotATypeID;
-__private_extern__
-serverSessionRef
-tempSession(mach_port_t server, CFStringRef name, audit_token_t auditToken)
+
+static CFStringRef
+__serverSessionCopyDescription(CFTypeRef cf)
{
- static dispatch_once_t once;
- SCDynamicStorePrivateRef storePrivate;
+ CFAllocatorRef allocator = CFGetAllocator(cf);
+ CFMutableStringRef result;
+ serverSessionRef session = (serverSessionRef)cf;
- if (sessions[0]->key != server) {
- // if not SCDynamicStore "server" port
- return NULL;
- }
+ result = CFStringCreateMutable(allocator, 0);
+ CFStringAppendFormat(result, NULL, CFSTR("<serverSession %p [%p]> {"), cf, allocator);
- dispatch_once(&once, ^{
- temp_session = sessions[0]; /* use "server" session */
- (void) __SCDynamicStoreOpen(&temp_session->store, NULL);
- });
+ // add client port
+ CFStringAppendFormat(result, NULL, CFSTR("port = 0x%x (%d)"), session->key, session->key);
- /* save audit token, caller entitlements */
- temp_session->auditToken = auditToken;
- temp_session->callerEUID = 1; /* not "root" */
- temp_session->callerRootAccess = UNKNOWN;
- if ((temp_session->callerWriteEntitlement != NULL) &&
- (temp_session->callerWriteEntitlement != kCFNull)) {
- CFRelease(temp_session->callerWriteEntitlement);
+ // add session info
+ if (session->name != NULL) {
+ CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), session->name);
}
- temp_session->callerWriteEntitlement = kCFNull; /* UNKNOWN */
-
- /* save name */
- storePrivate = (SCDynamicStorePrivateRef)temp_session->store;
- if (storePrivate->name != NULL) CFRelease(storePrivate->name);
- storePrivate->name = CFRetain(name);
- return temp_session;
+ CFStringAppendFormat(result, NULL, CFSTR("}"));
+ return result;
}
-__private_extern__
-serverSessionRef
-addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info))
+static void
+__serverSessionDeallocate(CFTypeRef cf)
{
- CFMachPortContext context = { 0, NULL, NULL, NULL, NULL };
- kern_return_t kr;
- mach_port_t mp = server;
- int n = -1;
- serverSessionRef newSession = NULL;
-
- /* save current (SCDynamicStore) runloop */
- if (sessionRunLoop == NULL) {
- sessionRunLoop = CFRunLoopGetCurrent();
- }
-
- if (nSessions <= 0) {
- /* if first session (the "server" port) */
- n = 0; /* use slot "0" */
- lastSession = 0; /* last used slot */
-
- nSessions = 64;
- sessions = malloc(nSessions * sizeof(serverSessionRef));
-
- // allocate a new session for "the" server
- newSession = calloc(1, sizeof(serverSession));
- } else {
- int i;
-#ifdef HAVE_MACHPORT_GUARDS
- mach_port_options_t opts;
-#endif // HAVE_MACHPORT_GUARDS
-
- /* check to see if we already have an open session (note: slot 0 is the "server" port) */
- for (i = 1; i <= lastSession; i++) {
- serverSessionRef thisSession = sessions[i];
+#pragma unused(cf)
+ serverSessionRef session = (serverSessionRef)cf;
- if (thisSession == NULL) {
- /* found an empty slot */
- if (n < 0) {
- /* keep track of the first [empty] slot */
- n = i;
- }
+ if (session->changedKeys != NULL) CFRelease(session->changedKeys);
+ if (session->name != NULL) CFRelease(session->name);
+ if (session->sessionKeys != NULL) CFRelease(session->sessionKeys);
- /* and keep looking for a matching session */
- continue;
- }
+ return;
+}
- if (thisSession->key == server) {
- /* we've seen this server before */
- return NULL;
- }
- if ((thisSession->store != NULL) &&
- (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) {
- /* we've seen this task port before */
- return NULL;
- }
- }
+static serverSessionRef
+__serverSessionCreate(CFAllocatorRef allocator, mach_port_t server)
+{
+ static dispatch_once_t once;
+ serverSessionRef session;
+ uint32_t size;
- /* add a new session */
- if (n < 0) {
- /* if no empty slots */
- n = ++lastSession;
- if (lastSession >= nSessions) {
- /* expand the session list */
- nSessions *= 2;
- sessions = reallocf(sessions, (nSessions * sizeof(serverSessionRef)));
- }
- }
+ // initialize runtime
+ dispatch_once(&once, ^{
+ __serverSessionTypeID = _CFRuntimeRegisterClass(&__serverSessionClass);
+ });
- // allocate a session for this client
- newSession = calloc(1, sizeof(serverSession));
+ // allocate session
+ size = sizeof(serverSession) - sizeof(CFRuntimeBase);
+ session = (serverSessionRef)_CFRuntimeCreateInstance(allocator,
+ __serverSessionTypeID,
+ size,
+ NULL);
+ if (session == NULL) {
+ return NULL;
+ }
- // create mach port for SCDynamicStore client
- mp = MACH_PORT_NULL;
+ // if needed, allocate a mach port for SCDynamicStore client
+ if (server == MACH_PORT_NULL) {
+ kern_return_t kr;
+ mach_port_t mp = MACH_PORT_NULL;
+#ifdef HAVE_MACHPORT_GUARDS
+ mach_port_options_t opts;
+#endif // HAVE_MACHPORT_GUARDS
retry_allocate :
#ifdef HAVE_MACHPORT_GUARDS
- bzero(&opts, sizeof(opts));
+ memset(&opts, 0, sizeof(opts));
opts.flags = MPO_CONTEXT_AS_GUARD;
- kr = mach_port_construct(mach_task_self(), &opts, newSession, &mp);
+ kr = mach_port_construct(mach_task_self(), &opts, (mach_port_context_t)session, &mp);
#else // HAVE_MACHPORT_GUARDS
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
#endif // HAVE_MACHPORT_GUARDS
if (kr != KERN_SUCCESS) {
char *err = NULL;
- SCLog(TRUE, LOG_ERR, CFSTR("addSession: could not allocate mach port: %s"), mach_error_string(kr));
+ SC_log(LOG_NOTICE, "could not allocate mach port: %s", mach_error_string(kr));
if ((kr == KERN_NO_SPACE) || (kr == KERN_RESOURCE_SHORTAGE)) {
sleep(1);
goto retry_allocate;
}
- (void) asprintf(&err, "addSession: could not allocate mach port: %s", mach_error_string(kr));
- _SC_crash(err != NULL ? err : "addSession: could not allocate mach port",
+ (void) asprintf(&err, "Could not allocate mach port: %s", mach_error_string(kr));
+ _SC_crash(err != NULL ? err : "Could not allocate new session (mach) port",
NULL,
NULL);
if (err != NULL) free(err);
-
- free(newSession);
+ CFRelease(session);
return NULL;
}
- }
- // create server port
- context.info = newSession;
- context.copyDescription = copyDescription;
-
- //
- // Note: we create the CFMachPort *before* we insert a send
- // right present to ensure that CF does not establish
- // its dead name notification.
- //
- newSession->serverPort = _SC_CFMachPortCreateWithPort("SCDynamicStore/session",
- mp,
- configdCallback,
- &context);
-
- if (n > 0) {
// insert send right that will be moved to the client
kr = mach_port_insert_right(mach_task_self(),
mp,
* only happen if someone stomped on OUR port (so let's leave
* the port alone).
*/
- SCLog(TRUE, LOG_ERR, CFSTR("addSession mach_port_insert_right(): %s"), mach_error_string(kr));
-
- free(newSession);
+ SC_log(LOG_ERR, "mach_port_insert_right() failed: %s", mach_error_string(kr));
+ CFRelease(session);
return NULL;
}
+
+ server = mp;
}
- sessions[n] = newSession;
- sessions[n]->key = mp;
-// sessions[n]->serverRunLoopSource = NULL;
-// sessions[n]->store = NULL;
- sessions[n]->callerEUID = 1; /* not "root" */
- sessions[n]->callerRootAccess = UNKNOWN;
- sessions[n]->callerWriteEntitlement = kCFNull; /* UNKNOWN */
+ session->callerEUID = 1; /* not "root" */
+ session->callerRootAccess = UNKNOWN;
+ session->callerWriteEntitlement = kCFNull; /* UNKNOWN */
+ session->key = server;
+// session->store = NULL;
- return newSession;
+ return session;
}
-__private_extern__
-void
-cleanupSession(mach_port_t server)
+#pragma mark -
+#pragma mark SCDynamicStore state handler
+
+
+static void
+addSessionReference(const void *key, const void *value, void *context)
{
- int i;
+#pragma unused(key)
+ CFMutableDictionaryRef dict = (CFMutableDictionaryRef)context;
+ serverSessionRef session = (serverSessionRef)value;
+
+ if (session->name != NULL) {
+ int cnt;
+ CFNumberRef num;
+
+ if (!CFDictionaryGetValueIfPresent(dict,
+ session->name,
+ (const void **)&num) ||
+ !CFNumberGetValue(num, kCFNumberIntType, &cnt)) {
+ // if first session
+ cnt = 0;
+ }
+ cnt++;
+ num = CFNumberCreate(NULL, kCFNumberIntType, &cnt);
+ CFDictionarySetValue(dict, session->name, num);
+ CFRelease(num);
+ }
- for (i = 1; i <= lastSession; i++) {
- CFStringRef sessionKey;
- serverSessionRef thisSession = sessions[i];
+ return;
+}
- if (thisSession == NULL) {
- /* found an empty slot, skip it */
- continue;
+
+static void
+add_state_handler()
+{
+ os_state_block_t state_block;
+
+ state_block = ^os_state_data_t(os_state_hints_t hints) {
+#pragma unused(hints)
+ CFDataRef data = NULL;
+ CFIndex n;
+ Boolean ok;
+ os_state_data_t state_data;
+ size_t state_data_size;
+ CFIndex state_len;
+
+ n = CFDictionaryGetCount(client_sessions);
+ if (n < client_sessions_advise) {
+ CFStringRef str;
+
+ str = CFStringCreateWithFormat(NULL, NULL, CFSTR("n = %ld"), n);
+ ok = _SCSerialize(str, &data, NULL, NULL);
+ CFRelease(str);
+ } else {
+ CFMutableDictionaryRef dict;
+
+ dict = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFDictionaryApplyFunction(client_sessions, addSessionReference, dict);
+ ok = _SCSerialize(dict, &data, NULL, NULL);
+ CFRelease(dict);
}
- if (thisSession->key == server) {
- /*
- * session entry still exists.
- */
+ state_len = (ok && (data != NULL)) ? CFDataGetLength(data) : 0;
+ state_data_size = OS_STATE_DATA_SIZE_NEEDED(state_len);
+ if (state_data_size > MAX_STATEDUMP_SIZE) {
+ SC_log(LOG_ERR, "SCDynamicStore/sessions : state data too large (%zd > %zd)",
+ state_data_size,
+ (size_t)MAX_STATEDUMP_SIZE);
+ if (data != NULL) CFRelease(data);
+ return NULL;
+ }
- if (_configd_trace) {
- SCTrace(TRUE, _configd_trace, CFSTR("cleanup : %5d\n"), server);
- }
+ state_data = calloc(1, state_data_size);
+ if (state_data == NULL) {
+ SC_log(LOG_ERR, "SCDynamicStore/sessions: could not allocate state data");
+ if (data != NULL) CFRelease(data);
+ return NULL;
+ }
- /*
- * Close any open connections including cancelling any outstanding
- * notification requests and releasing any locks.
- */
- __MACH_PORT_DEBUG(TRUE, "*** cleanupSession", server);
- (void) __SCDynamicStoreClose(&thisSession->store);
- __MACH_PORT_DEBUG(TRUE, "*** cleanupSession (after __SCDynamicStoreClose)", server);
+ state_data->osd_type = OS_STATE_DATA_SERIALIZED_NSCF_OBJECT;
+ state_data->osd_data_size = (uint32_t)state_len;
+ strlcpy(state_data->osd_title, "SCDynamicStore/sessions", sizeof(state_data->osd_title));
+ if (state_len > 0) {
+ memcpy(state_data->osd_data, CFDataGetBytePtr(data), state_len);
+ }
+ if (data != NULL) CFRelease(data);
- /*
- * Our send right has already been removed. Remove our receive right.
- */
-#ifdef HAVE_MACHPORT_GUARDS
- (void) mach_port_destruct(mach_task_self(), server, 0, thisSession);
-#else // HAVE_MACHPORT_GUARDS
- (void) mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_RECEIVE, -1);
-#endif // HAVE_MACHPORT_GUARDS
+ return state_data;
+ };
- /*
- * release any entitlement info
- */
- if ((thisSession->callerWriteEntitlement != NULL) &&
- (thisSession->callerWriteEntitlement != kCFNull)) {
- CFRelease(thisSession->callerWriteEntitlement);
- }
+ (void) os_state_add_handler(sessionQueue(), state_block);
+ return;
+}
- /*
- * We don't need any remaining information in the
- * sessionData dictionary, remove it.
- */
- sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), server);
- CFDictionaryRemoveValue(sessionData, sessionKey);
- CFRelease(sessionKey);
- /*
- * get rid of the per-session structure.
- */
- free(thisSession);
- sessions[i] = NULL;
-
- if (i == lastSession) {
- /* we are removing the last session, update last used slot */
- while (--lastSession > 0) {
- if (sessions[lastSession] != NULL) {
- break;
- }
- }
- }
+#pragma mark -
+#pragma mark SCDynamicStore session management
- return;
- }
+
+__private_extern__
+serverSessionRef
+getSession(mach_port_t server)
+{
+ __block serverSessionRef session;
+
+ assert(server != MACH_PORT_NULL);
+ dispatch_sync(sessionQueue(), ^{
+ session = (serverSessionRef)CFDictionaryGetValue(client_sessions,
+ (const void *)(uintptr_t)server);
+ });
+
+ return session;
+}
+
+
+__private_extern__
+serverSessionRef
+getSessionNum(CFNumberRef serverNum)
+{
+ union {
+ mach_port_t mp;
+ uint64_t val;
+ } server;
+ serverSessionRef session;
+
+ (void) CFNumberGetValue(serverNum, kCFNumberSInt64Type, &server.val);
+ session = getSession(server.mp);
+
+ return session;
+}
+
+
+__private_extern__
+serverSessionRef
+getSessionStr(CFStringRef serverKey)
+{
+ mach_port_t server;
+ serverSessionRef session;
+ char str[16];
+
+ (void) _SC_cfstring_to_cstring(serverKey, str, sizeof(str), kCFStringEncodingASCII);
+ server = atoi(str);
+ session = getSession(server);
+
+ return session;
+}
+
+
+#if __has_feature(ptrauth_intrinsics)
+extern const struct { char c; } objc_absolute_packed_isa_class_mask;
+#endif
+
+static void
+memcpy_objc_object(void* dst, const void* restrict src, size_t size)
+{
+ // first, we copy the object
+ memcpy(dst, src, size);
+
+ // then, if needed, fix the isa pointer
+ #if __has_feature(ptrauth_intrinsics)
+ uintptr_t flags;
+ uintptr_t isa_mask;
+ void ** opaqueObject;
+ uintptr_t raw_isa;
+ uintptr_t real_isa;
+
+ opaqueObject = (void**)src;
+ isa_mask = (uintptr_t)&objc_absolute_packed_isa_class_mask;
+ flags = (uintptr_t)(*opaqueObject) & ~isa_mask;
+ real_isa = (uintptr_t)(*opaqueObject) & isa_mask;
+
+ #if __has_feature(ptrauth_objc_isa)
+ raw_isa = (uintptr_t)ptrauth_auth_data((void *)real_isa,
+ ptrauth_key_process_independent_data,
+ ptrauth_blend_discriminator(opaqueObject, 0x6AE1));
+ #else // __has_feature(ptrauth_objc_isa)
+ raw_isa = (uintptr_t)ptrauth_strip((void*)real_isa, ptrauth_key_process_independent_data);
+ #endif // __has_feature(ptrauth_objc_isa)
+ ((CFRuntimeBase*)dst)->_cfisa = raw_isa;
+ ((uint64_t*)dst)[0] |= flags;
+ #endif // __has_feature(ptrauth_intrinsics)
+}
+
+
+__private_extern__
+serverSessionRef
+tempSession(mach_port_t server, CFStringRef name, audit_token_t auditToken)
+{
+ static dispatch_once_t once;
+ SCDynamicStorePrivateRef storePrivate; /* temp session */
+ static serverSession temp_session;
+
+ dispatch_once(&once, ^{
+ memcpy_objc_object(&temp_session, /* use "server" session clone */
+ server_session,
+ sizeof(temp_session));
+ (void) __SCDynamicStoreOpen(&temp_session.store, NULL);
+ });
+
+ if (temp_session.key != server) {
+ // if not SCDynamicStore "server" port
+ return NULL;
}
- 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;
+ /* save audit token, caller entitlements */
+ temp_session.auditToken = auditToken;
+ temp_session.callerEUID = 1; /* not "root" */
+ temp_session.callerRootAccess = UNKNOWN;
+ if ((temp_session.callerWriteEntitlement != NULL) &&
+ (temp_session.callerWriteEntitlement != kCFNull)) {
+ CFRelease(temp_session.callerWriteEntitlement);
+ }
+ temp_session.callerWriteEntitlement = kCFNull; /* UNKNOWN */
+
+ /* save name */
+ storePrivate = (SCDynamicStorePrivateRef)temp_session.store;
+ if (storePrivate->name != NULL) CFRelease(storePrivate->name);
+ storePrivate->name = CFRetain(name);
+
+ return &temp_session;
}
__private_extern__
void
-listSessions(FILE *f)
+addSession(serverSessionRef session, Boolean isMain)
{
- int i;
+ session->serverChannel = dispatch_mach_create_f("configd/SCDynamicStore",
+ server_queue(),
+ (void *)session,
+ server_mach_channel_handler);
+ if (!isMain) {
+ // if not main SCDynamicStore port, watch for exit
+ dispatch_mach_notify_no_senders(session->serverChannel, FALSE);
+ }
+#if TARGET_OS_SIMULATOR
+ // simulators don't support MiG QoS propagation yet
+ dispatch_set_qos_class_fallback(session->serverChannel, QOS_CLASS_USER_INITIATED);
+#else
+ dispatch_set_qos_class_fallback(session->serverChannel, QOS_CLASS_BACKGROUND);
+#endif
+ dispatch_mach_connect(session->serverChannel, session->key, MACH_PORT_NULL, NULL);
+ return;
+}
- SCPrint(TRUE, f, CFSTR("Current sessions :\n"));
- for (i = 0; i <= lastSession; i++) {
- serverSessionRef thisSession = sessions[i];
- if (thisSession == NULL) {
- continue;
- }
+__private_extern__
+serverSessionRef
+addClient(mach_port_t server, audit_token_t audit_token)
+{
- SCPrint(TRUE, f, CFSTR("\t%d : port = 0x%x"), i, thisSession->key);
+ __block serverSessionRef newSession = NULL;
- if (thisSession->store != NULL) {
- SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)thisSession->store;
+ dispatch_sync(sessionQueue(), ^{
+ Boolean ok;
- if (storePrivate->notifySignalTask != TASK_NULL) {
- SCPrint(TRUE, f, CFSTR(", task = %d"), storePrivate->notifySignalTask);
- }
+ // check to see if we already have an open session
+ ok = CFDictionaryContainsKey(client_sessions,
+ (const void *)(uintptr_t)server);
+ if (ok) {
+ // if we've already added a session for this port
+ return;
}
- if (sessionData != NULL) {
- CFDictionaryRef info;
- CFStringRef key;
+ // allocate a new session for "the" server
+ newSession = __serverSessionCreate(NULL, MACH_PORT_NULL);
+ if (newSession != NULL) {
+ // and add a port --> session mapping
+ CFDictionarySetValue(client_sessions,
+ (const void *)(uintptr_t)newSession->key,
+ newSession);
- key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), thisSession->key);
- info = CFDictionaryGetValue(sessionData, key);
- CFRelease(key);
- if (info != NULL) {
- CFStringRef name;
+ // save the audit_token in case we need to check the callers credentials
+ newSession->auditToken = audit_token;
- name = CFDictionaryGetValue(info, kSCDName);
- if (name != NULL) {
- SCPrint(TRUE, f, CFSTR(", name = %@"), name);
- }
- }
+ CFRelease(newSession); // reference held by dictionary
}
+ });
- if (thisSession->serverPort != NULL) {
- SCPrint(TRUE, f, CFSTR("\n\t\t%@"), thisSession->serverPort);
- }
+ if (newSession != NULL) {
+ addSession(newSession, FALSE);
+ }
- if (thisSession->serverRunLoopSource != NULL) {
- SCPrint(TRUE, f, CFSTR("\n\t\t%@"), thisSession->serverRunLoopSource);
- }
+ return newSession;
+}
- SCPrint(TRUE, f, CFSTR("\n"));
+
+__private_extern__
+serverSessionRef
+addServer(mach_port_t server)
+{
+ // allocate a session for "the" server
+ server_session = __serverSessionCreate(NULL, server);
+ addSession(server_session, TRUE);
+
+ // add a state dump handler
+ add_state_handler();
+
+ return server_session;
+}
+
+
+__private_extern__
+void
+cleanupSession(serverSessionRef session)
+{
+ mach_port_t server = session->key;
+
+ SC_trace("cleanup : %5d", server);
+
+ /*
+ * Close any open connections including cancelling any outstanding
+ * notification requests and releasing any locks.
+ */
+ __MACH_PORT_DEBUG(TRUE, "*** cleanupSession", server);
+ (void) __SCDynamicStoreClose(&session->store);
+ __MACH_PORT_DEBUG(TRUE, "*** cleanupSession (after __SCDynamicStoreClose)", server);
+
+ /*
+ * Our send right has already been removed. Remove our receive right.
+ */
+#ifdef HAVE_MACHPORT_GUARDS
+ (void) mach_port_destruct(mach_task_self(), server, 0, (mach_port_context_t)session);
+#else // HAVE_MACHPORT_GUARDS
+ (void) mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_RECEIVE, -1);
+#endif // HAVE_MACHPORT_GUARDS
+
+ /*
+ * release any entitlement info
+ */
+ if ((session->callerWriteEntitlement != NULL) &&
+ (session->callerWriteEntitlement != kCFNull)) {
+ CFRelease(session->callerWriteEntitlement);
}
- SCPrint(TRUE, f, CFSTR("\n"));
+ /*
+ * get rid of the per-session structure.
+ */
+ dispatch_sync(sessionQueue(), ^{
+ CFDictionaryRemoveValue(client_sessions,
+ (const void *)(uintptr_t)server);
+ });
+
return;
}
-#include <Security/Security.h>
-#include <Security/SecTask.h>
-
-static CFStringRef
-sessionName(serverSessionRef session)
+__private_extern__
+void
+closeSession(serverSessionRef session)
{
- CFDictionaryRef info;
- CFStringRef name = NULL;
- CFStringRef sessionKey;
+ /*
+ * cancel and release the mach channel
+ */
+ if (session->serverChannel != NULL) {
+ dispatch_mach_cancel(session->serverChannel);
+ dispatch_release(session->serverChannel);
+ session->serverChannel = NULL;
+ }
- sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), session->key);
- info = CFDictionaryGetValue(sessionData, sessionKey);
- CFRelease(sessionKey);
+ return;
+}
+
+
+typedef struct ReportSessionInfo {
+ FILE *f;
+ int n;
+} ReportSessionInfo, *ReportSessionInfoRef;
- if (info != NULL) {
- name = CFDictionaryGetValue(info, kSCDName);
+static void
+printOne(const void *key, const void *value, void *context)
+{
+#pragma unused(key)
+ ReportSessionInfoRef reportInfo = (ReportSessionInfoRef)context;
+ serverSessionRef session = (serverSessionRef)value;
+
+ SCPrint(TRUE, reportInfo->f, CFSTR(" %d : port = 0x%x"), ++reportInfo->n, session->key);
+ SCPrint(TRUE, reportInfo->f, CFSTR(", name = %@"), session->name);
+ if (session->changedKeys != NULL) {
+ SCPrint(TRUE, reportInfo->f, CFSTR("\n changedKeys = %@"), session->changedKeys);
+ }
+ if (session->sessionKeys != NULL) {
+ SCPrint(TRUE, reportInfo->f, CFSTR("\n sessionKeys = %@"), session->sessionKeys);
}
+ SCPrint(TRUE, reportInfo->f, CFSTR("\n"));
+ return;
+}
+
+
+__private_extern__
+void
+listSessions(FILE *f)
+{
+ dispatch_sync(sessionQueue(), ^{
+ ReportSessionInfo reportInfo = { .f = f, .n = 0 };
- return (name != NULL) ? name : CFSTR("???");
+ SCPrint(TRUE, f, CFSTR("Current sessions :\n"));
+ CFDictionaryApplyFunction(client_sessions,
+ printOne,
+ (void *)&reportInfo);
+ SCPrint(TRUE, f, CFSTR("\n"));
+ });
+ return;
}
+
+#include <Security/Security.h>
+#include <Security/SecTask.h>
+
static CFTypeRef
copyEntitlement(serverSessionRef session, CFStringRef entitlement)
{
if (!CFEqual(domain, kCFErrorDomainMach) ||
((code != kIOReturnInvalid) && (code != kIOReturnNotFound))) {
// if unexpected error
- SCLog(TRUE, LOG_ERR,
- CFSTR("SecTaskCopyValueForEntitlement(,\"%@\",) failed, error = %@ : %@"),
- entitlement,
- error,
- sessionName(session));
+ SC_log(LOG_NOTICE, "SecTaskCopyValueForEntitlement(,\"%@\",) failed, error = %@ : %@",
+ entitlement,
+ error,
+ session->name);
}
CFRelease(error);
}
CFRelease(task);
} else {
- SCLog(TRUE, LOG_ERR,
- CFSTR("SecTaskCreateWithAuditToken() failed: %@"),
- sessionName(session));
+ SC_log(LOG_NOTICE, "SecTaskCreateWithAuditToken() failed: %@",
+ session->name);
}
return value;
Boolean
hasRootAccess(serverSessionRef session)
{
-#if !TARGET_IPHONE_SIMULATOR
+#if !TARGET_OS_SIMULATOR
if (session->callerRootAccess == UNKNOWN) {
#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) && !TARGET_OS_IPHONE
return (session->callerRootAccess == YES) ? TRUE : FALSE;
-#else // !TARGET_IPHONE_SIMULATOR
+#else // !TARGET_OS_SIMULATOR
+#pragma unused(session)
/*
* assume that all processes interacting with
*/
return TRUE;
-#endif // !TARGET_IPHONE_SIMULATOR
+#endif // !TARGET_OS_SIMULATOR
}
__private_extern__
Boolean
-hasWriteAccess(serverSessionRef session, CFStringRef key)
+hasWriteAccess(serverSessionRef session, const char *op, CFStringRef key)
{
Boolean isSetup;
* general, this is unwise and we should at the
* very least complain.
*/
- SCLog(TRUE, LOG_ERR,
- CFSTR("*** Non-configd process (pid=%d) attempting to modify \"%@\" ***"),
- pid,
- key);
+ SC_log(LOG_NOTICE, "*** Non-configd process (pid=%d) attempting to %s \"%@\" ***",
+ pid,
+ op,
+ key);
}
return TRUE;
* something we should ever allow (regardless of
* any entitlements).
*/
- SCLog(TRUE, LOG_ERR,
- CFSTR("*** Non-root process (pid=%d) attempting to modify \"%@\" ***"),
- sessionPid(session),
- key);
+ SC_log(LOG_NOTICE, "*** Non-root process (pid=%d) attempting to modify \"%@\" ***",
+ sessionPid(session),
+ key);
- //return FALSE; // return FALSE when rdar://9811832 has beed fixed
+ return FALSE;
}
if (session->callerWriteEntitlement == kCFNull) {
char realPath[PATH_MAX];
if (realpath(path, realPath) == NULL) {
- SCLog(TRUE, LOG_DEBUG, CFSTR("hasPathAccess realpath() failed: %s"), strerror(errno));
+ SC_log(LOG_INFO, "realpath() failed: %s", strerror(errno));
return FALSE;
}
"file-write-data", // operation
SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT, // sandbox_filter_type
realPath) > 0) { // ...
- SCLog(TRUE, LOG_DEBUG, CFSTR("hasPathAccess sandbox access denied: %s"), strerror(errno));
+ SC_log(LOG_INFO, "sandbox access denied: %s", strerror(errno));
return FALSE;
}