SCNetworkService.c [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include "SCNetworkConfigurationInternal.h"
#include <SystemConfiguration/SCValidation.h>
#include <SystemConfiguration/SCPrivate.h>
#include "SCPreferencesInternal.h"
#include <pthread.h>
#define EXTERNAL_ID_DOMAIN_PREFIX "_"
static CFStringRef __SCNetworkServiceCopyDescription (CFTypeRef cf);
static void __SCNetworkServiceDeallocate (CFTypeRef cf);
static Boolean __SCNetworkServiceEqual (CFTypeRef cf1, CFTypeRef cf2);
static CFHashCode __SCNetworkServiceHash (CFTypeRef cf);
static CFTypeID __kSCNetworkServiceTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __SCNetworkServiceClass = {
0, "SCNetworkService", NULL, NULL, __SCNetworkServiceDeallocate, __SCNetworkServiceEqual, __SCNetworkServiceHash, NULL, __SCNetworkServiceCopyDescription };
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static CFStringRef
__SCNetworkServiceCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkService %p [%p]> {"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR("id = %@"), servicePrivate->serviceID);
if (servicePrivate->prefs != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), servicePrivate->prefs);
} else if (servicePrivate->store != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", store = %p"), servicePrivate->store);
}
if (servicePrivate->name != NULL) {
CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), servicePrivate->name);
}
CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
static void
__SCNetworkServiceDeallocate(CFTypeRef cf)
{
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
CFRelease(servicePrivate->serviceID);
if (servicePrivate->interface != NULL) CFRelease(servicePrivate->interface);
if (servicePrivate->prefs != NULL) CFRelease(servicePrivate->prefs);
if (servicePrivate->store != NULL) CFRelease(servicePrivate->store);
if (servicePrivate->name != NULL) CFRelease(servicePrivate->name);
if (servicePrivate->externalIDs != NULL) CFRelease(servicePrivate->externalIDs);
return;
}
static Boolean
__SCNetworkServiceEqual(CFTypeRef cf1, CFTypeRef cf2)
{
SCNetworkServicePrivateRef s1 = (SCNetworkServicePrivateRef)cf1;
SCNetworkServicePrivateRef s2 = (SCNetworkServicePrivateRef)cf2;
if (s1 == s2)
return TRUE;
if (s1->prefs != s2->prefs)
return FALSE;
if (!CFEqual(s1->serviceID, s2->serviceID))
return FALSE;
return TRUE;
}
static CFHashCode
__SCNetworkServiceHash(CFTypeRef cf)
{
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
return CFHash(servicePrivate->serviceID);
}
static void
__SCNetworkServiceInitialize(void)
{
__kSCNetworkServiceTypeID = _CFRuntimeRegisterClass(&__SCNetworkServiceClass);
return;
}
__private_extern__ SCNetworkServicePrivateRef
__SCNetworkServiceCreatePrivate(CFAllocatorRef allocator,
SCPreferencesRef prefs,
CFStringRef serviceID,
SCNetworkInterfaceRef interface)
{
SCNetworkServicePrivateRef servicePrivate;
uint32_t size;
pthread_once(&initialized, __SCNetworkServiceInitialize);
size = sizeof(SCNetworkServicePrivate) - sizeof(CFRuntimeBase);
servicePrivate = (SCNetworkServicePrivateRef)_CFRuntimeCreateInstance(allocator,
__kSCNetworkServiceTypeID,
size,
NULL);
if (servicePrivate == NULL) {
return NULL;
}
servicePrivate->prefs = (prefs != NULL) ? CFRetain(prefs): NULL;
servicePrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
servicePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL;
servicePrivate->name = NULL;
return servicePrivate;
}
#pragma mark -
#pragma mark Service ordering
CFComparisonResult
_SCNetworkServiceCompare(const void *val1, const void *val2, void *context)
{
CFStringRef id1;
CFStringRef id2;
CFArrayRef order = (CFArrayRef)context;
SCNetworkServiceRef s1 = (SCNetworkServiceRef)val1;
SCNetworkServiceRef s2 = (SCNetworkServiceRef)val2;
id1 = SCNetworkServiceGetServiceID(s1);
id2 = SCNetworkServiceGetServiceID(s2);
if (order != NULL) {
CFIndex o1;
CFIndex o2;
CFRange range;
range = CFRangeMake(0, CFArrayGetCount(order));
o1 = CFArrayGetFirstIndexOfValue(order, range, id1);
o2 = CFArrayGetFirstIndexOfValue(order, range, id2);
if (o1 > o2) {
return (o2 != kCFNotFound) ? kCFCompareGreaterThan : kCFCompareLessThan;
} else if (o1 < o2) {
return (o1 != kCFNotFound) ? kCFCompareLessThan : kCFCompareGreaterThan;
}
}
return CFStringCompare(id1, id2, 0);
}
#pragma mark -
#pragma mark SCNetworkService APIs
#define N_QUICK 64
__private_extern__ CFArrayRef
__SCNetworkServiceCopyAllEnabled(SCPreferencesRef prefs)
{
CFMutableArrayRef array = NULL;
CFIndex i_sets;
CFIndex n_sets;
CFArrayRef sets;
sets = SCNetworkSetCopyAll(prefs);
if (sets == NULL) {
return NULL;
}
n_sets = CFArrayGetCount(sets);
for (i_sets = 0; i_sets < n_sets; i_sets++) {
CFIndex i_services;
CFIndex n_services;
CFArrayRef services;
SCNetworkSetRef set;
set = CFArrayGetValueAtIndex(sets, i_sets);
services = SCNetworkSetCopyServices(set);
if (services == NULL) {
continue;
}
n_services = CFArrayGetCount(services);
for (i_services = 0; i_services < n_services; i_services++) {
SCNetworkServiceRef service;
service = CFArrayGetValueAtIndex(services, i_services);
if (!SCNetworkServiceGetEnabled(service)) {
continue;
}
if ((array == NULL) ||
!CFArrayContainsValue(array,
CFRangeMake(0, CFArrayGetCount(array)),
service)) {
if (array == NULL) {
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
CFArrayAppendValue(array, service);
}
}
CFRelease(services);
}
CFRelease(sets);
return array;
}
__private_extern__ 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;
}
static void
mergeDict(const void *key, const void *value, void *context)
{
CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context;
CFDictionarySetValue(newDict, key, value);
return;
}
static CF_RETURNS_RETAINED CFDictionaryRef
_protocolTemplate(SCNetworkServiceRef service, CFStringRef protocolType)
{
SCNetworkInterfaceRef interface;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
CFDictionaryRef template = NULL;
interface = servicePrivate->interface;
if (interface != NULL) {
SCNetworkInterfaceRef childInterface;
CFStringRef childInterfaceType = NULL;
CFStringRef interfaceType;
interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface);
childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface);
if (childInterface != NULL) {
childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
}
template = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType);
if (template != NULL) {
CFDictionaryRef overrides;
while (childInterface != NULL) {
interface = childInterface;
childInterface = SCNetworkInterfaceGetInterface(interface);
}
overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, protocolType);
if (overrides != NULL) {
CFMutableDictionaryRef newTemplate;
newTemplate = CFDictionaryCreateMutableCopy(NULL, 0, template);
CFDictionaryApplyFunction(overrides, mergeDict, newTemplate);
CFRelease(template);
template = newTemplate;
}
}
}
if (template == NULL) {
template = CFDictionaryCreate(NULL,
NULL,
NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
return template;
}
Boolean
SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
{
CFDictionaryRef entity;
CFDictionaryRef newEntity = NULL;
Boolean ok = FALSE;
CFStringRef path;
SCNetworkProtocolRef protocol;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!__SCNetworkProtocolIsValidType(protocolType)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, protocolType);
entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
if (entity != NULL) {
_SCErrorSet(kSCStatusKeyExists);
goto done;
}
newEntity = CFDictionaryCreate(NULL,
NULL,
NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
CFRelease(newEntity);
if (!ok) {
goto done;
}
protocol = SCNetworkServiceCopyProtocol(service, protocolType);
assert(protocol != NULL);
newEntity = _protocolTemplate(service, protocolType);
ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
CFRelease(newEntity);
CFRelease(protocol);
done :
CFRelease(path);
return ok;
}
CFArrayRef
SCNetworkServiceCopyAll(SCPreferencesRef prefs)
{
CFMutableArrayRef array;
CFIndex n;
CFStringRef path;
CFDictionaryRef services;
path = SCPreferencesPathKeyCreateNetworkServices(NULL);
services = SCPreferencesPathGetValue(prefs, path);
CFRelease(path);
if ((services != NULL) && !isA_CFDictionary(services)) {
return NULL;
}
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
n = (services != NULL) ? CFDictionaryGetCount(services) : 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(services, keys, vals);
for (i = 0; i < n; i++) {
CFDictionaryRef entity;
SCNetworkServicePrivateRef servicePrivate;
if (!isA_CFDictionary(vals[i])) {
SC_log(LOG_INFO, "error w/service \"%@\"", keys[i]);
continue;
}
entity = CFDictionaryGetValue(vals[i], kSCEntNetInterface);
if (!isA_CFDictionary(entity)) {
SC_log(LOG_INFO, "no \"%@\" entity for service \"%@\"",
kSCEntNetInterface,
keys[i]);
continue;
}
servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, keys[i], NULL);
assert(servicePrivate != NULL);
CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
CFRelease(servicePrivate);
}
if (keys != keys_q) {
CFAllocatorDeallocate(NULL, keys);
CFAllocatorDeallocate(NULL, vals);
}
}
return array;
}
__private_extern__
CFArrayRef
__SCNetworkServiceCopyAllInterfaces(SCPreferencesRef prefs)
{
CFMutableArrayRef interfaces = NULL;
CFArrayRef services = NULL;
CFIndex servicesCount = 0;
SCNetworkServiceRef service = NULL;
SCNetworkInterfaceRef interface = NULL;
services = SCNetworkServiceCopyAll(prefs);
if (services == NULL) {
goto done;
}
servicesCount = CFArrayGetCount(services);
if (servicesCount == 0) {
goto done;
}
interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
for (CFIndex idx = 0; idx < servicesCount; idx++) {
service = CFArrayGetValueAtIndex(services, idx);
interface = SCNetworkServiceGetInterface(service);
if (isA_SCNetworkInterface(interface) == NULL) {
continue;
}
CFArrayAppendValue(interfaces, interface);
}
if (CFArrayGetCount(interfaces) == 0) {
CFRelease(interfaces);
interfaces = NULL;
}
done:
if (services != NULL) {
CFRelease(services);
}
return interfaces;
}
static CFSetRef
_copyInterfaceEntityTypes(CFDictionaryRef protocols)
{
CFDictionaryRef interface;
CFMutableSetRef interface_entity_types;
interface_entity_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
interface = CFDictionaryGetValue(protocols, kSCEntNetInterface);
if (isA_CFDictionary(interface)) {
CFStringRef entities[] = { kSCPropNetInterfaceType,
kSCPropNetInterfaceSubType,
kSCPropNetInterfaceHardware };
int i;
CFSetAddValue(interface_entity_types, kSCEntNetInterface);
for (i = 0; i < sizeof(entities)/sizeof(entities[0]); i++) {
CFStringRef entity;
entity = CFDictionaryGetValue(interface, entities[i]);
if (isA_CFString(entity)) {
CFSetAddValue(interface_entity_types, entity);
}
}
CFSetAddValue(interface_entity_types, kSCEntNetPPP);
}
return interface_entity_types;
}
SCNetworkServiceRef
SCNetworkServiceCopy(SCPreferencesRef prefs, CFStringRef serviceID)
{
CFDictionaryRef entity;
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate;
if (!isA_CFString(serviceID)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, serviceID, kSCEntNetInterface); entity = SCPreferencesPathGetValue(prefs, path);
CFRelease(path);
if (!isA_CFDictionary(entity)) {
_SCErrorSet(kSCStatusNoKey);
return NULL;
}
servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
return (SCNetworkServiceRef)servicePrivate;
}
SCNetworkServiceRef
_SCNetworkServiceCopyActive(SCDynamicStoreRef store, CFStringRef serviceID)
{
SCNetworkServicePrivateRef servicePrivate;
if (!isA_CFString(serviceID)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
servicePrivate = __SCNetworkServiceCreatePrivate(NULL, NULL, serviceID, NULL);
assert(servicePrivate != NULL);
if (store != NULL) {
servicePrivate->store = CFRetain(store);
}
return (SCNetworkServiceRef)servicePrivate;
}
SCNetworkProtocolRef
SCNetworkServiceCopyProtocol(SCNetworkServiceRef service, CFStringRef protocolType)
{
CFSetRef non_protocol_entities;
CFStringRef path;
CFDictionaryRef protocols;
SCNetworkProtocolPrivateRef protocolPrivate = NULL;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (!isA_CFString(protocolType)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
CFRelease(path);
if (!isA_CFDictionary(protocols)) {
_SCErrorSet(kSCStatusFailed);
return NULL;
}
non_protocol_entities = _copyInterfaceEntityTypes(protocols);
if (CFSetContainsValue(non_protocol_entities, protocolType)) {
_SCErrorSet(kSCStatusInvalidArgument);
goto done;
}
if (!CFDictionaryContainsKey(protocols, protocolType)) {
_SCErrorSet(kSCStatusNoKey);
goto done;
}
protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, protocolType, service);
done :
CFRelease(non_protocol_entities);
return (SCNetworkProtocolRef)protocolPrivate;
}
CFArrayRef
SCNetworkServiceCopyProtocols(SCNetworkServiceRef service)
{
CFMutableArrayRef array;
CFIndex n;
CFSetRef non_protocol_entities;
CFStringRef path;
CFDictionaryRef protocols;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
CFRelease(path);
if (!isA_CFDictionary(protocols)) {
_SCErrorSet(kSCStatusFailed);
return NULL;
}
non_protocol_entities = _copyInterfaceEntityTypes(protocols);
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
n = CFDictionaryGetCount(protocols);
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(protocols, keys, vals);
for (i = 0; i < n; i++) {
SCNetworkProtocolPrivateRef protocolPrivate;
if (!isA_CFDictionary(vals[i])) {
continue;
}
if (CFSetContainsValue(non_protocol_entities, keys[i])) {
continue;
}
protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, keys[i], service);
CFArrayAppendValue(array, (SCNetworkProtocolRef)protocolPrivate);
CFRelease(protocolPrivate);
}
if (keys != keys_q) {
CFAllocatorDeallocate(NULL, keys);
CFAllocatorDeallocate(NULL, vals);
}
}
CFRelease(non_protocol_entities);
return array;
}
static Boolean
__SCNetworkServiceSetInterfaceEntity(SCNetworkServiceRef service,
SCNetworkInterfaceRef interface)
{
CFDictionaryRef entity;
Boolean ok;
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, kSCEntNetInterface); entity = __SCNetworkInterfaceCopyInterfaceEntity(interface);
ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, entity);
CFRelease(entity);
CFRelease(path);
return ok;
}
SCNetworkServiceRef
SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface)
{
CFArrayRef components;
CFArrayRef interface_config;
CFStringRef interface_name;
SCNetworkInterfaceRef newInterface;
CFStringRef path;
CFStringRef prefix;
CFStringRef serviceID;
SCNetworkServicePrivateRef servicePrivate;
CFArrayRef supported_protocols;
if (!isA_SCNetworkInterface(interface)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
supported_protocols = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
if (supported_protocols == NULL) {
CFStringRef interface_type;
interface_type = SCNetworkInterfaceGetInterfaceType(interface);
if (CFStringFind(interface_type, CFSTR("."), 0).location == kCFNotFound) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
}
if (__SCNetworkInterfaceIsMember(prefs, interface)) {
_SCErrorSet(kSCStatusKeyExists);
return NULL;
}
prefix = SCPreferencesPathKeyCreateNetworkServices(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);
serviceID = CFArrayGetValueAtIndex(components, 2);
servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
CFRelease(components);
newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,
interface,
prefs,
serviceID);
servicePrivate->interface = newInterface;
for (interface = newInterface;
interface != NULL;
interface = SCNetworkInterfaceGetInterface(interface)) {
SCNetworkInterfaceRef childInterface;
CFStringRef childInterfaceType = NULL;
CFDictionaryRef config;
CFStringRef interfaceType;
interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
childInterface = SCNetworkInterfaceGetInterface(interface);
if (childInterface != NULL) {
childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
}
config = __copyInterfaceTemplate(interfaceType, childInterfaceType);
if (config != NULL) {
if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBluetooth) ||
CFEqual(interfaceType, kSCNetworkInterfaceTypeIrDA ) ||
CFEqual(interfaceType, kSCNetworkInterfaceTypeModem ) ||
CFEqual(interfaceType, kSCNetworkInterfaceTypeSerial ) ||
CFEqual(interfaceType, kSCNetworkInterfaceTypeWWAN )) {
CFDictionaryRef overrides;
overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypeModem);
if (overrides != NULL) {
CFMutableDictionaryRef newConfig;
newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
if (CFDictionaryContainsKey(overrides, kSCPropNetModemConnectionScript)) {
CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionPersonality);
CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionScript);
CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceVendor);
CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceModel);
}
CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
CFRelease(config);
config = newConfig;
}
} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP) ||
CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
CFDictionaryRef overrides;
overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypePPP);
if (overrides != NULL) {
CFMutableDictionaryRef newConfig;
newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
CFRelease(config);
config = newConfig;
}
}
if (!__SCNetworkInterfaceSetConfiguration(interface, NULL, config, TRUE)) {
SC_log(LOG_INFO, "__SCNetworkInterfaceSetConfiguration failed(), interface=%@, type=NULL",
interface);
}
CFRelease(config);
}
}
(void) __SCNetworkServiceSetInterfaceEntity((SCNetworkServiceRef)servicePrivate,
servicePrivate->interface);
interface_config = __SCNetworkInterfaceCopyDeepConfiguration(NULL, servicePrivate->interface);
__SCNetworkInterfaceSetDeepConfiguration(NULL, servicePrivate->interface, interface_config);
if (interface_config != NULL) CFRelease(interface_config);
interface_name = SCNetworkServiceGetName((SCNetworkServiceRef)servicePrivate);
if (interface_name != NULL) {
(void) SCNetworkServiceSetName((SCNetworkServiceRef)servicePrivate,
interface_name);
}
return (SCNetworkServiceRef)servicePrivate;
}
Boolean
SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service)
{
CFIndex i;
SCNetworkInterfaceRef interface;
CFIndex n;
CFArrayRef protocolTypes;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
interface = SCNetworkServiceGetInterface(service);
if (interface == NULL) {
return FALSE;
}
protocolTypes = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
n = (protocolTypes != NULL) ? CFArrayGetCount(protocolTypes) : 0;
for (i = 0; i < n; i++) {
Boolean enabled;
CFDictionaryRef newEntity = NULL;
Boolean ok;
SCNetworkProtocolRef protocol = NULL;
CFStringRef protocolType;
protocolType = CFArrayGetValueAtIndex(protocolTypes, i);
ok = SCNetworkServiceAddProtocolType(service, protocolType);
if (!ok && (SCError() != kSCStatusKeyExists)) {
goto nextProtocol;
}
protocol = SCNetworkServiceCopyProtocol(service, protocolType);
if (protocol == NULL) {
goto nextProtocol;
}
newEntity = _protocolTemplate(service, protocolType);
ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
if (!ok) {
goto nextProtocol;
}
enabled = !CFDictionaryContainsKey(newEntity, kSCResvInactive);
ok = SCNetworkProtocolSetEnabled(protocol, enabled);
if (!ok) {
goto nextProtocol;
}
nextProtocol :
if (newEntity != NULL) CFRelease(newEntity);
if (protocol != NULL) CFRelease(protocol);
}
return TRUE;
}
Boolean
SCNetworkServiceGetEnabled(SCNetworkServiceRef service)
{
Boolean enabled;
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); enabled = __getPrefsEnabled(servicePrivate->prefs, path);
CFRelease(path);
return enabled;
}
SCNetworkInterfaceRef
SCNetworkServiceGetInterface(SCNetworkServiceRef service)
{
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (servicePrivate->interface == NULL) {
CFDictionaryRef entity;
CFStringRef path;
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, kSCEntNetInterface); entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
CFRelease(path);
if (isA_CFDictionary(entity)) {
servicePrivate->interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, service);
}
}
return servicePrivate->interface;
}
CFStringRef
SCNetworkServiceGetName(SCNetworkServiceRef service)
{
CFDictionaryRef entity;
SCNetworkInterfaceRef interface;
CFStringRef name = NULL;
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
Boolean useSystemInterfaces = TRUE;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (servicePrivate->name != NULL) {
return servicePrivate->name;
}
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
CFRelease(path);
useSystemInterfaces = ((__SCPreferencesUsingDefaultPrefs(servicePrivate->prefs)) &&
(__SCPreferencesGetLimitSCNetworkConfiguration(servicePrivate->prefs) == FALSE));
if (isA_CFDictionary(entity)) {
name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
if (isA_CFString(name)) {
servicePrivate->name = CFRetain(name);
if (useSystemInterfaces == FALSE) {
return servicePrivate->name;
}
}
}
interface = SCNetworkServiceGetInterface(service);
while (interface != NULL) {
SCNetworkInterfaceRef childInterface;
CFStringRef interfaceType;
interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
break;
}
childInterface = SCNetworkInterfaceGetInterface(interface);
if ((childInterface == NULL) ||
CFEqual(childInterface, kSCNetworkInterfaceIPv4)) {
break;
}
interface = childInterface;
}
if (interface != NULL) {
int i;
CFStringRef interface_name = NULL;
CFStringRef suffix = NULL;
for (i = 0; i < 3; i++) {
if (servicePrivate->name == NULL) {
break;
}
switch (i) {
case 0 :
interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
if (interface_name != NULL) {
CFRetain(interface_name);
}
break;
#if !TARGET_OS_IPHONE
case 1 :
interface_name = __SCNetworkInterfaceCopyXLocalizedDisplayName(interface);
break;
case 2 :
interface_name = __SCNetworkInterfaceCopyXNonLocalizedDisplayName(interface);
break;
#endif // !TARGET_OS_IPHONE
default :
continue;
}
if (interface_name != NULL) {
Boolean match = FALSE;
if (CFEqual(name, interface_name)) {
match = TRUE;
} else if (CFStringHasPrefix(name, interface_name)) {
CFIndex prefixLen = CFStringGetLength(interface_name);
CFIndex suffixLen = CFStringGetLength(name);
suffix = CFStringCreateWithSubstring(NULL,
name,
CFRangeMake(prefixLen, suffixLen - prefixLen));
match = TRUE;
}
CFRelease(interface_name);
if (match) {
CFRelease(servicePrivate->name);
servicePrivate->name = NULL;
break;
}
}
}
if (servicePrivate->name == NULL) {
interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
if (interface_name != NULL) {
if (suffix != NULL) {
servicePrivate->name = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("%@%@"),
interface_name,
suffix);
} else {
servicePrivate->name = CFRetain(interface_name);
}
}
}
if (suffix != NULL) CFRelease(suffix);
}
return servicePrivate->name;
}
CFStringRef
SCNetworkServiceGetServiceID(SCNetworkServiceRef service)
{
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
return servicePrivate->serviceID;
}
CFTypeID
SCNetworkServiceGetTypeID(void)
{
pthread_once(&initialized, __SCNetworkServiceInitialize);
return __kSCNetworkServiceTypeID;
}
Boolean
SCNetworkServiceRemove(SCNetworkServiceRef service)
{
Boolean ok = FALSE;
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
CFArrayRef sets;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
sets = SCNetworkSetCopyAll(servicePrivate->prefs);
if (sets != NULL) {
CFIndex i;
CFIndex n;
n = CFArrayGetCount(sets);
for (i = 0; i < n; i++) {
SCNetworkSetRef set;
set = CFArrayGetValueAtIndex(sets, i);
ok = SCNetworkSetRemoveService(set, service);
if (!ok && (SCError() != kSCStatusNoKey)) {
CFRelease(sets);
return ok;
}
}
CFRelease(sets);
}
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
CFRelease(path);
return ok;
}
Boolean
SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
{
CFDictionaryRef entity;
Boolean ok = FALSE;
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!__SCNetworkProtocolIsValidType(protocolType)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, protocolType);
entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
if (entity == NULL) {
_SCErrorSet(kSCStatusNoKey);
goto done;
}
ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
done :
CFRelease(path);
return ok;
}
Boolean
SCNetworkServiceSetEnabled(SCNetworkServiceRef service, Boolean enabled)
{
Boolean ok;
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (enabled) {
SCNetworkInterfaceRef interface;
interface = SCNetworkServiceGetInterface(service);
if ((interface != NULL) &&
__SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) {
_SCErrorSet(kSCStatusKeyExists);
return FALSE;
}
}
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); ok = __setPrefsEnabled(servicePrivate->prefs, path, enabled);
CFRelease(path);
return ok;
}
Boolean
SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name)
{
CFDictionaryRef entity;
Boolean ok = FALSE;
CFStringRef path;
CFStringRef saveName = NULL;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (name != NULL) {
if (!isA_CFString(name)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
saveName = CFRetain(name);
}
if (name != NULL) {
SCNetworkInterfaceRef interface;
interface = SCNetworkServiceGetInterface(service);
while (interface != NULL) {
SCNetworkInterfaceRef childInterface;
childInterface = SCNetworkInterfaceGetInterface(interface);
if (childInterface == NULL) {
break;
}
interface = childInterface;
}
if (interface != NULL) {
CFStringRef interface_name;
interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
if (interface_name != NULL) {
if (CFEqual(name, interface_name)) {
interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
if (interface_name != NULL) {
CFRelease(saveName);
saveName = CFRetain(interface_name);
}
} else if (CFStringHasPrefix(name, interface_name)) {
CFIndex prefixLen = CFStringGetLength(interface_name);
CFStringRef suffix;
CFIndex suffixLen = CFStringGetLength(name);
suffix = CFStringCreateWithSubstring(NULL,
name,
CFRangeMake(prefixLen, suffixLen - prefixLen));
interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
if (interface_name != NULL) {
CFRelease(saveName);
saveName = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("%@%@"),
interface_name,
suffix);
}
CFRelease(suffix);
}
}
}
}
#define PREVENT_DUPLICATE_SERVICE_NAMES
#ifdef PREVENT_DUPLICATE_SERVICE_NAMES
if (name != NULL) {
CFArrayRef sets;
sets = SCNetworkSetCopyAll(servicePrivate->prefs);
if (sets != NULL) {
CFIndex set_index;
CFIndex set_count;
set_count = CFArrayGetCount(sets);
for (set_index = 0; set_index < set_count; set_index++) {
CFIndex service_index;
Boolean isDup = FALSE;
Boolean isMember = FALSE;
CFIndex service_count;
CFArrayRef services;
SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, set_index);
services = SCNetworkSetCopyServices(set);
service_count = CFArrayGetCount(services);
for (service_index = 0; service_index < service_count; service_index++) {
CFStringRef otherID;
CFStringRef otherName;
SCNetworkServiceRef otherService;
otherService = CFArrayGetValueAtIndex(services, service_index);
otherID = SCNetworkServiceGetServiceID(otherService);
if (CFEqual(servicePrivate->serviceID, otherID)) {
isMember = TRUE;
continue;
}
otherName = SCNetworkServiceGetName(otherService);
if ((otherName != NULL) && CFEqual(name, otherName)) {
isDup = TRUE;
continue;
}
}
CFRelease(services);
if (isMember && isDup) {
CFRelease(sets);
if (saveName != NULL) CFRelease(saveName);
_SCErrorSet(kSCStatusKeyExists);
return FALSE;
}
}
CFRelease(sets);
}
}
#endif
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); entity = SCPreferencesPathGetValue(servicePrivate->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 (saveName != NULL) {
CFDictionarySetValue(newEntity, kSCPropUserDefinedName, saveName);
} else {
CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
}
ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
CFRelease(newEntity);
}
CFRelease(path);
if (saveName != NULL) CFRelease(saveName);
if (servicePrivate->name != NULL) CFRelease(servicePrivate->name);
if (name != NULL) CFRetain(name);
servicePrivate->name = name;
return ok;
}
#pragma mark -
#pragma mark SCNetworkService SPIs
SCNetworkServicePrimaryRank
SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service)
{
CFDictionaryRef entity;
Boolean ok = TRUE;
CFStringRef path;
SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault;
CFStringRef rankStr = NULL;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service)) {
_SCErrorSet(kSCStatusInvalidArgument);
return rank;
}
if (servicePrivate->prefs != NULL) {
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
servicePrivate->serviceID,
NULL);
entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
CFRelease(path);
if (isA_CFDictionary(entity)) {
rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
ok = __str_to_rank(rankStr, &rank);
}
} else if (servicePrivate->store != NULL) {
path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainState,
servicePrivate->serviceID,
NULL);
entity = SCDynamicStoreCopyValue(servicePrivate->store, path);
CFRelease(path);
if (entity != NULL) {
if (isA_CFDictionary(entity)) {
rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
ok = __str_to_rank(rankStr, &rank);
}
CFRelease(entity);
}
} else {
_SCErrorSet(kSCStatusInvalidArgument);
return rank;
}
if (!ok) {
rank = kSCNetworkServicePrimaryRankDefault;
_SCErrorSet(kSCStatusInvalidArgument);
} else if (rank == kSCNetworkServicePrimaryRankDefault) {
_SCErrorSet(kSCStatusOK);
}
return rank;
}
Boolean
SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service,
SCNetworkServicePrimaryRank newRank)
{
Boolean ok;
CFDictionaryRef entity;
CFMutableDictionaryRef newEntity;
CFStringRef path = NULL;
CFStringRef rankStr = NULL;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
ok = __rank_to_str(newRank, &rankStr);
if (!ok) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (servicePrivate->prefs != NULL) {
switch (newRank) {
case kSCNetworkServicePrimaryRankDefault:
case kSCNetworkServicePrimaryRankNever:
case kSCNetworkServicePrimaryRankScoped:
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
servicePrivate->serviceID,
NULL);
entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
if (entity != NULL) {
if (!isA_CFDictionary(entity)) {
_SCErrorSet(kSCStatusFailed);
goto done;
}
newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
} else {
newEntity = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
if (rankStr != NULL) {
CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
} else {
CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
}
if (CFDictionaryGetCount(newEntity) > 0) {
ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
} else {
ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
}
CFRelease(newEntity);
if (!ok) {
goto done;
}
break;
default:
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
} else if (servicePrivate->store != NULL) {
path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainState,
servicePrivate->serviceID,
NULL);
entity = SCDynamicStoreCopyValue(servicePrivate->store, path);
if (entity != NULL) {
if (!isA_CFDictionary(entity)) {
CFRelease(entity);
_SCErrorSet(kSCStatusFailed);
goto done;
}
newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
CFRelease(entity);
} else {
newEntity = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
if (rankStr != NULL) {
CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
} else {
CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
}
if (CFDictionaryGetCount(newEntity) > 0) {
ok = SCDynamicStoreSetValue(servicePrivate->store, path, newEntity);
} else {
ok = SCDynamicStoreRemoveValue(servicePrivate->store, path);
}
CFRelease(newEntity);
if (!ok) {
goto done;
}
} else {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
done :
if (path != NULL) CFRelease(path);
return ok;
}
Boolean
_SCNetworkServiceIsVPN(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;
}
} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
return TRUE;
} else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
return TRUE;
}
return FALSE;
}
Boolean
SCNetworkServiceSetExternalID(SCNetworkServiceRef service, CFStringRef identifierDomain, CFStringRef identifier)
{
CFStringRef prefs_path;
CFDictionaryRef service_dictionary;
SCNetworkServicePrivateRef service_private = (SCNetworkServicePrivateRef)service;
Boolean success = FALSE;
CFStringRef prefixed_domain;
if (!isA_SCNetworkService(service) || (service_private->prefs == NULL) || !isA_CFString(identifierDomain)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (identifier != NULL && !isA_CFString(identifier)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
prefixed_domain = CFStringCreateWithFormat(NULL, 0, CFSTR("%s%@"), EXTERNAL_ID_DOMAIN_PREFIX, identifierDomain);
prefs_path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
service_private->serviceID,
NULL);
service_dictionary = SCPreferencesPathGetValue(service_private->prefs, prefs_path);
if (isA_CFDictionary(service_dictionary) || ((service_dictionary == NULL) && (identifier != NULL))) {
CFMutableDictionaryRef new_service_dictionary;
if (service_dictionary != NULL) {
new_service_dictionary = CFDictionaryCreateMutableCopy(NULL, 0, service_dictionary);
} else {
new_service_dictionary = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
if (identifier != NULL) {
CFDictionarySetValue(new_service_dictionary, prefixed_domain, identifier);
} else {
CFDictionaryRemoveValue(new_service_dictionary, prefixed_domain);
}
success = SCPreferencesPathSetValue(service_private->prefs, prefs_path, new_service_dictionary);
CFRelease(new_service_dictionary);
}
CFRelease(prefs_path);
if (identifier != NULL) {
if (service_private->externalIDs == NULL) {
service_private->externalIDs = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(service_private->externalIDs, prefixed_domain, identifier);
} else {
if (service_private->externalIDs != NULL) {
CFDictionaryRemoveValue(service_private->externalIDs, prefixed_domain);
}
}
CFRelease(prefixed_domain);
if (!success) {
_SCErrorSet(kSCStatusFailed);
}
return success;
}
CFStringRef
SCNetworkServiceCopyExternalID(SCNetworkServiceRef service, CFStringRef identifierDomain)
{
SCNetworkServicePrivateRef service_private = (SCNetworkServicePrivateRef)service;
CFStringRef identifier = NULL;
CFStringRef prefixed_domain;
if (!isA_SCNetworkService(service) || (service_private->prefs == NULL) || !isA_CFString(identifierDomain)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
prefixed_domain = CFStringCreateWithFormat(NULL, 0, CFSTR("%s%@"), EXTERNAL_ID_DOMAIN_PREFIX, identifierDomain);
if (service_private->externalIDs != NULL) {
identifier = CFDictionaryGetValue(service_private->externalIDs, prefixed_domain);
if (identifier != NULL) {
CFRetain(identifier);
}
}
if (identifier == NULL) {
CFStringRef prefs_path;
CFDictionaryRef service_dictionary;
prefs_path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
service_private->serviceID,
NULL);
service_dictionary = SCPreferencesPathGetValue(service_private->prefs, prefs_path);
if (isA_CFDictionary(service_dictionary)) {
identifier = CFDictionaryGetValue(service_dictionary, prefixed_domain);
if (identifier != NULL) {
CFRetain(identifier);
if (service_private->externalIDs == NULL) {
service_private->externalIDs = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(service_private->externalIDs, prefixed_domain, identifier);
}
}
CFRelease(prefs_path);
}
CFRelease(prefixed_domain);
if (identifier == NULL) {
_SCErrorSet(kSCStatusNoKey);
}
return identifier;
}
typedef struct {
CFStringRef oldServiceID;
CFStringRef newServiceID;
} serviceContext, *serviceContextRef;
static void
replaceServiceID(const void *value, void *context)
{
CFStringRef link = NULL;
CFStringRef oldLink;
CFMutableArrayRef newServiceOrder;
CFStringRef path;
serviceContextRef service_context = (serviceContextRef)context;
CFArrayRef serviceOrder = NULL;
SCNetworkSetRef set = (SCNetworkSetRef)value;
SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
serviceOrder = SCNetworkSetGetServiceOrder(set);
if ((isA_CFArray(serviceOrder) != NULL) &&
(CFArrayContainsValue(serviceOrder,
CFRangeMake(0, CFArrayGetCount(serviceOrder)),
service_context->oldServiceID) == TRUE)) {
CFIndex count;
CFIndex serviceOrderIndex;
newServiceOrder = CFArrayCreateMutableCopy(NULL, 0, serviceOrder);
count = CFArrayGetCount(newServiceOrder);
for (serviceOrderIndex = 0; serviceOrderIndex < count; serviceOrderIndex++) {
CFStringRef serviceID;
serviceID = CFArrayGetValueAtIndex(newServiceOrder, serviceOrderIndex);
if (CFEqual(serviceID, service_context->oldServiceID)) {
CFArraySetValueAtIndex(newServiceOrder, serviceOrderIndex, service_context->newServiceID);
}
}
SCNetworkSetSetServiceOrder(set, newServiceOrder);
CFRelease(newServiceOrder);
}
path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, setPrivate->setID, service_context->oldServiceID, NULL); oldLink = SCPreferencesPathGetLink(setPrivate->prefs, path);
if (oldLink == NULL) {
goto done;
}
SCPreferencesPathRemoveValue(setPrivate->prefs, path);
CFRelease(path);
path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, setPrivate->setID, service_context->newServiceID, NULL); link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, service_context->newServiceID, NULL); SCPreferencesPathSetLink(setPrivate->prefs, path, link);
done:
if (path != NULL) {
CFRelease(path);
}
if (link != NULL) {
CFRelease(link);
}
return;
}
Boolean
_SCNetworkServiceSetServiceID(SCNetworkServiceRef service, CFStringRef newServiceID)
{
CFArrayRef allSets = NULL;
CFDictionaryRef entity;
CFStringRef newPath;
Boolean ok = FALSE;
CFStringRef oldPath = NULL;
serviceContext service_context;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (!isA_CFString(newServiceID)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (CFEqual(newServiceID, servicePrivate->serviceID)) {
return TRUE;
}
newPath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, newServiceID, NULL); entity = SCPreferencesPathGetValue(servicePrivate->prefs, newPath);
if (isA_CFDictionary(entity)) {
_SCErrorSet(kSCStatusKeyExists);
goto done;
}
oldPath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); entity = SCPreferencesPathGetValue(servicePrivate->prefs, oldPath);
if (!isA_CFDictionary(entity)) {
_SCErrorSet(kSCStatusNoKey);
goto done;
}
ok = SCPreferencesPathSetValue(servicePrivate->prefs, newPath, entity);
if (!ok) goto done;
ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, oldPath);
if (!ok) goto done;
allSets = SCNetworkSetCopyAll(servicePrivate->prefs);
service_context.newServiceID = newServiceID;
service_context.oldServiceID = servicePrivate->serviceID;
CFArrayApplyFunction(allSets,
CFRangeMake(0, CFArrayGetCount(allSets)),
replaceServiceID,
&service_context);
if (servicePrivate->interface != NULL) {
SCNetworkInterfaceRef newInterface;
newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,
servicePrivate->interface,
servicePrivate->prefs,
newServiceID);
CFRelease(servicePrivate->interface);
servicePrivate->interface = newInterface;
}
CFRetain(newServiceID);
CFRelease(servicePrivate->serviceID);
servicePrivate->serviceID = newServiceID;
done:
if (oldPath != NULL) {
CFRelease(oldPath);
}
if (newPath != NULL) {
CFRelease(newPath);
}
if (allSets != NULL) {
CFRelease(allSets);
}
return ok;
}
#define kVPNProtocolPayloadInfo CFSTR("com.apple.payload")
#define kSCEntNetLoginWindowEAPOL CFSTR("EAPOL.LoginWindow")
static void
copyInterfaceConfiguration(SCNetworkServiceRef oldService, SCNetworkServiceRef newService)
{
SCNetworkInterfaceRef oldInterface;
SCNetworkInterfaceRef newInterface;
oldInterface = SCNetworkServiceGetInterface(oldService);
newInterface = SCNetworkServiceGetInterface(newService);
while (oldInterface != NULL) {
CFDictionaryRef configuration;
CFStringRef interfaceType;
if (newInterface == NULL) {
return;
}
configuration = SCNetworkInterfaceGetConfiguration(oldInterface);
if ((configuration != NULL) ||
(SCError() == kSCStatusOK)) {
if (SCNetworkInterfaceSetConfiguration(newInterface, configuration) == FALSE) {
SC_log(LOG_INFO, "problem setting interface configuration");
}
}
interfaceType = SCNetworkInterfaceGetInterfaceType(oldInterface);
if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
SCNetworkInterfaceRef childInterface;
childInterface = SCNetworkInterfaceGetInterface(oldInterface);
if (childInterface != NULL) {
CFStringRef childInterfaceType;
childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
if (CFEqual(childInterfaceType, kSCNetworkInterfaceTypeL2TP)) {
configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetIPSec);
if ((configuration != NULL) ||
(SCError() == kSCStatusOK)) {
if (SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetIPSec, configuration) == FALSE) {
SC_log(LOG_INFO, "problem setting child interface configuration");
}
}
}
}
}
configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetEAPOL);
if ((configuration != NULL) ||
(SCError() == kSCStatusOK)) {
(void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetEAPOL, configuration);
}
configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kVPNProtocolPayloadInfo);
if ((configuration != NULL) ||
(SCError() == kSCStatusOK)) {
(void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kVPNProtocolPayloadInfo, configuration);
}
configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCValNetPPPAuthProtocolEAP);
if ((configuration != NULL) ||
(SCError() == kSCStatusOK)) {
(void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCValNetPPPAuthProtocolEAP, configuration);
}
configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetLoginWindowEAPOL);
if ((configuration != NULL) ||
(SCError() == kSCStatusOK)) {
(void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetLoginWindowEAPOL, configuration);
}
configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCNetworkInterfaceTypeIPSec);
if ((configuration != NULL) ||
(SCError() == kSCStatusOK)) {
(void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCNetworkInterfaceTypeIPSec, configuration);
}
oldInterface = SCNetworkInterfaceGetInterface(oldInterface);
newInterface = SCNetworkInterfaceGetInterface(newInterface);
}
return;
}
__private_extern__
void
__SCNetworkServiceAddProtocolToService(SCNetworkServiceRef service, CFStringRef protocolType, CFDictionaryRef configuration, Boolean enabled)
{
Boolean ok;
SCNetworkProtocolRef protocol;
protocol = SCNetworkServiceCopyProtocol(service, protocolType);
if ((protocol == NULL) &&
(SCError() == kSCStatusNoKey)) {
ok = SCNetworkServiceAddProtocolType(service, protocolType);
if (ok) {
protocol = SCNetworkServiceCopyProtocol(service, protocolType);
}
}
if (protocol != NULL) {
SCNetworkProtocolSetConfiguration(protocol, configuration);
SCNetworkProtocolSetEnabled(protocol, enabled);
CFRelease(protocol);
}
return;
}
__private_extern__
Boolean
__SCNetworkServiceMigrateNew(SCPreferencesRef prefs,
SCNetworkServiceRef service,
CFDictionaryRef bsdMapping,
CFDictionaryRef setMapping,
CFDictionaryRef serviceSetMapping)
{
CFStringRef deviceName = NULL;
Boolean enabled;
SCNetworkInterfaceRef interface = NULL;
CFDictionaryRef interfaceEntity = NULL;
CFMutableDictionaryRef interfaceEntityMutable = NULL;
SCNetworkSetRef newSet = NULL;
SCPreferencesRef ni_prefs = NULL;
SCNetworkInterfaceRef ni_interface = NULL;
SCNetworkInterfaceRef oldInterface = NULL;
SCNetworkSetRef oldSet = NULL;
SCNetworkServiceRef newService = NULL;
CFStringRef serviceID = NULL;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef) service;
CFMutableDictionaryRef servicesMutable = NULL;
CFArrayRef setList = NULL;
Boolean success = FALSE;
CFStringRef targetDeviceName = NULL;
CFStringRef userDefinedName = NULL;
CFStringRef userDefinedNameInterface = NULL;
CFArrayRef protocols = NULL;
CFStringRef subType;
if ((isA_SCNetworkService(service) == NULL) ||
(isA_SCNetworkInterface(servicePrivate->interface) == NULL) ||
(servicePrivate->prefs == NULL)) {
goto done;
}
serviceID = servicePrivate->serviceID;
newService = SCNetworkServiceCopy(prefs, serviceID);
if (newService != NULL) {
SC_log(LOG_INFO, "Service already exists");
goto done;
}
oldInterface = SCNetworkServiceGetInterface(service);
interfaceEntity = __SCNetworkInterfaceCopyInterfaceEntity(oldInterface);
if (interfaceEntity == NULL) {
SC_log(LOG_INFO, "No interface entity");
goto done;
}
interfaceEntityMutable = CFDictionaryCreateMutableCopy(NULL, 0, interfaceEntity);
if (isA_CFDictionary(bsdMapping) != NULL) {
deviceName = CFDictionaryGetValue(interfaceEntityMutable, kSCPropNetInterfaceDeviceName);
if (isA_CFString(deviceName) != NULL) {
targetDeviceName = CFDictionaryGetValue(bsdMapping, deviceName);
if (targetDeviceName != NULL) {
CFDictionarySetValue(interfaceEntityMutable, kSCPropNetInterfaceDeviceName, targetDeviceName);
ni_prefs = __SCPreferencesCreateNIPrefsFromPrefs(prefs);
ni_interface = __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL, ni_prefs, targetDeviceName);
if (ni_interface != NULL) {
userDefinedNameInterface = __SCNetworkInterfaceGetUserDefinedName(ni_interface);
}
}
}
if (userDefinedNameInterface == NULL) {
userDefinedNameInterface = CFDictionaryGetValue(interfaceEntityMutable, kSCPropUserDefinedName);
}
}
subType = CFDictionaryGetValue(interfaceEntityMutable, kSCPropNetInterfaceSubType);
interface = _SCNetworkInterfaceCreateWithEntity(NULL, interfaceEntityMutable, NULL);
if (userDefinedNameInterface != NULL) {
__SCNetworkInterfaceSetUserDefinedName(interface, userDefinedNameInterface);
}
if (subType != NULL &&
CFEqual(subType, kSCValNetInterfaceSubTypePPPoE)) {
SCNetworkInterfaceRef childInterface = SCNetworkInterfaceGetInterface(interface);
if (childInterface != NULL) {
__SCNetworkInterfaceSetUserDefinedName(childInterface, userDefinedNameInterface);
}
}
newService = SCNetworkServiceCreate(prefs, interface);
if (newService == NULL) {
SC_log(LOG_INFO, "SCNetworkServiceCreate() failed");
goto done;
}
enabled = SCNetworkServiceGetEnabled(service);
SCNetworkServiceSetEnabled(newService, enabled);
if (SCNetworkServiceEstablishDefaultConfiguration(newService) == FALSE) {
SCNetworkServiceRemove(newService);
SC_log(LOG_INFO, "SCNetworkServiceEstablishDefaultConfiguration() failed");
goto done;
}
_SCNetworkServiceSetServiceID(newService, serviceID);
userDefinedName = SCNetworkServiceGetName(service);
if (userDefinedName != NULL &&
SCNetworkServiceSetName(newService, userDefinedName) == FALSE) {
SC_log(LOG_INFO, "SCNetworkServiceSetName(, %@) failed", userDefinedName);
}
if (setMapping != NULL &&
serviceSetMapping != NULL) {
setList = CFDictionaryGetValue(serviceSetMapping, service);
if (setList != NULL) {
for (CFIndex idx = 0; idx < CFArrayGetCount(setList); idx++) {
oldSet = CFArrayGetValueAtIndex(setList, idx);
newSet = CFDictionaryGetValue(setMapping, oldSet);
if (newSet == NULL) {
continue;
}
if (SCNetworkSetAddService(newSet, newService) == FALSE) {
SC_log(LOG_INFO, "SCNetworkSetAddService() failed");
continue;
}
}
}
}
protocols = SCNetworkServiceCopyProtocols(service);
if (protocols != NULL) {
for (CFIndex idx = 0; idx < CFArrayGetCount(protocols); idx++) {
SCNetworkProtocolRef protocol = CFArrayGetValueAtIndex(protocols, idx);
CFDictionaryRef configuration = SCNetworkProtocolGetConfiguration(protocol);
CFStringRef protocolType = SCNetworkProtocolGetProtocolType(protocol);
enabled = SCNetworkProtocolGetEnabled(protocol);
__SCNetworkServiceAddProtocolToService(newService, protocolType, configuration, enabled);
}
CFRelease(protocols);
}
copyInterfaceConfiguration(service, newService);
success = TRUE;
done:
if (interface != NULL) {
CFRelease(interface);
}
if (interfaceEntity != NULL) {
CFRelease(interfaceEntity);
}
if (interfaceEntityMutable != NULL) {
CFRelease(interfaceEntityMutable);
}
if (newService != NULL) {
CFRelease(newService);
}
if (servicesMutable != NULL) {
CFRelease(servicesMutable);
}
if (ni_prefs != NULL) {
CFRelease(ni_prefs);
}
if (ni_interface != NULL) {
CFRelease(ni_interface);
}
return success;
}
__private_extern__
Boolean
__SCNetworkServiceCreate(SCPreferencesRef prefs,
SCNetworkInterfaceRef interface,
CFStringRef userDefinedName)
{
SCNetworkSetRef currentSet = NULL;
Boolean ok = FALSE;
SCNetworkServiceRef service = NULL;
if (interface == NULL) {
goto done;
}
if (userDefinedName == NULL) {
userDefinedName = __SCNetworkInterfaceGetUserDefinedName(interface);
if (userDefinedName == NULL) {
SC_log(LOG_INFO, "No userDefinedName");
goto done;
}
}
service = SCNetworkServiceCreate(prefs, interface);
if (service == NULL) {
SC_log(LOG_INFO, "SCNetworkServiceCreate() failed: %s", SCErrorString(SCError()));
} else {
ok = SCNetworkServiceSetName(service, userDefinedName);
if (ok == FALSE) {
SC_log(LOG_INFO, "SCNetworkServiceSetName() failed: %s", SCErrorString(SCError()));
SCNetworkServiceRemove(service);
goto done;
}
ok = SCNetworkServiceEstablishDefaultConfiguration(service);
if (ok == FALSE) {
SC_log(LOG_INFO, "SCNetworkServiceEstablishDefaultConfiguration() failed: %s", SCErrorString(SCError()));
SCNetworkServiceRemove(service);
goto done;
}
}
currentSet = SCNetworkSetCopyCurrent(prefs);
if (currentSet == NULL) {
SC_log(LOG_INFO, "No current set");
if (service != NULL) {
SCNetworkServiceRemove(service);
}
goto done;
}
if (service != NULL) {
ok = SCNetworkSetAddService(currentSet, service);
if (ok == FALSE) {
SC_log(LOG_INFO, "Could not add service to the current set");
SCNetworkServiceRemove(service);
goto done;
}
}
done:
if (service != NULL) {
CFRelease(service);
}
if (currentSet != NULL) {
CFRelease(currentSet);
}
return ok;
}