#include "configd.h"
#include "session.h"
#include "pattern.h"
__private_extern__
int
__SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef value, Boolean internal)
{
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
Boolean newEntry = FALSE;
int sc_status = kSCStatusOK;
CFStringRef sessionKey;
SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
CFStringRef storeSessionKey;
if (_configd_trace) {
SCTrace(TRUE, _configd_trace,
CFSTR("%s%s : %5d : %@\n"),
internal ? "*set " : "set ",
storePrivate->useSessionKeys ? "t " : " ",
storePrivate->server,
key);
}
dict = CFDictionaryGetValue(storeData, key);
if (dict) {
newDict = CFDictionaryCreateMutableCopy(NULL,
0,
dict);
} else {
newDict = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
newEntry = !CFDictionaryContainsKey(newDict, kSCDData);
CFDictionarySetValue(newDict, kSCDData, value);
sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
if (storePrivate->useSessionKeys) {
if (newEntry) {
CFArrayRef keys;
CFMutableDictionaryRef newSession;
CFMutableArrayRef newKeys;
CFDictionaryRef session;
session = CFDictionaryGetValue(sessionData, sessionKey);
keys = CFDictionaryGetValue(session, kSCDSessionKeys);
if ((keys == NULL) ||
(CFArrayGetFirstIndexOfValue(keys,
CFRangeMake(0, CFArrayGetCount(keys)),
key) == kCFNotFound)) {
if (keys != NULL) {
newKeys = CFArrayCreateMutableCopy(NULL, 0, keys);
} else {
newKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
CFArrayAppendValue(newKeys, key);
newSession = CFDictionaryCreateMutableCopy(NULL, 0, session);
CFDictionarySetValue(newSession, kSCDSessionKeys, newKeys);
CFRelease(newKeys);
CFDictionarySetValue(sessionData, sessionKey, newSession);
CFRelease(newSession);
}
CFDictionarySetValue(newDict, kSCDSession, sessionKey);
} else {
dict = CFDictionaryGetValue(storeData, key);
if (!CFDictionaryGetValueIfPresent(dict, kSCDSession, (void *)&storeSessionKey) ||
!CFEqual(sessionKey, storeSessionKey)) {
sc_status = kSCStatusKeyExists;
CFRelease(sessionKey);
CFRelease(newDict);
goto done;
}
}
} else {
if (!newEntry &&
CFDictionaryGetValueIfPresent(newDict, kSCDSession, (void *)&storeSessionKey) &&
!CFEqual(sessionKey, storeSessionKey)) {
CFStringRef removedKey;
CFDictionaryRemoveValue(newDict, kSCDSession);
removedKey = CFStringCreateWithFormat(NULL, 0, CFSTR("%@:%@"), storeSessionKey, key);
CFSetAddValue(removedSessionKeys, removedKey);
CFRelease(removedKey);
}
}
CFRelease(sessionKey);
CFDictionarySetValue(storeData, key, newDict);
CFRelease(newDict);
if (newEntry) {
if (CFSetContainsValue(deferredRemovals, key)) {
CFSetRemoveValue(deferredRemovals, key);
} else {
patternAddKey(key);
}
}
CFSetAddValue(changedKeys, key);
done :
if (!internal) {
__SCDynamicStorePush();
}
return sc_status;
}
__private_extern__
kern_return_t
_configset(mach_port_t server,
xmlData_t keyRef,
mach_msg_type_number_t keyLen,
xmlData_t dataRef,
mach_msg_type_number_t dataLen,
int oldInstance,
int *newInstance,
int *sc_status,
audit_token_t audit_token)
{
CFDataRef data = NULL;
CFStringRef key = NULL;
serverSessionRef mySession;
*sc_status = kSCStatusOK;
if (!_SCUnserializeString(&key, NULL, (void *)keyRef, keyLen)) {
*sc_status = kSCStatusFailed;
}
if (!_SCUnserializeData(&data, (void *)dataRef, dataLen)) {
*sc_status = kSCStatusFailed;
}
if (*sc_status != kSCStatusOK) {
goto done;
}
if (!isA_CFString(key)) {
*sc_status = kSCStatusInvalidArgument;
goto done;
}
mySession = getSession(server);
if (mySession == NULL) {
mySession = tempSession(server, CFSTR("SCDynamicStoreSetValue"), audit_token);
if (mySession == NULL) {
*sc_status = kSCStatusNoStoreSession;
goto done;
}
}
if (!hasWriteAccess(mySession)) {
*sc_status = kSCStatusAccessError;
goto done;
}
*sc_status = __SCDynamicStoreSetValue(mySession->store, key, data, FALSE);
*newInstance = 0;
done :
if (key) CFRelease(key);
if (data) CFRelease(data);
return KERN_SUCCESS;
}
static void
setSpecificKey(const void *key, const void *value, void *context)
{
CFStringRef k = (CFStringRef)key;
CFDataRef v = (CFDataRef)value;
SCDynamicStoreRef store = (SCDynamicStoreRef)context;
if (!isA_CFString(k)) {
return;
}
if (!isA_CFData(v)) {
return;
}
(void) __SCDynamicStoreSetValue(store, k, v, TRUE);
return;
}
static void
removeSpecificKey(const void *value, void *context)
{
CFStringRef k = (CFStringRef)value;
SCDynamicStoreRef store = (SCDynamicStoreRef)context;
if (!isA_CFString(k)) {
return;
}
(void) __SCDynamicStoreRemoveValue(store, k, TRUE);
return;
}
static void
notifySpecificKey(const void *value, void *context)
{
CFStringRef k = (CFStringRef)value;
SCDynamicStoreRef store = (SCDynamicStoreRef)context;
if (!isA_CFString(k)) {
return;
}
(void) __SCDynamicStoreNotifyValue(store, k, TRUE);
return;
}
__private_extern__
int
__SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFArrayRef keysToNotify)
{
int sc_status = kSCStatusOK;
SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
if (_configd_trace) {
SCTrace(TRUE, _configd_trace,
CFSTR("set m : %5d : %d set, %d remove, %d notify\n"),
storePrivate->server,
keysToSet ? CFDictionaryGetCount(keysToSet) : 0,
keysToRemove ? CFArrayGetCount (keysToRemove) : 0,
keysToNotify ? CFArrayGetCount (keysToNotify) : 0);
}
if (keysToSet) {
CFDictionaryApplyFunction(keysToSet,
setSpecificKey,
(void *)store);
}
if (keysToRemove) {
CFArrayApplyFunction(keysToRemove,
CFRangeMake(0, CFArrayGetCount(keysToRemove)),
removeSpecificKey,
(void *)store);
}
if (keysToNotify) {
CFArrayApplyFunction(keysToNotify,
CFRangeMake(0, CFArrayGetCount(keysToNotify)),
notifySpecificKey,
(void *)store);
}
__SCDynamicStorePush();
return sc_status;
}
__private_extern__
kern_return_t
_configset_m(mach_port_t server,
xmlData_t dictRef,
mach_msg_type_number_t dictLen,
xmlData_t removeRef,
mach_msg_type_number_t removeLen,
xmlData_t notifyRef,
mach_msg_type_number_t notifyLen,
int *sc_status,
audit_token_t audit_token)
{
CFDictionaryRef dict = NULL;
serverSessionRef mySession;
CFArrayRef notify = NULL;
CFArrayRef remove = NULL;
*sc_status = kSCStatusOK;
if ((dictRef != NULL) && (dictLen > 0)) {
if (!_SCUnserialize((CFPropertyListRef *)&dict, NULL, (void *)dictRef, dictLen)) {
*sc_status = kSCStatusFailed;
}
}
if ((removeRef != NULL) && (removeLen > 0)) {
if (!_SCUnserialize((CFPropertyListRef *)&remove, NULL, (void *)removeRef, removeLen)) {
*sc_status = kSCStatusFailed;
}
}
if ((notifyRef != NULL) && (notifyLen > 0)) {
if (!_SCUnserialize((CFPropertyListRef *)¬ify, NULL, (void *)notifyRef, notifyLen)) {
*sc_status = kSCStatusFailed;
}
}
if (*sc_status != kSCStatusOK) {
goto done;
}
if ((dict != NULL) && !isA_CFDictionary(dict)) {
*sc_status = kSCStatusInvalidArgument;
goto done;
}
if ((remove != NULL) && !isA_CFArray(remove)) {
*sc_status = kSCStatusInvalidArgument;
goto done;
}
if ((notify != NULL) && !isA_CFArray(notify)) {
*sc_status = kSCStatusInvalidArgument;
goto done;
}
mySession = getSession(server);
if (mySession == NULL) {
mySession = tempSession(server, CFSTR("SCDynamicStoreSetMultiple"), audit_token);
if (mySession == NULL) {
*sc_status = kSCStatusNoStoreSession;
goto done;
}
}
if (!hasWriteAccess(mySession)) {
*sc_status = kSCStatusAccessError;
goto done;
}
*sc_status = __SCDynamicStoreSetMultiple(mySession->store, dict, remove, notify);
done :
if (dict != NULL) CFRelease(dict);
if (remove != NULL) CFRelease(remove);
if (notify != NULL) CFRelease(notify);
return KERN_SUCCESS;
}