2 * Copyright (c) 2000-2004, 2006, 2008, 2011, 2012, 2014, 2015 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
42 __SCDynamicStoreSetValue(SCDynamicStoreRef store
, CFStringRef key
, CFDataRef value
, Boolean internal
)
45 CFMutableDictionaryRef newDict
;
46 Boolean newEntry
= FALSE
;
47 int sc_status
= kSCStatusOK
;
48 CFStringRef sessionKey
;
49 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
50 CFStringRef storeSessionKey
;
52 SC_trace(_configd_trace
, "%s%s : %5d : %@\n",
53 internal
? "*set " : "set ",
54 storePrivate
->useSessionKeys
? "t " : " ",
59 * Grab the current (or establish a new) dictionary for this key.
62 dict
= CFDictionaryGetValue(storeData
, key
);
64 newDict
= CFDictionaryCreateMutableCopy(NULL
,
68 newDict
= CFDictionaryCreateMutable(NULL
,
70 &kCFTypeDictionaryKeyCallBacks
,
71 &kCFTypeDictionaryValueCallBacks
);
75 * Update the dictionary entry to be saved to the store.
77 newEntry
= !CFDictionaryContainsKey(newDict
, kSCDData
);
78 CFDictionarySetValue(newDict
, kSCDData
, value
);
80 sessionKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), storePrivate
->server
);
83 * Manage per-session keys.
85 if (storePrivate
->useSessionKeys
) {
88 CFMutableDictionaryRef newSession
;
89 CFMutableArrayRef newKeys
;
90 CFDictionaryRef session
;
93 * Add this key to my list of per-session keys
95 session
= CFDictionaryGetValue(sessionData
, sessionKey
);
96 keys
= CFDictionaryGetValue(session
, kSCDSessionKeys
);
98 (CFArrayGetFirstIndexOfValue(keys
,
99 CFRangeMake(0, CFArrayGetCount(keys
)),
100 key
) == kCFNotFound
)) {
102 * if no session keys defined "or" keys defined but not
106 /* this is the first session key */
107 newKeys
= CFArrayCreateMutableCopy(NULL
, 0, keys
);
109 /* this is an additional session key */
110 newKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
112 CFArrayAppendValue(newKeys
, key
);
114 /* update session dictionary */
115 newSession
= CFDictionaryCreateMutableCopy(NULL
, 0, session
);
116 CFDictionarySetValue(newSession
, kSCDSessionKeys
, newKeys
);
118 CFDictionarySetValue(sessionData
, sessionKey
, newSession
);
119 CFRelease(newSession
);
123 * Mark the key as a "session" key and track the creator.
125 CFDictionarySetValue(newDict
, kSCDSession
, sessionKey
);
128 * Since we are using per-session keys and this key already
129 * exists, check if it was created by "our" session
131 dict
= CFDictionaryGetValue(storeData
, key
);
132 if (!CFDictionaryGetValueIfPresent(dict
, kSCDSession
, (void *)&storeSessionKey
) ||
133 !CFEqual(sessionKey
, storeSessionKey
)) {
135 * if the key exists and is not a session key or
136 * if the key exists it's not "our" session.
138 sc_status
= kSCStatusKeyExists
;
139 CFRelease(sessionKey
);
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.
151 CFDictionaryGetValueIfPresent(newDict
, kSCDSession
, (void *)&storeSessionKey
) &&
152 !CFEqual(sessionKey
, storeSessionKey
)) {
153 CFStringRef removedKey
;
155 /* We are no longer a session key! */
156 CFDictionaryRemoveValue(newDict
, kSCDSession
);
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
);
165 CFRelease(sessionKey
);
168 * Update the dictionary entry in the store.
171 CFDictionarySetValue(storeData
, key
, newDict
);
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
185 if (CFSetContainsValue(deferredRemovals
, key
)) {
186 CFSetRemoveValue(deferredRemovals
, key
);
193 * Mark this key as "changed". Any "watchers" will be notified
194 * as soon as the lock is released.
196 CFSetAddValue(changedKeys
, key
);
202 __SCDynamicStorePush();
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
,
218 audit_token_t audit_token
)
220 CFDataRef data
= NULL
; /* data (un-serialized) */
221 CFStringRef key
= NULL
; /* key (un-serialized) */
222 serverSessionRef mySession
;
224 *sc_status
= kSCStatusOK
;
226 /* un-serialize the key */
227 if (!_SCUnserializeString(&key
, NULL
, (void *)keyRef
, keyLen
)) {
228 *sc_status
= kSCStatusFailed
;
231 /* un-serialize the data */
232 if (!_SCUnserializeData(&data
, (void *)dataRef
, dataLen
)) {
233 *sc_status
= kSCStatusFailed
;
236 if (*sc_status
!= kSCStatusOK
) {
240 if (!isA_CFString(key
)) {
241 *sc_status
= kSCStatusInvalidArgument
;
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
;
255 if (!hasWriteAccess(mySession
, key
)) {
256 *sc_status
= kSCStatusAccessError
;
260 *sc_status
= __SCDynamicStoreSetValue(mySession
->store
, key
, data
, FALSE
);
265 if (key
) CFRelease(key
);
266 if (data
) CFRelease(data
);
271 setSpecificKey(const void *key
, const void *value
, void *context
)
273 CFStringRef k
= (CFStringRef
)key
;
274 CFDataRef v
= (CFDataRef
)value
;
275 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
277 if (!isA_CFString(k
)) {
281 if (!isA_CFData(v
)) {
285 (void) __SCDynamicStoreSetValue(store
, k
, v
, TRUE
);
291 removeSpecificKey(const void *value
, void *context
)
293 CFStringRef k
= (CFStringRef
)value
;
294 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
296 if (!isA_CFString(k
)) {
300 (void) __SCDynamicStoreRemoveValue(store
, k
, TRUE
);
306 notifySpecificKey(const void *value
, void *context
)
308 CFStringRef k
= (CFStringRef
)value
;
309 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
311 if (!isA_CFString(k
)) {
315 (void) __SCDynamicStoreNotifyValue(store
, k
, TRUE
);
322 __SCDynamicStoreSetMultiple(SCDynamicStoreRef store
, CFDictionaryRef keysToSet
, CFArrayRef keysToRemove
, CFArrayRef keysToNotify
)
324 int sc_status
= kSCStatusOK
;
325 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
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);
334 * Set the new/updated keys
337 CFDictionaryApplyFunction(keysToSet
,
343 * Remove the specified keys
346 CFArrayApplyFunction(keysToRemove
,
347 CFRangeMake(0, CFArrayGetCount(keysToRemove
)),
353 * Notify the specified keys
356 CFArrayApplyFunction(keysToNotify
,
357 CFRangeMake(0, CFArrayGetCount(keysToNotify
)),
363 __SCDynamicStorePush();
372 _configset_m(mach_port_t server
,
374 mach_msg_type_number_t dictLen
,
376 mach_msg_type_number_t removeLen
,
378 mach_msg_type_number_t notifyLen
,
380 audit_token_t audit_token
)
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) */
387 *sc_status
= kSCStatusOK
;
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
;
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
;
403 if ((notifyRef
!= NULL
) && (notifyLen
> 0)) {
404 /* un-serialize the keys to notify */
405 if (!_SCUnserialize((CFPropertyListRef
*)¬ify
, NULL
, (void *)notifyRef
, notifyLen
)) {
406 *sc_status
= kSCStatusFailed
;
410 if (*sc_status
!= kSCStatusOK
) {
414 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
415 *sc_status
= kSCStatusInvalidArgument
;
419 if ((remove
!= NULL
) && !isA_CFArray(remove
)) {
420 *sc_status
= kSCStatusInvalidArgument
;
424 if ((notify
!= NULL
) && !isA_CFArray(notify
)) {
425 *sc_status
= kSCStatusInvalidArgument
;
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
;
440 const void * keys_q
[N_QUICK
];
441 const void ** keys
= keys_q
;
444 Boolean writeOK
= TRUE
;
446 n
= CFDictionaryGetCount(dict
);
447 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFStringRef
))) {
448 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
450 CFDictionaryGetKeysAndValues(dict
, keys
, NULL
);
451 for (i
= 0; i
< n
; i
++) {
454 key
= (CFStringRef
)keys
[i
];
455 if (!hasWriteAccess(mySession
, key
)) {
460 if (keys
!= keys_q
) {
461 CFAllocatorDeallocate(NULL
, keys
);
465 *sc_status
= kSCStatusAccessError
;
470 if (remove
!= NULL
) {
472 CFIndex n
= CFArrayGetCount(remove
);
474 for (i
= 0; i
< n
; i
++) {
477 key
= CFArrayGetValueAtIndex(remove
, i
);
478 if (!hasWriteAccess(mySession
, key
)) {
479 *sc_status
= kSCStatusAccessError
;
485 if (notify
!= NULL
) {
487 CFIndex n
= CFArrayGetCount(notify
);
489 for (i
= 0; i
< n
; i
++) {
492 key
= CFArrayGetValueAtIndex(notify
, i
);
493 if (!hasWriteAccess(mySession
, key
)) {
494 *sc_status
= kSCStatusAccessError
;
500 *sc_status
= __SCDynamicStoreSetMultiple(mySession
->store
, dict
, remove
, notify
);
504 if (dict
!= NULL
) CFRelease(dict
);
505 if (remove
!= NULL
) CFRelease(remove
);
506 if (notify
!= NULL
) CFRelease(notify
);