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