SCNetworkConnectionPrivate.c [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h> // for SCLog
#include "SCNetworkConfigurationInternal.h"
#include <notify.h>
#include <pthread.h>
#include <ppp/PPPControllerPriv.h>
#pragma mark -
#pragma mark SCUserPreferences
typedef struct {
CFRuntimeBase cfBase;
CFStringRef serviceID;
CFStringRef prefsID;
} SCUserPreferencesPrivate, *SCUserPreferencesPrivateRef;
static CFStringRef __SCUserPreferencesCopyDescription (CFTypeRef cf);
static void __SCUserPreferencesDeallocate (CFTypeRef cf);
static Boolean __SCUserPreferencesEqual (CFTypeRef cf1, CFTypeRef cf2);
static CFHashCode __SCUserPreferencesHash (CFTypeRef cf);
static CFTypeID __kSCUserPreferencesTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __SCUserPreferencesClass = {
0, "SCUserPreferences", NULL, NULL, __SCUserPreferencesDeallocate, __SCUserPreferencesEqual, __SCUserPreferencesHash, NULL, __SCUserPreferencesCopyDescription };
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static CFStringRef
__SCUserPreferencesCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
SCUserPreferencesPrivateRef prefsPrivate = (SCUserPreferencesPrivateRef)cf;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<SCUserPreferences %p [%p]> {"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR("service = %@"), prefsPrivate->serviceID);
CFStringAppendFormat(result, NULL, CFSTR(", id = %@"), prefsPrivate->prefsID);
CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
static void
__SCUserPreferencesDeallocate(CFTypeRef cf)
{
SCUserPreferencesPrivateRef prefsPrivate = (SCUserPreferencesPrivateRef)cf;
CFRelease(prefsPrivate->prefsID);
CFRelease(prefsPrivate->serviceID);
return;
}
static Boolean
__SCUserPreferencesEqual(CFTypeRef cf1, CFTypeRef cf2)
{
SCUserPreferencesPrivateRef s1 = (SCUserPreferencesPrivateRef)cf1;
SCUserPreferencesPrivateRef s2 = (SCUserPreferencesPrivateRef)cf2;
if (s1 == s2)
return TRUE;
if (!CFEqual(s1->prefsID, s2->prefsID))
return FALSE;
return TRUE;
}
static CFHashCode
__SCUserPreferencesHash(CFTypeRef cf)
{
SCUserPreferencesPrivateRef prefsPrivate = (SCUserPreferencesPrivateRef)cf;
return CFHash(prefsPrivate->prefsID);
}
static void
__SCUserPreferencesInitialize(void)
{
__kSCUserPreferencesTypeID = _CFRuntimeRegisterClass(&__SCUserPreferencesClass);
return;
}
static SCUserPreferencesPrivateRef
__SCUserPreferencesCreatePrivate(CFAllocatorRef allocator,
CFStringRef serviceID,
CFStringRef prefsID)
{
SCUserPreferencesPrivateRef prefsPrivate;
uint32_t size;
pthread_once(&initialized, __SCUserPreferencesInitialize);
size = sizeof(SCUserPreferencesPrivate) - sizeof(CFRuntimeBase);
prefsPrivate = (SCUserPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
__kSCUserPreferencesTypeID,
size,
NULL);
if (prefsPrivate == NULL) {
return NULL;
}
prefsPrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
prefsPrivate->prefsID = CFStringCreateCopy(NULL, prefsID);
return prefsPrivate;
}
static __inline__ CFTypeRef
isA_SCUserPreferences(CFTypeRef obj)
{
return (isA_CFType(obj, SCUserPreferencesGetTypeID()));
}
#pragma mark -
#pragma mark SCUserPreferences SPIs
#define USER_PREFERENCES_NOTIFICATION "com.apple.networkConnect"
#define USER_PREFERENCES_APPLICATION_ID CFSTR("com.apple.networkConnect")
#define USER_PREFERENCES_ID CFSTR("UniqueIdentifier")
#define USER_PREFERENCES_DEFAULT CFSTR("ConnectByDefault")
static CFArrayRef
copyCFPreferencesForServiceID(CFStringRef serviceID)
{
CFArrayRef prefs;
(void) CFPreferencesAppSynchronize(USER_PREFERENCES_APPLICATION_ID);
prefs = CFPreferencesCopyAppValue(serviceID,
USER_PREFERENCES_APPLICATION_ID);
if ((prefs != NULL) && !isA_CFArray(prefs)) {
CFRelease(prefs);
return NULL;
}
return prefs;
}
static Boolean
setCFPreferencesForServiceID(CFStringRef serviceID, CFArrayRef newPreferences)
{
Boolean ok;
if (CFPreferencesAppValueIsForced(serviceID, USER_PREFERENCES_APPLICATION_ID)) {
return FALSE;
}
CFPreferencesSetValue(serviceID,
newPreferences,
USER_PREFERENCES_APPLICATION_ID,
kCFPreferencesCurrentUser,
kCFPreferencesCurrentHost);
ok = CFPreferencesSynchronize(USER_PREFERENCES_APPLICATION_ID,
kCFPreferencesCurrentUser,
kCFPreferencesCurrentHost);
(void) notify_post(USER_PREFERENCES_NOTIFICATION);
return ok;
}
static void
addPreference(CFMutableArrayRef *newPrefs, CFDictionaryRef newDict)
{
if (*newPrefs == NULL) {
*newPrefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
CFArrayAppendValue(*newPrefs, newDict);
return;
}
typedef CFDictionaryRef (*processPreferencesCallout) (CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3);
static Boolean
processPreferences(CFStringRef serviceID,
processPreferencesCallout callout,
void *context1,
void *context2,
void *context3)
{
Boolean changed = FALSE;
CFIndex i;
CFIndex n;
CFDictionaryRef newDict = NULL;
CFMutableArrayRef newPrefs = NULL;
Boolean ok = TRUE;
CFArrayRef prefs;
prefs = copyCFPreferencesForServiceID(serviceID);
n = (prefs != NULL) ? CFArrayGetCount(prefs) : 0;
for (i = 0; i < n; i++) {
CFDictionaryRef dict;
dict = CFArrayGetValueAtIndex(prefs, i);
if (isA_CFDictionary(dict)) {
newDict = (*callout)(serviceID, dict, context1, context2, context3);
if (newDict == NULL) {
changed = TRUE;
continue;
}
} else {
newDict = CFRetain(dict);
}
if (!CFEqual(dict, newDict)) {
changed = TRUE;
}
addPreference(&newPrefs, newDict);
CFRelease(newDict);
}
if (prefs != NULL) CFRelease(prefs);
newDict = (*callout)(serviceID, NULL, context1, context2, context3);
if (newDict != NULL) {
changed = TRUE;
addPreference(&newPrefs, newDict);
CFRelease(newDict);
}
if (changed) {
ok = setCFPreferencesForServiceID(serviceID, newPrefs);
}
if (newPrefs != NULL) CFRelease(newPrefs);
return ok;
}
static __inline__ Boolean
isMatchingPrefsID(CFDictionaryRef dict, CFStringRef matchID)
{
CFStringRef prefsID;
prefsID = CFDictionaryGetValue(dict, USER_PREFERENCES_ID);
if (isA_CFString(prefsID)) {
if (CFEqual(prefsID, matchID)) {
return TRUE;
}
}
return FALSE;
}
CFTypeID
SCUserPreferencesGetTypeID(void)
{
pthread_once(&initialized, __SCUserPreferencesInitialize);
return __kSCUserPreferencesTypeID;
}
CFStringRef
SCUserPreferencesGetUniqueID(SCUserPreferencesRef userPreferences)
{
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
return userPrivate->prefsID;
}
Boolean
SCUserPreferencesIsForced(SCUserPreferencesRef userPreferences)
{
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
return CFPreferencesAppValueIsForced(userPrivate->serviceID, USER_PREFERENCES_APPLICATION_ID);
}
static CFDictionaryRef
removeCallout(CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3)
{
CFStringRef matchID = (CFStringRef)context1;
if (current == NULL) {
return NULL;
}
if (isMatchingPrefsID(current, matchID)) {
return NULL;
}
return CFRetain(current);
}
Boolean
SCUserPreferencesRemove(SCUserPreferencesRef userPreferences)
{
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
return processPreferences(userPrivate->serviceID,
removeCallout,
(void *)userPrivate->prefsID,
NULL,
NULL);
}
static CFDictionaryRef
setCurrentCallout(CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3)
{
CFStringRef matchID = (CFStringRef)context1;
CFMutableDictionaryRef newDict;
if (current == NULL) {
return NULL;
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, current);
CFDictionaryRemoveValue(newDict, USER_PREFERENCES_DEFAULT);
if (isMatchingPrefsID(current, matchID)) {
CFDictionarySetValue(newDict, USER_PREFERENCES_DEFAULT, kCFBooleanTrue);
}
return newDict;
}
Boolean
SCUserPreferencesSetCurrent(SCUserPreferencesRef userPreferences)
{
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
return processPreferences(userPrivate->serviceID,
setCurrentCallout,
(void *)userPrivate->prefsID,
NULL,
NULL);
}
static CFDictionaryRef
copyNameCallout(CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3)
{
CFStringRef matchID = (CFStringRef)context1;
CFStringRef *name = (CFStringRef *)context3;
if (current == NULL) {
return NULL;
}
if (isMatchingPrefsID(current, matchID)) {
*name = CFDictionaryGetValue(current, kSCPropUserDefinedName);
if (*name == NULL) {
CFDictionaryRef ppp;
ppp = CFDictionaryGetValue(current, kSCEntNetPPP);
if (isA_CFDictionary(ppp)) {
*name = CFDictionaryGetValue(ppp, kSCPropUserDefinedName);
}
}
*name = isA_CFString(*name);
if (*name != NULL) {
CFRetain(*name);
}
}
return CFRetain(current);
}
CFStringRef
SCUserPreferencesCopyName(SCUserPreferencesRef userPreferences)
{
CFStringRef name = NULL;
Boolean ok;
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
ok = processPreferences(userPrivate->serviceID,
copyNameCallout,
(void *)userPrivate->prefsID,
NULL,
(void *)&name);
if (!ok) {
if (name != NULL) {
CFRelease(name);
name = NULL;
}
}
return name;
}
static CFDictionaryRef
setNameCallout(CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3)
{
CFStringRef matchID = (CFStringRef)context1;
CFMutableDictionaryRef newDict;
CFStringRef newName = (CFStringRef)context2;
if (current == NULL) {
return NULL;
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, current);
if (isMatchingPrefsID(current, matchID)) {
CFDictionaryRef pppEntity;
if (newName != NULL) {
CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
} else {
CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
}
pppEntity = CFDictionaryGetValue(newDict, kSCEntNetPPP);
if (isA_CFDictionary(pppEntity)) {
CFMutableDictionaryRef newPPPEntity;
newPPPEntity = CFDictionaryCreateMutableCopy(NULL, 0, pppEntity);
if (newName != NULL) {
CFDictionarySetValue(newPPPEntity, kSCPropUserDefinedName, newName);
} else {
CFDictionaryRemoveValue(newPPPEntity, kSCPropUserDefinedName);
}
CFDictionarySetValue(newDict, kSCEntNetPPP, newPPPEntity);
CFRelease(newPPPEntity);
}
}
return newDict;
}
Boolean
SCUserPreferencesSetName(SCUserPreferencesRef userPreferences, CFStringRef newName)
{
Boolean ok;
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if ((newName != NULL) && !isA_CFString(newName)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
ok = processPreferences(userPrivate->serviceID,
setNameCallout,
(void *)userPrivate->prefsID,
(void *)newName,
NULL);
return ok;
}
static CFDictionaryRef
copyInterfaceConfigurationCallout(CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3)
{
CFDictionaryRef *dict = (CFDictionaryRef *)context3;
CFStringRef interfaceType = (CFStringRef)context2;
CFStringRef matchID = (CFStringRef)context1;
if (current == NULL) {
return NULL;
}
if (isMatchingPrefsID(current, matchID)) {
*dict = CFDictionaryGetValue(current, interfaceType);
*dict = isA_CFDictionary(*dict);
if (*dict != NULL) {
CFRetain(*dict);
}
}
return CFRetain(current);
}
CFDictionaryRef
SCUserPreferencesCopyInterfaceConfiguration(SCUserPreferencesRef userPreferences,
SCNetworkInterfaceRef interface)
{
CFStringRef defaultType;
CFDictionaryRef entity = NULL;
Boolean ok;
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (!isA_SCNetworkInterface(interface)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
if (defaultType == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
ok = processPreferences(userPrivate->serviceID,
copyInterfaceConfigurationCallout,
(void *)userPrivate->prefsID,
(void *)defaultType,
(void *)&entity);
if (!ok) {
if (entity != NULL) {
CFRelease(entity);
entity = NULL;
}
}
return entity;
}
static CFDictionaryRef
setInterfaceConfigurationCallout(CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3)
{
CFStringRef interfaceType = (CFStringRef)context2;
CFStringRef matchID = (CFStringRef)context1;
CFMutableDictionaryRef newDict;
CFDictionaryRef newOptions = (CFDictionaryRef)context3;
if (current == NULL) {
return NULL;
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, current);
if (isMatchingPrefsID(current, matchID)) {
if (newOptions != NULL) {
CFDictionarySetValue(newDict, interfaceType, newOptions);
if (CFEqual(interfaceType, kSCEntNetPPP)) {
CFStringRef name;
name = CFDictionaryGetValue(newOptions, kSCPropUserDefinedName);
if (name != NULL) {
CFDictionarySetValue(newDict, kSCPropUserDefinedName, name);
} else {
name = CFDictionaryGetValue(newDict, kSCPropUserDefinedName);
if (name != NULL) {
CFMutableDictionaryRef newPPPEntity;
newPPPEntity = CFDictionaryCreateMutableCopy(NULL, 0, newOptions);
CFDictionarySetValue(newPPPEntity, kSCPropUserDefinedName, name);
CFDictionarySetValue(newDict, interfaceType, newPPPEntity);
CFRelease(newPPPEntity);
}
}
}
} else {
CFDictionaryRemoveValue(newDict, interfaceType);
}
}
return newDict;
}
Boolean
SCUserPreferencesSetInterfaceConfiguration(SCUserPreferencesRef userPreferences,
SCNetworkInterfaceRef interface,
CFDictionaryRef newOptions)
{
CFStringRef defaultType;
Boolean ok;
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_SCNetworkInterface(interface)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
if (defaultType == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
ok = processPreferences(userPrivate->serviceID,
setInterfaceConfigurationCallout,
(void *)userPrivate->prefsID,
(void *)defaultType,
(void *)newOptions);
return ok;
}
CFDictionaryRef
SCUserPreferencesCopyExtendedInterfaceConfiguration(SCUserPreferencesRef userPreferences,
SCNetworkInterfaceRef interface,
CFStringRef extendedType)
{
CFDictionaryRef entity = NULL;
Boolean ok;
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (!isA_SCNetworkInterface(interface)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, FALSE)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
ok = processPreferences(userPrivate->serviceID,
copyInterfaceConfigurationCallout,
(void *)userPrivate->prefsID,
(void *)extendedType,
(void *)&entity);
if (!ok) {
if (entity != NULL) {
CFRelease(entity);
entity = NULL;
}
}
return entity;
}
Boolean
SCUserPreferencesSetExtendedInterfaceConfiguration(SCUserPreferencesRef userPreferences,
SCNetworkInterfaceRef interface,
CFStringRef extendedType,
CFDictionaryRef newOptions)
{
Boolean ok;
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_SCNetworkInterface(interface)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, FALSE)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
ok = processPreferences(userPrivate->serviceID,
setInterfaceConfigurationCallout,
(void *)userPrivate->prefsID,
(void *)extendedType,
(void *)newOptions);
return ok;
}
#pragma mark -
#pragma mark SCNetworkConnection + SCUserPreferences SPIs
static CFDictionaryRef
copyAllCallout(CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3)
{
CFMutableArrayRef *prefs = (CFMutableArrayRef *)context3;
CFStringRef prefsID;
SCUserPreferencesPrivateRef userPrivate;
if (current == NULL) {
return NULL;
}
prefsID = CFDictionaryGetValue(current, USER_PREFERENCES_ID);
if (!isA_CFString(prefsID)) {
goto done;
}
userPrivate = __SCUserPreferencesCreatePrivate(NULL, serviceID, prefsID);
if (userPrivate != NULL) {
if (*prefs == NULL) {
*prefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
CFArrayAppendValue(*prefs, (SCUserPreferencesRef)userPrivate);
CFRelease(userPrivate);
}
done :
return CFRetain(current);
}
CFArrayRef
SCNetworkConnectionCopyAllUserPreferences(SCNetworkConnectionRef connection)
{
Boolean ok;
CFMutableArrayRef prefs = NULL;
CFStringRef serviceID;
serviceID = SCNetworkConnectionCopyServiceID(connection);
ok = processPreferences(serviceID,
copyAllCallout,
NULL,
NULL,
(void *)&prefs);
if (!ok) {
if (prefs != NULL) {
CFRelease(prefs);
prefs = NULL;
}
}
CFRelease(serviceID);
return prefs;
}
static CFDictionaryRef
copyCurrentCallout(CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3)
{
CFBooleanRef isDefault;
CFStringRef prefsID;
SCUserPreferencesPrivateRef *userPrivate = (SCUserPreferencesPrivateRef *)context3;
if (current == NULL) {
return NULL;
}
prefsID = CFDictionaryGetValue(current, USER_PREFERENCES_ID);
if (!isA_CFString(prefsID)) {
goto done;
}
isDefault = CFDictionaryGetValue(current, USER_PREFERENCES_DEFAULT);
if (!isA_CFBoolean(isDefault) || !CFBooleanGetValue(isDefault)) {
goto done;
}
*userPrivate = __SCUserPreferencesCreatePrivate(NULL, serviceID, prefsID);
done :
return CFRetain(current);
}
SCUserPreferencesRef
SCNetworkConnectionCopyCurrentUserPreferences(SCNetworkConnectionRef connection)
{
SCUserPreferencesRef current = NULL;
Boolean ok;
CFStringRef serviceID;
serviceID = SCNetworkConnectionCopyServiceID(connection);
ok = processPreferences(serviceID,
copyCurrentCallout,
NULL,
NULL,
(void *)¤t);
if (!ok) {
if (current != NULL) {
CFRelease(current);
current = NULL;
}
}
CFRelease(serviceID);
return current;
}
static CFDictionaryRef
createCallout(CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3)
{
CFMutableDictionaryRef newDict;
CFStringRef newPrefsID = (CFStringRef)context1;
if (current != NULL) {
return CFRetain(current);
}
newDict = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(newDict, USER_PREFERENCES_ID, newPrefsID);
return newDict;
}
SCUserPreferencesRef
SCNetworkConnectionCreateUserPreferences(SCNetworkConnectionRef connection)
{
CFStringRef newPrefsID;
CFStringRef serviceID;
SCUserPreferencesPrivateRef userPrivate;
CFUUIDRef uuid;
serviceID = SCNetworkConnectionCopyServiceID(connection);
uuid = CFUUIDCreate(NULL);
newPrefsID = CFUUIDCreateString(NULL, uuid);
CFRelease(uuid);
userPrivate = __SCUserPreferencesCreatePrivate(NULL, serviceID, newPrefsID);
if (userPrivate != NULL) {
(void) processPreferences(serviceID,
createCallout,
(void *)newPrefsID,
NULL,
NULL);
}
CFRelease(newPrefsID);
CFRelease(serviceID);
return (SCUserPreferencesRef)userPrivate;
}
#ifdef NOTNOW
Boolean
SCNetworkConnectionSelectService(CFDictionaryRef selectionOptions,
SCNetworkServiceRef *service,
SCUserPreferencesRef *userPreferences)
{
return FALSE;
}
#endif // NOTNOW
static void
update_PPP_entity(SCUserPreferencesRef userPreferences, CFDictionaryRef *userOptions)
{
CFStringRef encryption;
CFDictionaryRef entity;
CFStringRef keychainID;
entity = CFDictionaryGetValue(*userOptions, kSCEntNetPPP);
if (!isA_CFDictionary(entity)) {
return;
}
encryption = CFDictionaryGetValue(entity, kSCPropNetPPPAuthPasswordEncryption);
if (encryption == NULL) {
encryption = kSCValNetPPPAuthPasswordEncryptionKeychain;
}
if (!isA_CFString(encryption) ||
!CFEqual(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
return;
}
keychainID = CFDictionaryGetValue(entity, kSCPropNetPPPAuthPassword);
if (isA_CFString(keychainID)) {
} else if (isA_CFData(keychainID) &&
((CFDataGetLength((CFDataRef)keychainID) % sizeof(UniChar)) == 0)) {
return;
} else {
keychainID = SCUserPreferencesGetUniqueID(userPreferences);
}
if (_SCSecKeychainPasswordItemExists(NULL, keychainID)) {
CFMutableDictionaryRef new_entity;
CFMutableDictionaryRef new_options;
new_entity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
CFDictionarySetValue(new_entity,
kSCPropNetPPPAuthPassword,
keychainID);
CFDictionarySetValue(new_entity,
kSCPropNetPPPAuthPasswordEncryption,
kSCValNetPPPAuthPasswordEncryptionKeychain);
new_options = CFDictionaryCreateMutableCopy(NULL, 0, *userOptions);
CFDictionarySetValue(new_options, kSCEntNetPPP, new_entity);
CFRelease(new_entity);
CFRelease(*userOptions);
*userOptions = new_options;
}
return;
}
static void
update_IPSec_entity(SCUserPreferencesRef userPreferences, CFDictionaryRef *userOptions)
{
CFStringRef encryption;
CFDictionaryRef entity;
SecKeychainRef keychain = NULL;
CFStringRef keychainID;
CFStringRef method;
CFDataRef sharedSecret;
entity = CFDictionaryGetValue(*userOptions, kSCEntNetIPSec);
if (!isA_CFDictionary(entity)) {
return;
}
method = CFDictionaryGetValue(entity, kSCPropNetIPSecAuthenticationMethod);
if (!isA_CFString(method) ||
!CFEqual(method, kSCValNetIPSecAuthenticationMethodSharedSecret)) {
return;
}
encryption = CFDictionaryGetValue(entity, kSCPropNetIPSecSharedSecretEncryption);
if (encryption == NULL) {
encryption = kSCValNetIPSecSharedSecretEncryptionKeychain;
}
if (!isA_CFString(encryption) ||
!CFEqual(encryption, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
return;
}
keychainID = CFDictionaryGetValue(entity, kSCPropNetIPSecSharedSecret);
if (isA_CFString(keychainID)) {
CFRetain(keychainID);
} else if (isA_CFData(keychainID) &&
((CFDataGetLength((CFDataRef)keychainID) % sizeof(UniChar)) == 0)) {
return;
} else {
CFStringRef unique_id;
unique_id = SCUserPreferencesGetUniqueID(userPreferences);
keychainID = (CFStringRef)CFStringCreateMutableCopy(NULL, 0, unique_id);
CFStringAppend((CFMutableStringRef)keychainID, CFSTR(".SS"));
}
sharedSecret = _SCSecKeychainPasswordItemCopy(NULL, keychainID);
if (sharedSecret != NULL) {
CFMutableDictionaryRef new_entity;
CFMutableDictionaryRef new_options;
CFStringRef password;
new_entity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
password = CFStringCreateWithBytes(NULL,
CFDataGetBytePtr(sharedSecret),
CFDataGetLength(sharedSecret),
kCFStringEncodingUTF8,
FALSE);
CFRelease(sharedSecret);
CFDictionarySetValue(new_entity,
kSCPropNetIPSecSharedSecret,
password);
CFRelease(password);
CFDictionaryRemoveValue(new_entity,
kSCPropNetIPSecSharedSecretEncryption);
new_options = CFDictionaryCreateMutableCopy(NULL, 0, *userOptions);
CFDictionarySetValue(new_options, kSCEntNetIPSec, new_entity);
CFRelease(new_entity);
CFRelease(*userOptions);
*userOptions = new_options;
goto done;
}
keychain = _SCSecKeychainCopySystemKeychain();
if (keychain == NULL) {
goto done;
}
if (_SCSecKeychainPasswordItemExists(keychain, keychainID)) {
CFMutableDictionaryRef new_entity;
CFMutableDictionaryRef new_options;
new_entity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
CFDictionarySetValue(new_entity,
kSCPropNetIPSecSharedSecret,
keychainID);
CFDictionarySetValue(new_entity,
kSCPropNetIPSecSharedSecretEncryption,
kSCValNetIPSecSharedSecretEncryptionKeychain);
new_options = CFDictionaryCreateMutableCopy(NULL, 0, *userOptions);
CFDictionarySetValue(new_options, kSCEntNetIPSec, new_entity);
CFRelease(new_entity);
CFRelease(*userOptions);
*userOptions = new_options;
}
done :
if (keychain != NULL) CFRelease(keychain);
CFRelease(keychainID);
return;
}
static CFDictionaryRef
copyOptionsCallout(CFStringRef serviceID,
CFDictionaryRef current,
void *context1,
void *context2,
void *context3)
{
CFStringRef matchID = (CFStringRef)context1;
CFMutableDictionaryRef *userOptions = (CFMutableDictionaryRef *)context3;
if (current == NULL) {
return NULL;
}
if (isMatchingPrefsID(current, matchID)) {
if (*userOptions != NULL) CFRelease(*userOptions);
*userOptions = CFDictionaryCreateMutableCopy(NULL, 0, current);
CFDictionaryRemoveValue(*userOptions, USER_PREFERENCES_ID);
CFDictionaryRemoveValue(*userOptions, USER_PREFERENCES_DEFAULT);
}
return CFRetain(current);
}
Boolean
SCNetworkConnectionStartWithUserPreferences(SCNetworkConnectionRef connection,
SCUserPreferencesRef userPreferences,
Boolean linger)
{
Boolean ok;
CFDictionaryRef userOptions = NULL;
SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
(void) processPreferences(userPrivate->serviceID,
copyOptionsCallout,
(void *)userPrivate->prefsID,
NULL,
&userOptions);
if (userOptions != NULL) {
update_PPP_entity (userPreferences, &userOptions);
update_IPSec_entity(userPreferences, &userOptions);
}
ok = SCNetworkConnectionStart(connection, userOptions, linger);
if (userOptions != NULL) {
CFRelease(userOptions);
}
return ok;
}
#pragma mark -
#pragma mark SCUserPreferences + SCNetworkInterface Password SPIs
static CFStringRef
getUserPasswordID(CFDictionaryRef config, SCUserPreferencesRef userPreferences)
{
CFStringRef unique_id = NULL;
if (config != NULL) {
CFStringRef encryption;
encryption = CFDictionaryGetValue(config, kSCPropNetPPPAuthPasswordEncryption);
if (isA_CFString(encryption) &&
CFEqual(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
unique_id = CFDictionaryGetValue(config, kSCPropNetPPPAuthPassword);
}
}
if (unique_id == NULL) {
unique_id = SCUserPreferencesGetUniqueID(userPreferences);
}
return unique_id;
}
static CFStringRef
copyUserSharedSecretID(CFDictionaryRef config, SCUserPreferencesRef userPreferences)
{
CFMutableStringRef sharedSecret = NULL;
if (config != NULL) {
CFStringRef encryption;
encryption = CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecretEncryption);
if (isA_CFString(encryption) &&
CFEqual(encryption, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
sharedSecret = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecret);
if (sharedSecret != NULL) {
CFRetain(sharedSecret);
}
}
}
if (sharedSecret == NULL) {
CFStringRef unique_id;
unique_id = getUserPasswordID(config, userPreferences);
sharedSecret = CFStringCreateMutableCopy(NULL, 0, unique_id);
CFStringAppend(sharedSecret, CFSTR(".SS"));
}
return sharedSecret;
}
static Boolean
checkUserPreferencesPassword(SCUserPreferencesRef userPreferences,
SCNetworkInterfaceRef interface,
SCNetworkInterfacePasswordType passwordType)
{
if (!isA_SCUserPreferences(userPreferences)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_SCNetworkInterface(interface)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
switch (passwordType) {
case kSCNetworkInterfacePasswordTypePPP : {
CFStringRef interfaceType;
interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
if (!CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
break;
}
case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
CFStringRef interfaceType;
interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
if (!CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
interface = SCNetworkInterfaceGetInterface(interface);
if (interface == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
break;
}
case kSCNetworkInterfacePasswordTypeEAPOL : {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
default :
break;
}
return TRUE;
}
Boolean
SCUserPreferencesCheckInterfacePassword(SCUserPreferencesRef userPreferences,
SCNetworkInterfaceRef interface,
SCNetworkInterfacePasswordType passwordType)
{
Boolean exists = FALSE;
if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
return FALSE;
}
switch (passwordType) {
case kSCNetworkInterfacePasswordTypePPP : {
CFDictionaryRef config;
CFStringRef unique_id;
config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
unique_id = getUserPasswordID(config, userPreferences);
exists = __extract_password(NULL,
config,
kSCPropNetPPPAuthPassword,
kSCPropNetPPPAuthPasswordEncryption,
kSCValNetPPPAuthPasswordEncryptionKeychain,
unique_id,
NULL);
if (config != NULL) CFRelease(config);
break;
}
case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
CFDictionaryRef config;
CFStringRef shared_id;
config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
interface,
kSCEntNetIPSec);
shared_id = copyUserSharedSecretID(config, userPreferences);
exists = __extract_password(NULL,
config,
kSCPropNetIPSecSharedSecret,
kSCPropNetIPSecSharedSecretEncryption,
kSCValNetIPSecSharedSecretEncryptionKeychain,
shared_id,
NULL);
if (config != NULL) CFRelease(config);
CFRelease(shared_id);
break;
}
default :
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
return exists;
}
CFDataRef
SCUserPreferencesCopyInterfacePassword(SCUserPreferencesRef userPreferences,
SCNetworkInterfaceRef interface,
SCNetworkInterfacePasswordType passwordType)
{
CFDataRef password = NULL;
if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
return FALSE;
}
switch (passwordType) {
case kSCNetworkInterfacePasswordTypePPP : {
CFDictionaryRef config;
CFStringRef unique_id;
config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
unique_id = getUserPasswordID(config, userPreferences);
(void) __extract_password(NULL,
config,
kSCPropNetPPPAuthPassword,
kSCPropNetPPPAuthPasswordEncryption,
kSCValNetPPPAuthPasswordEncryptionKeychain,
unique_id,
&password);
if (config != NULL) CFRelease(config);
break;
}
case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
CFDictionaryRef config;
CFStringRef shared_id;
config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
interface,
kSCEntNetIPSec);
shared_id = copyUserSharedSecretID(config, userPreferences);
(void) __extract_password(NULL,
config,
kSCPropNetIPSecSharedSecret,
kSCPropNetIPSecSharedSecretEncryption,
kSCValNetIPSecSharedSecretEncryptionKeychain,
shared_id,
&password);
if (config != NULL) CFRelease(config);
CFRelease(shared_id);
break;
}
default :
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
return password;
}
Boolean
SCUserPreferencesRemoveInterfacePassword(SCUserPreferencesRef userPreferences,
SCNetworkInterfaceRef interface,
SCNetworkInterfacePasswordType passwordType)
{
Boolean ok = FALSE;
if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
return FALSE;
}
switch (passwordType) {
case kSCNetworkInterfacePasswordTypePPP : {
CFDictionaryRef config;
CFStringRef unique_id;
config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
unique_id = getUserPasswordID(config, userPreferences);
ok = _SCSecKeychainPasswordItemRemove(NULL, unique_id);
if (ok) {
CFDictionaryRef config;
CFMutableDictionaryRef newConfig;
config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
if (config != NULL) {
newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
CFDictionaryRemoveValue(newConfig, kSCPropNetPPPAuthPassword);
CFDictionaryRemoveValue(newConfig, kSCPropNetPPPAuthPasswordEncryption);
ok = SCUserPreferencesSetInterfaceConfiguration(userPreferences, interface, newConfig);
CFRelease(newConfig);
}
}
break;
}
case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
CFDictionaryRef config;
CFStringRef shared_id;
config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
interface,
kSCEntNetIPSec);
shared_id = copyUserSharedSecretID(config, userPreferences);
ok = _SCSecKeychainPasswordItemRemove(NULL, shared_id);
if (ok) {
CFMutableDictionaryRef newConfig;
if (config != NULL) {
newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
CFDictionaryRemoveValue(newConfig, kSCPropNetIPSecSharedSecret);
CFDictionaryRemoveValue(newConfig, kSCPropNetIPSecSharedSecretEncryption);
ok = SCUserPreferencesSetExtendedInterfaceConfiguration(userPreferences,
interface,
kSCEntNetIPSec,
newConfig);
CFRelease(newConfig);
}
}
if (config != NULL) CFRelease(config);
CFRelease(shared_id);
break;
}
default :
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
return ok;
}
Boolean
SCUserPreferencesSetInterfacePassword(SCUserPreferencesRef userPreferences,
SCNetworkInterfaceRef interface,
SCNetworkInterfacePasswordType passwordType,
CFDataRef password,
CFDictionaryRef options)
{
CFStringRef account = NULL;
CFBundleRef bundle;
CFDictionaryRef config;
CFStringRef description = NULL;
CFStringRef label = NULL;
Boolean ok = FALSE;
if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
return FALSE;
}
bundle = _SC_CFBundleGet();
switch (passwordType) {
case kSCNetworkInterfacePasswordTypePPP : {
CFStringRef unique_id;
config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
unique_id = getUserPasswordID(config, userPreferences);
if (config != NULL) {
account = CFDictionaryGetValue(config, kSCPropNetPPPAuthName);
}
label = SCUserPreferencesCopyName(userPreferences);
if (bundle != NULL) {
description = CFBundleCopyLocalizedString(bundle,
CFSTR("KEYCHAIN_PPP_PASSWORD"),
CFSTR("PPP Password"),
NULL);
}
ok = _SCSecKeychainPasswordItemSet(NULL,
unique_id,
(label != NULL) ? label : CFSTR("PPP"),
(description != NULL) ? description : CFSTR("PPP Password"),
account,
password,
options);
if (ok) {
CFMutableDictionaryRef newConfig;
if (config != NULL) {
newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
} else {
newConfig = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(newConfig,
kSCPropNetPPPAuthPassword,
unique_id);
CFDictionarySetValue(newConfig,
kSCPropNetPPPAuthPasswordEncryption,
kSCValNetPPPAuthPasswordEncryptionKeychain);
ok = SCUserPreferencesSetInterfaceConfiguration(userPreferences, interface, newConfig);
CFRelease(newConfig);
}
if (config != NULL) CFRelease(config);
if (description != NULL) CFRelease(description);
if (label != NULL) CFRelease(label);
break;
}
case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
CFStringRef shared_id;
config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
interface,
kSCEntNetIPSec);
shared_id = copyUserSharedSecretID(config, userPreferences);
label = SCUserPreferencesCopyName(userPreferences);
if (bundle != NULL) {
description = CFBundleCopyLocalizedString(bundle,
CFSTR("KEYCHAIN_IPSEC_SHARED_SECRET"),
CFSTR("IPSec Shared Secret"),
NULL);
}
ok = _SCSecKeychainPasswordItemSet(NULL,
shared_id,
(label != NULL) ? label : CFSTR("PPP"),
(description != NULL) ? description : CFSTR("IPSec Shared Secret"),
NULL,
password,
options);
if (ok) {
CFMutableDictionaryRef newConfig = NULL;
if (config != NULL) {
newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
} else {
newConfig = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(newConfig,
kSCPropNetIPSecSharedSecret,
shared_id);
CFDictionarySetValue(newConfig,
kSCPropNetIPSecSharedSecretEncryption,
kSCValNetIPSecSharedSecretEncryptionKeychain);
ok = SCUserPreferencesSetExtendedInterfaceConfiguration(userPreferences,
interface,
kSCEntNetIPSec,
newConfig);
CFRelease(newConfig);
}
if (config != NULL) CFRelease(config);
if (description != NULL) CFRelease(description);
if (label != NULL) CFRelease(label);
CFRelease(shared_id);
break;
}
default :
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
return ok;
}