]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_configset.c
configd-963.250.1.tar.gz
[apple/configd.git] / configd.tproj / _configset.c
1 /*
2 * Copyright (c) 2000-2004, 2006, 2008, 2011, 2012, 2014-2017, 2019 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("%s%s : %5d : %@",
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 #pragma unused(oldInstance)
221 CFDataRef data = NULL; /* data (un-serialized) */
222 CFStringRef key = NULL; /* key (un-serialized) */
223 serverSessionRef mySession;
224
225 *newInstance = 0;
226 *sc_status = kSCStatusOK;
227
228 /* un-serialize the key */
229 if (!_SCUnserializeString(&key, NULL, (void *)keyRef, keyLen)) {
230 *sc_status = kSCStatusFailed;
231 }
232
233 /* un-serialize the data */
234 if (!_SCUnserializeData(&data, (void *)dataRef, dataLen)) {
235 *sc_status = kSCStatusFailed;
236 }
237
238 if (*sc_status != kSCStatusOK) {
239 goto done;
240 }
241
242 if (!isA_CFString(key)) {
243 *sc_status = kSCStatusInvalidArgument;
244 goto done;
245 }
246
247 mySession = getSession(server);
248 if (mySession == NULL) {
249 mySession = tempSession(server, CFSTR("SCDynamicStoreSetValue"), audit_token);
250 if (mySession == NULL) {
251 /* you must have an open session to play */
252 *sc_status = kSCStatusNoStoreSession;
253 goto done;
254 }
255 }
256
257 if (!hasWriteAccess(mySession, "set", key)) {
258 *sc_status = kSCStatusAccessError;
259 goto done;
260 }
261
262 *sc_status = __SCDynamicStoreSetValue(mySession->store, key, data, FALSE);
263
264 done :
265
266 if (key) CFRelease(key);
267 if (data) CFRelease(data);
268 return KERN_SUCCESS;
269 }
270
271 static void
272 setSpecificKey(const void *key, const void *value, void *context)
273 {
274 CFStringRef k = (CFStringRef)key;
275 CFDataRef v = (CFDataRef)value;
276 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
277
278 if (!isA_CFString(k)) {
279 return;
280 }
281
282 if (!isA_CFData(v)) {
283 return;
284 }
285
286 (void) __SCDynamicStoreSetValue(store, k, v, TRUE);
287
288 return;
289 }
290
291 static void
292 removeSpecificKey(const void *value, void *context)
293 {
294 CFStringRef k = (CFStringRef)value;
295 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
296
297 if (!isA_CFString(k)) {
298 return;
299 }
300
301 (void) __SCDynamicStoreRemoveValue(store, k, TRUE);
302
303 return;
304 }
305
306 static void
307 notifySpecificKey(const void *value, void *context)
308 {
309 CFStringRef k = (CFStringRef)value;
310 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
311
312 if (!isA_CFString(k)) {
313 return;
314 }
315
316 (void) __SCDynamicStoreNotifyValue(store, k, TRUE);
317
318 return;
319 }
320
321 __private_extern__
322 int
323 __SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFArrayRef keysToNotify)
324 {
325 int sc_status = kSCStatusOK;
326 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
327
328 SC_trace("set m : %5d : %ld set, %ld remove, %ld notify",
329 storePrivate->server,
330 keysToSet ? CFDictionaryGetCount(keysToSet) : 0,
331 keysToRemove ? CFArrayGetCount (keysToRemove) : 0,
332 keysToNotify ? CFArrayGetCount (keysToNotify) : 0);
333
334 /*
335 * Set the new/updated keys
336 */
337 if (keysToSet) {
338 CFDictionaryApplyFunction(keysToSet,
339 setSpecificKey,
340 (void *)store);
341 }
342
343 /*
344 * Remove the specified keys
345 */
346 if (keysToRemove) {
347 CFArrayApplyFunction(keysToRemove,
348 CFRangeMake(0, CFArrayGetCount(keysToRemove)),
349 removeSpecificKey,
350 (void *)store);
351 }
352
353 /*
354 * Notify the specified keys
355 */
356 if (keysToNotify) {
357 CFArrayApplyFunction(keysToNotify,
358 CFRangeMake(0, CFArrayGetCount(keysToNotify)),
359 notifySpecificKey,
360 (void *)store);
361 }
362
363 /* push changes */
364 __SCDynamicStorePush();
365
366 return sc_status;
367 }
368
369 #define N_QUICK 32
370
371 __private_extern__
372 kern_return_t
373 _configset_m(mach_port_t server,
374 xmlData_t dictRef,
375 mach_msg_type_number_t dictLen,
376 xmlData_t removeRef,
377 mach_msg_type_number_t removeLen,
378 xmlData_t notifyRef,
379 mach_msg_type_number_t notifyLen,
380 int *sc_status,
381 audit_token_t audit_token)
382 {
383 CFDictionaryRef dict = NULL; /* key/value dictionary (un-serialized) */
384 serverSessionRef mySession;
385 CFArrayRef notify = NULL; /* keys to notify (un-serialized) */
386 CFArrayRef remove = NULL; /* keys to remove (un-serialized) */
387
388 *sc_status = kSCStatusOK;
389
390 if ((dictRef != NULL) && (dictLen > 0)) {
391 /* un-serialize the key/value pairs to set */
392 if (!_SCUnserialize((CFPropertyListRef *)&dict, NULL, (void *)dictRef, dictLen)) {
393 *sc_status = kSCStatusFailed;
394 }
395 }
396
397 if ((removeRef != NULL) && (removeLen > 0)) {
398 /* un-serialize the keys to remove */
399 if (!_SCUnserialize((CFPropertyListRef *)&remove, NULL, (void *)removeRef, removeLen)) {
400 *sc_status = kSCStatusFailed;
401 }
402 }
403
404 if ((notifyRef != NULL) && (notifyLen > 0)) {
405 /* un-serialize the keys to notify */
406 if (!_SCUnserialize((CFPropertyListRef *)&notify, NULL, (void *)notifyRef, notifyLen)) {
407 *sc_status = kSCStatusFailed;
408 }
409 }
410
411 if (*sc_status != kSCStatusOK) {
412 goto done;
413 }
414
415 if ((dict != NULL) && !isA_CFDictionary(dict)) {
416 *sc_status = kSCStatusInvalidArgument;
417 goto done;
418 }
419
420 if ((remove != NULL) && !isA_CFArray(remove)) {
421 *sc_status = kSCStatusInvalidArgument;
422 goto done;
423 }
424
425 if ((notify != NULL) && !isA_CFArray(notify)) {
426 *sc_status = kSCStatusInvalidArgument;
427 goto done;
428 }
429
430 mySession = getSession(server);
431 if (mySession == NULL) {
432 mySession = tempSession(server, CFSTR("SCDynamicStoreSetMultiple"), audit_token);
433 if (mySession == NULL) {
434 /* you must have an open session to play */
435 *sc_status = kSCStatusNoStoreSession;
436 goto done;
437 }
438 }
439
440 if (dict != NULL) {
441 const void * keys_q[N_QUICK];
442 const void ** keys = keys_q;
443 CFIndex i;
444 CFIndex n;
445 Boolean writeOK = TRUE;
446
447 n = CFDictionaryGetCount(dict);
448 if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFStringRef))) {
449 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
450 }
451 CFDictionaryGetKeysAndValues(dict, keys, NULL);
452 for (i = 0; i < n; i++) {
453 CFStringRef key;
454
455 key = (CFStringRef)keys[i];
456 if (!hasWriteAccess(mySession, "set (multiple)", key)) {
457 writeOK = FALSE;
458 break;
459 }
460 }
461 if (keys != keys_q) {
462 CFAllocatorDeallocate(NULL, keys);
463 }
464
465 if (!writeOK) {
466 *sc_status = kSCStatusAccessError;
467 goto done;
468 }
469 }
470
471 if (remove != NULL) {
472 CFIndex i;
473 CFIndex n = CFArrayGetCount(remove);
474
475 for (i = 0; i < n; i++) {
476 CFStringRef key;
477
478 key = CFArrayGetValueAtIndex(remove, i);
479 if (!hasWriteAccess(mySession, "set/remove (multiple)", key)) {
480 *sc_status = kSCStatusAccessError;
481 goto done;
482 }
483 }
484 }
485
486 if (notify != NULL) {
487 CFIndex i;
488 CFIndex n = CFArrayGetCount(notify);
489
490 for (i = 0; i < n; i++) {
491 CFStringRef key;
492
493 key = CFArrayGetValueAtIndex(notify, i);
494 if (!hasWriteAccess(mySession, "set/notify (multiple)", key)) {
495 *sc_status = kSCStatusAccessError;
496 goto done;
497 }
498 }
499 }
500
501 *sc_status = __SCDynamicStoreSetMultiple(mySession->store, dict, remove, notify);
502
503 done :
504
505 if (dict != NULL) CFRelease(dict);
506 if (remove != NULL) CFRelease(remove);
507 if (notify != NULL) CFRelease(notify);
508
509 return KERN_SUCCESS;
510 }