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 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
;
53 SC_trace("%s%s : %5d : %@",
54 internal
? "*set " : "set ",
55 storePrivate
->useSessionKeys
? "t " : " ",
60 * Grab the current (or establish a new) dictionary for this key.
63 dict
= CFDictionaryGetValue(storeData
, key
);
65 newDict
= CFDictionaryCreateMutableCopy(NULL
,
69 newDict
= CFDictionaryCreateMutable(NULL
,
71 &kCFTypeDictionaryKeyCallBacks
,
72 &kCFTypeDictionaryValueCallBacks
);
76 * Update the dictionary entry to be saved to the store.
78 newEntry
= !CFDictionaryContainsKey(newDict
, kSCDData
);
79 CFDictionarySetValue(newDict
, kSCDData
, value
);
82 * Manage per-session keys.
84 sessionKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), storePrivate
->server
);
85 if (storePrivate
->useSessionKeys
) {
88 * Add this key to my list of per-session keys
90 mySession
= getSession(storePrivate
->server
);
91 if ((mySession
->sessionKeys
== NULL
) ||
92 !CFArrayContainsValue(mySession
->sessionKeys
,
93 CFRangeMake(0, CFArrayGetCount(mySession
->sessionKeys
)),
96 * if no session keys defined "or" keys defined but not
99 if (mySession
->sessionKeys
== NULL
) {
100 /* this is an additional session key */
101 mySession
->sessionKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
103 CFArrayAppendValue(mySession
->sessionKeys
, key
);
107 * Mark the key as a "session" key and track the creator.
109 CFDictionarySetValue(newDict
, kSCDSession
, sessionKey
);
112 * Since we are using per-session keys and this key already
113 * exists, check if it was created by "our" session
115 dict
= CFDictionaryGetValue(storeData
, key
);
116 if (!CFDictionaryGetValueIfPresent(dict
, kSCDSession
, (void *)&storeSessionKey
) ||
117 !CFEqual(sessionKey
, storeSessionKey
)) {
119 * if the key exists and is not a session key or
120 * if the key exists it's not "our" session.
122 sc_status
= kSCStatusKeyExists
;
123 CFRelease(sessionKey
);
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.
135 CFDictionaryGetValueIfPresent(newDict
, kSCDSession
, (void *)&storeSessionKey
) &&
136 !CFEqual(sessionKey
, storeSessionKey
)) {
137 CFStringRef removedKey
;
139 /* We are no longer a session key! */
140 CFDictionaryRemoveValue(newDict
, kSCDSession
);
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
);
148 CFRelease(sessionKey
);
151 * Update the dictionary entry in the store.
154 CFDictionarySetValue(storeData
, key
, newDict
);
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
168 if (CFSetContainsValue(deferredRemovals
, key
)) {
169 CFSetRemoveValue(deferredRemovals
, key
);
176 * Mark this key as "changed". Any "watchers" will be notified
177 * as soon as the lock is released.
179 CFSetAddValue(changedKeys
, key
);
185 __SCDynamicStorePush();
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
,
201 audit_token_t audit_token
)
203 #pragma unused(oldInstance)
204 CFDataRef data
= NULL
; /* data (un-serialized) */
205 CFStringRef key
= NULL
; /* key (un-serialized) */
206 serverSessionRef mySession
;
209 *sc_status
= kSCStatusOK
;
211 /* un-serialize the key */
212 if (!_SCUnserializeString(&key
, NULL
, (void *)keyRef
, keyLen
)) {
213 *sc_status
= kSCStatusFailed
;
216 /* un-serialize the data */
217 if (!_SCUnserializeData(&data
, (void *)dataRef
, dataLen
)) {
218 *sc_status
= kSCStatusFailed
;
221 if (*sc_status
!= kSCStatusOK
) {
225 if (!isA_CFString(key
)) {
226 *sc_status
= kSCStatusInvalidArgument
;
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
;
240 if (!hasWriteAccess(mySession
, "set", key
)) {
241 *sc_status
= kSCStatusAccessError
;
245 *sc_status
= __SCDynamicStoreSetValue(mySession
->store
, key
, data
, FALSE
);
249 if (key
) CFRelease(key
);
250 if (data
) CFRelease(data
);
255 setSpecificKey(const void *key
, const void *value
, void *context
)
257 CFStringRef k
= (CFStringRef
)key
;
258 CFDataRef v
= (CFDataRef
)value
;
259 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
261 if (!isA_CFString(k
)) {
265 if (!isA_CFData(v
)) {
269 (void) __SCDynamicStoreSetValue(store
, k
, v
, TRUE
);
275 removeSpecificKey(const void *value
, void *context
)
277 CFStringRef k
= (CFStringRef
)value
;
278 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
280 if (!isA_CFString(k
)) {
284 (void) __SCDynamicStoreRemoveValue(store
, k
, TRUE
);
290 notifySpecificKey(const void *value
, void *context
)
292 CFStringRef k
= (CFStringRef
)value
;
293 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
295 if (!isA_CFString(k
)) {
299 (void) __SCDynamicStoreNotifyValue(store
, k
, TRUE
);
306 __SCDynamicStoreSetMultiple(SCDynamicStoreRef store
, CFDictionaryRef keysToSet
, CFArrayRef keysToRemove
, CFArrayRef keysToNotify
)
308 int sc_status
= kSCStatusOK
;
309 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
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);
318 * Set the new/updated keys
321 CFDictionaryApplyFunction(keysToSet
,
327 * Remove the specified keys
330 CFArrayApplyFunction(keysToRemove
,
331 CFRangeMake(0, CFArrayGetCount(keysToRemove
)),
337 * Notify the specified keys
340 CFArrayApplyFunction(keysToNotify
,
341 CFRangeMake(0, CFArrayGetCount(keysToNotify
)),
347 __SCDynamicStorePush();
356 _configset_m(mach_port_t server
,
358 mach_msg_type_number_t dictLen
,
360 mach_msg_type_number_t removeLen
,
362 mach_msg_type_number_t notifyLen
,
364 audit_token_t audit_token
)
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) */
371 *sc_status
= kSCStatusOK
;
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
;
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
;
387 if ((notifyRef
!= NULL
) && (notifyLen
> 0)) {
388 /* un-serialize the keys to notify */
389 if (!_SCUnserialize((CFPropertyListRef
*)¬ify
, NULL
, (void *)notifyRef
, notifyLen
)) {
390 *sc_status
= kSCStatusFailed
;
394 if (*sc_status
!= kSCStatusOK
) {
398 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
399 *sc_status
= kSCStatusInvalidArgument
;
403 if ((remove
!= NULL
) && !isA_CFArray(remove
)) {
404 *sc_status
= kSCStatusInvalidArgument
;
408 if ((notify
!= NULL
) && !isA_CFArray(notify
)) {
409 *sc_status
= kSCStatusInvalidArgument
;
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
;
424 const void * keys_q
[N_QUICK
];
425 const void ** keys
= keys_q
;
428 Boolean writeOK
= TRUE
;
430 n
= CFDictionaryGetCount(dict
);
431 if (n
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFStringRef
))) {
432 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
434 CFDictionaryGetKeysAndValues(dict
, keys
, NULL
);
435 for (i
= 0; i
< n
; i
++) {
438 key
= (CFStringRef
)keys
[i
];
439 if (!hasWriteAccess(mySession
, "set (multiple)", key
)) {
444 if (keys
!= keys_q
) {
445 CFAllocatorDeallocate(NULL
, keys
);
449 *sc_status
= kSCStatusAccessError
;
454 if (remove
!= NULL
) {
456 CFIndex n
= CFArrayGetCount(remove
);
458 for (i
= 0; i
< n
; i
++) {
461 key
= CFArrayGetValueAtIndex(remove
, i
);
462 if (!hasWriteAccess(mySession
, "set/remove (multiple)", key
)) {
463 *sc_status
= kSCStatusAccessError
;
469 if (notify
!= NULL
) {
471 CFIndex n
= CFArrayGetCount(notify
);
473 for (i
= 0; i
< n
; i
++) {
476 key
= CFArrayGetValueAtIndex(notify
, i
);
477 if (!hasWriteAccess(mySession
, "set/notify (multiple)", key
)) {
478 *sc_status
= kSCStatusAccessError
;
484 *sc_status
= __SCDynamicStoreSetMultiple(mySession
->store
, dict
, remove
, notify
);
488 if (dict
!= NULL
) CFRelease(dict
);
489 if (remove
!= NULL
) CFRelease(remove
);
490 if (notify
!= NULL
) CFRelease(notify
);