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