X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/17d3ee29fb04fcc79d3be0b9d5c7bcb377cfc610..d94708881e41bd90afd74b1a1dd0524d039ba3f7:/SystemConfiguration.fproj/SCNetworkSet.c diff --git a/SystemConfiguration.fproj/SCNetworkSet.c b/SystemConfiguration.fproj/SCNetworkSet.c index 126300f..bfcf499 100644 --- a/SystemConfiguration.fproj/SCNetworkSet.c +++ b/SystemConfiguration.fproj/SCNetworkSet.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2004-2007, 2009-2011 Apple Inc. All rights reserved. + * Copyright (c) 2004-2019 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,10 +31,7 @@ #include #include -#include #include "SCNetworkConfigurationInternal.h" -#include -#include #include @@ -69,15 +66,19 @@ __SCNetworkSetCopyDescription(CFTypeRef cf) { CFAllocatorRef allocator = CFGetAllocator(cf); CFMutableStringRef result; - SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf; + SCNetworkSetRef set = (SCNetworkSetRef)cf; + SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; result = CFStringCreateMutable(allocator, 0); - CFStringAppendFormat(result, NULL, CFSTR(" {"), cf, allocator); + CFStringAppendFormat(result, NULL, CFSTR(" {"), set, allocator); CFStringAppendFormat(result, NULL, CFSTR("id = %@"), setPrivate->setID); CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), setPrivate->prefs); if (setPrivate->name != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), setPrivate->name); } + if (!__SCNetworkSetExists(set)) { + CFStringAppendFormat(result, NULL, CFSTR(", REMOVED")); + } CFStringAppendFormat(result, NULL, CFSTR("}")); return result; @@ -157,10 +158,9 @@ __SCNetworkSetCreatePrivate(CFAllocatorRef allocator, return NULL; } + /* initialize non-zero/NULL members */ setPrivate->setID = CFStringCreateCopy(NULL, setID); setPrivate->prefs = CFRetain(prefs); - setPrivate->name = NULL; - setPrivate->established = FALSE; // "new" (not yet established) set return setPrivate; } @@ -183,15 +183,42 @@ _serviceOrder(SCNetworkServiceRef service) } +static CFIndex +_serviceOrder_clear(CFMutableArrayRef order, CFStringRef serviceID) +{ + CFIndex f; // # of serviceID's found + CFIndex i; + CFIndex n; + + f = 0; + i = 0; + n = CFArrayGetCount(order); + while (i < n) { + CFStringRef thisServiceID = CFArrayGetValueAtIndex(order, i); + + if (CFEqual(thisServiceID, serviceID)) { + // remove the serviceID + CFArrayRemoveValueAtIndex(order, i); + n--; + f++; + continue; + } + + i++; // move to the next serviceID + } + + return f; +} + + static void _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service) { - CFIndex i; CFIndex n; CFMutableArrayRef newOrder; CFArrayRef order; - CFStringRef serviceID; - CFIndex serviceOrder; + CFStringRef serviceID = SCNetworkServiceGetServiceID(service); + CFIndex serviceOrder = _serviceOrder(service); SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; CFIndex slot; @@ -201,18 +228,19 @@ _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service) } else { newOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } - n = CFArrayGetCount(newOrder); + assert(newOrder != NULL); - serviceID = SCNetworkServiceGetServiceID(service); - if (CFArrayContainsValue(newOrder, CFRangeMake(0, n), serviceID)) { - // if serviceID already present - goto done; + n = _serviceOrder_clear(newOrder, serviceID); + if (n > 0) { + SC_log(LOG_ERR, "SCNetworkSetAddService() w/service already in ServiceOrder\n service = %@\n matched = %ld", + service, + n); + _SC_crash_once("SCNetworkSetAddService() w/service already in ServiceOrder", NULL, NULL); } - serviceOrder = _serviceOrder(service); - slot = 0; - for (i = 0; i < n; i++) { + n = CFArrayGetCount(newOrder); + for (CFIndex i = 0; i < n; i++) { int slotOrder; SCNetworkServiceRef slotService; CFStringRef slotServiceID; @@ -240,9 +268,6 @@ _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service) CFArrayInsertValueAtIndex(newOrder, slot, serviceID); (void) SCNetworkSetSetServiceOrder(set, newOrder); - - done : - CFRelease(newOrder); return; @@ -252,6 +277,7 @@ _serviceOrder_add(SCNetworkSetRef set, SCNetworkServiceRef service) static void _serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service) { + CFIndex n; CFMutableArrayRef newOrder; CFArrayRef order; CFStringRef serviceID; @@ -260,22 +286,17 @@ _serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service) if (order == NULL) { return; } - - serviceID = SCNetworkServiceGetServiceID(service); - newOrder = CFArrayCreateMutableCopy(NULL, 0, order); - while (TRUE) { - CFIndex i; - i = CFArrayGetFirstIndexOfValue(newOrder, - CFRangeMake(0, CFArrayGetCount(newOrder)), - serviceID); - if (i == kCFNotFound) { - break; - } + serviceID = SCNetworkServiceGetServiceID(service); - CFArrayRemoveValueAtIndex(newOrder, i); + n = _serviceOrder_clear(newOrder, serviceID); + if (n > 1) { + SC_log(LOG_ERR, "SCNetworkSetRemoveService() w/multiple instances of service in ServiceOrder\n service = %@\n count = %ld", + service, + n); } + (void) SCNetworkSetSetServiceOrder(set, newOrder); CFRelease(newOrder); @@ -287,9 +308,159 @@ _serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service) #pragma mark SCNetworkSet APIs +#define DEFAULT_SET_NAME CFSTR("Automatic") #define N_QUICK 16 +static CFStringRef +copy_default_set_name(Boolean loc) +{ + CFStringRef name; + static CFStringRef non_localized = NULL; + static CFStringRef localized = NULL; + + if (!loc) { + static dispatch_once_t once; + + dispatch_once(&once, ^{ + CFBundleRef bundle; + + bundle = _SC_CFBundleGet(); + if (bundle != NULL) { + non_localized = _SC_CFBundleCopyNonLocalizedString(bundle, + CFSTR("DEFAULT_SET_NAME"), + DEFAULT_SET_NAME, + NULL); + } + }); + name = non_localized; + } else { + static dispatch_once_t once; + + dispatch_once(&once, ^{ + CFBundleRef bundle; + + bundle = _SC_CFBundleGet(); + if (bundle != NULL) { + localized = CFBundleCopyLocalizedString(bundle, + CFSTR("DEFAULT_SET_NAME"), + DEFAULT_SET_NAME, + NULL); + } + }); + name = localized; + } + + if (name == NULL) { + // if bundle or localized names not available + name = DEFAULT_SET_NAME; + } + + CFRetain(name); + return name; +} + + +#define PREVENT_DUPLICATE_SERVICE_NAMES +#ifdef PREVENT_DUPLICATE_SERVICE_NAMES +static CFStringRef +copy_next_name(CFStringRef name) +{ + CFArrayRef components; + CFIndex n; + CFMutableArrayRef newComponents; + SInt32 suffix = 2; + + if (name == NULL) { + return NULL; + } + + components = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR(" ")); + if (components != NULL) { + newComponents = CFArrayCreateMutableCopy(NULL, 0, components); + CFRelease(components); + } else { + newComponents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(newComponents, name); + } + + n = CFArrayGetCount(newComponents); + if (n > 1) { + CFStringRef str; + + str = CFArrayGetValueAtIndex(newComponents, n - 1); + suffix = CFStringGetIntValue(str); + if (suffix++ > 0) { + CFArrayRemoveValueAtIndex(newComponents, n - 1); + } else { + suffix = 2; + } + } + + name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), (int)suffix); + CFArrayAppendValue(newComponents, name); + CFRelease(name); + + name = CFStringCreateByCombiningStrings(NULL, newComponents, CFSTR(" ")); + CFRelease(newComponents); + + return name; +} + + +static Boolean +ensure_unique_service_name(SCNetworkServiceRef service) +{ + SCNetworkInterfaceRef interface; + CFStringRef name; + Boolean ok = TRUE; + + interface = SCNetworkServiceGetInterface(service); + + name = SCNetworkServiceGetName(service); + if (name != NULL) { + CFRetain(name); + } + + while (TRUE) { + CFStringRef newName; + + ok = SCNetworkServiceSetName(service, name); + if (ok) { + break; + } + + if (SCError() != kSCStatusKeyExists) { + SC_log(LOG_INFO, "could not update service name for \"%@\": %s", + SCNetworkInterfaceGetLocalizedDisplayName(interface), + SCErrorString(SCError())); + break; + } + + newName = copy_next_name(name); + if (newName == NULL) { + SC_log(LOG_INFO, "could not create unique name for \"%@\": %s", + SCNetworkInterfaceGetLocalizedDisplayName(interface), + SCErrorString(SCError())); + break; + } + + // try again with the "new" name + if (name != NULL) { + CFRelease(name); + } + name = newName; + } + + if (name != NULL) { + CFRelease(name); + } + + return ok; +} +#endif // PREVENT_DUPLICATE_SERVICE_NAMES + + Boolean SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service) { @@ -311,6 +482,23 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service) return FALSE; } + if (!__SCNetworkSetExists(set)) { + SC_log(LOG_ERR, "SCNetworkSetAddService() w/removed set\n set = %@\n service = %@", + set, + service); + _SC_crash_once("SCNetworkSetAddService() w/removed set", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + } + + if (!__SCNetworkServiceExists(service)) { + SC_log(LOG_ERR, "SCNetworkSetAddService() w/removed service\n set = %@\n service = %@", + set, + service); + _SC_crash_once("SCNetworkSetAddService() w/removed service", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + // make sure that we do not add an orphaned network service if its // associated interface is a member of a bond or bridge. interface = SCNetworkServiceGetInterface(service); @@ -320,42 +508,6 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service) return FALSE; } -#define PREVENT_DUPLICATE_SERVICE_NAMES -#ifdef PREVENT_DUPLICATE_SERVICE_NAMES - CFStringRef name; - - name = SCNetworkServiceGetName(service); - if (name != NULL) { - CFArrayRef services; - - services = SCNetworkSetCopyServices(set); - if (services != NULL) { - CFIndex i; - CFIndex n; - - n = CFArrayGetCount(services); - for (i = 0; i < n; i++) { - CFStringRef otherName; - SCNetworkServiceRef otherService; - - otherService = CFArrayGetValueAtIndex(services, i); - otherName = SCNetworkServiceGetName(otherService); - if ((otherName != NULL) && CFEqual(name, otherName)) { - /* - * if a service with the same "name" is - * already a member of the set. - */ - CFRelease(services); - _SCErrorSet(kSCStatusKeyExists); - return FALSE; - } - } - - CFRelease(services); - } - } -#endif // PREVENT_DUPLICATE_SERVICE_NAMES - //#define PREVENT_DUPLICATE_SETS #ifdef PREVENT_DUPLICATE_SETS CFArrayRef sets; @@ -404,6 +556,21 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service) servicePrivate->serviceID, // service NULL); // entity ok = SCPreferencesPathSetLink(setPrivate->prefs, path, link); +#ifdef PREVENT_DUPLICATE_SERVICE_NAMES + if (ok) { + // We use the interface cache here to not reach into the + // IORegistry for every service we go through + _SCNetworkInterfaceCacheOpen(); + ok = ensure_unique_service_name(service); + _SCNetworkInterfaceCacheClose(); + + if (!ok) { + // if we could not ensure a unique name, remove the (just added) + // link between the "set" and the "service" + (void) SCPreferencesPathRemoveValue(setPrivate->prefs, path); + } + } +#endif // PREVENT_DUPLICATE_SERVICE_NAMES CFRelease(path); CFRelease(link); if (!ok) { @@ -423,6 +590,10 @@ SCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service) done : + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkSetAddService(): %@, %@", set, service); + } + if (interface_config != NULL) CFRelease(interface_config); return ok; } @@ -450,6 +621,7 @@ SCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID) } setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID); + assert(setPrivate != NULL); // mark set as "old" (already established) setPrivate->established = TRUE; @@ -509,14 +681,12 @@ SCNetworkSetCopyAll(SCPreferencesRef prefs) SCNetworkSetPrivateRef setPrivate; if (!isA_CFDictionary(vals[i])) { - SCLog(TRUE, - LOG_INFO, - CFSTR("SCNetworkSetCopyAll(): error w/set \"%@\"\n"), - keys[i]); + SC_log(LOG_INFO, "error w/set \"%@\"", keys[i]); continue; } setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, keys[i]); + assert(setPrivate != NULL); // mark set as "old" (already established) setPrivate->established = TRUE; @@ -534,6 +704,80 @@ SCNetworkSetCopyAll(SCPreferencesRef prefs) } +CFArrayRef /* of SCNetworkInterfaceRef's */ +SCNetworkSetCopyAvailableInterfaces(SCNetworkSetRef set) +{ + CFMutableArrayRef available; + CFMutableSetRef excluded = NULL; + int i; + CFArrayRef interfaces; + CFIndex n_interfaces; + CFIndex n_exclusions = 0; + SCPreferencesRef prefs; + SCNetworkSetPrivateRef setPrivate; + + setPrivate = (SCNetworkSetPrivateRef)set; + prefs = setPrivate->prefs; + + interfaces = _SCNetworkInterfaceCopyAllWithPreferences(prefs); + n_interfaces = CFArrayGetCount(interfaces); + if (n_interfaces == 0) { + return interfaces; + } + + if (prefs != NULL) { + CFArrayRef bridges = NULL; + + excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + +#if !TARGET_OS_IPHONE + CFArrayRef bonds = NULL; + + bonds = SCBondInterfaceCopyAll(prefs); + if (bonds != NULL) { + __SCBondInterfaceListCollectMembers(bonds, excluded); + CFRelease(bonds); + } +#endif /* !TARGET_OS_IPHONE */ + + bridges = SCBridgeInterfaceCopyAll(prefs); + if (bridges != NULL) { + __SCBridgeInterfaceListCollectMembers(bridges, excluded); + CFRelease(bridges); + } + + n_exclusions = CFSetGetCount(excluded); + } + + if (n_exclusions == 0) { + if (excluded != NULL) { + CFRelease(excluded); + } + + return interfaces; + } + + available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + for (i = 0; i < n_interfaces; i++) { + SCNetworkInterfaceRef interface; + + interface = CFArrayGetValueAtIndex(interfaces, i); + if (CFSetContainsValue(excluded, interface)) { + // if excluded + continue; + } + + CFArrayAppendValue(available, interface); + } + + CFRelease(interfaces); + CFRelease(excluded); + + return available; +} + + SCNetworkSetRef SCNetworkSetCopyCurrent(SCPreferencesRef prefs) { @@ -555,11 +799,12 @@ SCNetworkSetCopyCurrent(SCPreferencesRef prefs) path = SCPreferencesPathKeyCreateSet(NULL, setID); if (CFEqual(path, currentID)) { setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID); + assert(setPrivate != NULL); // mark set as "old" (already established) setPrivate->established = TRUE; } else { - SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkSetCopyCurrent(): preferences are non-conformant")); + SC_log(LOG_NOTICE, "SCNetworkSetCopyCurrent(): preferences are non-conformant"); } CFRelease(path); } @@ -613,11 +858,9 @@ SCNetworkSetCopyServices(SCNetworkSetRef set) link = SCPreferencesPathGetLink(setPrivate->prefs, path); CFRelease(path); if (link == NULL) { - SCLog(TRUE, - LOG_INFO, - CFSTR("SCNetworkSetCopyServices(): service \"%@\" for set \"%@\" is not a link\n"), - keys[i], - setPrivate->setID); + SC_log(LOG_INFO, "service \"%@\" for set \"%@\" is not a link", + keys[i], + setPrivate->setID); continue; // if the service is not a link } @@ -630,14 +873,31 @@ SCNetworkSetCopyServices(SCNetworkSetRef set) serviceID, // service NULL); // entity if (CFEqual(path, link)) { - SCNetworkServicePrivateRef servicePrivate; - - servicePrivate = __SCNetworkServiceCreatePrivate(NULL, - setPrivate->prefs, - serviceID, - NULL); - CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate); - CFRelease(servicePrivate); + CFDictionaryRef entity; + CFStringRef interfacePath; + Boolean skip = FALSE; + + interfacePath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator + serviceID, // service + kSCEntNetInterface); // entity + entity = SCPreferencesPathGetValue(setPrivate->prefs, interfacePath); + CFRelease(interfacePath); + + if (__SCNetworkInterfaceEntityIsPPTP(entity)) { + SC_log(LOG_INFO, "PPTP services are no longer supported"); + skip = TRUE; + } + + if (!skip) { + SCNetworkServicePrivateRef servicePrivate; + + servicePrivate = __SCNetworkServiceCreatePrivate(NULL, + setPrivate->prefs, + serviceID, + NULL); + CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate); + CFRelease(servicePrivate); + } } CFRelease(path); } @@ -674,6 +934,7 @@ SCNetworkSetCreate(SCPreferencesRef prefs) components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/")); setID = CFArrayGetValueAtIndex(components, 2); setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID); + assert(setPrivate != NULL); CFRelease(components); // mark set as "new" (not yet established) @@ -692,10 +953,73 @@ SCNetworkSetCreate(SCPreferencesRef prefs) setPrivate = NULL; } + if (setPrivate != NULL) { + SC_log(LOG_DEBUG, "SCNetworkSetCreate(): %@", setPrivate); + } + return (SCNetworkSetRef)setPrivate; } +SCNetworkSetRef +_SCNetworkSetCreateDefault(SCPreferencesRef prefs) +{ + CFStringRef model; + Boolean ok = TRUE; + SCNetworkSetRef set; + CFStringRef setName = NULL; + + set = SCNetworkSetCopyCurrent(prefs); + if (set != NULL) { + SC_log(LOG_NOTICE, "creating default set w/already existing set"); + CFRelease(set); + _SCErrorSet(kSCStatusKeyExists); + return NULL; + } + + // create a new ("Automatic") set + set = SCNetworkSetCreate(prefs); + if (set == NULL) { + SC_log(LOG_NOTICE, "could not create \"new\" set: %s", + SCErrorString(SCError())); + goto done; + } + + setName = copy_default_set_name(TRUE); + ok = SCNetworkSetSetName(set, setName); + CFRelease(setName); + if (!ok) { + // if we could not save the new set's "name" + SC_log(LOG_NOTICE, "could not save the new set's name: %s", + SCErrorString(SCError())); + goto done; + } + + ok = SCNetworkSetSetCurrent(set); + if (!ok) { + // if we could not make this the "current" set + SC_log(LOG_NOTICE, "could not establish new set as current: %s", + SCErrorString(SCError())); +// goto done; + } + + model = SCPreferencesGetValue(prefs, MODEL); + if (model == NULL) { + model = _SC_hw_model(FALSE); + SCPreferencesSetValue(prefs, MODEL, model); + } + + done : + + if (!ok && (set != NULL)) { + SCNetworkSetRemove(set); + CFRelease(set); + set = NULL; + } + return set; +} + + CFStringRef SCNetworkSetGetSetID(SCNetworkSetRef set) { @@ -713,7 +1037,6 @@ SCNetworkSetGetSetID(SCNetworkSetRef set) CFStringRef SCNetworkSetGetName(SCNetworkSetRef set) { - CFBundleRef bundle; CFDictionaryRef entity; CFStringRef path; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; @@ -740,33 +1063,20 @@ SCNetworkSetGetName(SCNetworkSetRef set) } } - bundle = _SC_CFBundleGet(); - if (bundle != NULL) { - if (setPrivate->name != NULL) { - CFStringRef non_localized; - - non_localized = _SC_CFBundleCopyNonLocalizedString(bundle, - CFSTR("DEFAULT_SET_NAME"), - CFSTR("Automatic"), - NULL); - if (non_localized != NULL) { - if (CFEqual(setPrivate->name, non_localized)) { - CFStringRef localized; - - // if "Automatic", return localized name - localized = CFBundleCopyLocalizedString(bundle, - CFSTR("DEFAULT_SET_NAME"), - CFSTR("Automatic"), - NULL); - if (localized != NULL) { - CFRelease(setPrivate->name); - setPrivate->name = localized; - } - } + if (setPrivate->name != NULL) { + CFStringRef non_localized; - CFRelease(non_localized); - } + non_localized = copy_default_set_name(FALSE); + if (CFEqual(setPrivate->name, non_localized)) { + CFStringRef localized; + + // if "Automatic", return localized name + localized = copy_default_set_name(TRUE); + CFRelease(setPrivate->name); + setPrivate->name = localized; } + + CFRelease(non_localized); } return setPrivate->name; @@ -812,6 +1122,24 @@ SCNetworkSetGetTypeID(void) } +#if TARGET_OS_IPHONE +static Boolean +isDefaultSet(SCNetworkSetRef set) +{ + CFStringRef defaultName; + Boolean isDefault = FALSE; + CFStringRef setName; + + defaultName = copy_default_set_name(TRUE); + setName = SCNetworkSetGetName(set); + isDefault = _SC_CFEqual(setName, defaultName); + CFRelease(defaultName); + + return isDefault; +} +#endif // TARGET_OS_IPHONE + + Boolean SCNetworkSetRemove(SCNetworkSetRef set) { @@ -825,15 +1153,35 @@ SCNetworkSetRemove(SCNetworkSetRef set) return FALSE; } + if (!__SCNetworkSetExists(set)) { + SC_log(LOG_ERR, "SCNetworkSetRemove() w/removed set\n set = %@", set); + _SC_crash_once("SCNetworkSetRemove() w/removed set", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + } + +#if TARGET_OS_IPHONE + if (isDefaultSet(set) && (geteuid() != 0)) { + SC_log(LOG_ERR, "SCNetworkSetRemove() failed, cannot remove set : %@", set); + _SC_crash("The \"Automatic\" network set cannot be removed", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } +#endif // TARGET_OS_IPHONE + currentPath = SCPreferencesGetValue(setPrivate->prefs, kSCPrefCurrentSet); path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); if (!isA_CFString(currentPath) || !CFEqual(currentPath, path)) { ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path); } else { + SC_log(LOG_DEBUG, "SCNetworkSetRemove() failed, currently active: %@", setPrivate->setID); _SCErrorSet(kSCStatusInvalidArgument); } CFRelease(path); + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkSetRemove(): %@", set); + } + return ok; } @@ -859,6 +1207,23 @@ SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service) return FALSE; } + if (!__SCNetworkSetExists(set)) { + SC_log(LOG_ERR, "SCNetworkSetRemoveService() w/removed set\n set = %@\n service = %@", + set, + service); + _SC_crash_once("SCNetworkSetRemoveService() w/removed set", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + } + + if (!__SCNetworkServiceExists(service)) { + SC_log(LOG_ERR, "SCNetworkSetRemoveService() w/removed service\n set = %@\n service = %@", + set, + service); + _SC_crash_once("SCNetworkSetRemoveService() w/removed service", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + // remove service from ServiceOrder _serviceOrder_remove(set, service); @@ -886,12 +1251,15 @@ SCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service) // push the [deep] interface configuration [back] into all sets which contain the service. if (interface_config != NULL) { __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config); + CFRelease(interface_config); } - if (interface_config != NULL) CFRelease(interface_config); - if (!ok) { + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkSetRemoveService(): %@, %@", set, service); + } else { _SCErrorSet(sc_status); } + return ok; } @@ -908,9 +1276,21 @@ SCNetworkSetSetCurrent(SCNetworkSetRef set) return FALSE; } + if (!__SCNetworkSetExists(set)) { + SC_log(LOG_ERR, "SCNetworkSetSetCurrent() w/removed set\n set = %@", set); + _SC_crash_once("SCNetworkSetSetCurrent() w/removed set", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); ok = SCPreferencesSetValue(setPrivate->prefs, kSCPrefCurrentSet, path); CFRelease(path); + + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkSetSetCurrent(): %@", set); + } + return ok; } @@ -918,8 +1298,10 @@ SCNetworkSetSetCurrent(SCNetworkSetRef set) Boolean SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name) { - CFBundleRef bundle = NULL; CFDictionaryRef entity; +#if TARGET_OS_IPHONE + Boolean isDefaultName = FALSE; +#endif // TARGET_OS_IPHONE CFStringRef localized = NULL; CFStringRef non_localized = NULL; Boolean ok = FALSE; @@ -931,6 +1313,15 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name) return FALSE; } + if (!__SCNetworkSetExists(set)) { + SC_log(LOG_ERR, "SCNetworkSetSetName() w/removed set\n set = %@\n name = %@", + set, + name != NULL ? name : CFSTR("")); + _SC_crash_once("SCNetworkSetSetName() w/removed set", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + if ((name != NULL) && !isA_CFString(name)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; @@ -939,28 +1330,42 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name) // if known, compare against localized name if (name != NULL) { - bundle = _SC_CFBundleGet(); - if (bundle != NULL) { - non_localized = _SC_CFBundleCopyNonLocalizedString(bundle, - CFSTR("DEFAULT_SET_NAME"), - CFSTR("Automatic"), - NULL); - if (non_localized != NULL) { - if (CFEqual(name, non_localized)) { - localized = CFBundleCopyLocalizedString(bundle, - CFSTR("DEFAULT_SET_NAME"), - CFSTR("Automatic"), - NULL); - if (localized != NULL) { - name = localized; - } - } - } + non_localized = copy_default_set_name(FALSE); + if (CFEqual(name, non_localized)) { + localized = copy_default_set_name(TRUE); + name = localized; +#if TARGET_OS_IPHONE + isDefaultName = TRUE; +#endif // TARGET_OS_IPHONE } +#if TARGET_OS_IPHONE + else { + localized = copy_default_set_name(TRUE); + isDefaultName = CFEqual(name, non_localized); + } +#endif // TARGET_OS_IPHONE } -#define PREVENT_DUPLICATE_SET_NAMES -#ifdef PREVENT_DUPLICATE_SET_NAMES +#if TARGET_OS_IPHONE + if (!isDefaultName && isDefaultSet(set) && (geteuid() != 0)) { + // if we are trying to change the name of the "Automatic" set + SC_log(LOG_ERR, "SCNetworkSetSetName() failed, cannot rename : %@", set); + _SC_crash("The \"Automatic\" network set cannot be renamed", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + goto done; + } +#endif // TARGET_OS_IPHONE + +#define PREVENT_DUPLICATE_SET_NAMES +#ifdef PREVENT_DUPLICATE_SET_NAMES + +#if TARGET_OS_IPHONE + if (!isDefaultName) { + // On iOS, only block naming multiple sets with the name + // "Automatic". Others names are OK. + } else +#endif // TARGET_OS_IPHONE + if (name != NULL) { CFArrayRef sets; @@ -997,18 +1402,12 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name) // if known, store non-localized name - if ((name != NULL) && (bundle != NULL) && (non_localized != NULL)) { + if ((name != NULL) && (non_localized != NULL)) { if (localized == NULL) { - localized = CFBundleCopyLocalizedString(bundle, - CFSTR("DEFAULT_SET_NAME"), - CFSTR("Automatic"), - NULL); + localized = copy_default_set_name(TRUE); } - - if (localized != NULL) { - if (CFEqual(name, localized)) { - name = non_localized; - } + if (CFEqual(name, localized)) { + name = non_localized; } } @@ -1040,6 +1439,10 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name) done : + if (ok) { + SC_log(LOG_DEBUG, "SCNetworkSetSetName(): %@", set); + } + if (localized != NULL) CFRelease(localized); if (non_localized != NULL) CFRelease(non_localized); return ok; @@ -1049,7 +1452,10 @@ SCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name) Boolean SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder) { + CFMutableArrayRef cleanOrder; CFDictionaryRef dict; + CFIndex i; + CFIndex n; CFMutableDictionaryRef newDict; Boolean ok; CFStringRef path; @@ -1060,10 +1466,15 @@ SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder) return FALSE; } - if (isA_CFArray(newOrder)) { - CFIndex i; - CFIndex n = CFArrayGetCount(newOrder); + if (!__SCNetworkSetExists(set)) { + SC_log(LOG_ERR, "SCNetworkSetSetServiceOrder() w/removed set\n set = %@", set); + _SC_crash_once("SCNetworkSetSetServiceOrder() w/removed set", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + if (isA_CFArray(newOrder)) { + n = CFArrayGetCount(newOrder); for (i = 0; i < n; i++) { CFStringRef serviceID; @@ -1093,7 +1504,24 @@ SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder) &kCFTypeDictionaryValueCallBacks); } - CFDictionarySetValue(newDict, kSCPropNetServiceOrder, newOrder); + cleanOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + n = CFArrayGetCount(newOrder); + for (i = 0; i < n; i++) { + CFIndex nClean = CFArrayGetCount(cleanOrder); + CFStringRef serviceID = CFArrayGetValueAtIndex(newOrder, i); + + if ((nClean == 0) || + !CFArrayContainsValue(cleanOrder, CFRangeMake(0, nClean), serviceID)) { + // if first reference to this serviceID + CFArrayAppendValue(cleanOrder, serviceID); + } else { + // skip duplicate serviceID + SC_log(LOG_ERR, "SCNetworkSetSetServiceOrder() found duplicate serviceID: removed %@\n", serviceID); + } + } + CFDictionarySetValue(newDict, kSCPropNetServiceOrder, cleanOrder); + CFRelease(cleanOrder); + ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newDict); CFRelease(newDict); CFRelease(path); @@ -1106,6 +1534,31 @@ SCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder) #pragma mark SCNetworkSet SPIs +__private_extern__ +Boolean +__SCNetworkSetExists(SCNetworkSetRef set) +{ + CFDictionaryRef entity; + CFStringRef path; + SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; + + if (setPrivate->prefs == NULL) { + return FALSE; + } + + path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); + entity = SCPreferencesPathGetValue(setPrivate->prefs, path); + CFRelease(path); + + if (!isA_CFDictionary(entity)) { + // if no "set" + return FALSE; + } + + return TRUE; +} + + static void add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface) { @@ -1130,6 +1583,7 @@ add_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef return; } + static CFSetRef /* of SCNetworkInterfaceRef's */ copyExcludedInterfaces(SCPreferencesRef prefs) { @@ -1158,16 +1612,197 @@ copyExcludedInterfaces(SCPreferencesRef prefs) } +#if !TARGET_OS_IPHONE +static SCBridgeInterfaceRef +copyAutoBridgeInterface(SCPreferencesRef prefs, CFStringRef bridgeName) +{ + SCBridgeInterfaceRef bridge = NULL; + CFArrayRef interfaces; + + // exclude Bridge [member] interfaces + interfaces = SCBridgeInterfaceCopyAll(prefs); + if (interfaces != NULL) { + CFIndex i; + CFIndex n; + + n = CFArrayGetCount(interfaces); + for (i = 0; i < n; i++) { + SCBridgeInterfaceRef interface; + CFStringRef name = NULL; + CFDictionaryRef options; + + interface = CFArrayGetValueAtIndex(interfaces, i); + options = SCBridgeInterfaceGetOptions(interface); + if ((options != NULL) && + CFDictionaryGetValueIfPresent(options, + CFSTR("__AUTO__"), + (const void **)&name) && + _SC_CFEqual(name, bridgeName)) { + bridge = interface; + CFRetain(bridge); + break; + } + } + + CFRelease(interfaces); + } + + if (bridge == NULL) { + bridge = SCBridgeInterfaceCreate(prefs); + if (bridge != NULL) { + CFMutableDictionaryRef newOptions; + Boolean ok; + + newOptions = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(newOptions, CFSTR("__AUTO__"), bridgeName); + ok = SCBridgeInterfaceSetOptions(bridge, newOptions); + CFRelease(newOptions); + if (!ok) { + CFRelease(bridge); + bridge = NULL; + } + } + } + + return bridge; +} +#endif // !TARGET_OS_IPHONE + + +static CFArrayRef +copyServices(SCNetworkSetRef set) +{ + CFArrayRef services; + SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; + + // first, assume that we only want to add new services + // for those interfaces that are not represented in the + // current set. + services = SCNetworkSetCopyServices(set); + if ((services != NULL) && setPrivate->established) { + // but, if we are given an existing (or "established") set + // than we only want to add new services for those interfaces + // that are not represented in *any* set. + CFRelease(services); + services = SCNetworkServiceCopyAll(setPrivate->prefs); + } + + return services; +} + + +#if !TARGET_OS_IPHONE +static CF_RETURNS_RETAINED CFArrayRef +updateServices(CFArrayRef services, SCNetworkInterfaceRef interface) +{ + CFStringRef bsdName; + CFIndex i; + CFIndex n; + CFMutableArrayRef newServices; + + if (services == NULL) { + return NULL; + } + + bsdName = SCNetworkInterfaceGetBSDName(interface); + + newServices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + n = CFArrayGetCount(services); + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef interface; + CFStringRef interfaceName; + SCNetworkServiceRef newService; + SCNetworkServiceRef service; + CFStringRef serviceID; + SCNetworkServicePrivateRef servicePrivate; + + service = CFArrayGetValueAtIndex(services, i); + interface = SCNetworkServiceGetInterface(service); + interfaceName = SCNetworkInterfaceGetBSDName(interface); + if (!_SC_CFEqual(interfaceName, bsdName)) { + // if not a match, retain + CFArrayAppendValue(newServices, service); + continue; + } + + // if a match, update + serviceID = SCNetworkServiceGetServiceID(service); + servicePrivate = (SCNetworkServicePrivateRef)service; + newService = SCNetworkServiceCopy(servicePrivate->prefs, serviceID); + if (newService != NULL) { + CFArrayAppendValue(newServices, newService); + CFRelease(newService); + } + } + + return newServices; +} +#endif // !TARGET_OS_IPHONE + + +static __inline__ Boolean +skipInterface(SCNetworkInterfaceRef interface) +{ + CFStringRef action; + + action = _SCNetworkInterfaceGetConfigurationAction(interface); + if (isA_CFString(action) && + CFEqual(action, kSCNetworkInterfaceConfigurationActionValueNone)) { + return TRUE; + } + + return FALSE; +} + + +CFComparisonResult +_SCNetworkSetCompare(const void *val1, const void *val2, void *context) +{ +#pragma unused(context) + CFStringRef id1; + CFStringRef id2; + CFStringRef name1; + CFStringRef name2; + SCNetworkSetRef s1 = (SCNetworkSetRef)val1; + SCNetworkSetRef s2 = (SCNetworkSetRef)val2; + + name1 = SCNetworkSetGetName(s1); + name2 = SCNetworkSetGetName(s2); + + if (name1 != NULL) { + if (name2 != NULL) { + return CFStringCompare(name1, name2, 0); + } else { + return kCFCompareLessThan; + } + } + + if (name2 != NULL) { + return kCFCompareGreaterThan; + } + + id1 = SCNetworkSetGetSetID(s1); + id2 = SCNetworkSetGetSetID(s2); + return CFStringCompare(id1, id2, 0); +} + + static Boolean -__SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces) +__SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces, Boolean excludeHidden) { - CFSetRef excluded = NULL; + CFSetRef excluded; CFIndex i; CFIndex n = 0; Boolean ok = TRUE; CFArrayRef services; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; Boolean updated = FALSE; +#if !TARGET_OS_IPHONE + Boolean updatedIFs = FALSE; +#endif // !TARGET_OS_IPHONE #if TARGET_OS_IPHONE CFArrayRef orphans = NULL; @@ -1193,28 +1828,120 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF } #endif // TARGET_OS_IPHONE - // first, assume that we only want to add new services - // for those interfaces that are not represented in the - // current set. - services = SCNetworkSetCopyServices(set); - if ((services != NULL) && setPrivate->established) { - // but, if we are given an existing (or "established") set - // than we only want to add new services for those interfaces - // that are not represented in *any* set. - CFRelease(services); - services = SCNetworkServiceCopyAll(setPrivate->prefs); - } + // copy network services + services = copyServices(set); + // copy network interfaces to be excluded excluded = copyExcludedInterfaces(setPrivate->prefs); - n = (interfaces != NULL) ? CFArrayGetCount(interfaces) : 0; +#if !TARGET_OS_IPHONE + // look for interfaces that should auto-magically be added + // to an Ethernet bridge + n = ((services != NULL) && (interfaces != NULL)) ? CFArrayGetCount(interfaces) : 0; + for (i = 0; i < n; i++) { + SCBridgeInterfaceRef bridge = NULL; + SCNetworkInterfaceRef interface; + + interface = CFArrayGetValueAtIndex(interfaces, i); + + if (excludeHidden && skipInterface(interface)) { + // if not auto-configure + continue; + } + + if (CFSetContainsValue(excluded, interface)) { + // if this interface is a member of a Bond or Bridge + continue; + } + + if (__SCNetworkServiceExistsForInterface(services, interface)) { + // if this is not a new interface + continue; + } + + if (_SCNetworkInterfaceIsBuiltin(interface) && + _SCNetworkInterfaceIsThunderbolt(interface) && + !isA_SCBridgeInterface(interface)) { + // add built-in Thunderbolt interfaces to bridge + bridge = copyAutoBridgeInterface(setPrivate->prefs, CFSTR("thunderbolt-bridge")); + } + + if (bridge != NULL) { + CFIndex bridgeIndex; + CFArrayRef members; + CFMutableArrayRef newMembers; + CFMutableSetRef newExcluded; + CFMutableArrayRef newInterfaces; + CFArrayRef newServices; + + // track the bridge interface (if it's in our list) + bridgeIndex = CFArrayGetFirstIndexOfValue(interfaces, + CFRangeMake(0, CFArrayGetCount(interfaces)), + bridge); + + // add new member interface + members = SCBridgeInterfaceGetMemberInterfaces(bridge); + if ((members != NULL) && (CFArrayGetCount(members) > 0)) { + newMembers = CFArrayCreateMutableCopy(NULL, 0, members); + updated = TRUE; // if we're updating an existing bridge + } else { + newMembers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + CFArrayAppendValue(newMembers, interface); + ok = SCBridgeInterfaceSetMemberInterfaces(bridge, newMembers); + CFRelease(newMembers); + if (!ok) { + SC_log(LOG_INFO, "could not update bridge with \"%@\": %s", + SCNetworkInterfaceGetLocalizedDisplayName(interface), + SCErrorString(SCError())); + CFRelease(bridge); + continue; + } + + // exclude the new member interface + newExcluded = CFSetCreateMutableCopy(NULL, 0, excluded); + CFRelease(excluded); + CFSetAddValue(newExcluded, interface); + excluded = newExcluded; + + // update the list of interfaces to include the [new or updated] bridge + newInterfaces = CFArrayCreateMutableCopy(NULL, 0, interfaces); + if (bridgeIndex != kCFNotFound) { + CFArraySetValueAtIndex(newInterfaces, bridgeIndex, bridge); + } else { + CFArrayAppendValue(newInterfaces, bridge); + } + if (updatedIFs) { + CFRelease(interfaces); + } + interfaces = newInterfaces; + updatedIFs = TRUE; + + // refresh [existing] services + newServices = updateServices(services, bridge); + if (newServices != NULL) { + CFRelease(services); + services = newServices; + } + + CFRelease(bridge); + } + } +#endif // !TARGET_OS_IPHONE + + n = ((services != NULL) && (interfaces != NULL)) ? CFArrayGetCount(interfaces) : 0; for (i = 0; i < n; i++) { SCNetworkInterfaceRef interface; CFMutableArrayRef interface_list; interface = CFArrayGetValueAtIndex(interfaces, i); - if ((excluded != NULL) - && CFSetContainsValue(excluded, interface)) { + + if (excludeHidden && skipInterface(interface)) { + // if not auto-configure + continue; + } + + if (CFSetContainsValue(excluded, interface)) { // if this interface is a member of a Bond or Bridge continue; } @@ -1238,72 +1965,31 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF service = SCNetworkServiceCreate(setPrivate->prefs, interface); if (service == NULL) { - SCLog(TRUE, LOG_DEBUG, - CFSTR("could not create service for \"%@\": %s\n"), - SCNetworkInterfaceGetLocalizedDisplayName(interface), - SCErrorString(SCError())); + SC_log(LOG_ERR, "could not create service for \"%@\": %s", + SCNetworkInterfaceGetLocalizedDisplayName(interface), + SCErrorString(SCError())); ok = FALSE; goto nextInterface; } ok = SCNetworkServiceEstablishDefaultConfiguration(service); if (!ok) { - SCLog(TRUE, LOG_DEBUG, - CFSTR("could not estabish default configuration for \"%@\": %s\n"), - SCNetworkInterfaceGetLocalizedDisplayName(interface), - SCErrorString(SCError())); + SC_log(LOG_ERR, "could not estabish default configuration for \"%@\": %s", + SCNetworkInterfaceGetLocalizedDisplayName(interface), + SCErrorString(SCError())); SCNetworkServiceRemove(service); CFRelease(service); goto nextInterface; } - while (TRUE) { - CFStringRef newName; - - ok = SCNetworkSetAddService(set, service); - if (ok) { - break; - } - - if (SCError() != kSCStatusKeyExists) { - SCLog(TRUE, LOG_DEBUG, - CFSTR("could not add service for \"%@\": %s\n"), - SCNetworkInterfaceGetLocalizedDisplayName(interface), - SCErrorString(SCError())); - SCNetworkServiceRemove(service); - CFRelease(service); - goto nextInterface; - } - - // we have two interfaces with the same service - // name, acquire a new, hopefully unique, name - - newName = __SCNetworkServiceNextName(service); - if (newName == NULL) { - SCLog(TRUE, LOG_DEBUG, - CFSTR("could not set unique name for \"%@\": %s\n"), - SCNetworkInterfaceGetLocalizedDisplayName(interface), - SCErrorString(SCError())); - SCNetworkServiceRemove(service); - CFRelease(service); - goto nextInterface; - } - - ok = SCNetworkServiceSetName(service, newName); - CFRelease(newName); - if (ok) { - continue; - } - - if (SCError() != kSCStatusKeyExists) { - SCLog(TRUE, LOG_DEBUG, - CFSTR("could not set unique name for \"%@\": %s\n"), - SCNetworkInterfaceGetLocalizedDisplayName(interface), - SCErrorString(SCError())); - SCNetworkServiceRemove(service); - CFRelease(service); - goto nextInterface; - } + ok = SCNetworkSetAddService(set, service); + if (!ok) { + SC_log(LOG_ERR, "could not add service for \"%@\": %s", + SCNetworkInterfaceGetLocalizedDisplayName(interface), + SCErrorString(SCError())); + SCNetworkServiceRemove(service); + CFRelease(service); + goto nextInterface; } CFRelease(service); @@ -1318,8 +2004,13 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF } CFRelease(interface_list); } +#if !TARGET_OS_IPHONE + if (updatedIFs && (interfaces != NULL)) { + CFRelease(interfaces); + } +#endif // !TARGET_OS_IPHONE if (services != NULL) CFRelease(services); - if (excluded != NULL) CFRelease(excluded); + CFRelease(excluded); #if TARGET_OS_IPHONE if (orphans != NULL) { @@ -1344,9 +2035,19 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF } #endif // TARGET_OS_IPHONE - if (ok && !updated) { - // if no changes were made - _SCErrorSet(kSCStatusOK); + if (ok) { + if (updated) { + CFStringRef model; + + model = SCPreferencesGetValue(setPrivate->prefs, MODEL); + if (model == NULL) { + model = _SC_hw_model(FALSE); + SCPreferencesSetValue(setPrivate->prefs, MODEL, model); + } + } else { + // if no changes were made + _SCErrorSet(kSCStatusOK); + } } return updated; @@ -1367,7 +2068,7 @@ SCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set) interfaces = _SCNetworkInterfaceCopyAllWithPreferences(setPrivate->prefs); if (interfaces != NULL) { - updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces); + updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, TRUE); CFRelease(interfaces); } @@ -1392,7 +2093,8 @@ SCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetwor } interfaces = CFArrayCreate(NULL, (const void **)&interface, 1, &kCFTypeArrayCallBacks); - updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces); + assert(interfaces != NULL); + updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, FALSE); CFRelease(interfaces); return updated; @@ -1544,3 +2246,99 @@ SCNetworkSetSetSelectedVPNService(SCNetworkSetRef set, SCNetworkServiceRef servi if (services != NULL) CFRelease(services); return ok; } + + +Boolean +_SCNetworkSetSetSetID(SCNetworkSetRef set, CFStringRef newSetID) +{ + SCNetworkSetRef currentSet = NULL; + SCNetworkSetPrivateRef currentSetPrivate = NULL; + CFDictionaryRef entity; + CFStringRef newPath; + Boolean ok = FALSE; + CFStringRef oldPath = NULL; + SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; + Boolean updateCurrentSet = FALSE; + + if (!isA_SCNetworkSet(set)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + if (!isA_CFString(newSetID)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + if (!__SCNetworkSetExists(set)) { + SC_log(LOG_ERR, "_SCNetworkSetSetSetID() w/removed set\n set = %@\n setID = %@", + set, + newSetID); + _SC_crash_once("_SCNetworkSetSetSetID() w/removed set", NULL, NULL); + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + // If newSetID is equal to current setID, our work is done + if (CFEqual(newSetID, setPrivate->setID)) { + return TRUE; + } + + newPath = SCPreferencesPathKeyCreateSet(NULL, newSetID); + entity = SCPreferencesPathGetValue(setPrivate->prefs, newPath); + if (isA_CFDictionary(entity)) { + // if the new set already exists + _SCErrorSet(kSCStatusKeyExists); + goto done; + } + + oldPath = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); + entity = SCPreferencesPathGetValue(setPrivate->prefs, oldPath); + if (!isA_CFDictionary(entity)) { + // if the set has already been removed + _SCErrorSet(kSCStatusNoKey); + goto done; + } + + ok = SCPreferencesPathSetValue(setPrivate->prefs, newPath, entity); + if (!ok) { + goto done; + } + + ok = SCPreferencesPathRemoveValue(setPrivate->prefs, oldPath); + if (!ok) { + goto done; + } + + // update current set (if needed) + currentSet = SCNetworkSetCopyCurrent(setPrivate->prefs); + if (currentSet != NULL) { + currentSetPrivate = (SCNetworkSetPrivateRef)currentSet; + if (CFEqual(currentSetPrivate->setID, setPrivate->setID)) { + updateCurrentSet = TRUE; + } + CFRelease(currentSet); + } + + SC_log(LOG_DEBUG, "_SCNetworkSetSetID(): %@ --> %@", set, newSetID); + + // replace setID with new one + CFRetain(newSetID); + CFRelease(setPrivate->setID); + setPrivate->setID = newSetID; + + if (updateCurrentSet) { + SCNetworkSetSetCurrent(set); + } + + done: + + if (oldPath != NULL) { + CFRelease(oldPath); + } + if (newPath != NULL) { + CFRelease(newPath); + } + + return ok; +}