2 * Copyright (c) 2000-2004, 2006, 2008, 2011, 2012, 2014-2017, 2019 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("%s%s : %5d : %@",
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 #pragma unused(oldInstance)
221 CFDataRef data
= NULL
; /* data (un-serialized) */
222 CFStringRef key
= NULL
; /* key (un-serialized) */
223 serverSessionRef mySession
;
226 *sc_status
= kSCStatusOK
;
228 /* un-serialize the key */
229 if (!_SCUnserializeString(&key
, NULL
, (void *)keyRef
, keyLen
)) {
230 *sc_status
= kSCStatusFailed
;
233 /* un-serialize the data */
234 if (!_SCUnserializeData(&data
, (void *)dataRef
, dataLen
)) {
235 *sc_status
= kSCStatusFailed
;
238 if (*sc_status
!= kSCStatusOK
) {
242 if (!isA_CFString(key
)) {
243 *sc_status
= kSCStatusInvalidArgument
;
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
;
257 if (!hasWriteAccess(mySession
, "set", key
)) {
258 *sc_status
= kSCStatusAccessError
;
262 *sc_status
= __SCDynamicStoreSetValue(mySession
->store
, key
, data
, FALSE
);
266 if (key
) CFRelease(key
);
267 if (data
) CFRelease(data
);
272 setSpecificKey(const void *key
, const void *value
, void *context
)
274 CFStringRef k
= (CFStringRef
)key
;
275 CFDataRef v
= (CFDataRef
)value
;
276 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
278 if (!isA_CFString(k
)) {
282 if (!isA_CFData(v
)) {
286 (void) __SCDynamicStoreSetValue(store
, k
, v
, TRUE
);
292 removeSpecificKey(const void *value
, void *context
)
294 CFStringRef k
= (CFStringRef
)value
;
295 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
297 if (!isA_CFString(k
)) {
301 (void) __SCDynamicStoreRemoveValue(store
, k
, TRUE
);
307 notifySpecificKey(const void *value
, void *context
)
309 CFStringRef k
= (CFStringRef
)value
;
310 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
312 if (!isA_CFString(k
)) {
316 (void) __SCDynamicStoreNotifyValue(store
, k
, TRUE
);
323 __SCDynamicStoreSetMultiple(SCDynamicStoreRef store
, CFDictionaryRef keysToSet
, CFArrayRef keysToRemove
, CFArrayRef keysToNotify
)
325 int sc_status
= kSCStatusOK
;
326 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
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);
335 * Set the new/updated keys
338 CFDictionaryApplyFunction(keysToSet
,
344 * Remove the specified keys
347 CFArrayApplyFunction(keysToRemove
,
348 CFRangeMake(0, CFArrayGetCount(keysToRemove
)),
354 * Notify the specified keys
357 CFArrayApplyFunction(keysToNotify
,
358 CFRangeMake(0, CFArrayGetCount(keysToNotify
)),
364 __SCDynamicStorePush();
373 _configset_m(mach_port_t server
,
375 mach_msg_type_number_t dictLen
,
377 mach_msg_type_number_t removeLen
,
379 mach_msg_type_number_t notifyLen
,
381 audit_token_t audit_token
)
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) */
388 *sc_status
= kSCStatusOK
;
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
;
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
;
404 if ((notifyRef
!= NULL
) && (notifyLen
> 0)) {
405 /* un-serialize the keys to notify */
406 if (!_SCUnserialize((CFPropertyListRef
*)¬ify
, NULL
, (void *)notifyRef
, notifyLen
)) {
407 *sc_status
= kSCStatusFailed
;
411 if (*sc_status
!= kSCStatusOK
) {
415 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
416 *sc_status
= kSCStatusInvalidArgument
;
420 if ((remove
!= NULL
) && !isA_CFArray(remove
)) {
421 *sc_status
= kSCStatusInvalidArgument
;
425 if ((notify
!= NULL
) && !isA_CFArray(notify
)) {
426 *sc_status
= kSCStatusInvalidArgument
;
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
;
441 const void * keys_q
[N_QUICK
];
442 const void ** keys
= keys_q
;
445 Boolean writeOK
= TRUE
;
447 n
= CFDictionaryGetCount(dict
);
448 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFStringRef
))) {
449 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
451 CFDictionaryGetKeysAndValues(dict
, keys
, NULL
);
452 for (i
= 0; i
< n
; i
++) {
455 key
= (CFStringRef
)keys
[i
];
456 if (!hasWriteAccess(mySession
, "set (multiple)", key
)) {
461 if (keys
!= keys_q
) {
462 CFAllocatorDeallocate(NULL
, keys
);
466 *sc_status
= kSCStatusAccessError
;
471 if (remove
!= NULL
) {
473 CFIndex n
= CFArrayGetCount(remove
);
475 for (i
= 0; i
< n
; i
++) {
478 key
= CFArrayGetValueAtIndex(remove
, i
);
479 if (!hasWriteAccess(mySession
, "set/remove (multiple)", key
)) {
480 *sc_status
= kSCStatusAccessError
;
486 if (notify
!= NULL
) {
488 CFIndex n
= CFArrayGetCount(notify
);
490 for (i
= 0; i
< n
; i
++) {
493 key
= CFArrayGetValueAtIndex(notify
, i
);
494 if (!hasWriteAccess(mySession
, "set/notify (multiple)", key
)) {
495 *sc_status
= kSCStatusAccessError
;
501 *sc_status
= __SCDynamicStoreSetMultiple(mySession
->store
, dict
, remove
, notify
);
505 if (dict
!= NULL
) CFRelease(dict
);
506 if (remove
!= NULL
) CFRelease(remove
);
507 if (notify
!= NULL
) CFRelease(notify
);