1/* 2 * Copyright (c) 2000-2004, 2006, 2008, 2010, 2011, 2014 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 "session.h" 36#include "pattern.h" 37 38 39static __inline__ void 40my_CFArrayApplyFunction(CFArrayRef theArray, 41 CFArrayApplierFunction applier, 42 void *context) 43{ 44 CFAllocatorRef myAllocator; 45 CFArrayRef myArray; 46 47 myAllocator = CFGetAllocator(theArray); 48 myArray = CFArrayCreateCopy(myAllocator, theArray); 49 CFArrayApplyFunction(myArray, CFRangeMake(0, CFArrayGetCount(myArray)), applier, context); 50 CFRelease(myArray); 51 return; 52} 53 54 55static int 56hasKey(CFMutableArrayRef keys, CFStringRef key) 57{ 58 if (keys != NULL) { 59 CFIndex n; 60 61 n = CFArrayGetCount(keys); 62 if (CFArrayContainsValue(keys, CFRangeMake(0, n), key)) { 63 /* sorry, pattern already exists in notifier list */ 64 return kSCStatusKeyExists; 65 } 66 } 67 68 return kSCStatusOK; 69} 70 71 72static void 73addKey(CFMutableArrayRef *keysP, CFStringRef key) 74{ 75 if (*keysP == NULL) { 76 *keysP = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 77 } 78 79 CFArrayAppendValue(*keysP, key); 80 return; 81} 82 83 84__private_extern__ 85int 86__SCDynamicStoreAddWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boolean isRegex, Boolean internal) 87{ 88 int sc_status = kSCStatusOK; 89 CFNumberRef sessionNum = NULL; 90 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 91 92 if (_configd_trace) { 93 SCTrace(TRUE, _configd_trace, 94 CFSTR("%s : %5d : %s : %@\n"), 95 internal ? "*watch+" : "watch+ ", 96 storePrivate->server, 97 isRegex ? "pattern" : "key", 98 key); 99 } 100 101 sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &storePrivate->server); 102 103 if (isRegex) { 104 sc_status = hasKey(storePrivate->patterns, key); 105 if (sc_status != kSCStatusOK) { 106 goto done; 107 } 108 109 /* 110 * add this session as a pattern watcher 111 */ 112 if (!patternAddSession(key, sessionNum)) { 113 sc_status = kSCStatusInvalidArgument; 114 goto done; 115 } 116 117 /* add pattern to this sessions notifier list */ 118 addKey(&storePrivate->patterns, key); 119 } else { 120 sc_status = hasKey(storePrivate->keys, key); 121 if (sc_status != kSCStatusOK) { 122 goto done; 123 } 124 125 /* 126 * We are watching a specific key. As such, update the 127 * store to mark our interest in any changes. 128 */ 129 _addWatcher(sessionNum, key); 130 131 /* add key to this sessions notifier list */ 132 addKey(&storePrivate->keys, key); 133 } 134 135 done : 136 137 if (sessionNum != NULL) CFRelease(sessionNum); 138 return sc_status; 139} 140 141 142__private_extern__ 143kern_return_t 144_notifyadd(mach_port_t server, 145 xmlData_t keyRef, /* raw XML bytes */ 146 mach_msg_type_number_t keyLen, 147 int isRegex, 148 int *sc_status 149) 150{ 151 CFStringRef key = NULL; /* key (un-serialized) */ 152 serverSessionRef mySession; 153 154 /* un-serialize the key */ 155 if (!_SCUnserializeString(&key, NULL, (void *)keyRef, keyLen)) { 156 *sc_status = kSCStatusFailed; 157 goto done; 158 } 159 160 if (!isA_CFString(key)) { 161 *sc_status = kSCStatusInvalidArgument; 162 goto done; 163 } 164 165 mySession = getSession(server); 166 if (mySession == NULL) { 167 *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ 168 goto done; 169 } 170 171 *sc_status = __SCDynamicStoreAddWatchedKey(mySession->store, key, isRegex != 0, FALSE); 172 173 done : 174 175 if (key) CFRelease(key); 176 return KERN_SUCCESS; 177} 178 179 180/* 181 * "context" argument for removeOldKey() and addNewKey() 182 */ 183typedef struct { 184 SCDynamicStoreRef store; 185 CFArrayRef oldKeys; /* for addNewKey */ 186 CFArrayRef newKeys; /* for removeOldKey */ 187 Boolean isRegex; 188 int sc_status; 189} updateKeysContext, *updateKeysContextRef; 190 191 192static void 193removeOldKey(const void *value, void *context) 194{ 195 CFStringRef oldKey = (CFStringRef)value; 196 updateKeysContextRef myContextRef = (updateKeysContextRef)context; 197 198 if (myContextRef->sc_status != kSCStatusOK) { 199 return; 200 } 201 202 if ((myContextRef->newKeys == NULL) || 203 !CFArrayContainsValue(myContextRef->newKeys, 204 CFRangeMake(0, CFArrayGetCount(myContextRef->newKeys)), 205 oldKey)) { 206 /* the old notification key is not being retained, remove it */ 207 myContextRef->sc_status = __SCDynamicStoreRemoveWatchedKey(myContextRef->store, 208 oldKey, 209 myContextRef->isRegex, 210 TRUE); 211 } 212 213 return; 214} 215 216 217static void 218addNewKey(const void *value, void *context) 219{ 220 CFStringRef newKey = (CFStringRef)value; 221 updateKeysContextRef myContextRef = (updateKeysContextRef)context; 222 223 if (myContextRef->sc_status != kSCStatusOK) { 224 return; 225 } 226 227 if ((myContextRef->oldKeys == NULL) || 228 !CFArrayContainsValue(myContextRef->oldKeys, 229 CFRangeMake(0, CFArrayGetCount(myContextRef->oldKeys)), 230 newKey)) { 231 /* if this is a new notification key */ 232 myContextRef->sc_status = __SCDynamicStoreAddWatchedKey(myContextRef->store, 233 newKey, 234 myContextRef->isRegex, 235 TRUE); 236 } 237 238 return; 239} 240 241 242__private_extern__ 243int 244__SCDynamicStoreSetNotificationKeys(SCDynamicStoreRef store, CFArrayRef keys, CFArrayRef patterns) 245{ 246 updateKeysContext myContext; 247 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; 248 249 if (_configd_trace) { 250 SCTrace(TRUE, _configd_trace, 251 CFSTR("watch : %5d : %ld keys, %ld patterns\n"), 252 storePrivate->server, 253 keys ? CFArrayGetCount(keys) : 0, 254 patterns ? CFArrayGetCount(patterns) : 0); 255 } 256 257 myContext.store = store; 258 myContext.sc_status = kSCStatusOK; 259 260 /* remove any previously registered keys, register any new keys */ 261 myContext.oldKeys = NULL; 262 myContext.newKeys = keys; 263 myContext.isRegex = FALSE; 264 if (storePrivate->keys != NULL) { 265 myContext.oldKeys = CFArrayCreateCopy(NULL, storePrivate->keys); 266 my_CFArrayApplyFunction(storePrivate->keys, removeOldKey, &myContext); 267 } 268 if (keys != NULL) { 269 CFArrayApplyFunction(keys, 270 CFRangeMake(0, CFArrayGetCount(keys)), 271 addNewKey, 272 &myContext); 273 } 274 if (myContext.oldKeys != NULL) CFRelease(myContext.oldKeys); 275 276 /* remove any previously registered patterns, register any new patterns */ 277 myContext.oldKeys = NULL; 278 myContext.newKeys = patterns; 279 myContext.isRegex = TRUE; 280 if (storePrivate->patterns != NULL) { 281 myContext.oldKeys = CFArrayCreateCopy(NULL, storePrivate->patterns); 282 my_CFArrayApplyFunction(storePrivate->patterns, removeOldKey, &myContext); 283 } 284 if (patterns != NULL) { 285 CFArrayApplyFunction(patterns, 286 CFRangeMake(0, CFArrayGetCount(patterns)), 287 addNewKey, 288 &myContext); 289 } 290 if (myContext.oldKeys != NULL) CFRelease(myContext.oldKeys); 291 292 return myContext.sc_status; 293} 294 295 296__private_extern__ 297kern_return_t 298_notifyset(mach_port_t server, 299 xmlData_t keysRef, /* raw XML bytes */ 300 mach_msg_type_number_t keysLen, 301 xmlData_t patternsRef, /* raw XML bytes */ 302 mach_msg_type_number_t patternsLen, 303 int *sc_status 304) 305{ 306 CFArrayRef keys = NULL; /* key (un-serialized) */ 307 serverSessionRef mySession; 308 CFArrayRef patterns = NULL; /* patterns (un-serialized) */ 309 310 *sc_status = kSCStatusOK; 311 312 if ((keysRef != NULL) && (keysLen > 0)) { 313 /* un-serialize the keys */ 314 if (!_SCUnserialize((CFPropertyListRef *)&keys, NULL, (void *)keysRef, keysLen)) { 315 *sc_status = kSCStatusFailed; 316 } 317 } 318 319 if ((patternsRef != NULL) && (patternsLen > 0)) { 320 /* un-serialize the patterns */ 321 if (!_SCUnserialize((CFPropertyListRef *)&patterns, NULL, (void *)patternsRef, patternsLen)) { 322 *sc_status = kSCStatusFailed; 323 } 324 } 325 326 if (*sc_status != kSCStatusOK) { 327 goto done; 328 } 329 330 if ((keys != NULL) && !isA_CFArray(keys)) { 331 *sc_status = kSCStatusInvalidArgument; 332 goto done; 333 } 334 335 if ((patterns != NULL) && !isA_CFArray(patterns)) { 336 *sc_status = kSCStatusInvalidArgument; 337 goto done; 338 } 339 340 mySession = getSession(server); 341 if (mySession == NULL) { 342 /* you must have an open session to play */ 343 *sc_status = kSCStatusNoStoreSession; 344 goto done; 345 } 346 347 *sc_status = __SCDynamicStoreSetNotificationKeys(mySession->store, keys, patterns); 348 349 done : 350 351 if (keys != NULL) CFRelease(keys); 352 if (patterns != NULL) CFRelease(patterns); 353 354 return KERN_SUCCESS; 355} 356