X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/a40a14f8bcc57d8bed0203ddee43e8d64db39796..d94708881e41bd90afd74b1a1dd0524d039ba3f7:/SystemConfiguration.fproj/SCNetworkService.c diff --git a/SystemConfiguration.fproj/SCNetworkService.c b/SystemConfiguration.fproj/SCNetworkService.c index d01acc0..d9c8d4b 100644 --- a/SystemConfiguration.fproj/SCNetworkService.c +++ b/SystemConfiguration.fproj/SCNetworkService.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2004-2009 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); @@ -69,10 +68,11 @@ __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); if (servicePrivate->prefs != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), servicePrivate->prefs); @@ -82,6 +82,9 @@ __SCNetworkServiceCopyDescription(CFTypeRef cf) 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; @@ -100,6 +103,7 @@ __SCNetworkServiceDeallocate(CFTypeRef cf) 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; } @@ -163,15 +167,51 @@ __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator, return NULL; } + /* initialize non-zero/NULL members */ 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 @@ -179,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; } @@ -216,10 +369,11 @@ 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) || (servicePrivate->prefs == NULL)) { @@ -232,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 @@ -251,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; } @@ -304,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); } @@ -336,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, ...) @@ -357,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]); @@ -408,6 +639,12 @@ 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; } @@ -424,6 +661,7 @@ _SCNetworkServiceCopyActive(SCDynamicStoreRef store, CFStringRef serviceID) } servicePrivate = __SCNetworkServiceCreatePrivate(NULL, NULL, serviceID, NULL); + assert(servicePrivate != NULL); if (store != NULL) { servicePrivate->store = CFRetain(store); } @@ -580,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) { @@ -617,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); @@ -666,38 +902,32 @@ SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) CFEqual(interfaceType, kSCNetworkInterfaceTypeModem ) || CFEqual(interfaceType, kSCNetworkInterfaceTypeSerial ) || CFEqual(interfaceType, kSCNetworkInterfaceTypeWWAN )) { - CFDictionaryRef overrides; + 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; - } - - 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); @@ -708,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); } @@ -742,6 +971,8 @@ SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) interface_name); } + SC_log(LOG_DEBUG, "SCNetworkServiceCreate(): %@", servicePrivate); + return (SCNetworkServiceRef)servicePrivate; } @@ -752,7 +983,9 @@ SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service) CFIndex i; SCNetworkInterfaceRef interface; CFIndex n; + Boolean ok; CFArrayRef protocolTypes; + CFStringRef rankStr; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { @@ -768,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; } @@ -870,6 +1098,7 @@ SCNetworkServiceGetName(SCNetworkServiceRef service) CFStringRef name = NULL; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; + Boolean useSystemInterfaces = TRUE; if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); @@ -886,19 +1115,32 @@ SCNetworkServiceGetName(SCNetworkServiceRef service) entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); + useSystemInterfaces = ((__SCPreferencesUsingDefaultPrefs(servicePrivate->prefs)) && + !__SCPreferencesGetLimitSCNetworkConfiguration(servicePrivate->prefs)); + if (isA_CFDictionary(entity)) { name = CFDictionaryGetValue(entity, kSCPropUserDefinedName); 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) || CFEqual(childInterface, kSCNetworkInterfaceIPv4)) { + if ((childInterface == NULL) || + CFEqual(childInterface, kSCNetworkInterfaceIPv4)) { break; } @@ -935,6 +1177,7 @@ SCNetworkServiceGetName(SCNetworkServiceRef service) CFRetain(interface_name); } break; +#if !TARGET_OS_IPHONE case 1 : // compare the older "Built-in XXX" localized name interface_name = __SCNetworkInterfaceCopyXLocalizedDisplayName(interface); @@ -943,11 +1186,15 @@ SCNetworkServiceGetName(SCNetworkServiceRef service) // 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 @@ -1030,15 +1277,21 @@ SCNetworkServiceRemove(SCNetworkServiceRef service) 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; + } + // remove service from all sets 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); @@ -1059,6 +1312,10 @@ SCNetworkServiceRemove(SCNetworkServiceRef service) ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path); CFRelease(path); + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkServiceRemove(): %@", service); + } + return ok; } @@ -1076,6 +1333,15 @@ SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef prot 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; + } + if (!__SCNetworkProtocolIsValidType(protocolType)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; @@ -1096,6 +1362,10 @@ SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef prot done : + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkServiceRemoveProtocolType(): %@, %@", service, protocolType); + } + CFRelease(path); return ok; } @@ -1113,12 +1383,38 @@ SCNetworkServiceSetEnabled(SCNetworkServiceRef service, Boolean enabled) 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; } @@ -1137,6 +1433,15 @@ SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) return FALSE; } + 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); @@ -1294,6 +1599,10 @@ SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) if (name != NULL) CFRetain(name); servicePrivate->name = name; + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkServiceSetName(): %@", service); + } + return ok; } @@ -1302,22 +1611,27 @@ SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) #pragma mark SCNetworkService SPIs -static Boolean -str_to_rank(CFStringRef rankStr, SCNetworkServicePrimaryRank *rank) +__private_extern__ +Boolean +__SCNetworkServiceExists(SCNetworkServiceRef service) { - if (isA_CFString(rankStr)) { - if (CFEqual(rankStr, kSCValNetServicePrimaryRankFirst)) { - *rank = kSCNetworkServicePrimaryRankFirst; - } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankLast)) { - *rank = kSCNetworkServicePrimaryRankLast; - } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankNever)) { - *rank = kSCNetworkServicePrimaryRankNever; - } else { - return FALSE; - } - } else if (rankStr == NULL) { - *rank = kSCNetworkServicePrimaryRankDefault; - } else { + 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; } @@ -1348,7 +1662,7 @@ SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service) CFRelease(path); if (isA_CFDictionary(entity)) { rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank); - ok = str_to_rank(rankStr, &rank); + ok = __str_to_rank(rankStr, &rank); } } else if (servicePrivate->store != NULL) { path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, @@ -1360,7 +1674,7 @@ SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service) if (entity != NULL) { if (isA_CFDictionary(entity)) { rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank); - ok = str_to_rank(rankStr, &rank); + ok = __str_to_rank(rankStr, &rank); } CFRelease(entity); } @@ -1380,30 +1694,6 @@ SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service) } -static Boolean -rank_to_str(SCNetworkServicePrimaryRank rank, CFStringRef *rankStr) -{ - switch (rank) { - case kSCNetworkServicePrimaryRankDefault : - *rankStr = NULL; - break; - case kSCNetworkServicePrimaryRankFirst : - *rankStr = kSCValNetServicePrimaryRankFirst; - break; - case kSCNetworkServicePrimaryRankLast : - *rankStr = kSCValNetServicePrimaryRankLast; - break; - case kSCNetworkServicePrimaryRankNever : - *rankStr = kSCValNetServicePrimaryRankNever; - break; - default : - return FALSE; - } - - return TRUE; -} - - Boolean SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service, SCNetworkServicePrimaryRank newRank) @@ -1420,14 +1710,24 @@ SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service, return FALSE; } - ok = rank_to_str(newRank, &rankStr); + 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) { - if ((newRank == kSCNetworkServicePrimaryRankDefault) || (newRank == kSCNetworkServicePrimaryRankNever)) { + switch (newRank) { + case kSCNetworkServicePrimaryRankDefault: + case kSCNetworkServicePrimaryRankNever: + case kSCNetworkServicePrimaryRankScoped: path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, servicePrivate->serviceID, NULL); @@ -1459,7 +1759,8 @@ SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service, if (!ok) { goto done; } - } else { + break; + default: _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } @@ -1508,3 +1809,748 @@ SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service, 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; +}