Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
59 kB · 2344 lines
C
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345/* * 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, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * 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@ */
/* * Modification History * * May 13, 2004 Allan Nathanson <ajn@apple.com> * - initial revision */
#include <CoreFoundation/CoreFoundation.h>#include <CoreFoundation/CFRuntime.h>#include "SCNetworkConfigurationInternal.h"
#include <pthread.h>
static CFStringRef __SCNetworkSetCopyDescription (CFTypeRef cf);static void __SCNetworkSetDeallocate (CFTypeRef cf);static Boolean __SCNetworkSetEqual (CFTypeRef cf1, CFTypeRef cf2);static CFHashCode __SCNetworkSetHash (CFTypeRef cf);
static CFTypeID __kSCNetworkSetTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __SCNetworkSetClass = { 0, // version "SCNetworkSet", // className NULL, // init NULL, // copy __SCNetworkSetDeallocate, // dealloc __SCNetworkSetEqual, // equal __SCNetworkSetHash, // hash NULL, // copyFormattingDesc __SCNetworkSetCopyDescription // copyDebugDesc};
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static CFStringRef__SCNetworkSetCopyDescription(CFTypeRef cf){ CFAllocatorRef allocator = CFGetAllocator(cf); CFMutableStringRef result; SCNetworkSetRef set = (SCNetworkSetRef)cf; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
result = CFStringCreateMutable(allocator, 0); CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkSet %p [%p]> {"), 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;}
static void__SCNetworkSetDeallocate(CFTypeRef cf){ SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
/* release resources */
CFRelease(setPrivate->setID); CFRelease(setPrivate->prefs); if (setPrivate->name != NULL) CFRelease(setPrivate->name);
return;}
static Boolean__SCNetworkSetEqual(CFTypeRef cf1, CFTypeRef cf2){ SCNetworkSetPrivateRef s1 = (SCNetworkSetPrivateRef)cf1; SCNetworkSetPrivateRef s2 = (SCNetworkSetPrivateRef)cf2;
if (s1 == s2) return TRUE;
if (s1->prefs != s2->prefs) return FALSE; // if not the same prefs
if (!CFEqual(s1->setID, s2->setID)) return FALSE; // if not the same set identifier
return TRUE;}
static CFHashCode__SCNetworkSetHash(CFTypeRef cf){ SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)cf;
return CFHash(setPrivate->setID);}
static void__SCNetworkSetInitialize(void){ __kSCNetworkSetTypeID = _CFRuntimeRegisterClass(&__SCNetworkSetClass); return;}
static SCNetworkSetPrivateRef__SCNetworkSetCreatePrivate(CFAllocatorRef allocator, SCPreferencesRef prefs, CFStringRef setID){ SCNetworkSetPrivateRef setPrivate; uint32_t size;
/* initialize runtime */ pthread_once(&initialized, __SCNetworkSetInitialize);
/* allocate target */ size = sizeof(SCNetworkSetPrivate) - sizeof(CFRuntimeBase); setPrivate = (SCNetworkSetPrivateRef)_CFRuntimeCreateInstance(allocator, __kSCNetworkSetTypeID, size, NULL); if (setPrivate == NULL) { return NULL; }
/* initialize non-zero/NULL members */ setPrivate->setID = CFStringCreateCopy(NULL, setID); setPrivate->prefs = CFRetain(prefs);
return setPrivate;}
#pragma mark -
static int_serviceOrder(SCNetworkServiceRef service){ SCNetworkInterfaceRef interface;
interface = SCNetworkServiceGetInterface(service); if ((interface == NULL) || _SCNetworkServiceIsVPN(service)) { return 100000; // if unknown or VPN interface, sort last }
return __SCNetworkInterfaceOrder(interface);}
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 n; CFMutableArrayRef newOrder; CFArrayRef order; CFStringRef serviceID = SCNetworkServiceGetServiceID(service); CFIndex serviceOrder = _serviceOrder(service); SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; CFIndex slot;
order = SCNetworkSetGetServiceOrder(set); if (order != NULL) { newOrder = CFArrayCreateMutableCopy(NULL, 0, order); } else { newOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } assert(newOrder != NULL);
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); }
slot = 0; n = CFArrayGetCount(newOrder); for (CFIndex i = 0; i < n; i++) { int slotOrder; SCNetworkServiceRef slotService; CFStringRef slotServiceID;
slotServiceID = CFArrayGetValueAtIndex(newOrder, i); if (!isA_CFString(slotServiceID)) { // if bad prefs continue; }
slotService = SCNetworkServiceCopy(setPrivate->prefs, slotServiceID); if (slotService == NULL) { // if serviceID not valid continue; }
slotOrder = _serviceOrder(slotService); if (serviceOrder >= slotOrder) { // add the service *after* this one slot = i + 1; }
CFRelease(slotService); }
CFArrayInsertValueAtIndex(newOrder, slot, serviceID); (void) SCNetworkSetSetServiceOrder(set, newOrder); CFRelease(newOrder);
return;}
static void_serviceOrder_remove(SCNetworkSetRef set, SCNetworkServiceRef service){ CFIndex n; CFMutableArrayRef newOrder; CFArrayRef order; CFStringRef serviceID;
order = SCNetworkSetGetServiceOrder(set); if (order == NULL) { return; } newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
serviceID = SCNetworkServiceGetServiceID(service);
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);
return;}
#pragma mark -#pragma mark SCNetworkSet APIs
#define DEFAULT_SET_NAME CFSTR("Automatic")#define N_QUICK 16
static CFStringRefcopy_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_NAMESstatic CFStringRefcopy_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 Booleanensure_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
BooleanSCNetworkSetAddService(SCNetworkSetRef set, SCNetworkServiceRef service){ SCNetworkInterfaceRef interface; CFArrayRef interface_config = NULL; CFStringRef link; Boolean ok; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
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); if ((interface != NULL) && __SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) { _SCErrorSet(kSCStatusKeyExists); return FALSE; }
//#define PREVENT_DUPLICATE_SETS#ifdef PREVENT_DUPLICATE_SETS CFArrayRef sets;
// ensure that each service is only a member of ONE set sets = SCNetworkSetCopyAll(setPrivate->prefs); if (sets != NULL) { CFIndex i; CFIndex n;
n = CFArrayGetCount(sets); for (i = 0; i < n; i++) { Boolean found; CFArrayRef services; SCNetworkSetRef set;
set = CFArrayGetValueAtIndex(sets, i); services = SCNetworkSetCopyServices(set); found = CFArrayContainsValue(services, CFRangeMake(0, CFArrayGetCount(services)), service); CFRelease(services);
if (found) { CFRelease(sets); _SCErrorSet(kSCStatusKeyExists); return FALSE; } } CFRelease(sets); }#endif /* PREVENT_DUPLICATE_SETS */
// get the [deep] interface configuration settings interface = SCNetworkServiceGetInterface(service); if (interface != NULL) { interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface); }
// create the link between "set" and the "service" path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator setPrivate->setID, // set servicePrivate->serviceID, // service NULL); // entity link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator 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) { goto done; }
// push the [deep] interface configuration into all sets which contain this service. if (interface != NULL) { __SCNetworkInterfaceSetDeepConfiguration(set, interface, interface_config); }
// add service to ServiceOrder _serviceOrder_add(set, service);
// mark set as no longer "new" setPrivate->established = TRUE;
done :
if (ok) { SC_log(LOG_DEBUG, "SCNetworkSetAddService(): %@, %@", set, service); }
if (interface_config != NULL) CFRelease(interface_config); return ok;}
SCNetworkSetRefSCNetworkSetCopy(SCPreferencesRef prefs, CFStringRef setID){ CFDictionaryRef entity; CFStringRef path; SCNetworkSetPrivateRef setPrivate;
if (!isA_CFString(setID)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
path = SCPreferencesPathKeyCreateSet(NULL, setID); entity = SCPreferencesPathGetValue(prefs, path); CFRelease(path);
if (!isA_CFDictionary(entity)) { _SCErrorSet(kSCStatusNoKey); return NULL; }
setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID); assert(setPrivate != NULL);
// mark set as "old" (already established) setPrivate->established = TRUE;
return (SCNetworkSetRef)setPrivate;}
BooleanSCNetworkSetContainsInterface(SCNetworkSetRef set, SCNetworkInterfaceRef interface){ Boolean found = FALSE; CFArrayRef services;
services = SCNetworkSetCopyServices(set); if (services != NULL) { found = __SCNetworkServiceExistsForInterface(services, interface); CFRelease(services); }
return found;}
CFArrayRef /* of SCNetworkSetRef's */SCNetworkSetCopyAll(SCPreferencesRef prefs){ CFMutableArrayRef array; CFIndex n; CFStringRef path; CFDictionaryRef sets;
path = SCPreferencesPathKeyCreateSets(NULL); sets = SCPreferencesPathGetValue(prefs, path); CFRelease(path);
if ((sets != NULL) && !isA_CFDictionary(sets)) { return NULL; }
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
n = (sets != NULL) ? CFDictionaryGetCount(sets) : 0; if (n > 0) { CFIndex i; const void * keys_q[N_QUICK]; const void ** keys = keys_q; const void * vals_q[N_QUICK]; const void ** vals = vals_q;
if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0); } CFDictionaryGetKeysAndValues(sets, keys, vals); for (i = 0; i < n; i++) { SCNetworkSetPrivateRef setPrivate;
if (!isA_CFDictionary(vals[i])) { 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;
CFArrayAppendValue(array, (SCNetworkSetRef)setPrivate); CFRelease(setPrivate); } if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); CFAllocatorDeallocate(NULL, vals); } }
return array;}
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;}
SCNetworkSetRefSCNetworkSetCopyCurrent(SCPreferencesRef prefs){ CFArrayRef components; CFStringRef currentID; SCNetworkSetPrivateRef setPrivate = NULL;
currentID = SCPreferencesGetValue(prefs, kSCPrefCurrentSet); if (!isA_CFString(currentID)) { return NULL; }
components = CFStringCreateArrayBySeparatingStrings(NULL, currentID, CFSTR("/")); if (CFArrayGetCount(components) == 3) { CFStringRef setID; CFStringRef path;
setID = CFArrayGetValueAtIndex(components, 2); path = SCPreferencesPathKeyCreateSet(NULL, setID); if (CFEqual(path, currentID)) { setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID); assert(setPrivate != NULL);
// mark set as "old" (already established) setPrivate->established = TRUE; } else { SC_log(LOG_NOTICE, "SCNetworkSetCopyCurrent(): preferences are non-conformant"); } CFRelease(path); } CFRelease(components);
return (SCNetworkSetRef)setPrivate;}
CFArrayRef /* of SCNetworkServiceRef's */SCNetworkSetCopyServices(SCNetworkSetRef set){ CFMutableArrayRef array; CFDictionaryRef dict; CFIndex n; CFStringRef path; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
path = SCPreferencesPathKeyCreateSetNetworkService(NULL, setPrivate->setID, NULL); dict = SCPreferencesPathGetValue(setPrivate->prefs, path); CFRelease(path); if ((dict != NULL) && !isA_CFDictionary(dict)) { return NULL; }
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
n = (dict != NULL) ? CFDictionaryGetCount(dict) : 0; if (n > 0) { CFIndex i; const void * keys_q[N_QUICK]; const void ** keys = keys_q;
if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); } CFDictionaryGetKeysAndValues(dict, keys, NULL); for (i = 0; i < n; i++) { CFArrayRef components; CFStringRef link;
path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, setPrivate->setID, (CFStringRef)keys[i], NULL); link = SCPreferencesPathGetLink(setPrivate->prefs, path); CFRelease(path); if (link == NULL) { SC_log(LOG_INFO, "service \"%@\" for set \"%@\" is not a link", keys[i], setPrivate->setID); continue; // if the service is not a link }
components = CFStringCreateArrayBySeparatingStrings(NULL, link, CFSTR("/")); if (CFArrayGetCount(components) == 3) { CFStringRef serviceID;
serviceID = CFArrayGetValueAtIndex(components, 2); path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator serviceID, // service NULL); // entity if (CFEqual(path, link)) { 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); } CFRelease(components); } if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); } }
return array;}
SCNetworkSetRefSCNetworkSetCreate(SCPreferencesRef prefs){ CFArrayRef components; CFDictionaryRef entity; Boolean ok; CFStringRef path; CFStringRef prefix; CFStringRef setID; SCNetworkSetPrivateRef setPrivate;
prefix = SCPreferencesPathKeyCreateSets(NULL); path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix); if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix); CFRelease(prefix); if (path == NULL) { return NULL; }
components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/")); setID = CFArrayGetValueAtIndex(components, 2); setPrivate = __SCNetworkSetCreatePrivate(NULL, prefs, setID); assert(setPrivate != NULL); CFRelease(components);
// mark set as "new" (not yet established) setPrivate->established = FALSE;
// establish the set in the preferences entity = CFDictionaryCreate(NULL, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ok = SCPreferencesPathSetValue(prefs, path, entity); CFRelease(path); CFRelease(entity); if (!ok) { CFRelease(setPrivate); 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;}
CFStringRefSCNetworkSetGetSetID(SCNetworkSetRef set){ SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
return setPrivate->setID;}
CFStringRefSCNetworkSetGetName(SCNetworkSetRef set){ CFDictionaryRef entity; CFStringRef path; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
if (setPrivate->name != NULL) { return setPrivate->name; }
path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); entity = SCPreferencesPathGetValue(setPrivate->prefs, path); CFRelease(path);
if (isA_CFDictionary(entity)) { CFStringRef name;
name = CFDictionaryGetValue(entity, kSCPropUserDefinedName); if (isA_CFString(name)) { setPrivate->name = CFRetain(name); } }
if (setPrivate->name != NULL) { CFStringRef 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;}
CFArrayRef /* of serviceID CFStringRef's */SCNetworkSetGetServiceOrder(SCNetworkSetRef set){ CFDictionaryRef dict; CFStringRef path; CFArrayRef serviceOrder; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4); if (path == NULL) { return NULL; }
dict = SCPreferencesPathGetValue(setPrivate->prefs, path); CFRelease(path); if (!isA_CFDictionary(dict)) { return NULL; }
serviceOrder = CFDictionaryGetValue(dict, kSCPropNetServiceOrder); serviceOrder = isA_CFArray(serviceOrder);
return serviceOrder;}
CFTypeIDSCNetworkSetGetTypeID(void){ pthread_once(&initialized, __SCNetworkSetInitialize); /* initialize runtime */ return __kSCNetworkSetTypeID;}
#if TARGET_OS_IPHONEstatic BooleanisDefaultSet(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
BooleanSCNetworkSetRemove(SCNetworkSetRef set){ CFStringRef currentPath; Boolean ok = FALSE; CFStringRef path; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); 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;}
BooleanSCNetworkSetRemoveService(SCNetworkSetRef set, SCNetworkServiceRef service){ SCNetworkInterfaceRef interface; CFArrayRef interface_config = NULL; Boolean ok; CFStringRef path; int sc_status = kSCStatusOK; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
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);
// get the [deep] interface configuration settings interface = SCNetworkServiceGetInterface(service); if (interface != NULL) { interface_config = __SCNetworkInterfaceCopyDeepConfiguration(set, interface); if (interface_config != NULL) { // remove the interface configuration from all sets which contain this service. __SCNetworkInterfaceSetDeepConfiguration(set, interface, NULL); } }
// remove the link between "set" and the "service" path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, setPrivate->setID, servicePrivate->serviceID, NULL); ok = SCPreferencesPathRemoveValue(setPrivate->prefs, path); if (!ok) { sc_status = SCError(); // preserve the error } CFRelease(path);
// 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 (ok) { SC_log(LOG_DEBUG, "SCNetworkSetRemoveService(): %@, %@", set, service); } else { _SCErrorSet(sc_status); }
return ok;}
BooleanSCNetworkSetSetCurrent(SCNetworkSetRef set){ Boolean ok; CFStringRef path; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); 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;}
BooleanSCNetworkSetSetName(SCNetworkSetRef set, CFStringRef name){ CFDictionaryRef entity;#if TARGET_OS_IPHONE Boolean isDefaultName = FALSE;#endif // TARGET_OS_IPHONE CFStringRef localized = NULL; CFStringRef non_localized = NULL; Boolean ok = FALSE; CFStringRef path; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
if (!__SCNetworkSetExists(set)) { SC_log(LOG_ERR, "SCNetworkSetSetName() w/removed set\n set = %@\n name = %@", set, name != NULL ? name : CFSTR("<NULL>")); _SC_crash_once("SCNetworkSetSetName() w/removed set", NULL, NULL); _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
if ((name != NULL) && !isA_CFString(name)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
// if known, compare against localized name
if (name != NULL) { 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 }
#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;
// ensure that each set is uniquely named
sets = SCNetworkSetCopyAll(setPrivate->prefs); if (sets != NULL) { CFIndex i; CFIndex n;
n = CFArrayGetCount(sets); for (i = 0; i < n; i++) { CFStringRef otherID; CFStringRef otherName; SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, i);
otherID = SCNetworkSetGetSetID(set); if (CFEqual(setPrivate->setID, otherID)) { continue; // skip current set }
otherName = SCNetworkSetGetName(set); if ((otherName != NULL) && CFEqual(name, otherName)) { // if "name" not unique CFRelease(sets); _SCErrorSet(kSCStatusKeyExists); goto done; } } CFRelease(sets); } }#endif /* PREVENT_DUPLICATE_SET_NAMES */
// if known, store non-localized name
if ((name != NULL) && (non_localized != NULL)) { if (localized == NULL) { localized = copy_default_set_name(TRUE); } if (CFEqual(name, localized)) { name = non_localized; } }
// update the "name"
path = SCPreferencesPathKeyCreateSet(NULL, setPrivate->setID); entity = SCPreferencesPathGetValue(setPrivate->prefs, path); if (isA_CFDictionary(entity) || ((entity == NULL) && (name != NULL))) { CFMutableDictionaryRef newEntity;
if (entity != NULL) { newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity); } else { newEntity = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } if (name != NULL) { CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name); } else { CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName); } ok = SCPreferencesPathSetValue(setPrivate->prefs, path, newEntity); CFRelease(newEntity); } CFRelease(path);
done :
if (ok) { SC_log(LOG_DEBUG, "SCNetworkSetSetName(): %@", set); }
if (localized != NULL) CFRelease(localized); if (non_localized != NULL) CFRelease(non_localized); return ok;}
BooleanSCNetworkSetSetServiceOrder(SCNetworkSetRef set, CFArrayRef newOrder){ CFMutableArrayRef cleanOrder; CFDictionaryRef dict; CFIndex i; CFIndex n; CFMutableDictionaryRef newDict; Boolean ok; CFStringRef path; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
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;
serviceID = CFArrayGetValueAtIndex(newOrder, i); if (!isA_CFString(serviceID)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } } } else { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
path = SCPreferencesPathKeyCreateSetNetworkGlobalEntity(NULL, setPrivate->setID, kSCEntNetIPv4); if (path == NULL) { return FALSE; }
dict = SCPreferencesPathGetValue(setPrivate->prefs, path); if (dict != NULL) { newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); } else { newDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); }
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);
return ok;}
#pragma mark -#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 voidadd_supported_interfaces(CFMutableArrayRef interface_list, SCNetworkInterfaceRef interface){ CFIndex i; CFArrayRef interface_types; CFIndex n;
interface_types = SCNetworkInterfaceGetSupportedInterfaceTypes(interface); n = (interface_types != NULL) ? CFArrayGetCount(interface_types) : 0; for (i = 0; i < n; i++) { SCNetworkInterfaceRef parent; CFStringRef interface_type;
interface_type = CFArrayGetValueAtIndex(interface_types, i); parent = SCNetworkInterfaceCreateWithInterface(interface, interface_type); if (parent != NULL) { CFArrayAppendValue(interface_list, parent); CFRelease(parent); } }
return;}
static CFSetRef /* of SCNetworkInterfaceRef's */copyExcludedInterfaces(SCPreferencesRef prefs){ CFMutableSetRef excluded; CFArrayRef interfaces;
excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
#if !TARGET_OS_IPHONE // exclude Bond [member] interfaces interfaces = SCBondInterfaceCopyAll(prefs); if (interfaces != NULL) { __SCBondInterfaceListCollectMembers(interfaces, excluded); CFRelease(interfaces); }#endif // !TARGET_OS_IPHONE
// exclude Bridge [member] interfaces interfaces = SCBridgeInterfaceCopyAll(prefs); if (interfaces != NULL) { __SCBridgeInterfaceListCollectMembers(interfaces, excluded); CFRelease(interfaces); }
return excluded;}
#if !TARGET_OS_IPHONEstatic SCBridgeInterfaceRefcopyAutoBridgeInterface(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 CFArrayRefcopyServices(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_IPHONEstatic CF_RETURNS_RETAINED CFArrayRefupdateServices(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__ BooleanskipInterface(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, Boolean excludeHidden){ 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; CFArrayRef sets;
sets = SCNetworkSetCopyAll(setPrivate->prefs); if (sets != NULL) { if (CFArrayGetCount(sets) == 1) { services = SCNetworkSetCopyServices(set); if (services != NULL) { n = CFArrayGetCount(services); CFRelease(services); }
if ((n == 0) && CFEqual(set, CFArrayGetValueAtIndex(sets, 0))) { // after a "Reset Network Settings" we need to find (and // add back) any VPN services that were orphaned. orphans = SCNetworkServiceCopyAll(setPrivate->prefs); } }
CFRelease(sets); }#endif // TARGET_OS_IPHONE
// copy network services services = copyServices(set);
// copy network interfaces to be excluded excluded = copyExcludedInterfaces(setPrivate->prefs);
#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 (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; }
interface_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFArrayAppendValue(interface_list, interface);
while (ok && (CFArrayGetCount(interface_list) > 0)) { CFArrayRef protocol_types;
interface = CFArrayGetValueAtIndex(interface_list, 0);
protocol_types = SCNetworkInterfaceGetSupportedProtocolTypes(interface); if ((protocol_types != NULL) && (CFArrayGetCount(protocol_types) > 0)) { SCNetworkServiceRef service;
service = SCNetworkServiceCreate(setPrivate->prefs, interface); if (service == NULL) { SC_log(LOG_ERR, "could not create service for \"%@\": %s", SCNetworkInterfaceGetLocalizedDisplayName(interface), SCErrorString(SCError())); ok = FALSE; goto nextInterface; }
ok = SCNetworkServiceEstablishDefaultConfiguration(service); if (!ok) { SC_log(LOG_ERR, "could not estabish default configuration for \"%@\": %s", 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); updated = TRUE; } else { add_supported_interfaces(interface_list, interface); }
nextInterface :
CFArrayRemoveValueAtIndex(interface_list, 0); } CFRelease(interface_list); }#if !TARGET_OS_IPHONE if (updatedIFs && (interfaces != NULL)) { CFRelease(interfaces); }#endif // !TARGET_OS_IPHONE if (services != NULL) CFRelease(services); CFRelease(excluded);
#if TARGET_OS_IPHONE if (orphans != NULL) { if (ok && updated) { CFIndex i; CFIndex n = CFArrayGetCount(orphans);
for (i = 0; i < n; i++) { SCNetworkServiceRef service;
service = CFArrayGetValueAtIndex(orphans, i); if (_SCNetworkServiceIsVPN(service)) { ok = SCNetworkSetAddService(set, service); if (!ok) { break; } } } }
CFRelease(orphans); }#endif // TARGET_OS_IPHONE
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;}
BooleanSCNetworkSetEstablishDefaultConfiguration(SCNetworkSetRef set){ CFArrayRef interfaces; SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set; Boolean updated = FALSE;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
interfaces = _SCNetworkInterfaceCopyAllWithPreferences(setPrivate->prefs); if (interfaces != NULL) { updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, TRUE); CFRelease(interfaces); }
return updated;}
BooleanSCNetworkSetEstablishDefaultInterfaceConfiguration(SCNetworkSetRef set, SCNetworkInterfaceRef interface){ CFArrayRef interfaces; Boolean updated;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
if (!isA_SCNetworkInterface(interface)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
interfaces = CFArrayCreate(NULL, (const void **)&interface, 1, &kCFTypeArrayCallBacks); assert(interfaces != NULL); updated = __SCNetworkSetEstablishDefaultConfigurationForInterfaces(set, interfaces, FALSE); CFRelease(interfaces);
return updated;}
SCNetworkServiceRefSCNetworkSetCopySelectedVPNService(SCNetworkSetRef set){ CFIndex i; CFIndex n; SCNetworkServiceRef selected = NULL; CFArrayRef services; CFMutableArrayRef services_vpn = NULL;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; }
services = SCNetworkSetCopyServices(set); if (services != NULL) { n = CFArrayGetCount(services); for (i = 0; i < n; i++) { SCNetworkServiceRef service;
service = CFArrayGetValueAtIndex(services, i); if (!SCNetworkServiceGetEnabled(service)) { // if not enabled continue; }
if (!_SCNetworkServiceIsVPN(service)) { // if not VPN service continue; }
if (services_vpn == NULL) { services_vpn = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } CFArrayAppendValue(services_vpn, service); }
CFRelease(services); }
if (services_vpn == NULL) { // if no VPN services return NULL; }
n = CFArrayGetCount(services_vpn); if (n > 1) { CFArrayRef order; CFMutableArrayRef sorted;
order = SCNetworkSetGetServiceOrder(set); sorted = CFArrayCreateMutableCopy(NULL, 0, services_vpn); CFArraySortValues(sorted, CFRangeMake(0, CFArrayGetCount(sorted)), _SCNetworkServiceCompare, (void *)order); CFRelease(services_vpn); services_vpn = sorted; }
#if TARGET_OS_IPHONE if (n > 1) { CFStringRef serviceID_prefs;
#define VPN_PREFERENCES CFSTR("com.apple.mobilevpn")#define VPN_SERVICE_ID CFSTR("activeVPNID")
CFPreferencesAppSynchronize(VPN_PREFERENCES); serviceID_prefs = CFPreferencesCopyAppValue(VPN_SERVICE_ID, VPN_PREFERENCES); if (serviceID_prefs != NULL) { for (i = 0; i < n; i++) { SCNetworkServiceRef service; CFStringRef serviceID;
service = CFArrayGetValueAtIndex(services_vpn, i); serviceID = SCNetworkServiceGetServiceID(service); if (CFEqual(serviceID, serviceID_prefs)) { selected = service; CFRetain(selected); break; }
}
CFRelease(serviceID_prefs); } }#endif // TARGET_OS_IPHONE
if (selected == NULL) { selected = CFArrayGetValueAtIndex(services_vpn, 0); CFRetain(selected); }
CFRelease(services_vpn); return selected;}
BooleanSCNetworkSetSetSelectedVPNService(SCNetworkSetRef set, SCNetworkServiceRef service){ Boolean ok = TRUE; CFArrayRef services;
if (!isA_SCNetworkSet(set)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
if (!isA_SCNetworkService(service) || !_SCNetworkServiceIsVPN(service)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; }
services = SCNetworkSetCopyServices(set); if (services != NULL) { CFIndex i; CFIndex n = CFArrayGetCount(services);
if (!CFArrayContainsValue(services, CFRangeMake(0, n), service)) { // if selected service not a member of the current set _SCErrorSet(kSCStatusInvalidArgument); ok = FALSE; goto done; }
for (i = 0; ok && (i < n); i++) { SCNetworkServiceRef vpn;
vpn = CFArrayGetValueAtIndex(services, i); if (!_SCNetworkServiceIsVPN(vpn)) { // if not VPN service continue; }
ok = SCNetworkServiceSetEnabled(vpn, CFEqual(service, vpn)); } }
done :
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;}