2 * Copyright (c) 2000-2004, 2006, 2008, 2011 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
;
53 SCTrace(TRUE
, _configd_trace
,
54 CFSTR("%s%s : %5d : %@\n"),
55 internal
? "*set " : "set ",
56 storePrivate
->useSessionKeys
? "t " : " ",
62 * Grab the current (or establish a new) dictionary for this key.
65 dict
= CFDictionaryGetValue(storeData
, key
);
67 newDict
= CFDictionaryCreateMutableCopy(NULL
,
71 newDict
= CFDictionaryCreateMutable(NULL
,
73 &kCFTypeDictionaryKeyCallBacks
,
74 &kCFTypeDictionaryValueCallBacks
);
78 * Update the dictionary entry to be saved to the store.
80 newEntry
= !CFDictionaryContainsKey(newDict
, kSCDData
);
81 CFDictionarySetValue(newDict
, kSCDData
, value
);
83 sessionKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%d"), storePrivate
->server
);
86 * Manage per-session keys.
88 if (storePrivate
->useSessionKeys
) {
91 CFMutableDictionaryRef newSession
;
92 CFMutableArrayRef newKeys
;
93 CFDictionaryRef session
;
96 * Add this key to my list of per-session keys
98 session
= CFDictionaryGetValue(sessionData
, sessionKey
);
99 keys
= CFDictionaryGetValue(session
, kSCDSessionKeys
);
100 if ((keys
== NULL
) ||
101 (CFArrayGetFirstIndexOfValue(keys
,
102 CFRangeMake(0, CFArrayGetCount(keys
)),
103 key
) == kCFNotFound
)) {
105 * if no session keys defined "or" keys defined but not
109 /* this is the first session key */
110 newKeys
= CFArrayCreateMutableCopy(NULL
, 0, keys
);
112 /* this is an additional session key */
113 newKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
115 CFArrayAppendValue(newKeys
, key
);
117 /* update session dictionary */
118 newSession
= CFDictionaryCreateMutableCopy(NULL
, 0, session
);
119 CFDictionarySetValue(newSession
, kSCDSessionKeys
, newKeys
);
121 CFDictionarySetValue(sessionData
, sessionKey
, newSession
);
122 CFRelease(newSession
);
126 * Mark the key as a "session" key and track the creator.
128 CFDictionarySetValue(newDict
, kSCDSession
, sessionKey
);
131 * Since we are using per-session keys and this key already
132 * exists, check if it was created by "our" session
134 dict
= CFDictionaryGetValue(storeData
, key
);
135 if (!CFDictionaryGetValueIfPresent(dict
, kSCDSession
, (void *)&storeSessionKey
) ||
136 !CFEqual(sessionKey
, storeSessionKey
)) {
138 * if the key exists and is not a session key or
139 * if the key exists it's not "our" session.
141 sc_status
= kSCStatusKeyExists
;
142 CFRelease(sessionKey
);
149 * Since we are updating this key we need to check and, if
150 * necessary, remove the indication that this key is on
151 * another session's remove-on-close list.
154 CFDictionaryGetValueIfPresent(newDict
, kSCDSession
, (void *)&storeSessionKey
) &&
155 !CFEqual(sessionKey
, storeSessionKey
)) {
156 CFStringRef removedKey
;
158 /* We are no longer a session key! */
159 CFDictionaryRemoveValue(newDict
, kSCDSession
);
161 /* add this session key to the (session) removal list */
162 removedKey
= CFStringCreateWithFormat(NULL
, 0, CFSTR("%@:%@"), storeSessionKey
, key
);
163 CFSetAddValue(removedSessionKeys
, removedKey
);
164 CFRelease(removedKey
);
168 CFRelease(sessionKey
);
171 * Update the dictionary entry in the store.
174 CFDictionarySetValue(storeData
, key
, newDict
);
178 * For "new" entries to the store, check the deferred cleanup
179 * list. If the key is flagged for removal, remove it from the
180 * list since any defined regex's for this key are still defined
181 * and valid. If the key is not flagged then iterate over the
182 * sessionData dictionary looking for regex keys which match the
183 * updated key. If a match is found then we mark those keys as
188 if (CFSetContainsValue(deferredRemovals
, key
)) {
189 CFSetRemoveValue(deferredRemovals
, key
);
196 * Mark this key as "changed". Any "watchers" will be notified
197 * as soon as the lock is released.
199 CFSetAddValue(changedKeys
, key
);
205 __SCDynamicStorePush();
213 _configset(mach_port_t server
,
214 xmlData_t keyRef
, /* raw XML bytes */
215 mach_msg_type_number_t keyLen
,
216 xmlData_t dataRef
, /* raw XML bytes */
217 mach_msg_type_number_t dataLen
,
221 audit_token_t audit_token
)
223 CFDataRef data
= NULL
; /* data (un-serialized) */
224 CFStringRef key
= NULL
; /* key (un-serialized) */
225 serverSessionRef mySession
;
227 *sc_status
= kSCStatusOK
;
229 /* un-serialize the key */
230 if (!_SCUnserializeString(&key
, NULL
, (void *)keyRef
, keyLen
)) {
231 *sc_status
= kSCStatusFailed
;
234 /* un-serialize the data */
235 if (!_SCUnserializeData(&data
, (void *)dataRef
, dataLen
)) {
236 *sc_status
= kSCStatusFailed
;
239 if (*sc_status
!= kSCStatusOK
) {
243 if (!isA_CFString(key
)) {
244 *sc_status
= kSCStatusInvalidArgument
;
248 mySession
= getSession(server
);
249 if (mySession
== NULL
) {
250 mySession
= tempSession(server
, CFSTR("SCDynamicStoreSetValue"), audit_token
);
251 if (mySession
== NULL
) {
252 /* you must have an open session to play */
253 *sc_status
= kSCStatusNoStoreSession
;
258 if (!hasWriteAccess(mySession
)) {
259 *sc_status
= kSCStatusAccessError
;
263 *sc_status
= __SCDynamicStoreSetValue(mySession
->store
, key
, data
, FALSE
);
268 if (key
) CFRelease(key
);
269 if (data
) CFRelease(data
);
274 setSpecificKey(const void *key
, const void *value
, void *context
)
276 CFStringRef k
= (CFStringRef
)key
;
277 CFDataRef v
= (CFDataRef
)value
;
278 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
280 if (!isA_CFString(k
)) {
284 if (!isA_CFData(v
)) {
288 (void) __SCDynamicStoreSetValue(store
, k
, v
, TRUE
);
294 removeSpecificKey(const void *value
, void *context
)
296 CFStringRef k
= (CFStringRef
)value
;
297 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
299 if (!isA_CFString(k
)) {
303 (void) __SCDynamicStoreRemoveValue(store
, k
, TRUE
);
309 notifySpecificKey(const void *value
, void *context
)
311 CFStringRef k
= (CFStringRef
)value
;
312 SCDynamicStoreRef store
= (SCDynamicStoreRef
)context
;
314 if (!isA_CFString(k
)) {
318 (void) __SCDynamicStoreNotifyValue(store
, k
, TRUE
);
325 __SCDynamicStoreSetMultiple(SCDynamicStoreRef store
, CFDictionaryRef keysToSet
, CFArrayRef keysToRemove
, CFArrayRef keysToNotify
)
327 int sc_status
= kSCStatusOK
;
328 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
330 if (_configd_trace
) {
331 SCTrace(TRUE
, _configd_trace
,
332 CFSTR("set m : %5d : %d set, %d remove, %d notify\n"),
333 storePrivate
->server
,
334 keysToSet
? CFDictionaryGetCount(keysToSet
) : 0,
335 keysToRemove
? CFArrayGetCount (keysToRemove
) : 0,
336 keysToNotify
? CFArrayGetCount (keysToNotify
) : 0);
340 * Set the new/updated keys
343 CFDictionaryApplyFunction(keysToSet
,
349 * Remove the specified keys
352 CFArrayApplyFunction(keysToRemove
,
353 CFRangeMake(0, CFArrayGetCount(keysToRemove
)),
359 * Notify the specified keys
362 CFArrayApplyFunction(keysToNotify
,
363 CFRangeMake(0, CFArrayGetCount(keysToNotify
)),
369 __SCDynamicStorePush();
376 _configset_m(mach_port_t server
,
378 mach_msg_type_number_t dictLen
,
380 mach_msg_type_number_t removeLen
,
382 mach_msg_type_number_t notifyLen
,
384 audit_token_t audit_token
)
386 CFDictionaryRef dict
= NULL
; /* key/value dictionary (un-serialized) */
387 serverSessionRef mySession
;
388 CFArrayRef notify
= NULL
; /* keys to notify (un-serialized) */
389 CFArrayRef remove
= NULL
; /* keys to remove (un-serialized) */
391 *sc_status
= kSCStatusOK
;
393 if ((dictRef
!= NULL
) && (dictLen
> 0)) {
394 /* un-serialize the key/value pairs to set */
395 if (!_SCUnserialize((CFPropertyListRef
*)&dict
, NULL
, (void *)dictRef
, dictLen
)) {
396 *sc_status
= kSCStatusFailed
;
400 if ((removeRef
!= NULL
) && (removeLen
> 0)) {
401 /* un-serialize the keys to remove */
402 if (!_SCUnserialize((CFPropertyListRef
*)&remove
, NULL
, (void *)removeRef
, removeLen
)) {
403 *sc_status
= kSCStatusFailed
;
407 if ((notifyRef
!= NULL
) && (notifyLen
> 0)) {
408 /* un-serialize the keys to notify */
409 if (!_SCUnserialize((CFPropertyListRef
*)¬ify
, NULL
, (void *)notifyRef
, notifyLen
)) {
410 *sc_status
= kSCStatusFailed
;
414 if (*sc_status
!= kSCStatusOK
) {
418 if ((dict
!= NULL
) && !isA_CFDictionary(dict
)) {
419 *sc_status
= kSCStatusInvalidArgument
;
423 if ((remove
!= NULL
) && !isA_CFArray(remove
)) {
424 *sc_status
= kSCStatusInvalidArgument
;
428 if ((notify
!= NULL
) && !isA_CFArray(notify
)) {
429 *sc_status
= kSCStatusInvalidArgument
;
433 mySession
= getSession(server
);
434 if (mySession
== NULL
) {
435 mySession
= tempSession(server
, CFSTR("SCDynamicStoreSetMultiple"), audit_token
);
436 if (mySession
== NULL
) {
437 /* you must have an open session to play */
438 *sc_status
= kSCStatusNoStoreSession
;
443 if (!hasWriteAccess(mySession
)) {
444 *sc_status
= kSCStatusAccessError
;
448 *sc_status
= __SCDynamicStoreSetMultiple(mySession
->store
, dict
, remove
, notify
);
452 if (dict
!= NULL
) CFRelease(dict
);
453 if (remove
!= NULL
) CFRelease(remove
);
454 if (notify
!= NULL
) CFRelease(notify
);