#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include "SCNetworkConfigurationInternal.h"
#include <SystemConfiguration/SCValidation.h>
#include <SystemConfiguration/SCPrivate.h>
#include <pthread.h>
static CFStringRef __SCNetworkSetCopyDescription (CFTypeRef cf);
static void __SCNetworkSetDeallocate (CFTypeRef cf);
static Boolean __SCNetworkSetEqual (CFTypeRef cf1, CFTypeRef cf2);
static CFHashCode __SCNetworkSetHash (CFTypeRef cf);
static CFTypeID __kSCNetworkSetTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __SCNetworkSetClass = {
0, "SCNetworkSet", NULL, NULL, __SCNetworkSetDeallocate, __SCNetworkSetEqual, __SCNetworkSetHash, NULL, __SCNetworkSetCopyDescription };
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static CFStringRef
__SCNetworkSetCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkSet %p [%p]> {"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR("id = %@"), setPrivate->setID);
CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), setPrivate->prefs);
if (setPrivate->name != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), setPrivate->name);
}
CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
static void
__SCNetworkSetDeallocate(CFTypeRef cf)
{
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
CFRelease(setPrivate->setID);
CFRelease(setPrivate->prefs);
if (setPrivate->name != NULL)
CFRelease(setPrivate->name);
return;
}
static Boolean
__SCNetworkSetEqual(CFTypeRef cf1, CFTypeRef cf2)
{
SCNetworkSetPrivateRef s1 = (SCNetworkSetPrivateRef)cf1;
SCNetworkSetPrivateRef s2 = (SCNetworkSetPrivateRef)cf2;
if (s1 == s2)
return TRUE;
if (s1->prefs != s2->prefs)
return FALSE;
if (!CFEqual(s1->setID, s2->setID))
return FALSE;
return TRUE;
}
static CFHashCode
__SCNetworkSetHash(CFTypeRef cf)
{
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
return CFHash(setPrivate->setID);
}
static void
__SCNetworkSetInitialize(void)
{
__kSCNetworkSetTypeID = _CFRuntimeRegisterClass(&__SCNetworkSetClass);
return;
}
static SCNetworkSetPrivateRef
__SCNetworkSetCreatePrivate(CFAllocatorRef allocator,
SCPreferencesRef prefs,
CFStringRef setID)
{
SCNetworkSetPrivateRef setPrivate;
uint32_t size;
pthread_once(&initialized, __SCNetworkSetInitialize);
size = sizeof(SCNetworkSetPrivate) - sizeof(CFRuntimeBase);
setPrivate = (SCNetworkSetPrivateRef)_CFRuntimeCreateInstance(allocator,
__kSCNetworkSetTypeID,
size,
NULL);
if (setPrivate == NULL) {
return NULL;
}
setPrivate->setID = CFStringCreateCopy(NULL, setID);
setPrivate->prefs = CFRetain(prefs);
setPrivate->name = NULL;
setPrivate->established = FALSE;
return setPrivate;
}
#pragma mark -
static Boolean
_serviceIsVPN(SCNetworkServiceRef service)
{
SCNetworkInterfaceRef interface;
CFStringRef interfaceType;
interface = SCNetworkServiceGetInterface(service);
if (interface == NULL) {
return FALSE;
}
interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
interface = SCNetworkInterfaceGetInterface(interface);
if (interface == NULL) {
return FALSE;
}
interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
return TRUE;
}
if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
return TRUE;
}
return FALSE;
}
if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
return TRUE;
}
return FALSE;
}
static int
_serviceOrder(SCNetworkServiceRef service)
{
SCNetworkInterfaceRef interface;
interface = SCNetworkServiceGetInterface(service);
if ((interface == NULL) || _serviceIsVPN(service)) {
return 100000; }
return __SCNetworkInterfaceOrder(interface);
}
static void
_serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service)
{
CFIndex i;
CFIndex n;
CFMutableArrayRef newOrder;
CFArrayRef order;
CFStringRef serviceID;
CFIndex serviceOrder;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
CFIndex slot;
order = SCNetworkSetGetServiceOrder(set);
if (order != NULL) {
newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
} else {
newOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
n = CFArrayGetCount(newOrder);
serviceID = SCNetworkServiceGetServiceID(service);
if (CFArrayContainsValue(newOrder, CFRangeMake(0, n), serviceID)) {
goto done;
}
serviceOrder = _serviceOrder(service);
slot = 0;
for (i = 0; i < n; i++) {
int slotOrder;
SCNetworkServiceRef slotService;
CFStringRef slotServiceID;
slotServiceID = CFArrayGetValueAtIndex(newOrder, i);
if (!isA_CFString(slotServiceID)) {
continue;
}
slotService = SCNetworkServiceCopy(setPrivate->prefs, slotServiceID);
if (slotService == NULL) {
continue;
}
slotOrder = _serviceOrder(slotService);
if (serviceOrder >= slotOrder) {
slot = i + 1;
}
CFRelease(slotService);
}
CFArrayInsertValueAtIndex(newOrder, slot, serviceID);
(void) SCNetworkSetSetServiceOrder(set, newOrder);
done :
CFRelease(newOrder);
return;
}
static void
_serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service)
{
CFMutableArrayRef newOrder;
CFArrayRef order;
CFStringRef serviceID;
order = SCNetworkSetGetServiceOrder(set);
if (order == NULL) {
return;
}
serviceID = SCNetworkServiceGetServiceID(service);
newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
while (TRUE) {
CFIndex i;
i = CFArrayGetFirstIndexOfValue(newOrder,
CFRangeMake(0, CFArrayGetCount(newOrder)),
serviceID);
if (i == kCFNotFound) {
break;
}
CFArrayRemoveValueAtIndex(newOrder, i);
}
(void) SCNetworkSetSetServiceOrder(set, newOrder);
CFRelease(newOrder);
return;
}
#pragma mark -
#pragma mark SCNetworkSet APIs
#define N_QUICK 16
Boolean
SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service)
{
SCNetworkInterfaceRef interface;
CFArrayRef interface_config = NULL;
CFStringRef link;
Boolean ok;
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
#define PREVENT_DUPLICATE_SERVICE_NAMES
#ifdef PREVENT_DUPLICATE_SERVICE_NAMES
CFStringRef name;
name = SCNetworkServiceGetName(service);
if (name != NULL) {
CFArrayRef services;
services = SCNetworkSetCopyServices(set);
if (services != NULL) {
CFIndex i;
CFIndex n;
n = CFArrayGetCount(services);
for (i = 0; i < n; i++) {
CFStringRef otherName;
SCNetworkServiceRef otherService;
otherService = CFArrayGetValueAtIndex(services, i);
otherName = SCNetworkServiceGetName(otherService);
if ((otherName != NULL) && CFEqual(name, otherName)) {
CFRelease(services);
_SCErrorSet(kSCStatusKeyExists);
return FALSE;
}
}
}
CFRelease(services);
}
#endif // PREVENT_DUPLICATE_SERVICE_NAMES
#ifdef PREVENT_DUPLICATE_SETS
CFArrayRef sets;
sets = SCNetworkSetCopyAll(setPrivate->prefs);
if (sets != NULL) {
CFIndex i;
CFIndex n;
n = CFArrayGetCount(sets);
for (i = 0; i < n; i++) {
Boolean found;
CFArrayRef services;
SCNetworkSetRef set;
set = CFArrayGetValueAtIndex(sets, i);
services = SCNetworkSetCopyServices(set);
found = CFArrayContainsValue(services,
CFRangeMake(0, CFArrayGetCount(services)),
service);
CFRelease(services);
if (found) {
CFRelease(sets);
_SCErrorSet(kSCStatusKeyExists);
return FALSE;
}
}
CFRelease(sets);
}
#endif
interface = SCNetworkServiceGetInterface(service);
if (interface != NULL) {
interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface);
}
path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, setPrivate->setID, servicePrivate->serviceID, NULL); link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); ok = SCPreferencesPathSetLink(setPrivate->prefs, path, link);
CFRelease(path);
CFRelease(link);
if (!ok) {
goto done;
}
if (interface != NULL) {
__SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config);
}
_serviceOrder_add(set, service);
setPrivate->established = TRUE;
done :
if (interface_config != NULL) CFRelease(interface_config);
return ok;
}
SCNetworkSetRef
SCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID)
{
CFDictionaryRef entity;
CFStringRef path;
SCNetworkSetPrivateRef setPrivate;
if (!isA_CFString(setID)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
path = SCPreferencesPathKeyCreateSet(NULL, setID);
entity = SCPreferencesPathGetValue(prefs, path);
CFRelease(path);
if (!isA_CFDictionary(entity)) {
_SCErrorSet(kSCStatusNoKey);
return NULL;
}
setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
setPrivate->established = TRUE;
return (SCNetworkSetRef)setPrivate;
}
static Boolean
_SCNetworkServiceExistsForInterface(CFArrayRef services, SCNetworkInterfaceRef interface)
{
CFIndex i;
CFIndex n;
n = isA_CFArray(services) ? CFArrayGetCount(services) : 0;
for (i = 0; i < n; i++) {
SCNetworkServiceRef service;
SCNetworkInterfaceRef service_interface;
service = CFArrayGetValueAtIndex(services, i);
service_interface = SCNetworkServiceGetInterface(service);
while (service_interface != NULL) {
if (CFEqual(interface, service_interface)) {
return TRUE;
}
service_interface = SCNetworkInterfaceGetInterface(service_interface);
}
}
return FALSE;
}
Boolean
SCNetworkSetContainsInterface(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
{
Boolean found = FALSE;
CFArrayRef services;
services = SCNetworkSetCopyServices(set);
if (services != NULL) {
found = _SCNetworkServiceExistsForInterface(services, interface);
CFRelease(services);
}
return found;
}
CFArrayRef
SCNetworkSetCopyAll(SCPreferencesRef prefs)
{
CFMutableArrayRef array;
CFIndex n;
CFStringRef path;
CFDictionaryRef sets;
path = SCPreferencesPathKeyCreateSets(NULL);
sets = SCPreferencesPathGetValue(prefs, path);
CFRelease(path);
if ((sets != NULL) && !isA_CFDictionary(sets)) {
return NULL;
}
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
n = (sets != NULL) ? CFDictionaryGetCount(sets) : 0;
if (n > 0) {
CFIndex i;
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
const void * vals_q[N_QUICK];
const void ** vals = vals_q;
if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
}
CFDictionaryGetKeysAndValues(sets, keys, vals);
for (i = 0; i < n; i++) {
SCNetworkSetPrivateRef setPrivate;
if (!isA_CFDictionary(vals[i])) {
SCLog(TRUE,
LOG_INFO,
CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"),
keys[i]);
continue;
}
setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, keys[i]);
setPrivate->established = TRUE;
CFArrayAppendValue(array, (SCNetworkSetRef)setPrivate);
CFRelease(setPrivate);
}
if (keys != keys_q) {
CFAllocatorDeallocate(NULL, keys);
CFAllocatorDeallocate(NULL, vals);
}
}
return array;
}
SCNetworkSetRef
SCNetworkSetCopyCurrent(SCPreferencesRef prefs)
{
CFArrayRef components;
CFStringRef currentID;
SCNetworkSetPrivateRef setPrivate = NULL;
currentID = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
if (!isA_CFString(currentID)) {
return NULL;
}
components = CFStringCreateArrayBySeparatingStrings(NULL, currentID, CFSTR("/"));
if (CFArrayGetCount(components) == 3) {
CFStringRef setID;
CFStringRef path;
setID = CFArrayGetValueAtIndex(components, 2);
path = SCPreferencesPathKeyCreateSet(NULL, setID);
if (CFEqual(path, currentID)) {
setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
setPrivate->established = TRUE;
} else {
SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant"));
}
CFRelease(path);
}
CFRelease(components);
return (SCNetworkSetRef)setPrivate;
}
CFArrayRef
SCNetworkSetCopyServices(SCNetworkSetRef set)
{
CFMutableArrayRef array;
CFDictionaryRef dict;
CFIndex n;
CFStringRef path;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
path = SCPreferencesPathKeyCreateSetNetworkService(NULL, setPrivate->setID, NULL);
dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
CFRelease(path);
if ((dict != NULL) && !isA_CFDictionary(dict)) {
return NULL;
}
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
n = (dict != NULL) ? CFDictionaryGetCount(dict) : 0;
if (n > 0) {
CFIndex i;
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
}
CFDictionaryGetKeysAndValues(dict, keys, NULL);
for (i = 0; i < n; i++) {
CFArrayRef components;
CFStringRef link;
path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
setPrivate->setID,
(CFStringRef)keys[i],
NULL);
link = SCPreferencesPathGetLink(setPrivate->prefs, path);
CFRelease(path);
if (link == NULL) {
SCLog(TRUE,
LOG_INFO,
CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"),
keys[i],
setPrivate->setID);
continue; }
components = CFStringCreateArrayBySeparatingStrings(NULL, link, CFSTR("/"));
if (CFArrayGetCount(components) == 3) {
CFStringRef serviceID;
serviceID = CFArrayGetValueAtIndex(components, 2);
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, serviceID, NULL); if (CFEqual(path, link)) {
SCNetworkServicePrivateRef servicePrivate;
servicePrivate = __SCNetworkServiceCreatePrivate(NULL,
setPrivate->prefs,
serviceID,
NULL);
CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
CFRelease(servicePrivate);
}
CFRelease(path);
}
CFRelease(components);
}
if (keys != keys_q) {
CFAllocatorDeallocate(NULL, keys);
}
}
return array;
}
SCNetworkSetRef
SCNetworkSetCreate(SCPreferencesRef prefs)
{
CFArrayRef components;
CFStringRef path;
CFStringRef prefix;
CFStringRef setID;
SCNetworkSetPrivateRef setPrivate;
prefix = SCPreferencesPathKeyCreateSets(NULL);
path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
CFRelease(prefix);
if (path == NULL) {
return NULL;
}
components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
CFRelease(path);
setID = CFArrayGetValueAtIndex(components, 2);
setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID);
CFRelease(components);
setPrivate->established = FALSE;
return (SCNetworkSetRef)setPrivate;
}
CFStringRef
SCNetworkSetGetSetID(SCNetworkSetRef set)
{
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
return setPrivate->setID;
}
CFStringRef
SCNetworkSetGetName(SCNetworkSetRef set)
{
CFBundleRef bundle;
CFDictionaryRef entity;
CFStringRef path;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (setPrivate->name != NULL) {
return setPrivate->name;
}
path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
CFRelease(path);
if (isA_CFDictionary(entity)) {
CFStringRef name;
name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
if (isA_CFString(name)) {
setPrivate->name = CFRetain(name);
}
}
bundle = _SC_CFBundleGet();
if (bundle != NULL) {
if (setPrivate->name != NULL) {
CFStringRef non_localized;
non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
CFSTR("DEFAULT_SET_NAME"),
CFSTR("Automatic"),
NULL);
if (non_localized != NULL) {
if (CFEqual(setPrivate->name, non_localized)) {
CFStringRef localized;
localized = CFBundleCopyLocalizedString(bundle,
CFSTR("DEFAULT_SET_NAME"),
CFSTR("Automatic"),
NULL);
if (localized != NULL) {
CFRelease(setPrivate->name);
setPrivate->name = localized;
}
}
CFRelease(non_localized);
}
}
}
return setPrivate->name;
}
CFArrayRef
SCNetworkSetGetServiceOrder(SCNetworkSetRef set)
{
CFDictionaryRef dict;
CFStringRef path;
CFArrayRef serviceOrder;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
if (path == NULL) {
return NULL;
}
dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
CFRelease(path);
if (!isA_CFDictionary(dict)) {
return NULL;
}
serviceOrder = CFDictionaryGetValue(dict, kSCPropNetServiceOrder);
serviceOrder = isA_CFArray(serviceOrder);
return serviceOrder;
}
CFTypeID
SCNetworkSetGetTypeID(void)
{
pthread_once(&initialized, __SCNetworkSetInitialize);
return __kSCNetworkSetTypeID;
}
Boolean
SCNetworkSetRemove(SCNetworkSetRef set)
{
CFStringRef currentPath;
Boolean ok = FALSE;
CFStringRef path;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
currentPath = SCPreferencesGetValue(setPrivate->prefs, kSCPrefCurrentSet);
path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
if (!isA_CFString(currentPath) || !CFEqual(currentPath, path)) {
ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
}
CFRelease(path);
return ok;
}
Boolean
SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service)
{
SCNetworkInterfaceRef interface;
CFArrayRef interface_config = NULL;
Boolean ok;
CFStringRef path;
int sc_status = kSCStatusOK;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
_serviceOrder_remove(set, service);
interface = SCNetworkServiceGetInterface(service);
if (interface != NULL) {
interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface);
if (interface_config != NULL) {
__SCNetworkInterfaceSetDeepConfiguration(set, interface, NULL);
}
}
path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL,
setPrivate->setID,
servicePrivate->serviceID,
NULL);
ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path);
if (!ok) {
sc_status = SCError(); }
CFRelease(path);
if (interface_config != NULL) {
__SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config);
}
if (interface_config != NULL) CFRelease(interface_config);
if (!ok) {
_SCErrorSet(sc_status);
}
return ok;
}
Boolean
SCNetworkSetSetCurrent(SCNetworkSetRef set)
{
Boolean ok;
CFStringRef path;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
ok = SCPreferencesSetValue(setPrivate->prefs, kSCPrefCurrentSet, path);
CFRelease(path);
return ok;
}
Boolean
SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name)
{
CFBundleRef bundle = NULL;
CFDictionaryRef entity;
CFStringRef localized = NULL;
CFStringRef non_localized = NULL;
Boolean ok = FALSE;
CFStringRef path;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if ((name != NULL) && !isA_CFString(name)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (name != NULL) {
bundle = _SC_CFBundleGet();
if (bundle != NULL) {
non_localized = _SC_CFBundleCopyNonLocalizedString(bundle,
CFSTR("DEFAULT_SET_NAME"),
CFSTR("Automatic"),
NULL);
if (non_localized != NULL) {
if (CFEqual(name, non_localized)) {
localized = CFBundleCopyLocalizedString(bundle,
CFSTR("DEFAULT_SET_NAME"),
CFSTR("Automatic"),
NULL);
if (localized != NULL) {
name = localized;
}
}
}
}
}
#define PREVENT_DUPLICATE_SET_NAMES
#ifdef PREVENT_DUPLICATE_SET_NAMES
if (name != NULL) {
CFArrayRef sets;
sets = SCNetworkSetCopyAll(setPrivate->prefs);
if (sets != NULL) {
CFIndex i;
CFIndex n;
n = CFArrayGetCount(sets);
for (i = 0; i < n; i++) {
CFStringRef otherID;
CFStringRef otherName;
SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, i);
otherID = SCNetworkSetGetSetID(set);
if (CFEqual(setPrivate->setID, otherID)) {
continue; }
otherName = SCNetworkSetGetName(set);
if ((otherName != NULL) && CFEqual(name, otherName)) {
CFRelease(sets);
_SCErrorSet(kSCStatusKeyExists);
goto done;
}
}
CFRelease(sets);
}
}
#endif
if ((name != NULL) && (bundle != NULL) && (non_localized != NULL)) {
if (localized == NULL) {
localized = CFBundleCopyLocalizedString(bundle,
CFSTR("DEFAULT_SET_NAME"),
CFSTR("Automatic"),
NULL);
}
if (localized != NULL) {
if (CFEqual(name, localized)) {
name = non_localized;
}
}
}
path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID);
entity = SCPreferencesPathGetValue(setPrivate->prefs, path);
if (isA_CFDictionary(entity) ||
((entity == NULL) && (name != NULL))) {
CFMutableDictionaryRef newEntity;
if (entity != NULL) {
newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
} else {
newEntity = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
if (name != NULL) {
CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
} else {
CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
}
ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newEntity);
CFRelease(newEntity);
}
CFRelease(path);
done :
if (localized != NULL) CFRelease(localized);
if (non_localized != NULL) CFRelease(non_localized);
return ok;
}
Boolean
SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder)
{
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
Boolean ok;
CFStringRef path;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (isA_CFArray(newOrder)) {
CFIndex i;
CFIndex n = CFArrayGetCount(newOrder);
for (i = 0; i < n; i++) {
CFStringRef serviceID;
serviceID = CFArrayGetValueAtIndex(newOrder, i);
if (!isA_CFString(serviceID)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
}
} else {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4);
if (path == NULL) {
return FALSE;
}
dict = SCPreferencesPathGetValue(setPrivate->prefs, path);
if (dict != NULL) {
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
} else {
newDict = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(newDict, kSCPropNetServiceOrder, newOrder);
ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newDict);
CFRelease(newDict);
CFRelease(path);
return ok;
}
#pragma mark -
#pragma mark SCNetworkSet SPIs
static void
add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface)
{
CFIndex i;
CFArrayRef interface_types;
CFIndex n;
interface_types = SCNetworkInterfaceGetSupportedInterfaceTypes(interface);
n = (interface_types != NULL) ? CFArrayGetCount(interface_types) : 0;
for (i = 0; i < n; i++) {
SCNetworkInterfaceRef parent;
CFStringRef interface_type;
interface_type = CFArrayGetValueAtIndex(interface_types, i);
parent = SCNetworkInterfaceCreateWithInterface(interface, interface_type);
if (parent != NULL) {
CFArrayAppendValue(interface_list, parent);
CFRelease(parent);
}
}
return;
}
static CFStringRef
next_service_name(SCNetworkServiceRef service)
{
CFArrayRef components;
CFIndex n;
CFStringRef name;
CFMutableArrayRef newComponents;
SInt32 suffix = 2;
name = SCNetworkServiceGetName(service);
if (name == NULL) {
return NULL;
}
components = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR(" "));
if (components != NULL) {
newComponents = CFArrayCreateMutableCopy(NULL, 0, components);
CFRelease(components);
} else {
newComponents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(newComponents, name);
}
n = CFArrayGetCount(newComponents);
if (n > 1) {
CFStringRef str;
str = CFArrayGetValueAtIndex(newComponents, n - 1);
suffix = CFStringGetIntValue(str);
if (suffix++ > 0) {
CFArrayRemoveValueAtIndex(newComponents, n - 1);
} else {
suffix = 2;
}
}
name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), suffix);
CFArrayAppendValue(newComponents, name);
CFRelease(name);
name = CFStringCreateByCombiningStrings(NULL, newComponents, CFSTR(" "));
CFRelease(newComponents);
return name;
}
static Boolean
__SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces)
{
CFIndex i;
CFIndex n;
Boolean ok = TRUE;
CFArrayRef services;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
Boolean updated = FALSE;
services = SCNetworkSetCopyServices(set);
if ((services != NULL) && setPrivate->established) {
CFRelease(services);
services = SCNetworkServiceCopyAll(setPrivate->prefs);
}
n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0;
for (i = 0; i < n; i++) {
SCNetworkInterfaceRef interface;
CFMutableArrayRef interface_list;
interface = CFArrayGetValueAtIndex(interfaces, i);
if (_SCNetworkServiceExistsForInterface(services, interface)) {
continue;
}
interface_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(interface_list, interface);
while (ok && (CFArrayGetCount(interface_list) > 0)) {
CFArrayRef protocol_types;
interface = CFArrayGetValueAtIndex(interface_list, 0);
protocol_types = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
if ((protocol_types != NULL) && (CFArrayGetCount(protocol_types) > 0)) {
SCNetworkServiceRef service;
service = SCNetworkServiceCreate(setPrivate->prefs, interface);
if (service == NULL) {
SCLog(TRUE, LOG_DEBUG,
CFSTR("could not create service for \"%@\": %s\n"),
SCNetworkInterfaceGetLocalizedDisplayName(interface),
SCErrorString(SCError()));
ok = FALSE;
goto nextInterface;
}
ok = SCNetworkServiceEstablishDefaultConfiguration(service);
if (!ok) {
SCLog(TRUE, LOG_DEBUG,
CFSTR("could not estabish default configuration for \"%@\": %s\n"),
SCNetworkInterfaceGetLocalizedDisplayName(interface),
SCErrorString(SCError()));
SCNetworkServiceRemove(service);
CFRelease(service);
goto nextInterface;
}
while (TRUE) {
CFStringRef newName;
ok = SCNetworkSetAddService(set, service);
if (ok) {
break;
}
if (SCError() != kSCStatusKeyExists) {
SCLog(TRUE, LOG_DEBUG,
CFSTR("could not add service for \"%@\": %s\n"),
SCNetworkInterfaceGetLocalizedDisplayName(interface),
SCErrorString(SCError()));
SCNetworkServiceRemove(service);
CFRelease(service);
goto nextInterface;
}
newName = next_service_name(service);
if (newName == NULL) {
SCLog(TRUE, LOG_DEBUG,
CFSTR("could not set unique name for \"%@\": %s\n"),
SCNetworkInterfaceGetLocalizedDisplayName(interface),
SCErrorString(SCError()));
SCNetworkServiceRemove(service);
CFRelease(service);
goto nextInterface;
}
ok = SCNetworkServiceSetName(service, newName);
CFRelease(newName);
if (ok) {
continue;
}
if (SCError() != kSCStatusKeyExists) {
SCLog(TRUE, LOG_DEBUG,
CFSTR("could not set unique name for \"%@\": %s\n"),
SCNetworkInterfaceGetLocalizedDisplayName(interface),
SCErrorString(SCError()));
SCNetworkServiceRemove(service);
CFRelease(service);
goto nextInterface;
}
}
CFRelease(service);
updated = TRUE;
} else {
add_supported_interfaces(interface_list, interface);
}
nextInterface :
CFArrayRemoveValueAtIndex(interface_list, 0);
}
CFRelease(interface_list);
}
if (services != NULL) CFRelease(services);
if (ok && !updated) {
_SCErrorSet(kSCStatusOK);
}
return updated;
}
Boolean
SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set)
{
CFArrayRef interfaces;
Boolean updated;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
interfaces = SCNetworkInterfaceCopyAll();
updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
if (interfaces != NULL) CFRelease(interfaces);
return updated;
}
Boolean
SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface)
{
CFMutableArrayRef interfaces;
Boolean updated;
if (!isA_SCNetworkSet(set)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_SCNetworkInterface(interface)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(interfaces, interface);
updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces);
CFRelease(interfaces);
return updated;
}