]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_configset.c
configd-699.1.5.tar.gz
[apple/configd.git] / configd.tproj / _configset.c
1 /*
2 * Copyright (c) 2000-2004, 2006, 2008, 2011, 2012, 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
35 #include "configd.h"
36 #include "session.h"
37 #include "pattern.h"
38
39
40 __private_extern__
41 int
42 __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef value, Boolean internal)
43 {
44 CFDictionaryRef dict;
45 CFMutableDictionaryRef newDict;
46 Boolean newEntry = FALSE;
47 int sc_status = kSCStatusOK;
48 CFStringRef sessionKey;
49 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
50 CFStringRef storeSessionKey;
51
52 if (_configd_trace) {
53 SCTrace(TRUE, _configd_trace,
54 CFSTR("%s%s : %5d : %@\n"),
55 internal ? "*set " : "set ",
56 storePrivate->useSessionKeys ? "t " : " ",
57 storePrivate->server,
58 key);
59 }
60
61 /*
62 * Grab the current (or establish a new) dictionary for this key.
63 */
64
65 dict = CFDictionaryGetValue(storeData, key);
66 if (dict) {
67 newDict = CFDictionaryCreateMutableCopy(NULL,
68 0,
69 dict);
70 } else {
71 newDict = CFDictionaryCreateMutable(NULL,
72 0,
73 &kCFTypeDictionaryKeyCallBacks,
74 &kCFTypeDictionaryValueCallBacks);
75 }
76
77 /*
78 * Update the dictionary entry to be saved to the store.
79 */
80 newEntry = !CFDictionaryContainsKey(newDict, kSCDData);
81 CFDictionarySetValue(newDict, kSCDData, value);
82
83 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
84
85 /*
86 * Manage per-session keys.
87 */
88 if (storePrivate->useSessionKeys) {
89 if (newEntry) {
90 CFArrayRef keys;
91 CFMutableDictionaryRef newSession;
92 CFMutableArrayRef newKeys;
93 CFDictionaryRef session;
94
95 /*
96 * Add this key to my list of per-session keys
97 */
98 session = CFDictionaryGetValue(sessionData, sessionKey);
99 keys = CFDictionaryGetValue(session, kSCDSessionKeys);
100 if ((keys == NULL) ||
101 (CFArrayGetFirstIndexOfValue(keys,
102 CFRangeMake(0, CFArrayGetCount(keys)),
103 key) == kCFNotFound)) {
104 /*
105 * if no session keys defined "or" keys defined but not
106 * this one...
107 */
108 if (keys != NULL) {
109 /* this is the first session key */
110 newKeys = CFArrayCreateMutableCopy(NULL, 0, keys);
111 } else {
112 /* this is an additional session key */
113 newKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
114 }
115 CFArrayAppendValue(newKeys, key);
116
117 /* update session dictionary */
118 newSession = CFDictionaryCreateMutableCopy(NULL, 0, session);
119 CFDictionarySetValue(newSession, kSCDSessionKeys, newKeys);
120 CFRelease(newKeys);
121 CFDictionarySetValue(sessionData, sessionKey, newSession);
122 CFRelease(newSession);
123 }
124
125 /*
126 * Mark the key as a "session" key and track the creator.
127 */
128 CFDictionarySetValue(newDict, kSCDSession, sessionKey);
129 } else {
130 /*
131 * Since we are using per-session keys and this key already
132 * exists, check if it was created by "our" session
133 */
134 dict = CFDictionaryGetValue(storeData, key);
135 if (!CFDictionaryGetValueIfPresent(dict, kSCDSession, (void *)&storeSessionKey) ||
136 !CFEqual(sessionKey, storeSessionKey)) {
137 /*
138 * if the key exists and is not a session key or
139 * if the key exists it's not "our" session.
140 */
141 sc_status = kSCStatusKeyExists;
142 CFRelease(sessionKey);
143 CFRelease(newDict);
144 goto done;
145 }
146 }
147 } else {
148 /*
149 * Since we are updating this key we need to check and, if
150 * necessary, remove the indication that this key is on
151 * another session's remove-on-close list.
152 */
153 if (!newEntry &&
154 CFDictionaryGetValueIfPresent(newDict, kSCDSession, (void *)&storeSessionKey) &&
155 !CFEqual(sessionKey, storeSessionKey)) {
156 CFStringRef removedKey;
157
158 /* We are no longer a session key! */
159 CFDictionaryRemoveValue(newDict, kSCDSession);
160
161 /* add this session key to the (session) removal list */
162 removedKey = CFStringCreateWithFormat(NULL, 0, CFSTR("%@:%@"), storeSessionKey, key);
163 CFSetAddValue(removedSessionKeys, removedKey);
164 CFRelease(removedKey);
165 }
166 }
167
168 CFRelease(sessionKey);
169
170 /*
171 * Update the dictionary entry in the store.
172 */
173
174 CFDictionarySetValue(storeData, key, newDict);
175 CFRelease(newDict);
176
177 /*
178 * For "new" entries to the store, check the deferred cleanup
179 * list. If the key is flagged for removal, remove it from the
180 * list since any defined regex's for this key are still defined
181 * and valid. If the key is not flagged then iterate over the
182 * sessionData dictionary looking for regex keys which match the
183 * updated key. If a match is found then we mark those keys as
184 * being watched.
185 */
186
187 if (newEntry) {
188 if (CFSetContainsValue(deferredRemovals, key)) {
189 CFSetRemoveValue(deferredRemovals, key);
190 } else {
191 patternAddKey(key);
192 }
193 }
194
195 /*
196 * Mark this key as "changed". Any "watchers" will be notified
197 * as soon as the lock is released.
198 */
199 CFSetAddValue(changedKeys, key);
200
201 done :
202
203 if (!internal) {
204 /* push changes */
205 __SCDynamicStorePush();
206 }
207
208 return sc_status;
209 }
210
211 __private_extern__
212 kern_return_t
213 _configset(mach_port_t server,
214 xmlData_t keyRef, /* raw XML bytes */
215 mach_msg_type_number_t keyLen,
216 xmlData_t dataRef, /* raw XML bytes */
217 mach_msg_type_number_t dataLen,
218 int oldInstance,
219 int *newInstance,
220 int *sc_status,
221 audit_token_t audit_token)
222 {
223 CFDataRef data = NULL; /* data (un-serialized) */
224 CFStringRef key = NULL; /* key (un-serialized) */
225 serverSessionRef mySession;
226
227 *sc_status = kSCStatusOK;
228
229 /* un-serialize the key */
230 if (!_SCUnserializeString(&key, NULL, (void *)keyRef, keyLen)) {
231 *sc_status = kSCStatusFailed;
232 }
233
234 /* un-serialize the data */
235 if (!_SCUnserializeData(&data, (void *)dataRef, dataLen)) {
236 *sc_status = kSCStatusFailed;
237 }
238
239 if (*sc_status != kSCStatusOK) {
240 goto done;
241 }
242
243 if (!isA_CFString(key)) {
244 *sc_status = kSCStatusInvalidArgument;
245 goto done;
246 }
247
248 mySession = getSession(server);
249 if (mySession == NULL) {
250 mySession = tempSession(server, CFSTR("SCDynamicStoreSetValue"), audit_token);
251 if (mySession == NULL) {
252 /* you must have an open session to play */
253 *sc_status = kSCStatusNoStoreSession;
254 goto done;
255 }
256 }
257
258 if (!hasWriteAccess(mySession, key)) {
259 *sc_status = kSCStatusAccessError;
260 goto done;
261 }
262
263 *sc_status = __SCDynamicStoreSetValue(mySession->store, key, data, FALSE);
264 *newInstance = 0;
265
266 done :
267
268 if (key) CFRelease(key);
269 if (data) CFRelease(data);
270 return KERN_SUCCESS;
271 }
272
273 static void
274 setSpecificKey(const void *key, const void *value, void *context)
275 {
276 CFStringRef k = (CFStringRef)key;
277 CFDataRef v = (CFDataRef)value;
278 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
279
280 if (!isA_CFString(k)) {
281 return;
282 }
283
284 if (!isA_CFData(v)) {
285 return;
286 }
287
288 (void) __SCDynamicStoreSetValue(store, k, v, TRUE);
289
290 return;
291 }
292
293 static void
294 removeSpecificKey(const void *value, void *context)
295 {
296 CFStringRef k = (CFStringRef)value;
297 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
298
299 if (!isA_CFString(k)) {
300 return;
301 }
302
303 (void) __SCDynamicStoreRemoveValue(store, k, TRUE);
304
305 return;
306 }
307
308 static void
309 notifySpecificKey(const void *value, void *context)
310 {
311 CFStringRef k = (CFStringRef)value;
312 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
313
314 if (!isA_CFString(k)) {
315 return;
316 }
317
318 (void) __SCDynamicStoreNotifyValue(store, k, TRUE);
319
320 return;
321 }
322
323 __private_extern__
324 int
325 __SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFArrayRef keysToNotify)
326 {
327 int sc_status = kSCStatusOK;
328 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
329
330 if (_configd_trace) {
331 SCTrace(TRUE, _configd_trace,
332 CFSTR("set m : %5d : %ld set, %ld remove, %ld notify\n"),
333 storePrivate->server,
334 keysToSet ? CFDictionaryGetCount(keysToSet) : 0,
335 keysToRemove ? CFArrayGetCount (keysToRemove) : 0,
336 keysToNotify ? CFArrayGetCount (keysToNotify) : 0);
337 }
338
339 /*
340 * Set the new/updated keys
341 */
342 if (keysToSet) {
343 CFDictionaryApplyFunction(keysToSet,
344 setSpecificKey,
345 (void *)store);
346 }
347
348 /*
349 * Remove the specified keys
350 */
351 if (keysToRemove) {
352 CFArrayApplyFunction(keysToRemove,
353 CFRangeMake(0, CFArrayGetCount(keysToRemove)),
354 removeSpecificKey,
355 (void *)store);
356 }
357
358 /*
359 * Notify the specified keys
360 */
361 if (keysToNotify) {
362 CFArrayApplyFunction(keysToNotify,
363 CFRangeMake(0, CFArrayGetCount(keysToNotify)),
364 notifySpecificKey,
365 (void *)store);
366 }
367
368 /* push changes */
369 __SCDynamicStorePush();
370
371 return sc_status;
372 }
373
374 #define N_QUICK 32
375
376 __private_extern__
377 kern_return_t
378 _configset_m(mach_port_t server,
379 xmlData_t dictRef,
380 mach_msg_type_number_t dictLen,
381 xmlData_t removeRef,
382 mach_msg_type_number_t removeLen,
383 xmlData_t notifyRef,
384 mach_msg_type_number_t notifyLen,
385 int *sc_status,
386 audit_token_t audit_token)
387 {
388 CFDictionaryRef dict = NULL; /* key/value dictionary (un-serialized) */
389 serverSessionRef mySession;
390 CFArrayRef notify = NULL; /* keys to notify (un-serialized) */
391 CFArrayRef remove = NULL; /* keys to remove (un-serialized) */
392
393 *sc_status = kSCStatusOK;
394
395 if ((dictRef != NULL) && (dictLen > 0)) {
396 /* un-serialize the key/value pairs to set */
397 if (!_SCUnserialize((CFPropertyListRef *)&dict, NULL, (void *)dictRef, dictLen)) {
398 *sc_status = kSCStatusFailed;
399 }
400 }
401
402 if ((removeRef != NULL) && (removeLen > 0)) {
403 /* un-serialize the keys to remove */
404 if (!_SCUnserialize((CFPropertyListRef *)&remove, NULL, (void *)removeRef, removeLen)) {
405 *sc_status = kSCStatusFailed;
406 }
407 }
408
409 if ((notifyRef != NULL) && (notifyLen > 0)) {
410 /* un-serialize the keys to notify */
411 if (!_SCUnserialize((CFPropertyListRef *)&notify, NULL, (void *)notifyRef, notifyLen)) {
412 *sc_status = kSCStatusFailed;
413 }
414 }
415
416 if (*sc_status != kSCStatusOK) {
417 goto done;
418 }
419
420 if ((dict != NULL) && !isA_CFDictionary(dict)) {
421 *sc_status = kSCStatusInvalidArgument;
422 goto done;
423 }
424
425 if ((remove != NULL) && !isA_CFArray(remove)) {
426 *sc_status = kSCStatusInvalidArgument;
427 goto done;
428 }
429
430 if ((notify != NULL) && !isA_CFArray(notify)) {
431 *sc_status = kSCStatusInvalidArgument;
432 goto done;
433 }
434
435 mySession = getSession(server);
436 if (mySession == NULL) {
437 mySession = tempSession(server, CFSTR("SCDynamicStoreSetMultiple"), audit_token);
438 if (mySession == NULL) {
439 /* you must have an open session to play */
440 *sc_status = kSCStatusNoStoreSession;
441 goto done;
442 }
443 }
444
445 if (dict != NULL) {
446 const void * keys_q[N_QUICK];
447 const void ** keys = keys_q;
448 CFIndex i;
449 CFIndex n;
450 Boolean writeOK = TRUE;
451
452 n = CFDictionaryGetCount(dict);
453 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFStringRef))) {
454 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
455 }
456 CFDictionaryGetKeysAndValues(dict, keys, NULL);
457 for (i = 0; i < n; i++) {
458 CFStringRef key;
459
460 key = (CFStringRef)keys[i];
461 if (!hasWriteAccess(mySession, key)) {
462 writeOK = FALSE;
463 break;
464 }
465 }
466 if (keys != keys_q) {
467 CFAllocatorDeallocate(NULL, keys);
468 }
469
470 if (!writeOK) {
471 *sc_status = kSCStatusAccessError;
472 goto done;
473 }
474 }
475
476 if (remove != NULL) {
477 CFIndex i;
478 CFIndex n = CFArrayGetCount(remove);
479
480 for (i = 0; i < n; i++) {
481 CFStringRef key;
482
483 key = CFArrayGetValueAtIndex(remove, i);
484 if (!hasWriteAccess(mySession, key)) {
485 *sc_status = kSCStatusAccessError;
486 goto done;
487 }
488 }
489 }
490
491 if (notify != NULL) {
492 CFIndex i;
493 CFIndex n = CFArrayGetCount(notify);
494
495 for (i = 0; i < n; i++) {
496 CFStringRef key;
497
498 key = CFArrayGetValueAtIndex(notify, i);
499 if (!hasWriteAccess(mySession, key)) {
500 *sc_status = kSCStatusAccessError;
501 goto done;
502 }
503 }
504 }
505
506 *sc_status = __SCDynamicStoreSetMultiple(mySession->store, dict, remove, notify);
507
508 done :
509
510 if (dict != NULL) CFRelease(dict);
511 if (remove != NULL) CFRelease(remove);
512 if (notify != NULL) CFRelease(notify);
513
514 return KERN_SUCCESS;
515 }