#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include "SCDynamicStoreInternal.h"
#include "v1Compatibility.h"
extern void __Initialize();
typedef struct {
CFPropertyListRef data;
int instance;
} SCDHandlePrivate, *SCDHandlePrivateRef;
SCDHandleRef
SCDHandleInit()
{
SCDHandlePrivateRef privateHandle = CFAllocatorAllocate(NULL, sizeof(SCDHandlePrivate), 0);
privateHandle->data = NULL;
privateHandle->instance = 0;
return (SCDHandleRef)privateHandle;
}
void
SCDHandleRelease(SCDHandleRef handle)
{
SCDHandlePrivateRef privateHandle = (SCDHandlePrivateRef)handle;
if (privateHandle->data)
CFRelease(privateHandle->data);
CFAllocatorDeallocate(NULL, privateHandle);
return;
}
int
SCDHandleGetInstance(SCDHandleRef handle)
{
SCDHandlePrivateRef privateHandle = (SCDHandlePrivateRef)handle;
return privateHandle->instance;
}
void
_SCDHandleSetInstance(SCDHandleRef handle, int instance)
{
SCDHandlePrivateRef privateHandle = (SCDHandlePrivateRef)handle;
privateHandle->instance = instance;
return;
}
CFPropertyListRef
SCDHandleGetData(SCDHandleRef handle)
{
SCDHandlePrivateRef privateHandle = (SCDHandlePrivateRef)handle;
if (privateHandle->data == NULL) {
return CFSTR("SCDHandleRef not initialized.");
}
return privateHandle->data;
}
void
SCDHandleSetData(SCDHandleRef handle, CFPropertyListRef data)
{
SCDHandlePrivateRef privateHandle = (SCDHandlePrivateRef)handle;
if (privateHandle->data)
CFRelease(privateHandle->data);
privateHandle->data = data;
if (privateHandle->data)
CFRetain(privateHandle->data);
return;
}
static int
convert_SCDStatus_To_SCStatus(SCDStatus status)
{
switch (status) {
case SCD_OK : return kSCStatusOK;
case SCD_NOSESSION : return kSCStatusNoStoreSession;
case SCD_NOSERVER : return kSCStatusNoStoreServer;
case SCD_LOCKED : return kSCStatusLocked;
case SCD_NEEDLOCK : return kSCStatusNeedLock;
case SCD_EACCESS : return kSCStatusAccessError;
case SCD_NOKEY : return kSCStatusNoKey;
case SCD_EXISTS : return kSCStatusKeyExists;
case SCD_STALE : return kSCStatusStale;
case SCD_INVALIDARGUMENT : return kSCStatusInvalidArgument;
case SCD_NOTIFIERACTIVE : return kSCStatusNotifierActive;
case SCD_FAILED : return kSCStatusFailed;
default : return kSCStatusFailed;
}
}
SCDStatus
SCDOpen(SCDSessionRef *session, CFStringRef name)
{
SCDynamicStoreRef newStore;
__Initialize();
newStore = SCDynamicStoreCreate(NULL, name, NULL, NULL);
if (!newStore) {
return SCD_NOSERVER;
}
*session = (SCDSessionRef)newStore;
return SCD_OK;
}
SCDStatus
SCDClose(SCDSessionRef *session)
{
CFRelease(*session);
*session = NULL;
return SCD_OK;
}
SCDStatus
SCDLock(SCDSessionRef session)
{
return SCDynamicStoreLock((SCDynamicStoreRef)session) ? SCD_OK : SCD_FAILED;
}
SCDStatus
SCDUnlock(SCDSessionRef session)
{
return SCDynamicStoreUnlock((SCDynamicStoreRef)session) ? SCD_OK : SCD_FAILED;
}
SCDStatus
SCDList(SCDSessionRef session, CFStringRef key, int regexOptions, CFArrayRef *subKeys)
{
CFMutableStringRef pattern;
pattern = CFStringCreateMutableCopy(NULL, 0, key);
if ((regexOptions & kSCDRegexKey) != kSCDRegexKey) {
CFStringAppend(pattern, CFSTR(".*"));
}
*subKeys = SCDynamicStoreCopyKeyList((SCDynamicStoreRef)session, pattern);
CFRelease(pattern);
return (*subKeys) ? SCD_OK : SCD_FAILED;
}
SCDStatus
SCDAdd(SCDSessionRef session, CFStringRef key, SCDHandleRef handle)
{
CFTypeRef value = SCDHandleGetData(handle);
return SCDynamicStoreAddValue((SCDynamicStoreRef)session, key, value) ? SCD_OK : SCD_EXISTS;
}
SCDStatus
SCDAddSession(SCDSessionRef session, CFStringRef key, SCDHandleRef handle)
{
CFTypeRef value = SCDHandleGetData(handle);
return SCDynamicStoreAddTemporaryValue((SCDynamicStoreRef)session, key, value) ? SCD_OK : SCD_EXISTS;
}
SCDStatus
SCDGet(SCDSessionRef session, CFStringRef key, SCDHandleRef *handle)
{
CFTypeRef value;
value = SCDynamicStoreCopyValue((SCDynamicStoreRef)session, key);
if (value) {
*handle = SCDHandleInit();
SCDHandleSetData(*handle, value);
CFRelease(value);
return SCD_OK;
}
return SCD_NOKEY;
}
SCDStatus
SCDSet(SCDSessionRef session, CFStringRef key, SCDHandleRef handle)
{
CFTypeRef value = SCDHandleGetData(handle);
return SCDynamicStoreSetValue((SCDynamicStoreRef)session, key, value) ? SCD_OK : SCD_EXISTS;
}
SCDStatus
SCDRemove(SCDSessionRef session, CFStringRef key)
{
return SCDynamicStoreRemoveValue((SCDynamicStoreRef)session, key) ? SCD_OK : SCD_NOKEY;
}
SCDStatus
SCDTouch(SCDSessionRef session, CFStringRef key)
{
return SCDynamicStoreTouchValue((SCDynamicStoreRef)session, key) ? SCD_OK : SCD_FAILED;
}
SCDStatus
SCDNotifierList(SCDSessionRef session, int regexOptions, CFArrayRef *notifierKeys)
{
*notifierKeys = SCDynamicStoreCopyWatchedKeyList((SCDynamicStoreRef)session,
((regexOptions & kSCDRegexKey) == kSCDRegexKey));
return (*notifierKeys) ? SCD_OK : SCD_FAILED;
}
SCDStatus
SCDNotifierAdd(SCDSessionRef session, CFStringRef key, int regexOptions)
{
return SCDynamicStoreAddWatchedKey((SCDynamicStoreRef)session,
key,
((regexOptions & kSCDRegexKey) == kSCDRegexKey)) ? SCD_OK : SCD_EXISTS;
}
SCDStatus
SCDNotifierRemove(SCDSessionRef session, CFStringRef key, int regexOptions)
{
return SCDynamicStoreRemoveWatchedKey((SCDynamicStoreRef)session,
key,
((regexOptions & kSCDRegexKey) == kSCDRegexKey)) ? SCD_OK : SCD_NOKEY;
}
SCDStatus
SCDNotifierGetChanges(SCDSessionRef session, CFArrayRef *changedKeys)
{
*changedKeys = SCDynamicStoreCopyNotifiedKeys((SCDynamicStoreRef)session);
return (*changedKeys) ? SCD_OK : SCD_FAILED;
}
SCDStatus
SCDNotifierWait(SCDSessionRef session)
{
return SCDynamicStoreNotifyWait((SCDynamicStoreRef)session) ? SCD_OK : SCD_FAILED;
}
SCDStatus
SCDNotifierInformViaCallback(SCDSessionRef session, SCDCallbackRoutine_t func, void *arg)
{
return SCDynamicStoreNotifyCallback((SCDynamicStoreRef)session,
CFRunLoopGetCurrent(),
(SCDynamicStoreCallBack_v1)func,
arg) ? SCD_OK : SCD_NOTIFIERACTIVE;
}
SCDStatus
SCDNotifierInformViaMachPort(SCDSessionRef session, mach_msg_id_t msgid, mach_port_t *port)
{
return SCDynamicStoreNotifyMachPort((SCDynamicStoreRef)session, msgid, port) ? SCD_OK : SCD_NOTIFIERACTIVE;
}
SCDStatus
SCDNotifierInformViaFD(SCDSessionRef session, int32_t identifier, int *fd)
{
return SCDynamicStoreNotifyFileDescriptor((SCDynamicStoreRef)session, identifier, fd) ? SCD_OK : SCD_NOTIFIERACTIVE;
}
SCDStatus
SCDNotifierInformViaSignal(SCDSessionRef session, pid_t pid, int sig)
{
return SCDynamicStoreNotifySignal((SCDynamicStoreRef)session, pid, sig) ? SCD_OK : SCD_NOTIFIERACTIVE;
}
SCDStatus
SCDNotifierCancel(SCDSessionRef session)
{
return SCDynamicStoreNotifyCancel((SCDynamicStoreRef)session) ? SCD_OK : SCD_NOTIFIERACTIVE;
}
SCDStatus
SCDSnapshot(SCDSessionRef session)
{
return SCDynamicStoreSnapshot((SCDynamicStoreRef)session) ? SCD_OK : SCD_NOTIFIERACTIVE;
}
int
SCDOptionGet(SCDSessionRef session, int option)
{
int value = 0;
if (session) {
static Boolean warned = FALSE;
if (!warned) {
SCLog(TRUE, LOG_NOTICE, CFSTR("per-session options are no longer supported, using global options."));
warned = TRUE;
}
}
switch (option) {
case kSCDOptionDebug :
value = _sc_debug ? 1 : 0;
break;
case kSCDOptionVerbose :
value = _sc_verbose ? 1 : 0;
break;
case kSCDOptionUseSyslog :
value = _sc_log ? 1 : 0;
break;
case kSCDOptionUseCFRunLoop :
value = 1;
break;
}
return value;
}
void
SCDOptionSet(SCDSessionRef session, int option, int value)
{
if (session) {
static Boolean warned = FALSE;
if (!warned) {
SCLog(TRUE, LOG_NOTICE, CFSTR("per-session options are no longer supported, using global options."));
warned = TRUE;
}
}
switch (option) {
case kSCDOptionDebug :
_sc_debug = (value != 0);
_sc_log = (value == 0);
break;
case kSCDOptionVerbose :
_sc_verbose = (value != 0);
break;
case kSCDOptionUseSyslog :
{
_sc_log = (value != 0);
break;
}
case kSCDOptionUseCFRunLoop :
{
static Boolean warned = FALSE;
if ((value == FALSE) && !warned) {
SCLog(TRUE, LOG_NOTICE, CFSTR("The kSCDOptionUseCFRunLoop option can no longer be set FALSE. The"));
SCLog(TRUE, LOG_NOTICE, CFSTR("SCDNotifierInformViaCallback requires the use of a CFRunLoop."));
warned = TRUE;
}
break;
}
}
return;
}
void
SCDSessionLog(SCDSessionRef session, int level, CFStringRef formatString, ...)
{
va_list argList;
FILE *f = (LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout;
CFStringRef resultString;
if ((LOG_PRI(level) == LOG_DEBUG) && !SCDOptionGet(session, kSCDOptionVerbose)) {
return;
}
va_start(argList, formatString);
resultString = CFStringCreateWithFormatAndArguments(NULL, NULL, formatString, argList);
va_end(argList);
if (SCDOptionGet(session, kSCDOptionUseSyslog)) {
__SCLog(level, resultString);
} else {
CFStringRef newString;
newString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\n"), resultString);
__SCPrint(f, newString);
CFRelease(newString);
}
CFRelease(resultString);
}
void
SCDLog(int level, CFStringRef formatString, ...)
{
va_list argList;
FILE *f = (LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout;
CFStringRef resultString;
if ((LOG_PRI(level) == LOG_DEBUG) && !SCDOptionGet(NULL, kSCDOptionVerbose)) {
return;
}
va_start(argList, formatString);
resultString = CFStringCreateWithFormatAndArguments(NULL, NULL, formatString, argList);
va_end(argList);
if (SCDOptionGet(NULL, kSCDOptionUseSyslog)) {
__SCLog(level, resultString);
} else {
CFStringRef newString;
newString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\n"), resultString);
__SCPrint(f, newString);
CFRelease(newString);
}
CFRelease(resultString);
}
const char *
SCDError(SCDStatus status)
{
return SCErrorString(convert_SCDStatus_To_SCStatus(status));
}
CFStringRef
SCDKeyCreate(CFStringRef fmt, ...)
{
va_list args;
va_start(args, fmt);
return (CFStringCreateWithFormatAndArguments(NULL,
NULL,
fmt,
args));
}
CFStringRef
SCDKeyCreateNetworkGlobalEntity(CFStringRef domain, CFStringRef entity)
{
return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, domain, entity);
}
CFStringRef
SCDKeyCreateNetworkInterface(CFStringRef domain)
{
return SCDynamicStoreKeyCreateNetworkInterface(NULL, domain);
}
CFStringRef
SCDKeyCreateNetworkInterfaceEntity(CFStringRef domain, CFStringRef ifname, CFStringRef entity)
{
return SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, domain, ifname, entity);
}
CFStringRef
SCDKeyCreateNetworkServiceEntity(CFStringRef domain, CFStringRef serviceID, CFStringRef entity)
{
return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, domain, serviceID, entity);
}
static int
convert_SCPStatus_To_SCStatus(SCPStatus status)
{
switch (status) {
case SCP_OK : return kSCStatusOK;
case SCP_NOSESSION : return kSCStatusNoPrefsSession;
case SCP_BUSY : return kSCStatusPrefsBusy;
case SCP_NEEDLOCK : return kSCStatusNeedLock;
case SCP_EACCESS : return kSCStatusAccessError;
case SCP_ENOENT : return kSCStatusNoConfigFile;
case SCP_BADCF : return kSCStatusFailed;
case SCP_NOKEY : return kSCStatusNoKey;
case SCP_NOLINK : return kSCStatusNoLink;
case SCP_EXISTS : return kSCStatusKeyExists;
case SCP_STALE : return kSCStatusStale;
case SCP_INVALIDARGUMENT : return kSCStatusInvalidArgument;
case SCP_FAILED : return kSCStatusFailed;
default : return kSCStatusFailed;
}
}
SCPStatus
SCPOpen(SCPSessionRef *session, CFStringRef name, CFStringRef prefsID, int options)
{
CFArrayRef keys;
CFIndex nKeys;
__Initialize();
*session = (SCPSessionRef)SCPreferencesCreate(NULL, name, prefsID);
if (*session == NULL) {
return SCP_EACCESS;
}
keys = SCPreferencesCopyKeyList(*session);
nKeys = CFArrayGetCount(keys);
CFRelease(keys);
if ((nKeys == 0) &&
((options & kSCPOpenCreatePrefs) != kSCPOpenCreatePrefs)) {
return SCP_ENOENT;
}
return SCP_OK;
}
SCPStatus
SCPUserOpen(SCPSessionRef *session, CFStringRef name, CFStringRef prefsID, CFStringRef user, int options)
{
CFArrayRef keys;
CFIndex nKeys;
__Initialize();
*session = (SCPSessionRef)SCUserPreferencesCreate(NULL, name, prefsID, user);
if (*session == NULL) {
return SCP_EACCESS;
}
keys = SCPreferencesCopyKeyList(*session);
nKeys = CFArrayGetCount(keys);
CFRelease(keys);
if ((nKeys == 0) &&
((options & kSCPOpenCreatePrefs) != kSCPOpenCreatePrefs)) {
return SCP_ENOENT;
}
return SCP_OK;
}
SCPStatus
SCPClose(SCPSessionRef *session)
{
CFRelease(*session);
*session = NULL;
return SCD_OK;
}
SCPStatus
SCPLock(SCPSessionRef session, boolean_t wait)
{
return SCPreferencesLock((SCPreferencesRef)session, wait) ? SCP_OK : SCP_FAILED;
}
SCPStatus
SCPCommit(SCPSessionRef session)
{
return SCPreferencesCommitChanges((SCPreferencesRef)session) ? SCP_OK : SCP_FAILED;
}
SCPStatus
SCPApply(SCPSessionRef session)
{
return SCPreferencesApplyChanges((SCPreferencesRef)session) ? SCP_OK : SCP_EACCESS;
}
SCPStatus
SCPUnlock(SCPSessionRef session)
{
return SCPreferencesUnlock((SCPreferencesRef)session) ? SCP_OK : SCP_FAILED;
}
SCPStatus
SCPGetSignature(SCPSessionRef session, CFDataRef *signature)
{
*signature = SCPreferencesGetSignature((SCPreferencesRef)session);
return (*signature) ? SCP_OK : SCP_FAILED;
}
SCPStatus
SCPList(SCPSessionRef session, CFArrayRef *keys)
{
*keys = SCPreferencesCopyKeyList((SCPreferencesRef)session);
return (*keys) ? SCP_OK : SCP_FAILED;
}
SCPStatus
SCPGet(SCPSessionRef session, CFStringRef key, CFPropertyListRef *data)
{
*data = SCPreferencesGetValue((SCPreferencesRef)session, key);
return (*data) ? SCP_OK : SCP_NOKEY;
}
SCPStatus
SCPAdd(SCPSessionRef session, CFStringRef key, CFPropertyListRef data)
{
return SCPreferencesAddValue((SCPreferencesRef)session, key, data) ? SCP_OK : SCP_EXISTS;
}
SCPStatus
SCPSet(SCPSessionRef session, CFStringRef key, CFPropertyListRef data)
{
return SCPreferencesSetValue((SCPreferencesRef)session, key, data) ? SCP_OK : SCP_FAILED;
}
SCPStatus
SCPRemove(SCPSessionRef session, CFStringRef key)
{
return SCPreferencesRemoveValue((SCPreferencesRef)session, key) ? SCP_OK : SCP_NOKEY;
}
CFStringRef
SCPNotificationKeyCreate(CFStringRef prefsID, int keyType)
{
return SCDynamicStoreKeyCreatePreferences(NULL, prefsID, keyType);
}
CFStringRef
SCPUserNotificationKeyCreate(CFStringRef prefsID, CFStringRef user, int keyType)
{
return SCDynamicStoreKeyCreateUserPreferences(NULL, prefsID, user, keyType);
}
SCPStatus
SCPPathCreateUniqueChild(SCPSessionRef session, CFStringRef prefix, CFStringRef *newPath)
{
*newPath = SCPreferencesPathCreateUniqueChild((SCPreferencesRef)session, prefix);
return (*newPath) ? SCP_OK : SCP_NOKEY;
}
SCPStatus
SCPPathGetValue(SCPSessionRef session, CFStringRef path, CFDictionaryRef *value)
{
*value = SCPreferencesPathGetValue((SCPreferencesRef)session, path);
return (*value) ? SCP_OK : SCP_NOKEY;
}
SCPStatus
SCPPathGetLink(SCPSessionRef session, CFStringRef path, CFStringRef *link)
{
*link = SCPreferencesPathGetLink((SCPreferencesRef)session, path);
return (*link) ? SCP_OK : SCP_NOKEY;
}
SCPStatus
SCPPathSetValue(SCPSessionRef session, CFStringRef path, CFDictionaryRef value)
{
return SCPreferencesPathSetValue((SCPreferencesRef)session, path, value) ? SCP_OK : SCP_FAILED;
}
SCPStatus
SCPPathSetLink(SCPSessionRef session, CFStringRef path, CFStringRef link)
{
return SCPreferencesPathSetLink((SCPreferencesRef)session, path, link) ? SCP_OK : SCP_FAILED;
}
SCPStatus
SCPPathRemove(SCPSessionRef session, CFStringRef path)
{
return SCPreferencesPathRemoveValue((SCPreferencesRef)session, path) ? SCP_OK : SCP_NOKEY;
}
const char *
SCPError(SCPStatus status)
{
return SCErrorString(convert_SCPStatus_To_SCStatus(status));
}
CFStringRef
SCDKeyCreateConsoleUser()
{
return SCDynamicStoreKeyCreateConsoleUser(NULL);
}
SCDStatus
SCDConsoleUserGet(char *user, int userlen, uid_t *uid, gid_t *gid)
{
CFStringRef consoleUser;
consoleUser = SCDynamicStoreCopyConsoleUser(NULL, uid, gid);
if (!consoleUser) {
return SCD_NOKEY;
}
if (user && (userlen > 0)) {
CFIndex len;
CFRange range;
bzero(user, userlen);
range = CFRangeMake(0, CFStringGetLength(consoleUser));
(void) CFStringGetBytes(consoleUser,
range,
kCFStringEncodingMacRoman,
0,
FALSE,
user,
userlen,
&len);
}
CFRelease(consoleUser);
return SCD_OK;
}
SCDStatus
SCDConsoleUserSet(const char *user, uid_t uid, gid_t gid)
{
return SCDynamicStoreSetConsoleUser(NULL, user, uid, gid) ? SCD_OK : SCD_FAILED;
}
CFStringRef
SCDKeyCreateHostName()
{
return SCDynamicStoreKeyCreateComputerName(NULL);
}
SCDStatus
SCDHostNameGet(CFStringRef *name, CFStringEncoding *nameEncoding)
{
*name = SCDynamicStoreCopyComputerName(NULL, nameEncoding);
return (*name) ? SCD_OK : SCD_FAILED;
}
static SCNStatus
convertReachability(int newFlags, int *oldFlags)
{
SCNStatus scn_status = SCN_REACHABLE_NO;
if (newFlags & kSCNetworkFlagsTransientConnection) {
if (oldFlags) {
*oldFlags |= kSCNFlagsTransientConnection;
}
}
if (newFlags & kSCNetworkFlagsReachable) {
scn_status = SCN_REACHABLE_YES;
if (newFlags & kSCNetworkFlagsConnectionRequired) {
scn_status = SCN_REACHABLE_CONNECTION_REQUIRED;
}
if (newFlags & kSCNetworkFlagsConnectionAutomatic) {
if (oldFlags) {
*oldFlags |= kSCNFlagsConnectionAutomatic;
}
}
if (newFlags & kSCNetworkFlagsInterventionRequired) {
if (oldFlags) {
*oldFlags |= kSCNFlagsInterventionRequired;
}
}
}
return scn_status;
}
SCNStatus
SCNIsReachableByAddress(const struct sockaddr *address, const int addrlen, int *flags, const char **errorMessage)
{
SCNetworkConnectionFlags newFlags;
if (!SCNetworkCheckReachabilityByAddress(address, addrlen, &newFlags)) {
if (errorMessage) {
*errorMessage = SCErrorString(kSCStatusReachabilityUnknown);
}
return SCN_REACHABLE_UNKNOWN;
}
return convertReachability(newFlags, flags);
}
SCNStatus
SCNIsReachableByName(const char *nodename, int *flags, const char **errorMessage)
{
SCNetworkConnectionFlags newFlags;
if (!SCNetworkCheckReachabilityByName(nodename, &newFlags)) {
if (errorMessage) {
*errorMessage = SCErrorString(kSCStatusReachabilityUnknown);
}
return SCN_REACHABLE_UNKNOWN;
}
return convertReachability(newFlags, flags);
}