X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/edebe297f772e4cdd76278ebb777820466d2917b..d94708881e41bd90afd74b1a1dd0524d039ba3f7:/SystemConfiguration.fproj/SCNetworkService.c?ds=sidebyside diff --git a/SystemConfiguration.fproj/SCNetworkService.c b/SystemConfiguration.fproj/SCNetworkService.c index 8245e5c..d9c8d4b 100644 --- a/SystemConfiguration.fproj/SCNetworkService.c +++ b/SystemConfiguration.fproj/SCNetworkService.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2004-2007 Apple Inc. All rights reserved. + * Copyright (c) 2004-2018 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,7 +17,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ @@ -31,13 +31,12 @@ #include #include -#include #include "SCNetworkConfigurationInternal.h" -#include -#include +#include "SCPreferencesInternal.h" #include +#define EXTERNAL_ID_DOMAIN_PREFIX "_" static CFStringRef __SCNetworkServiceCopyDescription (CFTypeRef cf); static void __SCNetworkServiceDeallocate (CFTypeRef cf); @@ -45,7 +44,7 @@ static Boolean __SCNetworkServiceEqual (CFTypeRef cf1, CFTypeRef cf2); static CFHashCode __SCNetworkServiceHash (CFTypeRef cf); -static CFTypeID __kSCNetworkServiceTypeID = _kCFRuntimeNotATypeID; +static CFTypeID __kSCNetworkServiceTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __SCNetworkServiceClass = { @@ -61,7 +60,7 @@ static const CFRuntimeClass __SCNetworkServiceClass = { }; -static pthread_once_t initialized = PTHREAD_ONCE_INIT; +static pthread_once_t initialized = PTHREAD_ONCE_INIT; static CFStringRef @@ -69,12 +68,23 @@ __SCNetworkServiceCopyDescription(CFTypeRef cf) { CFAllocatorRef allocator = CFGetAllocator(cf); CFMutableStringRef result; - SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf; + SCNetworkServiceRef service = (SCNetworkServiceRef)cf; + SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; result = CFStringCreateMutable(allocator, 0); - CFStringAppendFormat(result, NULL, CFSTR(" {"), cf, allocator); + CFStringAppendFormat(result, NULL, CFSTR(" {"), service, allocator); CFStringAppendFormat(result, NULL, CFSTR("id = %@"), servicePrivate->serviceID); - CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), servicePrivate->prefs); + 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); + } + if (!__SCNetworkServiceExists(service)) { + CFStringAppendFormat(result, NULL, CFSTR(", REMOVED")); + } CFStringAppendFormat(result, NULL, CFSTR("}")); return result; @@ -89,8 +99,11 @@ __SCNetworkServiceDeallocate(CFTypeRef cf) /* release resources */ CFRelease(servicePrivate->serviceID); - if (servicePrivate->interface != NULL) CFRelease(servicePrivate->interface); - CFRelease(servicePrivate->prefs); + 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; } @@ -154,7 +167,8 @@ __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator, return NULL; } - servicePrivate->prefs = CFRetain(prefs); + /* initialize non-zero/NULL members */ + servicePrivate->prefs = (prefs != NULL) ? CFRetain(prefs): NULL; servicePrivate->serviceID = CFStringCreateCopy(NULL, serviceID); servicePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL; @@ -162,6 +176,42 @@ __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator, } +#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 @@ -169,36 +219,149 @@ __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator, #define N_QUICK 64 -static CFDictionaryRef +__private_extern__ CFArrayRef /* of SCNetworkServiceRef's */ +__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)) { + // if not enabled + 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) { - CFDictionaryRef newEntity = NULL; + SCNetworkInterfaceRef interface; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; + CFDictionaryRef template = NULL; - if (servicePrivate->interface != NULL) { + interface = servicePrivate->interface; + if (interface != NULL) { SCNetworkInterfaceRef childInterface; CFStringRef childInterfaceType = NULL; CFStringRef interfaceType; + // get the template interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface); childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface); if (childInterface != NULL) { childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface); } - newEntity = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType); + template = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType); + if (template != NULL) { + CFDictionaryRef overrides; + + // move to the interface at the lowest layer + while (childInterface != NULL) { + interface = childInterface; + childInterface = SCNetworkInterfaceGetInterface(interface); + } + + overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, protocolType); + if (isA_CFDictionary(overrides)) { + CFMutableDictionaryRef newTemplate; + + newTemplate = CFDictionaryCreateMutableCopy(NULL, 0, template); + CFDictionaryApplyFunction(overrides, mergeDict, newTemplate); + CFRelease(template); + template = newTemplate; + } + } } - if (newEntity == NULL) { - newEntity = CFDictionaryCreate(NULL, - NULL, - NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + if (template == NULL) { + template = CFDictionaryCreate(NULL, + NULL, + NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); } - return newEntity; + return template; } @@ -206,13 +369,14 @@ Boolean SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protocolType) { CFDictionaryRef entity; + Boolean newEnabled; CFDictionaryRef newEntity = NULL; Boolean ok = FALSE; CFStringRef path; - SCNetworkProtocolRef protocol; + SCNetworkProtocolRef protocol = NULL; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; - if (!isA_SCNetworkService(service)) { + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } @@ -222,6 +386,15 @@ SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protoco return FALSE; } + if (!__SCNetworkServiceExists(service)) { + SC_log(LOG_ERR, "SCNetworkServiceAddProtocolType() w/removed service\n service = %@\n protocol = %@", + service, + protocolType); + _SC_crash_once("SCNetworkServiceAddProtocolType() w/removed service", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service protocolType); // entity @@ -241,18 +414,39 @@ SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protoco &kCFTypeDictionaryValueCallBacks); ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity); CFRelease(newEntity); + newEntity = NULL; if (!ok) { goto done; } protocol = SCNetworkServiceCopyProtocol(service, protocolType); + assert(protocol != NULL); + newEntity = _protocolTemplate(service, protocolType); + assert(newEntity != NULL); + ok = SCNetworkProtocolSetConfiguration(protocol, newEntity); - CFRelease(newEntity); - CFRelease(protocol); + if (!ok) { + // could not set default configuration + goto done; + } + + newEnabled = !CFDictionaryContainsKey(newEntity, kSCResvInactive); + ok = SCNetworkProtocolSetEnabled(protocol, newEnabled); + if (!ok) { + // could not enable/disable protocol + goto done; + } done : + if (newEntity != NULL) CFRelease(newEntity); + if (protocol != NULL) CFRelease(protocol); + + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkServiceAddProtocolType(): %@, %@", service, protocolType); + } + CFRelease(path); return ok; } @@ -294,25 +488,26 @@ SCNetworkServiceCopyAll(SCPreferencesRef prefs) SCNetworkServicePrivateRef servicePrivate; if (!isA_CFDictionary(vals[i])) { - SCLog(TRUE, - LOG_INFO, - CFSTR("SCNetworkServiceCopyAll(): error w/service \"%@\"\n"), - keys[i]); + SC_log(LOG_INFO, "error w/service \"%@\"", keys[i]); continue; } entity = CFDictionaryGetValue(vals[i], kSCEntNetInterface); if (!isA_CFDictionary(entity)) { // if no "interface" - SCLog(TRUE, - LOG_INFO, - CFSTR("SCNetworkServiceCopyAll(): no \"%@\" entity for service \"%@\"\n"), - kSCEntNetInterface, - keys[i]); + SC_log(LOG_INFO, "no \"%@\" entity for service \"%@\"", + kSCEntNetInterface, + keys[i]); + continue; + } + + if (__SCNetworkInterfaceEntityIsPPTP(entity)) { + SC_log(LOG_INFO, "PPTP services are no longer supported"); continue; } servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, keys[i], NULL); + assert(servicePrivate != NULL); CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate); CFRelease(servicePrivate); } @@ -326,8 +521,55 @@ SCNetworkServiceCopyAll(SCPreferencesRef prefs) } +__private_extern__ +CFArrayRef /* of SCNetworkInterfaceRef's */ +__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) { + // Do not return an empty array + CFRelease(interfaces); + interfaces = NULL; + } + + done: + + if (services != NULL) { + CFRelease(services); + } + return interfaces; +} + + /* - * build a list of all of a servives entity types that are associated + * build a list of all of a services entity types that are associated * with the services interface. The list will include : * * - entity types associated with the interface type (Ethernet, FireWire, PPP, ...) @@ -347,13 +589,12 @@ _copyInterfaceEntityTypes(CFDictionaryRef protocols) CFStringRef entities[] = { kSCPropNetInterfaceType, kSCPropNetInterfaceSubType, kSCPropNetInterfaceHardware }; - int i; // include the "Interface" entity itself CFSetAddValue(interface_entity_types, kSCEntNetInterface); // include the entities associated with the interface - for (i = 0; i < sizeof(entities)/sizeof(entities[0]); i++) { + for (size_t i = 0; i < sizeof(entities)/sizeof(entities[0]); i++) { CFStringRef entity; entity = CFDictionaryGetValue(interface, entities[i]); @@ -398,11 +639,36 @@ SCNetworkServiceCopy(SCPreferencesRef prefs, CFStringRef serviceID) return NULL; } + if (__SCNetworkInterfaceEntityIsPPTP(entity)) { + SC_log(LOG_INFO, "PPTP services are no longer supported"); + _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) { @@ -412,7 +678,7 @@ SCNetworkServiceCopyProtocol(SCNetworkServiceRef service, CFStringRef protocolTy SCNetworkProtocolPrivateRef protocolPrivate = NULL; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; - if (!isA_SCNetworkService(service)) { + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } @@ -428,7 +694,7 @@ SCNetworkServiceCopyProtocol(SCNetworkServiceRef service, CFStringRef protocolTy protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); - if ((protocols != NULL) && !isA_CFDictionary(protocols)) { + if (!isA_CFDictionary(protocols)) { // if corrupt prefs _SCErrorSet(kSCStatusFailed); return NULL; @@ -467,7 +733,7 @@ SCNetworkServiceCopyProtocols(SCNetworkServiceRef service) CFDictionaryRef protocols; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; - if (!isA_SCNetworkService(service)) { + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } @@ -479,6 +745,8 @@ SCNetworkServiceCopyProtocols(SCNetworkServiceRef service) CFRelease(path); if (!isA_CFDictionary(protocols)) { + // if corrupt prefs + _SCErrorSet(kSCStatusFailed); return NULL; } @@ -550,16 +818,6 @@ __SCNetworkServiceSetInterfaceEntity(SCNetworkServiceRef service, } -static void -mergeDict(const void *key, const void *value, void *context) -{ - CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context; - - CFDictionarySetValue(newDict, key, value); - return; -} - - SCNetworkServiceRef SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) { @@ -587,10 +845,18 @@ SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) interface_type = SCNetworkInterfaceGetInterfaceType(interface); if (CFStringFind(interface_type, CFSTR("."), 0).location == kCFNotFound) { + _SCErrorSet(kSCStatusInvalidArgument); return NULL; } } + // do not allow creation of a network service if the interface is a + // member of a bond or bridge + if (__SCNetworkInterfaceIsMember(prefs, interface)) { + _SCErrorSet(kSCStatusKeyExists); + return NULL; + } + // establish the service prefix = SCPreferencesPathKeyCreateNetworkServices(NULL); path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix); @@ -636,59 +902,32 @@ SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) CFEqual(interfaceType, kSCNetworkInterfaceTypeModem ) || CFEqual(interfaceType, kSCNetworkInterfaceTypeSerial ) || CFEqual(interfaceType, kSCNetworkInterfaceTypeWWAN )) { - CFDictionaryRef overrides; - CFStringRef script; + CFDictionaryRef overrides; overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypeModem); // a ConnectionScript (and related keys) from the interface // should trump the settings from the configuration template. - if ((overrides != NULL) && - CFDictionaryContainsKey(overrides, kSCPropNetModemConnectionScript)) { - CFMutableDictionaryRef newConfig; - - newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); - CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionPersonality); - CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionScript); - CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceVendor); - CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceModel); - CFRelease(config); - config = newConfig; - } - - // update template for v.92 modems - if ((overrides == NULL) && - CFDictionaryGetValueIfPresent(config, - kSCPropNetModemConnectionScript, - (const void **)&script) && - CFEqual(script, CFSTR("v.34 Personality")) && - _SCNetworkInterfaceIsModemV92(interface)) { - CFMutableDictionaryRef newConfig; - - newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); - CFDictionarySetValue(newConfig, - kSCPropNetModemConnectionPersonality, - CFSTR("v.92 Personality")); - CFDictionarySetValue(newConfig, - kSCPropNetModemDeviceModel, - CFSTR("Apple Modem (v.92)")); - CFRelease(config); - config = newConfig; - } - - if (overrides != NULL) { + if (isA_CFDictionary(overrides)) { 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)) { + } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP) || + CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) { CFDictionaryRef overrides; overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypePPP); - if (overrides != NULL) { + if (isA_CFDictionary(overrides)) { CFMutableDictionaryRef newConfig; newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config); @@ -699,9 +938,8 @@ SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) } if (!__SCNetworkInterfaceSetConfiguration(interface, NULL, config, TRUE)) { - SCLog(TRUE, LOG_DEBUG, - CFSTR("SCNetworkService __SCNetworkInterfaceSetConfiguration failed(), interface=%@, type=NULL"), - interface); + SC_log(LOG_INFO, "__SCNetworkInterfaceSetConfiguration failed(), interface=%@, type=NULL", + interface); } CFRelease(config); } @@ -712,8 +950,8 @@ SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) servicePrivate->interface); // push the [deep] interface configuration into the service. - interface_config = __SCNetworkInterfaceCopyDeepConfiguration(servicePrivate->interface); - __SCNetworkInterfaceSetDeepConfiguration(servicePrivate->interface, interface_config); + interface_config = __SCNetworkInterfaceCopyDeepConfiguration(NULL, servicePrivate->interface); + __SCNetworkInterfaceSetDeepConfiguration(NULL, servicePrivate->interface, interface_config); if (interface_config != NULL) CFRelease(interface_config); // set the service name to match that of the associated interface @@ -733,6 +971,8 @@ SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) interface_name); } + SC_log(LOG_DEBUG, "SCNetworkServiceCreate(): %@", servicePrivate); + return (SCNetworkServiceRef)servicePrivate; } @@ -740,10 +980,18 @@ SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) Boolean SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service) { - CFIndex i; - SCNetworkInterfaceRef interface; - CFIndex n; - CFArrayRef protocolTypes; + CFIndex i; + SCNetworkInterfaceRef interface; + CFIndex n; + Boolean ok; + CFArrayRef protocolTypes; + CFStringRef rankStr; + SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; + + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } interface = SCNetworkServiceGetInterface(service); if (interface == NULL) { @@ -753,45 +1001,40 @@ SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service) 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; + CFStringRef protocolType; protocolType = CFArrayGetValueAtIndex(protocolTypes, i); ok = SCNetworkServiceAddProtocolType(service, protocolType); - if (!ok && (SCError() != kSCStatusKeyExists)) { - // could not add protocol - goto nextProtocol; + if (!ok) { + SC_log(LOG_INFO, + "SCNetworkServiceEstablishDefaultConfiguration(): could not add protocol \"%@\"", + protocolType); } + } - protocol = SCNetworkServiceCopyProtocol(service, protocolType); - if (protocol == NULL) { - // oops, somethings wrong (should never happen) - goto nextProtocol; - } + rankStr = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCPropNetServicePrimaryRank); + if (isA_CFString(rankStr)) { + SCNetworkServicePrimaryRank rank; - newEntity = _protocolTemplate(service, protocolType); - ok = SCNetworkProtocolSetConfiguration(protocol, newEntity); + ok = __str_to_rank(rankStr, &rank); if (!ok) { - // could not set default configuration - goto nextProtocol; + SC_log(LOG_INFO, + "SCNetworkServiceEstablishDefaultConfiguration(): unknown rank \"%@\"", + rankStr); + goto done; } - enabled = !CFDictionaryContainsKey(newEntity, kSCResvInactive); - ok = SCNetworkProtocolSetEnabled(protocol, enabled); + ok = SCNetworkServiceSetPrimaryRank(service, rank); if (!ok) { - // could not enable/disable protocol - goto nextProtocol; + SC_log(LOG_INFO, + "SCNetworkServiceEstablishDefaultConfiguration(): could not set rank \"%@\"", + rankStr); + goto done; } - - nextProtocol : - - if (newEntity != NULL) CFRelease(newEntity); - if (protocol != NULL) CFRelease(protocol); } + done : + return TRUE; } @@ -803,7 +1046,7 @@ SCNetworkServiceGetEnabled(SCNetworkServiceRef service) CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; - if (!isA_SCNetworkService(service)) { + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } @@ -823,7 +1066,7 @@ SCNetworkServiceGetInterface(SCNetworkServiceRef service) { SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; - if (!isA_SCNetworkService(service)) { + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } @@ -852,32 +1095,52 @@ SCNetworkServiceGetName(SCNetworkServiceRef service) { CFDictionaryRef entity; SCNetworkInterfaceRef interface; - SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; CFStringRef name = NULL; CFStringRef path; + SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; + Boolean useSystemInterfaces = TRUE; - if (!isA_SCNetworkService(service)) { + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } + if (servicePrivate->name != NULL) { + return servicePrivate->name; + } + path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); + useSystemInterfaces = ((__SCPreferencesUsingDefaultPrefs(servicePrivate->prefs)) && + !__SCPreferencesGetLimitSCNetworkConfiguration(servicePrivate->prefs)); + if (isA_CFDictionary(entity)) { name = CFDictionaryGetValue(entity, kSCPropUserDefinedName); - name = isA_CFString(name); + if (isA_CFString(name)) { + servicePrivate->name = CFRetain(name); + if (!useSystemInterfaces) { + 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) { + if ((childInterface == NULL) || + CFEqual(childInterface, kSCNetworkInterfaceIPv4)) { break; } @@ -885,23 +1148,97 @@ SCNetworkServiceGetName(SCNetworkServiceRef service) } if (interface != NULL) { - if (name != NULL) { - CFStringRef interface_name; + int i; + CFStringRef interface_name = NULL; + CFStringRef suffix = NULL; + + // + // check if the [stored] service name matches the non-localized interface + // name. If so, return the localized name. + // + // Also, the older "Built-in XXX" interface names are too long for the + // current UI. If we find that the [stored] service name matches the older + // name, return the newer (and shorter) localized name. + // + // Note: the user/admin will no longer be able to set the service name + // to "Built-in Ethernet". + // + for (i = 0; i < 3; i++) { + if (servicePrivate->name == NULL) { + // if no [stored] service name to compare + break; + } + + switch (i) { + case 0 : + // compare the non-localized interface name + interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface); + if (interface_name != NULL) { + CFRetain(interface_name); + } + break; +#if !TARGET_OS_IPHONE + case 1 : + // compare the older "Built-in XXX" localized name + interface_name = __SCNetworkInterfaceCopyXLocalizedDisplayName(interface); + break; + case 2 : + // compare the older "Built-in XXX" non-localized name + interface_name = __SCNetworkInterfaceCopyXNonLocalizedDisplayName(interface); + break; +#else // !TARGET_OS_IPHONE + default : + continue; +#endif // !TARGET_OS_IPHONE + } + + if (interface_name != NULL) { + Boolean match = FALSE; + + if (CFEqual(name, interface_name)) { + // if service name matches the OLD localized + // 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); - interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface); - if ((interface_name != NULL) && CFEqual(name, interface_name)) { - // if service name matches the [non-]localized - // interface name - name = NULL; + if (match) { + CFRelease(servicePrivate->name); + servicePrivate->name = NULL; + break; + } } } - if (name == NULL) { - name = SCNetworkInterfaceGetLocalizedDisplayName(interface); + // + // if the service name has not been set, use the localized interface name + // + 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 name; + return servicePrivate->name; } @@ -931,11 +1268,18 @@ Boolean SCNetworkServiceRemove(SCNetworkServiceRef service) { Boolean ok = FALSE; + CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; CFArrayRef sets; - CFStringRef path; - if (!isA_SCNetworkService(service)) { + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + if (!__SCNetworkServiceExists(service)) { + SC_log(LOG_ERR, "SCNetworkServiceRemove() w/removed service\n service = %@", service); + _SC_crash_once("SCNetworkServiceRemove() w/removed service", NULL, NULL); _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } @@ -944,11 +1288,10 @@ SCNetworkServiceRemove(SCNetworkServiceRef service) sets = SCNetworkSetCopyAll(servicePrivate->prefs); if (sets != NULL) { - CFIndex i; CFIndex n; n = CFArrayGetCount(sets); - for (i = 0; i < n; i++) { + for (CFIndex i = 0; i < n; i++) { SCNetworkSetRef set; set = CFArrayGetValueAtIndex(sets, i); @@ -969,6 +1312,10 @@ SCNetworkServiceRemove(SCNetworkServiceRef service) ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path); CFRelease(path); + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkServiceRemove(): %@", service); + } + return ok; } @@ -981,7 +1328,16 @@ SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef prot CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; - if (!isA_SCNetworkService(service)) { + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + if (!__SCNetworkServiceExists(service)) { + SC_log(LOG_ERR, "SCNetworkServiceRemoveProtocolType() w/removed service\n service = %@\n protocol = %@", + service, + protocolType); + _SC_crash_once("SCNetworkServiceRemoveProtocolType() w/removed service", NULL, NULL); _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } @@ -1006,6 +1362,10 @@ SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef prot done : + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkServiceRemoveProtocolType(): %@, %@", service, protocolType); + } + CFRelease(path); return ok; } @@ -1018,17 +1378,43 @@ SCNetworkServiceSetEnabled(SCNetworkServiceRef service, Boolean enabled) CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; - if (!isA_SCNetworkService(service)) { + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + if (!__SCNetworkServiceExists(service)) { + SC_log(LOG_ERR, "SCNetworkServiceSetEnabled() w/removed service\n service = %@", service); + _SC_crash_once("SCNetworkProtocolSetEnabled() w/removed service", NULL, NULL); _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } + // make sure that we do not enable a network service if the + // associated interface is a member of a bond or bridge. + if (enabled) { + SCNetworkInterfaceRef interface; + + interface = SCNetworkServiceGetInterface(service); + if ((interface != NULL) && + __SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) { + _SCErrorSet(kSCStatusKeyExists); + return FALSE; + } + } + path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity ok = __setPrefsEnabled(servicePrivate->prefs, path, enabled); CFRelease(path); + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkServiceSetEnabled(): %@ -> %s", + service, + enabled ? "Enabled" : "Disabled"); + } + return ok; } @@ -1039,18 +1425,31 @@ SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) CFDictionaryRef entity; Boolean ok = FALSE; CFStringRef path; + CFStringRef saveName = NULL; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; - if (!isA_SCNetworkService(service)) { + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } - if ((name != NULL) && !isA_CFString(name)) { + if (!__SCNetworkServiceExists(service)) { + SC_log(LOG_ERR, "SCNetworkServiceSetName() w/removed service\n service = %@\n name = %@", + service, + name != NULL ? name : CFSTR("")); + _SC_crash_once("SCNetworkServiceSetName() w/removed service", NULL, NULL); _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } + if (name != NULL) { + if (!isA_CFString(name)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + saveName = CFRetain(name); + } + if (name != NULL) { SCNetworkInterfaceRef interface; @@ -1070,12 +1469,36 @@ SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) CFStringRef interface_name; interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); - if ((interface_name != NULL) && CFEqual(name, interface_name)) { - // if service name matches the localized interface name - // then store the non-localized name. - interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface); - if (interface_name != NULL) { - name = interface_name; + if (interface_name != NULL) { + if (CFEqual(name, interface_name)) { + // if service name matches the localized interface name + // then store the non-localized 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); + + // if service name matches the localized interface name plus + // a few extra characters) then store the non-localized name with + // the same suffix. + 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); } } } @@ -1134,6 +1557,7 @@ SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) * the "name" is not unique. */ CFRelease(sets); + if (saveName != NULL) CFRelease(saveName); _SCErrorSet(kSCStatusKeyExists); return FALSE; } @@ -1148,20 +1572,20 @@ SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) servicePrivate->serviceID, // service NULL); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); - if ((entity == NULL) && (name != NULL)) { - entity = CFDictionaryCreate(NULL, - NULL, - NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - } - if (isA_CFDictionary(entity)) { + if (isA_CFDictionary(entity) || + ((entity == NULL) && (name != NULL))) { CFMutableDictionaryRef newEntity; - newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity); - if (name != NULL) { - CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name); + 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); } @@ -1169,6 +1593,964 @@ SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) CFRelease(newEntity); } CFRelease(path); + if (saveName != NULL) CFRelease(saveName); + + if (servicePrivate->name != NULL) CFRelease(servicePrivate->name); + if (name != NULL) CFRetain(name); + servicePrivate->name = name; + + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkServiceSetName(): %@", service); + } return ok; } + + +#pragma mark - +#pragma mark SCNetworkService SPIs + + +__private_extern__ +Boolean +__SCNetworkServiceExists(SCNetworkServiceRef service) +{ + CFDictionaryRef entity; + CFStringRef path; + SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; + + if (servicePrivate->prefs == NULL) { + // if no prefs + return FALSE; + } + + path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator + servicePrivate->serviceID, // service + kSCEntNetInterface); // entity + entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); + CFRelease(path); + + if (!isA_CFDictionary(entity)) { + // a "service" must have an "interface" + return FALSE; + } + + return TRUE; +} + + +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; + } + + if ((servicePrivate->prefs != NULL) && !__SCNetworkServiceExists(service)) { + SC_log(LOG_ERR, "SCNetworkServiceSetPrimaryRank() w/removed\n service = %@", service); + _SC_crash_once("SCNetworkServiceSetPrimaryRank() w/removed service", NULL, NULL); + _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)) { + // if corrupt prefs + _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)) { + // if corrupt prefs + 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; + } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated" + if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) { + return TRUE; + } +#pragma GCC diagnostic pop + } 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 servicePrivate = (SCNetworkServicePrivateRef)service; + Boolean success = FALSE; + CFStringRef prefixed_domain; + + if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL) || !isA_CFString(identifierDomain)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + if (!__SCNetworkServiceExists(service)) { + SC_log(LOG_ERR, "SCNetworkServiceSetExternalID() w/removed\n service = %@\n id = %@", + service, + identifier); + _SC_crash_once("SCNetworkServiceSetExternalID() w/removed service", NULL, NULL); + _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, + servicePrivate->serviceID, + NULL); + + service_dictionary = SCPreferencesPathGetValue(servicePrivate->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(servicePrivate->prefs, prefs_path, new_service_dictionary); + CFRelease(new_service_dictionary); + } + CFRelease(prefs_path); + + if (identifier != NULL) { + if (servicePrivate->externalIDs == NULL) { + servicePrivate->externalIDs = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(servicePrivate->externalIDs, prefixed_domain, identifier); + } else { + if (servicePrivate->externalIDs != NULL) { + CFDictionaryRemoveValue(servicePrivate->externalIDs, prefixed_domain); + } + } + + CFRelease(prefixed_domain); + + if (!success) { + _SCErrorSet(kSCStatusFailed); + } + + return success; +} + + +CFStringRef +SCNetworkServiceCopyExternalID(SCNetworkServiceRef service, CFStringRef identifierDomain) +{ + CFStringRef identifier = NULL; + CFStringRef prefixed_domain; + SCNetworkServicePrivateRef service_private = (SCNetworkServicePrivateRef)service; + + 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; + + // update service order + serviceOrder = SCNetworkSetGetServiceOrder(set); + if ((isA_CFArray(serviceOrder) != NULL) && + CFArrayContainsValue(serviceOrder, + CFRangeMake(0, CFArrayGetCount(serviceOrder)), + service_context->oldServiceID)) { + CFIndex count; + CFIndex serviceOrderIndex; + + // replacing all instances of old service ID with new one + 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); + } + + // check if service with old serviceID is part of the set + path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator + setPrivate->setID, // set + service_context->oldServiceID, // service + NULL); // entity + oldLink = SCPreferencesPathGetLink(setPrivate->prefs, path); + if (oldLink == NULL) { + // don't make any changes if service with old serviceID is not found + goto done; + } + + // remove link between "set" and old "service" + (void) SCPreferencesPathRemoveValue(setPrivate->prefs, path); + CFRelease(path); + + // create the link between "set" and the "service" + path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator + setPrivate->setID, // set + service_context->newServiceID, // service + NULL); // entity + link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator + service_context->newServiceID, // service + NULL); // entity + (void) 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)) { + // no work needs to be done if new service ID is equal to current service ID + return TRUE; + } + + if (!__SCNetworkServiceExists(service)) { + SC_log(LOG_ERR, "_SCNetworkServiceSetServiceID() w/removed service\n service = %@\n serviceID = %@", + service, + newServiceID); + _SC_crash_once("_SCNetworkServiceSetServiceID() w/removed service", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + newPath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator + newServiceID, // service + NULL); // entity + entity = SCPreferencesPathGetValue(servicePrivate->prefs, newPath); + if (isA_CFDictionary(entity)) { + // if the new service already exists + _SCErrorSet(kSCStatusKeyExists); + goto done; + } + + oldPath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator + servicePrivate->serviceID, // service + NULL); // entity + entity = SCPreferencesPathGetValue(servicePrivate->prefs, oldPath); + if (!isA_CFDictionary(entity)) { + // if the service has already been removed + _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; + + // find all sets w/oldServiceID and update + // ... and update the serviceOrder + CFArrayApplyFunction(allSets, + CFRangeMake(0, CFArrayGetCount(allSets)), + replaceServiceID, + &service_context); + + if (servicePrivate->interface != NULL) { + SCNetworkInterfaceRef newInterface; + + // duplicate the interface and associate the copy with the new service ID + newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, + servicePrivate->interface, + servicePrivate->prefs, + newServiceID); + CFRelease(servicePrivate->interface); + servicePrivate->interface = newInterface; + } + + SC_log(LOG_DEBUG, "_SCNetworkServiceSetServiceID(): %@ --> %@", service, newServiceID); + + // replace serviceID with new one + 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) { + // oops ... interface layering does not match + return; + } + + // copy interface configuration + configuration = SCNetworkInterfaceGetConfiguration(oldInterface); + + if ((configuration != NULL) || + (SCError() == kSCStatusOK)) { + if (!SCNetworkInterfaceSetConfiguration(newInterface, configuration)) { + SC_log(LOG_INFO, "problem setting interface configuration"); + } + + } + + // special case: PPP/L2TP + IPSec + 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)) { + SC_log(LOG_INFO, "problem setting child interface configuration"); + } + } + } + } + } + + // special case: 802.1x + configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetEAPOL); + if ((configuration != NULL) || + (SCError() == kSCStatusOK)) { + (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetEAPOL, configuration); + } + + // special case: Managed Client + configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kVPNProtocolPayloadInfo); + if ((configuration != NULL) || + (SCError() == kSCStatusOK)) { + (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kVPNProtocolPayloadInfo, configuration); + } + + // special case: Network Pref + configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCValNetPPPAuthProtocolEAP); + if ((configuration != NULL) || + (SCError() == kSCStatusOK)) { + (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCValNetPPPAuthProtocolEAP, configuration); + } + + // special case: Remote Pref + configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetLoginWindowEAPOL); + if ((configuration != NULL) || + (SCError() == kSCStatusOK)) { + (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetLoginWindowEAPOL, configuration); + } + + // special case: Network Extension + 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; + 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) { + // Cannot add service if it already exists + 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) { + // update mapping + 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); + } + // Supporting PPPoE subtype + 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); + if (!SCNetworkServiceSetEnabled(newService, enabled)) { + SCNetworkServiceRemove(newService); + SC_log(LOG_INFO, "SCNetworkServiceSetEnabled() failed"); + goto done; + } + + if (!SCNetworkServiceEstablishDefaultConfiguration(newService)) { + SCNetworkServiceRemove(newService); + SC_log(LOG_INFO, "SCNetworkServiceEstablishDefaultConfiguration() failed"); + goto done; + } + + // Set service ID + _SCNetworkServiceSetServiceID(newService, serviceID); + + userDefinedName = SCNetworkServiceGetName(service); + if ((userDefinedName != NULL) && + !SCNetworkServiceSetName(newService, userDefinedName)) { + SC_log(LOG_INFO, "SCNetworkServiceSetName(, %@) failed", userDefinedName); + } + + // Determine which sets to add service + 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)) { + SC_log(LOG_INFO, "SCNetworkSetAddService() failed"); + } + } + } + } + + 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 (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) { + SC_log(LOG_INFO, "SCNetworkServiceSetName() failed: %s", SCErrorString(SCError())); + SCNetworkServiceRemove(service); + goto done; + } + + ok = SCNetworkServiceEstablishDefaultConfiguration(service); + if (!ok) { + 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) { + 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; +} + +__private_extern__ Boolean +__SCNetworkServiceIsPPTP(SCNetworkServiceRef service) +{ + CFStringRef intfSubtype; + SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; + + if (servicePrivate == NULL || servicePrivate->interface == NULL) { + return FALSE; + } + + intfSubtype = __SCNetworkInterfaceGetEntitySubType(servicePrivate->interface); + if (intfSubtype == NULL) { + return FALSE; + } + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated" + if (CFEqual(intfSubtype, kSCValNetInterfaceSubTypePPTP)) { + return TRUE; + } +#pragma GCC diagnostic pop + + return FALSE; +}