1/* 2 * Copyright (c) 2000-2009, 2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Modification History 26 * 27 * June 1, 2001 Allan Nathanson <ajn@apple.com> 28 * - public API conversion 29 * 30 * March 24, 2000 Allan Nathanson <ajn@apple.com> 31 * - initial revision 32 */ 33 34#include "configd.h" 35#include "configd_server.h" 36#include "session.h" 37 38#include <bsm/libbsm.h> 39#include <sys/types.h> 40#include <unistd.h> 41 42__private_extern__ 43int 44__SCDynamicStoreOpen(SCDynamicStoreRef *store, CFStringRef name) 45{ 46 /* 47 * allocate and initialize a new session 48 */ 49 *store = (SCDynamicStoreRef)__SCDynamicStoreCreatePrivate(NULL, name, NULL, NULL); 50 51 /* 52 * If necessary, initialize the store and session data dictionaries 53 */ 54 if (storeData == NULL) { 55 sessionData = CFDictionaryCreateMutable(NULL, 56 0, 57 &kCFTypeDictionaryKeyCallBacks, 58 &kCFTypeDictionaryValueCallBacks); 59 storeData = CFDictionaryCreateMutable(NULL, 60 0, 61 &kCFTypeDictionaryKeyCallBacks, 62 &kCFTypeDictionaryValueCallBacks); 63 patternData = CFDictionaryCreateMutable(NULL, 64 0, 65 &kCFTypeDictionaryKeyCallBacks, 66 &kCFTypeDictionaryValueCallBacks); 67 changedKeys = CFSetCreateMutable(NULL, 68 0, 69 &kCFTypeSetCallBacks); 70 deferredRemovals = CFSetCreateMutable(NULL, 71 0, 72 &kCFTypeSetCallBacks); 73 removedSessionKeys = CFSetCreateMutable(NULL, 74 0, 75 &kCFTypeSetCallBacks); 76 } 77 78 return kSCStatusOK; 79} 80 81 82static CFStringRef 83openMPCopyDescription(const void *info) 84{ 85 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SCDynamicStore MP>")); 86} 87 88 89__private_extern__ 90kern_return_t 91_configopen(mach_port_t server, 92 xmlData_t nameRef, /* raw XML bytes */ 93 mach_msg_type_number_t nameLen, 94 xmlData_t optionsRef, /* raw XML bytes */ 95 mach_msg_type_number_t optionsLen, 96 mach_port_t *newServer, 97 int *sc_status, 98 audit_token_t audit_token) 99{ 100 CFDictionaryRef info; 101 serverSessionRef mySession; 102 CFStringRef name = NULL; /* name (un-serialized) */ 103 CFMutableDictionaryRef newInfo; 104 mach_port_t oldNotify; 105 CFDictionaryRef options = NULL; /* options (un-serialized) */ 106 CFStringRef sessionKey; 107 kern_return_t status; 108 SCDynamicStorePrivateRef storePrivate; 109 CFBooleanRef useSessionKeys = NULL; 110 111 *sc_status = kSCStatusOK; 112 113 /* un-serialize the name */ 114 if (!_SCUnserializeString(&name, NULL, (void *)nameRef, nameLen)) { 115 *sc_status = kSCStatusFailed; 116 } 117 118 if ((optionsRef != NULL) && (optionsLen > 0)) { 119 /* un-serialize the [session] options */ 120 if (!_SCUnserialize((CFPropertyListRef *)&options, NULL, (void *)optionsRef, optionsLen)) { 121 *sc_status = kSCStatusFailed; 122 } 123 } 124 125 if (*sc_status != kSCStatusOK) { 126 goto done; 127 } 128 129 if (!isA_CFString(name)) { 130 *sc_status = kSCStatusInvalidArgument; 131 goto done; 132 } 133 134 if (options != NULL) { 135 if (!isA_CFDictionary(options)) { 136 *sc_status = kSCStatusInvalidArgument; 137 goto done; 138 } 139 140 /* 141 * [pre-]process any provided options 142 */ 143 useSessionKeys = CFDictionaryGetValue(options, kSCDynamicStoreUseSessionKeys); 144 if (useSessionKeys != NULL) { 145 if (!isA_CFBoolean(useSessionKeys)) { 146 *sc_status = kSCStatusInvalidArgument; 147 goto done; 148 } 149 } 150 } 151 152 /* 153 * establish the new session 154 */ 155 mySession = addSession(server, openMPCopyDescription); 156 if (mySession == NULL) { 157#ifdef DEBUG 158 SCLog(TRUE, LOG_DEBUG, CFSTR("_configopen(): session is already open.")); 159#endif /* DEBUG */ 160 *sc_status = kSCStatusFailed; /* you can't re-open an "open" session */ 161 goto done; 162 } 163 164 *newServer = mySession->key; 165 __MACH_PORT_DEBUG(TRUE, "*** _configopen (after addSession)", *newServer); 166 167 /* save the audit_token in case we need to check the callers credentials */ 168 mySession->auditToken = audit_token; 169 170 /* Create and add a run loop source for the port */ 171 mySession->serverRunLoopSource = CFMachPortCreateRunLoopSource(NULL, mySession->serverPort, 0); 172 CFRunLoopAddSource(CFRunLoopGetCurrent(), 173 mySession->serverRunLoopSource, 174 kCFRunLoopDefaultMode); 175 176 if (_configd_trace) { 177 SCTrace(TRUE, _configd_trace, 178 CFSTR("open : %5d : %@\n"), 179 *newServer, 180 name); 181 } 182 183 *sc_status = __SCDynamicStoreOpen(&mySession->store, name); 184 storePrivate = (SCDynamicStorePrivateRef)mySession->store; 185 186 /* 187 * Make the server port accessible to the framework routines. 188 * ... and be sure to clear before calling CFRelease(store) 189 */ 190 storePrivate->server = *newServer; 191 192 /* 193 * Process any provided [session] options 194 */ 195 if (useSessionKeys != NULL) { 196 storePrivate->useSessionKeys = CFBooleanGetValue(useSessionKeys); 197 } 198 199 /* Request a notification when/if the client dies */ 200 status = mach_port_request_notification(mach_task_self(), 201 *newServer, 202 MACH_NOTIFY_NO_SENDERS, 203 1, 204 *newServer, 205 MACH_MSG_TYPE_MAKE_SEND_ONCE, 206 &oldNotify); 207 if (status != KERN_SUCCESS) { 208 SCLog(TRUE, LOG_ERR, CFSTR("_configopen() mach_port_request_notification() failed: %s"), mach_error_string(status)); 209 cleanupSession(*newServer); 210 *newServer = MACH_PORT_NULL; 211 *sc_status = kSCStatusFailed; 212 goto done; 213 } 214 __MACH_PORT_DEBUG(TRUE, "*** _configopen (after mach_port_request_notification)", *newServer); 215 216 if (oldNotify != MACH_PORT_NULL) { 217 SCLog(TRUE, LOG_ERR, CFSTR("_configopen(): oldNotify != MACH_PORT_NULL")); 218 } 219 220 /* 221 * Save the name of the calling application / plug-in with the session data. 222 */ 223 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), *newServer); 224 info = CFDictionaryGetValue(sessionData, sessionKey); 225 if (info != NULL) { 226 newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info); 227 } else { 228 newInfo = CFDictionaryCreateMutable(NULL, 229 0, 230 &kCFTypeDictionaryKeyCallBacks, 231 &kCFTypeDictionaryValueCallBacks); 232 } 233 CFDictionarySetValue(newInfo, kSCDName, name); 234 CFDictionarySetValue(sessionData, sessionKey, newInfo); 235 CFRelease(newInfo); 236 CFRelease(sessionKey); 237 238 /* 239 * Note: at this time we should be holding ONE send right and 240 * ONE receive right to the server. The send right is 241 * moved to the caller. 242 */ 243 244 done : 245 246 if (name != NULL) CFRelease(name); 247 if (options != NULL) CFRelease(options); 248 return KERN_SUCCESS; 249} 250