/*
- * Copyright (c) 2004, 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2018 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* 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@
*/
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
-#include <SystemConfiguration/SystemConfiguration.h>
-#include <SystemConfiguration/SCNetworkConfigurationInternal.h>
-#include <SystemConfiguration/SCValidation.h>
-#include <SystemConfiguration/SCPrivate.h>
+#include "SCNetworkConfigurationInternal.h"
+#include "SCPreferencesInternal.h"
#include <pthread.h>
+#define EXTERNAL_ID_DOMAIN_PREFIX "_"
static CFStringRef __SCNetworkServiceCopyDescription (CFTypeRef cf);
static void __SCNetworkServiceDeallocate (CFTypeRef cf);
static Boolean __SCNetworkServiceEqual (CFTypeRef cf1, CFTypeRef cf2);
+static CFHashCode __SCNetworkServiceHash (CFTypeRef cf);
-static CFTypeID __kSCNetworkServiceTypeID = _kCFRuntimeNotATypeID;
+static CFTypeID __kSCNetworkServiceTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __SCNetworkServiceClass = {
NULL, // copy
__SCNetworkServiceDeallocate, // dealloc
__SCNetworkServiceEqual, // equal
- NULL, // hash
+ __SCNetworkServiceHash, // hash
NULL, // copyFormattingDesc
__SCNetworkServiceCopyDescription // copyDebugDesc
};
-static pthread_once_t initialized = PTHREAD_ONCE_INIT;
-
-
-static __inline__ CFTypeRef
-isA_SCNetworkService(CFTypeRef obj)
-{
- return (isA_CFType(obj, SCNetworkServiceGetTypeID()));
-}
+static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static CFStringRef
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
- SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
+ SCNetworkServiceRef service = (SCNetworkServiceRef)cf;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
result = CFStringCreateMutable(allocator, 0);
- CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkService %p [%p]> { "), cf, allocator);
- CFStringAppendFormat(result, NULL, CFSTR("id=%@"), servicePrivate->serviceID);
-// CFStringAppendFormat(result, NULL, CFSTR(", prefs=%@"), servicePrivate->prefs);
- CFStringAppendFormat(result, NULL, CFSTR(" }"));
+ CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkService %p [%p]> {"), service, allocator);
+ CFStringAppendFormat(result, NULL, CFSTR("id = %@"), servicePrivate->serviceID);
+ if (servicePrivate->prefs != NULL) {
+ CFStringAppendFormat(result, NULL, CFSTR(", prefs = %p"), servicePrivate->prefs);
+ } else if (servicePrivate->store != NULL) {
+ CFStringAppendFormat(result, NULL, CFSTR(", store = %p"), servicePrivate->store);
+ }
+ if (servicePrivate->name != NULL) {
+ CFStringAppendFormat(result, NULL, CFSTR(", name = %@"), servicePrivate->name);
+ }
+ if (!__SCNetworkServiceExists(service)) {
+ CFStringAppendFormat(result, NULL, CFSTR(", REMOVED"));
+ }
+ CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
/* release resources */
CFRelease(servicePrivate->serviceID);
- if (servicePrivate->interface != NULL) CFRelease(servicePrivate->interface);
- CFRelease(servicePrivate->prefs);
+ if (servicePrivate->interface != NULL) CFRelease(servicePrivate->interface);
+ if (servicePrivate->prefs != NULL) CFRelease(servicePrivate->prefs);
+ if (servicePrivate->store != NULL) CFRelease(servicePrivate->store);
+ if (servicePrivate->name != NULL) CFRelease(servicePrivate->name);
+ if (servicePrivate->externalIDs != NULL) CFRelease(servicePrivate->externalIDs);
return;
}
}
+static CFHashCode
+__SCNetworkServiceHash(CFTypeRef cf)
+{
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf;
+
+ return CFHash(servicePrivate->serviceID);
+}
+
+
static void
__SCNetworkServiceInitialize(void)
{
__private_extern__ SCNetworkServicePrivateRef
__SCNetworkServiceCreatePrivate(CFAllocatorRef allocator,
+ SCPreferencesRef prefs,
CFStringRef serviceID,
- SCNetworkInterfaceRef interface,
- SCPreferencesRef prefs)
+ SCNetworkInterfaceRef interface)
{
SCNetworkServicePrivateRef servicePrivate;
uint32_t size;
return NULL;
}
- servicePrivate->prefs = CFRetain(prefs);
+ /* initialize non-zero/NULL members */
+ servicePrivate->prefs = (prefs != NULL) ? CFRetain(prefs): NULL;
servicePrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
servicePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL;
}
-/* ---------- SCNetworkService APIs ---------- */
+#pragma mark -
+#pragma mark Service ordering
+
+
+CFComparisonResult
+_SCNetworkServiceCompare(const void *val1, const void *val2, void *context)
+{
+ CFStringRef id1;
+ CFStringRef id2;
+ CFArrayRef order = (CFArrayRef)context;
+ SCNetworkServiceRef s1 = (SCNetworkServiceRef)val1;
+ SCNetworkServiceRef s2 = (SCNetworkServiceRef)val2;
+
+ id1 = SCNetworkServiceGetServiceID(s1);
+ id2 = SCNetworkServiceGetServiceID(s2);
+
+ if (order != NULL) {
+ CFIndex o1;
+ CFIndex o2;
+ CFRange range;
+
+ range = CFRangeMake(0, CFArrayGetCount(order));
+ o1 = CFArrayGetFirstIndexOfValue(order, range, id1);
+ o2 = CFArrayGetFirstIndexOfValue(order, range, id2);
+
+ if (o1 > o2) {
+ return (o2 != kCFNotFound) ? kCFCompareGreaterThan : kCFCompareLessThan;
+ } else if (o1 < o2) {
+ return (o1 != kCFNotFound) ? kCFCompareLessThan : kCFCompareGreaterThan;
+ }
+ }
+
+ return CFStringCompare(id1, id2, 0);
+}
+
+
+#pragma mark -
+#pragma mark SCNetworkService APIs
#define N_QUICK 64
+__private_extern__ CFArrayRef /* of SCNetworkServiceRef's */
+__SCNetworkServiceCopyAllEnabled(SCPreferencesRef prefs)
+{
+ CFMutableArrayRef array = NULL;
+ CFIndex i_sets;
+ CFIndex n_sets;
+ CFArrayRef sets;
+
+ sets = SCNetworkSetCopyAll(prefs);
+ if (sets == NULL) {
+ return NULL;
+ }
+
+ n_sets = CFArrayGetCount(sets);
+ for (i_sets = 0; i_sets < n_sets; i_sets++) {
+ CFIndex i_services;
+ CFIndex n_services;
+ CFArrayRef services;
+ SCNetworkSetRef set;
+
+ set = CFArrayGetValueAtIndex(sets, i_sets);
+ services = SCNetworkSetCopyServices(set);
+ if (services == NULL) {
+ continue;
+ }
+
+ n_services = CFArrayGetCount(services);
+ for (i_services = 0; i_services < n_services; i_services++) {
+ SCNetworkServiceRef service;
+
+ service = CFArrayGetValueAtIndex(services, i_services);
+ if (!SCNetworkServiceGetEnabled(service)) {
+ // if not enabled
+ continue;
+ }
+
+ if ((array == NULL) ||
+ !CFArrayContainsValue(array,
+ CFRangeMake(0, CFArrayGetCount(array)),
+ service)) {
+ if (array == NULL) {
+ array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+ CFArrayAppendValue(array, service);
+ }
+ }
+ CFRelease(services);
+ }
+ CFRelease(sets);
+
+ return array;
+}
+
+
+__private_extern__ Boolean
+__SCNetworkServiceExistsForInterface(CFArrayRef services, SCNetworkInterfaceRef interface)
+{
+ CFIndex i;
+ CFIndex n;
+
+ n = isA_CFArray(services) ? CFArrayGetCount(services) : 0;
+ for (i = 0; i < n; i++) {
+ SCNetworkServiceRef service;
+ SCNetworkInterfaceRef service_interface;
+
+ service = CFArrayGetValueAtIndex(services, i);
+
+ service_interface = SCNetworkServiceGetInterface(service);
+ while (service_interface != NULL) {
+ if (CFEqual(interface, service_interface)) {
+ return TRUE;
+ }
+
+ service_interface = SCNetworkInterfaceGetInterface(service_interface);
+ }
+ }
+
+ return FALSE;
+}
+
+
+static void
+mergeDict(const void *key, const void *value, void *context)
+{
+ CFMutableDictionaryRef newDict = (CFMutableDictionaryRef)context;
+
+ CFDictionarySetValue(newDict, key, value);
+ return;
+}
+
+
+static CF_RETURNS_RETAINED CFDictionaryRef
+_protocolTemplate(SCNetworkServiceRef service, CFStringRef protocolType)
+{
+ SCNetworkInterfaceRef interface;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ CFDictionaryRef template = NULL;
+
+ interface = servicePrivate->interface;
+ if (interface != NULL) {
+ SCNetworkInterfaceRef childInterface;
+ CFStringRef childInterfaceType = NULL;
+ CFStringRef interfaceType;
+
+ // get the template
+ interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface);
+ childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface);
+ if (childInterface != NULL) {
+ childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
+ }
+
+ template = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType);
+ if (template != NULL) {
+ CFDictionaryRef overrides;
+
+ // move to the interface at the lowest layer
+ while (childInterface != NULL) {
+ interface = childInterface;
+ childInterface = SCNetworkInterfaceGetInterface(interface);
+ }
+
+ overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, protocolType);
+ if (isA_CFDictionary(overrides)) {
+ CFMutableDictionaryRef newTemplate;
+
+ newTemplate = CFDictionaryCreateMutableCopy(NULL, 0, template);
+ CFDictionaryApplyFunction(overrides, mergeDict, newTemplate);
+ CFRelease(template);
+ template = newTemplate;
+ }
+ }
+ }
+
+ if (template == NULL) {
+ template = CFDictionaryCreate(NULL,
+ NULL,
+ NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+
+ return template;
+}
+
+
Boolean
SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protocolType)
{
CFDictionaryRef entity;
+ Boolean newEnabled;
CFDictionaryRef newEntity = NULL;
Boolean ok = FALSE;
CFStringRef path;
+ SCNetworkProtocolRef protocol = NULL;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
if (!__SCNetworkProtocolIsValidType(protocolType)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
+ if (!__SCNetworkServiceExists(service)) {
+ SC_log(LOG_ERR, "SCNetworkServiceAddProtocolType() w/removed service\n service = %@\n protocol = %@",
+ service,
+ protocolType);
+ _SC_crash_once("SCNetworkServiceAddProtocolType() w/removed service", NULL, NULL);
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
servicePrivate->serviceID, // service
protocolType); // entity
goto done;
}
- if (servicePrivate->interface != NULL) {
- SCNetworkInterfaceRef childInterface;
- CFStringRef childInterfaceType = NULL;
- CFStringRef interfaceType;
+ newEntity = CFDictionaryCreate(NULL,
+ NULL,
+ NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
+ CFRelease(newEntity);
+ newEntity = NULL;
+ if (!ok) {
+ goto done;
+ }
- interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface);
- childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface);
- if (childInterface != NULL) {
- childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
- }
+ protocol = SCNetworkServiceCopyProtocol(service, protocolType);
+ assert(protocol != NULL);
- newEntity = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType);
+ newEntity = _protocolTemplate(service, protocolType);
+ assert(newEntity != NULL);
+
+ ok = SCNetworkProtocolSetConfiguration(protocol, newEntity);
+ if (!ok) {
+ // could not set default configuration
+ goto done;
}
- if (newEntity == NULL) {
- newEntity = CFDictionaryCreate(NULL,
- NULL,
- NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
+ newEnabled = !CFDictionaryContainsKey(newEntity, kSCResvInactive);
+ ok = SCNetworkProtocolSetEnabled(protocol, newEnabled);
+ if (!ok) {
+ // could not enable/disable protocol
+ goto done;
}
- ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
- CFRelease(newEntity);
-
done :
+ if (newEntity != NULL) CFRelease(newEntity);
+ if (protocol != NULL) CFRelease(protocol);
+
+ if (ok) {
+ SC_log(LOG_DEBUG, "SCNetworkServiceAddProtocolType(): %@, %@", service, protocolType);
+ }
+
CFRelease(path);
return ok;
}
SCNetworkServicePrivateRef servicePrivate;
if (!isA_CFDictionary(vals[i])) {
- SCLog(TRUE,
- LOG_INFO,
- CFSTR("SCNetworkServiceCopyAll(): error w/service \"%@\"\n"),
- keys[i]);
+ SC_log(LOG_INFO, "error w/service \"%@\"", keys[i]);
continue;
}
entity = CFDictionaryGetValue(vals[i], kSCEntNetInterface);
if (!isA_CFDictionary(entity)) {
// if no "interface"
- SCLog(TRUE,
- LOG_INFO,
- CFSTR("SCNetworkServiceCopyAll(): no \"%@\" entity for service \"%@\"\n"),
- kSCEntNetInterface,
- keys[i]);
+ SC_log(LOG_INFO, "no \"%@\" entity for service \"%@\"",
+ kSCEntNetInterface,
+ keys[i]);
+ continue;
+ }
+
+ if (__SCNetworkInterfaceEntityIsPPTP(entity)) {
+ SC_log(LOG_INFO, "PPTP services are no longer supported");
continue;
}
- servicePrivate = __SCNetworkServiceCreatePrivate(NULL, keys[i], NULL, prefs);
+ servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, keys[i], NULL);
+ assert(servicePrivate != NULL);
CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate);
CFRelease(servicePrivate);
}
}
+__private_extern__
+CFArrayRef /* of SCNetworkInterfaceRef's */
+__SCNetworkServiceCopyAllInterfaces(SCPreferencesRef prefs)
+{
+ CFMutableArrayRef interfaces = NULL;
+ CFArrayRef services = NULL;
+ CFIndex servicesCount = 0;
+ SCNetworkServiceRef service = NULL;
+ SCNetworkInterfaceRef interface = NULL;
+
+ services = SCNetworkServiceCopyAll(prefs);
+ if (services == NULL) {
+ goto done;
+ }
+
+ servicesCount = CFArrayGetCount(services);
+ if (servicesCount == 0) {
+ goto done;
+ }
+
+ interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ for (CFIndex idx = 0; idx < servicesCount; idx++) {
+ service = CFArrayGetValueAtIndex(services, idx);
+ interface = SCNetworkServiceGetInterface(service);
+
+ if (isA_SCNetworkInterface(interface) == NULL) {
+ continue;
+ }
+ CFArrayAppendValue(interfaces, interface);
+ }
+
+ if (CFArrayGetCount(interfaces) == 0) {
+ // Do not return an empty array
+ CFRelease(interfaces);
+ interfaces = NULL;
+ }
+
+ done:
+
+ if (services != NULL) {
+ CFRelease(services);
+ }
+ return interfaces;
+}
+
+
/*
- * build a list of all of a servives entity types that are associated
+ * build a list of all of a services entity types that are associated
* with the services interface. The list will include :
*
* - entity types associated with the interface type (Ethernet, FireWire, PPP, ...)
CFStringRef entities[] = { kSCPropNetInterfaceType,
kSCPropNetInterfaceSubType,
kSCPropNetInterfaceHardware };
- int i;
// include the "Interface" entity itself
CFSetAddValue(interface_entity_types, kSCEntNetInterface);
// include the entities associated with the interface
- for (i = 0; i < sizeof(entities)/sizeof(entities[0]); i++) {
+ for (size_t i = 0; i < sizeof(entities)/sizeof(entities[0]); i++) {
CFStringRef entity;
entity = CFDictionaryGetValue(interface, entities[i]);
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate;
+ if (!isA_CFString(serviceID)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
serviceID, // service
kSCEntNetInterface); // entity
return NULL;
}
- servicePrivate = __SCNetworkServiceCreatePrivate(NULL, serviceID, NULL, prefs);
+ if (__SCNetworkInterfaceEntityIsPPTP(entity)) {
+ SC_log(LOG_INFO, "PPTP services are no longer supported");
+ _SCErrorSet(kSCStatusNoKey);
+ return NULL;
+ }
+
+ servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
+ return (SCNetworkServiceRef)servicePrivate;
+}
+
+
+SCNetworkServiceRef
+_SCNetworkServiceCopyActive(SCDynamicStoreRef store, CFStringRef serviceID)
+{
+ SCNetworkServicePrivateRef servicePrivate;
+
+ if (!isA_CFString(serviceID)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ servicePrivate = __SCNetworkServiceCreatePrivate(NULL, NULL, serviceID, NULL);
+ assert(servicePrivate != NULL);
+ if (store != NULL) {
+ servicePrivate->store = CFRetain(store);
+ }
return (SCNetworkServiceRef)servicePrivate;
}
SCNetworkProtocolPrivateRef protocolPrivate = NULL;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if (!isA_CFString(protocolType)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
servicePrivate->serviceID, // service
NULL); // entity
protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path);
CFRelease(path);
- if ((protocols != NULL) && !isA_CFDictionary(protocols)) {
+ if (!isA_CFDictionary(protocols)) {
// if corrupt prefs
_SCErrorSet(kSCStatusFailed);
return NULL;
CFDictionaryRef protocols;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
servicePrivate->serviceID, // service
NULL); // entity
CFRelease(path);
if (!isA_CFDictionary(protocols)) {
+ // if corrupt prefs
+ _SCErrorSet(kSCStatusFailed);
return NULL;
}
{
CFArrayRef components;
CFArrayRef interface_config;
+ CFStringRef interface_name;
SCNetworkInterfaceRef newInterface;
CFStringRef path;
CFStringRef prefix;
SCNetworkServicePrivateRef servicePrivate;
CFArrayRef supported_protocols;
+ if (!isA_SCNetworkInterface(interface)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
// only allow network interfaces which support one or more protocols
// to be added to a service. The one exception is that we allow
// third-party interface types to be configured.
interface_type = SCNetworkInterfaceGetInterfaceType(interface);
if (CFStringFind(interface_type, CFSTR("."), 0).location == kCFNotFound) {
+ _SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
}
+ // do not allow creation of a network service if the interface is a
+ // member of a bond or bridge
+ if (__SCNetworkInterfaceIsMember(prefs, interface)) {
+ _SCErrorSet(kSCStatusKeyExists);
+ return NULL;
+ }
+
// establish the service
prefix = SCPreferencesPathKeyCreateNetworkServices(NULL);
- path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
+ path = __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(prefs, prefix);
+ if (path == NULL) path = SCPreferencesPathCreateUniqueChild(prefs, prefix);
CFRelease(prefix);
if (path == NULL) {
return NULL;
CFRelease(path);
serviceID = CFArrayGetValueAtIndex(components, 2);
- servicePrivate = __SCNetworkServiceCreatePrivate(NULL, serviceID, NULL, prefs);
+ servicePrivate = __SCNetworkServiceCreatePrivate(NULL, prefs, serviceID, NULL);
CFRelease(components);
// duplicate the interface and associate the copy with the new service
newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,
interface,
- (SCNetworkServiceRef)servicePrivate);
+ prefs,
+ serviceID);
servicePrivate->interface = newInterface;
// establish "default" configuration(s) for the interface
config = __copyInterfaceTemplate(interfaceType, childInterfaceType);
if (config != NULL) {
- if (CFEqual(interfaceType, kSCNetworkInterfaceTypeModem) ||
- CFEqual(interfaceType, kSCNetworkInterfaceTypeSerial)) {
- CFStringRef modemCCL;
-
- modemCCL = __SCNetworkInterfaceGetModemCCL(interface);
- if (modemCCL == NULL) {
- if (__SCNetworkInterfaceIsModemV92(interface)) {
- modemCCL = CFSTR("Apple Internal 56K Modem (v.92)");
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypeBluetooth) ||
+ CFEqual(interfaceType, kSCNetworkInterfaceTypeIrDA ) ||
+ CFEqual(interfaceType, kSCNetworkInterfaceTypeModem ) ||
+ CFEqual(interfaceType, kSCNetworkInterfaceTypeSerial ) ||
+ CFEqual(interfaceType, kSCNetworkInterfaceTypeWWAN )) {
+ CFDictionaryRef overrides;
+
+ overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypeModem);
+
+ // a ConnectionScript (and related keys) from the interface
+ // should trump the settings from the configuration template.
+ if (isA_CFDictionary(overrides)) {
+ CFMutableDictionaryRef newConfig;
+
+ newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
+ if (CFDictionaryContainsKey(overrides, kSCPropNetModemConnectionScript)) {
+ CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionPersonality);
+ CFDictionaryRemoveValue(newConfig, kSCPropNetModemConnectionScript);
+ CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceVendor);
+ CFDictionaryRemoveValue(newConfig, kSCPropNetModemDeviceModel);
}
+ CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
+ CFRelease(config);
+ config = newConfig;
}
+ } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP) ||
+ CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
+ CFDictionaryRef overrides;
- if (modemCCL != NULL) {
+ overrides = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCNetworkInterfaceTypePPP);
+ if (isA_CFDictionary(overrides)) {
CFMutableDictionaryRef newConfig;
newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
- CFDictionarySetValue(newConfig, kSCPropNetModemConnectionScript, modemCCL);
-
+ CFDictionaryApplyFunction(overrides, mergeDict, newConfig);
CFRelease(config);
config = newConfig;
}
}
- (void) __SCNetworkInterfaceSetConfiguration(interface, config, TRUE);
+ if (!__SCNetworkInterfaceSetConfiguration(interface, NULL, config, TRUE)) {
+ SC_log(LOG_INFO, "__SCNetworkInterfaceSetConfiguration failed(), interface=%@, type=NULL",
+ interface);
+ }
CFRelease(config);
}
}
servicePrivate->interface);
// push the [deep] interface configuration into the service.
- interface_config = __SCNetworkInterfaceCopyDeepConfiguration(servicePrivate->interface);
- __SCNetworkInterfaceSetDeepConfiguration(servicePrivate->interface, interface_config);
+ interface_config = __SCNetworkInterfaceCopyDeepConfiguration(NULL, servicePrivate->interface);
+ __SCNetworkInterfaceSetDeepConfiguration(NULL, servicePrivate->interface, interface_config);
+ if (interface_config != NULL) CFRelease(interface_config);
+
+ // set the service name to match that of the associated interface
+ //
+ // Note: It might seem a bit odd to call SCNetworkServiceGetName
+ // followed by an immediate call to SCNetworkServiceSetName. The
+ // trick here is that if no name has previously been set, the
+ // "get" function will return the name of the associated interface.
+ //
+ // ... and we "set" a name to ensure that applications that do
+ // not use the APIs will still find a UserDefinedName property
+ // in the SCDynamicStore.
+ //
+ interface_name = SCNetworkServiceGetName((SCNetworkServiceRef)servicePrivate);
+ if (interface_name != NULL) {
+ (void) SCNetworkServiceSetName((SCNetworkServiceRef)servicePrivate,
+ interface_name);
+ }
+
+ SC_log(LOG_DEBUG, "SCNetworkServiceCreate(): %@", servicePrivate);
return (SCNetworkServiceRef)servicePrivate;
}
+Boolean
+SCNetworkServiceEstablishDefaultConfiguration(SCNetworkServiceRef service)
+{
+ CFIndex i;
+ SCNetworkInterfaceRef interface;
+ CFIndex n;
+ Boolean ok;
+ CFArrayRef protocolTypes;
+ CFStringRef rankStr;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ interface = SCNetworkServiceGetInterface(service);
+ if (interface == NULL) {
+ return FALSE;
+ }
+
+ protocolTypes = SCNetworkInterfaceGetSupportedProtocolTypes(interface);
+ n = (protocolTypes != NULL) ? CFArrayGetCount(protocolTypes) : 0;
+ for (i = 0; i < n; i++) {
+ CFStringRef protocolType;
+
+ protocolType = CFArrayGetValueAtIndex(protocolTypes, i);
+ ok = SCNetworkServiceAddProtocolType(service, protocolType);
+ if (!ok) {
+ SC_log(LOG_INFO,
+ "SCNetworkServiceEstablishDefaultConfiguration(): could not add protocol \"%@\"",
+ protocolType);
+ }
+ }
+
+ rankStr = __SCNetworkInterfaceGetTemplateOverrides(interface, kSCPropNetServicePrimaryRank);
+ if (isA_CFString(rankStr)) {
+ SCNetworkServicePrimaryRank rank;
+
+ ok = __str_to_rank(rankStr, &rank);
+ if (!ok) {
+ SC_log(LOG_INFO,
+ "SCNetworkServiceEstablishDefaultConfiguration(): unknown rank \"%@\"",
+ rankStr);
+ goto done;
+ }
+
+ ok = SCNetworkServiceSetPrimaryRank(service, rank);
+ if (!ok) {
+ SC_log(LOG_INFO,
+ "SCNetworkServiceEstablishDefaultConfiguration(): could not set rank \"%@\"",
+ rankStr);
+ goto done;
+ }
+ }
+
+ done :
+
+ return TRUE;
+}
+
+
Boolean
SCNetworkServiceGetEnabled(SCNetworkServiceRef service)
{
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
servicePrivate->serviceID, // service
NULL); // entity
{
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
if (servicePrivate->interface == NULL) {
CFDictionaryRef entity;
CFStringRef path;
CFRelease(path);
if (isA_CFDictionary(entity)) {
- servicePrivate->interface = __SCNetworkInterfaceCreateWithEntity(NULL, entity, service);
+ servicePrivate->interface = _SCNetworkInterfaceCreateWithEntity(NULL, entity, service);
}
}
SCNetworkServiceGetName(SCNetworkServiceRef service)
{
CFDictionaryRef entity;
- SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ SCNetworkInterfaceRef interface;
CFStringRef name = NULL;
CFStringRef path;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ Boolean useSystemInterfaces = TRUE;
+
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ if (servicePrivate->name != NULL) {
+ return servicePrivate->name;
+ }
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
servicePrivate->serviceID, // service
entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
CFRelease(path);
+ useSystemInterfaces = ((__SCPreferencesUsingDefaultPrefs(servicePrivate->prefs)) &&
+ !__SCPreferencesGetLimitSCNetworkConfiguration(servicePrivate->prefs));
+
if (isA_CFDictionary(entity)) {
name = CFDictionaryGetValue(entity, kSCPropUserDefinedName);
+ if (isA_CFString(name)) {
+ servicePrivate->name = CFRetain(name);
+ if (!useSystemInterfaces) {
+ return servicePrivate->name;
+ }
+ }
}
- return isA_CFString(name) ? name : NULL;
-}
+ interface = SCNetworkServiceGetInterface(service);
+ while (interface != NULL) {
+ SCNetworkInterfaceRef childInterface;
+ CFStringRef interfaceType;
+ interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
+ break;
+ }
-CFStringRef
-SCNetworkServiceGetServiceID(SCNetworkServiceRef service)
-{
- SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ childInterface = SCNetworkInterfaceGetInterface(interface);
+ if ((childInterface == NULL) ||
+ CFEqual(childInterface, kSCNetworkInterfaceIPv4)) {
+ break;
+ }
+
+ interface = childInterface;
+ }
+
+ if (interface != NULL) {
+ int i;
+ CFStringRef interface_name = NULL;
+ CFStringRef suffix = NULL;
+
+ //
+ // check if the [stored] service name matches the non-localized interface
+ // name. If so, return the localized name.
+ //
+ // Also, the older "Built-in XXX" interface names are too long for the
+ // current UI. If we find that the [stored] service name matches the older
+ // name, return the newer (and shorter) localized name.
+ //
+ // Note: the user/admin will no longer be able to set the service name
+ // to "Built-in Ethernet".
+ //
+ for (i = 0; i < 3; i++) {
+ if (servicePrivate->name == NULL) {
+ // if no [stored] service name to compare
+ break;
+ }
+
+ switch (i) {
+ case 0 :
+ // compare the non-localized interface name
+ interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
+ if (interface_name != NULL) {
+ CFRetain(interface_name);
+ }
+ break;
+#if !TARGET_OS_IPHONE
+ case 1 :
+ // compare the older "Built-in XXX" localized name
+ interface_name = __SCNetworkInterfaceCopyXLocalizedDisplayName(interface);
+ break;
+ case 2 :
+ // compare the older "Built-in XXX" non-localized name
+ interface_name = __SCNetworkInterfaceCopyXNonLocalizedDisplayName(interface);
+ break;
+#else // !TARGET_OS_IPHONE
+ default :
+ continue;
+#endif // !TARGET_OS_IPHONE
+ }
+
+ if (interface_name != NULL) {
+ Boolean match = FALSE;
+
+ if (CFEqual(name, interface_name)) {
+ // if service name matches the OLD localized
+ // interface name
+ match = TRUE;
+ } else if (CFStringHasPrefix(name, interface_name)) {
+ CFIndex prefixLen = CFStringGetLength(interface_name);
+ CFIndex suffixLen = CFStringGetLength(name);
+
+ suffix = CFStringCreateWithSubstring(NULL,
+ name,
+ CFRangeMake(prefixLen, suffixLen - prefixLen));
+ match = TRUE;
+ }
+ CFRelease(interface_name);
+
+ if (match) {
+ CFRelease(servicePrivate->name);
+ servicePrivate->name = NULL;
+ break;
+ }
+ }
+ }
+
+ //
+ // if the service name has not been set, use the localized interface name
+ //
+ if (servicePrivate->name == NULL) {
+ interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
+ if (interface_name != NULL) {
+ if (suffix != NULL) {
+ servicePrivate->name = CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@%@"),
+ interface_name,
+ suffix);
+ } else {
+ servicePrivate->name = CFRetain(interface_name);
+ }
+ }
+ }
+ if (suffix != NULL) CFRelease(suffix);
+ }
+
+ return servicePrivate->name;
+}
+
+
+CFStringRef
+SCNetworkServiceGetServiceID(SCNetworkServiceRef service)
+{
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+
+ if (!isA_SCNetworkService(service)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
return servicePrivate->serviceID;
}
SCNetworkServiceRemove(SCNetworkServiceRef service)
{
Boolean ok = FALSE;
+ CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
CFArrayRef sets;
- CFStringRef path;
+
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (!__SCNetworkServiceExists(service)) {
+ SC_log(LOG_ERR, "SCNetworkServiceRemove() w/removed service\n service = %@", service);
+ _SC_crash_once("SCNetworkServiceRemove() w/removed service", NULL, NULL);
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
// remove service from all sets
sets = SCNetworkSetCopyAll(servicePrivate->prefs);
if (sets != NULL) {
- CFIndex i;
CFIndex n;
n = CFArrayGetCount(sets);
- for (i = 0; i < n; i++) {
+ for (CFIndex i = 0; i < n; i++) {
SCNetworkSetRef set;
set = CFArrayGetValueAtIndex(sets, i);
ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
CFRelease(path);
+ if (ok) {
+ SC_log(LOG_DEBUG, "SCNetworkServiceRemove(): %@", service);
+ }
+
return ok;
}
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (!__SCNetworkServiceExists(service)) {
+ SC_log(LOG_ERR, "SCNetworkServiceRemoveProtocolType() w/removed service\n service = %@\n protocol = %@",
+ service,
+ protocolType);
+ _SC_crash_once("SCNetworkServiceRemoveProtocolType() w/removed service", NULL, NULL);
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (!__SCNetworkProtocolIsValidType(protocolType)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
servicePrivate->serviceID, // service
protocolType); // entity
done :
+ if (ok) {
+ SC_log(LOG_DEBUG, "SCNetworkServiceRemoveProtocolType(): %@, %@", service, protocolType);
+ }
+
CFRelease(path);
return ok;
}
CFStringRef path;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (!__SCNetworkServiceExists(service)) {
+ SC_log(LOG_ERR, "SCNetworkServiceSetEnabled() w/removed service\n service = %@", service);
+ _SC_crash_once("SCNetworkProtocolSetEnabled() w/removed service", NULL, NULL);
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ // make sure that we do not enable a network service if the
+ // associated interface is a member of a bond or bridge.
+ if (enabled) {
+ SCNetworkInterfaceRef interface;
+
+ interface = SCNetworkServiceGetInterface(service);
+ if ((interface != NULL) &&
+ __SCNetworkInterfaceIsMember(servicePrivate->prefs, interface)) {
+ _SCErrorSet(kSCStatusKeyExists);
+ return FALSE;
+ }
+ }
+
path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
servicePrivate->serviceID, // service
NULL); // entity
ok = __setPrefsEnabled(servicePrivate->prefs, path, enabled);
CFRelease(path);
+ if (ok) {
+ SC_log(LOG_DEBUG, "SCNetworkServiceSetEnabled(): %@ -> %s",
+ service,
+ enabled ? "Enabled" : "Disabled");
+ }
+
return ok;
}
CFDictionaryRef entity;
Boolean ok = FALSE;
CFStringRef path;
+ CFStringRef saveName = NULL;
SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (!__SCNetworkServiceExists(service)) {
+ SC_log(LOG_ERR, "SCNetworkServiceSetName() w/removed service\n service = %@\n name = %@",
+ service,
+ name != NULL ? name : CFSTR("<NULL>"));
+ _SC_crash_once("SCNetworkServiceSetName() w/removed service", NULL, NULL);
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (name != NULL) {
+ if (!isA_CFString(name)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+ saveName = CFRetain(name);
+ }
+
+ if (name != NULL) {
+ SCNetworkInterfaceRef interface;
+
+ interface = SCNetworkServiceGetInterface(service);
+ while (interface != NULL) {
+ SCNetworkInterfaceRef childInterface;
+
+ childInterface = SCNetworkInterfaceGetInterface(interface);
+ if (childInterface == NULL) {
+ break;
+ }
+
+ interface = childInterface;
+ }
+
+ if (interface != NULL) {
+ CFStringRef interface_name;
+
+ interface_name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
+ if (interface_name != NULL) {
+ if (CFEqual(name, interface_name)) {
+ // if service name matches the localized interface name
+ // then store the non-localized name.
+ interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
+ if (interface_name != NULL) {
+ CFRelease(saveName);
+ saveName = CFRetain(interface_name);
+ }
+ } else if (CFStringHasPrefix(name, interface_name)) {
+ CFIndex prefixLen = CFStringGetLength(interface_name);
+ CFStringRef suffix;
+ CFIndex suffixLen = CFStringGetLength(name);
+
+ // if service name matches the localized interface name plus
+ // a few extra characters) then store the non-localized name with
+ // the same suffix.
+ suffix = CFStringCreateWithSubstring(NULL,
+ name,
+ CFRangeMake(prefixLen, suffixLen - prefixLen));
+ interface_name = __SCNetworkInterfaceGetNonLocalizedDisplayName(interface);
+ if (interface_name != NULL) {
+ CFRelease(saveName);
+ saveName = CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@%@"),
+ interface_name,
+ suffix);
+ }
+ CFRelease(suffix);
+ }
+ }
+ }
+ }
+
#define PREVENT_DUPLICATE_SERVICE_NAMES
#ifdef PREVENT_DUPLICATE_SERVICE_NAMES
- if (isA_CFString(name)) {
+ if (name != NULL) {
CFArrayRef sets;
// ensure that each service is uniquely named within its sets
* the "name" is not unique.
*/
CFRelease(sets);
+ if (saveName != NULL) CFRelease(saveName);
_SCErrorSet(kSCStatusKeyExists);
return FALSE;
}
servicePrivate->serviceID, // service
NULL); // entity
entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
- if ((entity == NULL) && (name != NULL)) {
- entity = CFDictionaryCreate(NULL,
- NULL,
- NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- }
- if (isA_CFDictionary(entity)) {
+ if (isA_CFDictionary(entity) ||
+ ((entity == NULL) && (name != NULL))) {
CFMutableDictionaryRef newEntity;
- newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
- if (isA_CFString(name)) {
- CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name);
+ if (entity != NULL) {
+ newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
+ } else {
+ newEntity = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ if (saveName != NULL) {
+ CFDictionarySetValue(newEntity, kSCPropUserDefinedName, saveName);
} else {
CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName);
}
CFRelease(newEntity);
}
CFRelease(path);
+ if (saveName != NULL) CFRelease(saveName);
+
+ if (servicePrivate->name != NULL) CFRelease(servicePrivate->name);
+ if (name != NULL) CFRetain(name);
+ servicePrivate->name = name;
+
+ if (ok) {
+ SC_log(LOG_DEBUG, "SCNetworkServiceSetName(): %@", service);
+ }
+
+ return ok;
+}
+
+
+#pragma mark -
+#pragma mark SCNetworkService SPIs
+
+
+__private_extern__
+Boolean
+__SCNetworkServiceExists(SCNetworkServiceRef service)
+{
+ CFDictionaryRef entity;
+ CFStringRef path;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+
+ if (servicePrivate->prefs == NULL) {
+ // if no prefs
+ return FALSE;
+ }
+
+ path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
+ servicePrivate->serviceID, // service
+ kSCEntNetInterface); // entity
+ entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
+ CFRelease(path);
+
+ if (!isA_CFDictionary(entity)) {
+ // a "service" must have an "interface"
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+SCNetworkServicePrimaryRank
+SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service)
+{
+ CFDictionaryRef entity;
+ Boolean ok = TRUE;
+ CFStringRef path;
+ SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault;
+ CFStringRef rankStr = NULL;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+
+ if (!isA_SCNetworkService(service)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return rank;
+ }
+
+ if (servicePrivate->prefs != NULL) {
+ path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
+ servicePrivate->serviceID,
+ NULL);
+ entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
+ CFRelease(path);
+ if (isA_CFDictionary(entity)) {
+ rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
+ ok = __str_to_rank(rankStr, &rank);
+ }
+ } else if (servicePrivate->store != NULL) {
+ path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+ kSCDynamicStoreDomainState,
+ servicePrivate->serviceID,
+ NULL);
+ entity = SCDynamicStoreCopyValue(servicePrivate->store, path);
+ CFRelease(path);
+ if (entity != NULL) {
+ if (isA_CFDictionary(entity)) {
+ rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank);
+ ok = __str_to_rank(rankStr, &rank);
+ }
+ CFRelease(entity);
+ }
+ } else {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return rank;
+ }
+
+ if (!ok) {
+ rank = kSCNetworkServicePrimaryRankDefault;
+ _SCErrorSet(kSCStatusInvalidArgument);
+ } else if (rank == kSCNetworkServicePrimaryRankDefault) {
+ _SCErrorSet(kSCStatusOK);
+ }
+
+ return rank;
+}
+
+
+Boolean
+SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service,
+ SCNetworkServicePrimaryRank newRank)
+{
+ Boolean ok;
+ CFDictionaryRef entity;
+ CFMutableDictionaryRef newEntity;
+ CFStringRef path = NULL;
+ CFStringRef rankStr = NULL;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+
+ if (!isA_SCNetworkService(service)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if ((servicePrivate->prefs != NULL) && !__SCNetworkServiceExists(service)) {
+ SC_log(LOG_ERR, "SCNetworkServiceSetPrimaryRank() w/removed\n service = %@", service);
+ _SC_crash_once("SCNetworkServiceSetPrimaryRank() w/removed service", NULL, NULL);
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ ok = __rank_to_str(newRank, &rankStr);
+ if (!ok) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (servicePrivate->prefs != NULL) {
+ switch (newRank) {
+ case kSCNetworkServicePrimaryRankDefault:
+ case kSCNetworkServicePrimaryRankNever:
+ case kSCNetworkServicePrimaryRankScoped:
+ path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
+ servicePrivate->serviceID,
+ NULL);
+ entity = SCPreferencesPathGetValue(servicePrivate->prefs, path);
+ if (entity != NULL) {
+ if (!isA_CFDictionary(entity)) {
+ // if corrupt prefs
+ _SCErrorSet(kSCStatusFailed);
+ goto done;
+ }
+ newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
+ } else {
+ newEntity = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ if (rankStr != NULL) {
+ CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
+ } else {
+ CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
+ }
+ if (CFDictionaryGetCount(newEntity) > 0) {
+ ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity);
+ } else {
+ ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path);
+ }
+ CFRelease(newEntity);
+ if (!ok) {
+ goto done;
+ }
+ break;
+ default:
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+ } else if (servicePrivate->store != NULL) {
+ path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
+ kSCDynamicStoreDomainState,
+ servicePrivate->serviceID,
+ NULL);
+ entity = SCDynamicStoreCopyValue(servicePrivate->store, path);
+ if (entity != NULL) {
+ if (!isA_CFDictionary(entity)) {
+ // if corrupt prefs
+ CFRelease(entity);
+ _SCErrorSet(kSCStatusFailed);
+ goto done;
+ }
+ newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
+ CFRelease(entity);
+ } else {
+ newEntity = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ if (rankStr != NULL) {
+ CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr);
+ } else {
+ CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank);
+ }
+ if (CFDictionaryGetCount(newEntity) > 0) {
+ ok = SCDynamicStoreSetValue(servicePrivate->store, path, newEntity);
+ } else {
+ ok = SCDynamicStoreRemoveValue(servicePrivate->store, path);
+ }
+ CFRelease(newEntity);
+ if (!ok) {
+ goto done;
+ }
+ } else {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ done :
+
+ if (path != NULL) CFRelease(path);
+ return ok;
+}
+
+
+Boolean
+_SCNetworkServiceIsVPN(SCNetworkServiceRef service)
+{
+ SCNetworkInterfaceRef interface;
+ CFStringRef interfaceType;
+
+ interface = SCNetworkServiceGetInterface(service);
+ if (interface == NULL) {
+ return FALSE;
+ }
+
+ interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
+ interface = SCNetworkInterfaceGetInterface(interface);
+ if (interface == NULL) {
+ return FALSE;
+ }
+
+ interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
+ return TRUE;
+ }
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated"
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPTP)) {
+ return TRUE;
+ }
+#pragma GCC diagnostic pop
+ } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeVPN)) {
+ return TRUE;
+ } else if (CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+Boolean
+SCNetworkServiceSetExternalID(SCNetworkServiceRef service, CFStringRef identifierDomain, CFStringRef identifier)
+{
+ CFStringRef prefs_path;
+ CFDictionaryRef service_dictionary;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+ Boolean success = FALSE;
+ CFStringRef prefixed_domain;
+
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL) || !isA_CFString(identifierDomain)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (!__SCNetworkServiceExists(service)) {
+ SC_log(LOG_ERR, "SCNetworkServiceSetExternalID() w/removed\n service = %@\n id = %@",
+ service,
+ identifier);
+ _SC_crash_once("SCNetworkServiceSetExternalID() w/removed service", NULL, NULL);
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (identifier != NULL && !isA_CFString(identifier)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ prefixed_domain = CFStringCreateWithFormat(NULL, 0, CFSTR("%s%@"), EXTERNAL_ID_DOMAIN_PREFIX, identifierDomain);
+
+ prefs_path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
+ servicePrivate->serviceID,
+ NULL);
+
+ service_dictionary = SCPreferencesPathGetValue(servicePrivate->prefs, prefs_path);
+ if (isA_CFDictionary(service_dictionary) || ((service_dictionary == NULL) && (identifier != NULL))) {
+ CFMutableDictionaryRef new_service_dictionary;
+
+ if (service_dictionary != NULL) {
+ new_service_dictionary = CFDictionaryCreateMutableCopy(NULL, 0, service_dictionary);
+ } else {
+ new_service_dictionary = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+
+ if (identifier != NULL) {
+ CFDictionarySetValue(new_service_dictionary, prefixed_domain, identifier);
+ } else {
+ CFDictionaryRemoveValue(new_service_dictionary, prefixed_domain);
+ }
+ success = SCPreferencesPathSetValue(servicePrivate->prefs, prefs_path, new_service_dictionary);
+ CFRelease(new_service_dictionary);
+ }
+ CFRelease(prefs_path);
+
+ if (identifier != NULL) {
+ if (servicePrivate->externalIDs == NULL) {
+ servicePrivate->externalIDs = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(servicePrivate->externalIDs, prefixed_domain, identifier);
+ } else {
+ if (servicePrivate->externalIDs != NULL) {
+ CFDictionaryRemoveValue(servicePrivate->externalIDs, prefixed_domain);
+ }
+ }
+
+ CFRelease(prefixed_domain);
+
+ if (!success) {
+ _SCErrorSet(kSCStatusFailed);
+ }
+
+ return success;
+}
+
+
+CFStringRef
+SCNetworkServiceCopyExternalID(SCNetworkServiceRef service, CFStringRef identifierDomain)
+{
+ CFStringRef identifier = NULL;
+ CFStringRef prefixed_domain;
+ SCNetworkServicePrivateRef service_private = (SCNetworkServicePrivateRef)service;
+
+ if (!isA_SCNetworkService(service) || (service_private->prefs == NULL) || !isA_CFString(identifierDomain)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return NULL;
+ }
+
+ prefixed_domain = CFStringCreateWithFormat(NULL, 0, CFSTR("%s%@"), EXTERNAL_ID_DOMAIN_PREFIX, identifierDomain);
+
+ if (service_private->externalIDs != NULL) {
+ identifier = CFDictionaryGetValue(service_private->externalIDs, prefixed_domain);
+ if (identifier != NULL) {
+ CFRetain(identifier);
+ }
+ }
+
+ if (identifier == NULL) {
+ CFStringRef prefs_path;
+ CFDictionaryRef service_dictionary;
+
+ prefs_path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL,
+ service_private->serviceID,
+ NULL);
+
+ service_dictionary = SCPreferencesPathGetValue(service_private->prefs, prefs_path);
+ if (isA_CFDictionary(service_dictionary)) {
+ identifier = CFDictionaryGetValue(service_dictionary, prefixed_domain);
+ if (identifier != NULL) {
+ CFRetain(identifier);
+ if (service_private->externalIDs == NULL) {
+ service_private->externalIDs = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(service_private->externalIDs, prefixed_domain, identifier);
+ }
+ }
+ CFRelease(prefs_path);
+ }
+
+ CFRelease(prefixed_domain);
+
+ if (identifier == NULL) {
+ _SCErrorSet(kSCStatusNoKey);
+ }
+
+ return identifier;
+}
+
+
+typedef struct {
+ CFStringRef oldServiceID;
+ CFStringRef newServiceID;
+} serviceContext, *serviceContextRef;
+
+
+static void
+replaceServiceID(const void *value, void *context)
+{
+ CFStringRef link = NULL;
+ CFStringRef oldLink;
+ CFMutableArrayRef newServiceOrder;
+ CFStringRef path;
+ serviceContextRef service_context = (serviceContextRef)context;
+ CFArrayRef serviceOrder = NULL;
+ SCNetworkSetRef set = (SCNetworkSetRef)value;
+ SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
+
+ // update service order
+ serviceOrder = SCNetworkSetGetServiceOrder(set);
+ if ((isA_CFArray(serviceOrder) != NULL) &&
+ CFArrayContainsValue(serviceOrder,
+ CFRangeMake(0, CFArrayGetCount(serviceOrder)),
+ service_context->oldServiceID)) {
+ CFIndex count;
+ CFIndex serviceOrderIndex;
+
+ // replacing all instances of old service ID with new one
+ newServiceOrder = CFArrayCreateMutableCopy(NULL, 0, serviceOrder);
+ count = CFArrayGetCount(newServiceOrder);
+ for (serviceOrderIndex = 0; serviceOrderIndex < count; serviceOrderIndex++) {
+ CFStringRef serviceID;
+
+ serviceID = CFArrayGetValueAtIndex(newServiceOrder, serviceOrderIndex);
+ if (CFEqual(serviceID, service_context->oldServiceID)) {
+ CFArraySetValueAtIndex(newServiceOrder, serviceOrderIndex, service_context->newServiceID);
+ }
+ }
+ SCNetworkSetSetServiceOrder(set, newServiceOrder);
+ CFRelease(newServiceOrder);
+ }
+
+ // check if service with old serviceID is part of the set
+ path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator
+ setPrivate->setID, // set
+ service_context->oldServiceID, // service
+ NULL); // entity
+ oldLink = SCPreferencesPathGetLink(setPrivate->prefs, path);
+ if (oldLink == NULL) {
+ // don't make any changes if service with old serviceID is not found
+ goto done;
+ }
+
+ // remove link between "set" and old "service"
+ (void) SCPreferencesPathRemoveValue(setPrivate->prefs, path);
+ CFRelease(path);
+
+ // create the link between "set" and the "service"
+ path = SCPreferencesPathKeyCreateSetNetworkServiceEntity(NULL, // allocator
+ setPrivate->setID, // set
+ service_context->newServiceID, // service
+ NULL); // entity
+ link = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
+ service_context->newServiceID, // service
+ NULL); // entity
+ (void) SCPreferencesPathSetLink(setPrivate->prefs, path, link);
+
+ done:
+
+ if (path != NULL) {
+ CFRelease(path);
+ }
+ if (link != NULL) {
+ CFRelease(link);
+ }
+
+ return;
+}
+
+
+Boolean
+_SCNetworkServiceSetServiceID(SCNetworkServiceRef service, CFStringRef newServiceID)
+{
+ CFArrayRef allSets = NULL;
+ CFDictionaryRef entity;
+ CFStringRef newPath;
+ Boolean ok = FALSE;
+ CFStringRef oldPath = NULL;
+ serviceContext service_context;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+
+ if (!isA_SCNetworkService(service) || (servicePrivate->prefs == NULL)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (!isA_CFString(newServiceID)) {
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ if (CFEqual(newServiceID, servicePrivate->serviceID)) {
+ // no work needs to be done if new service ID is equal to current service ID
+ return TRUE;
+ }
+
+ if (!__SCNetworkServiceExists(service)) {
+ SC_log(LOG_ERR, "_SCNetworkServiceSetServiceID() w/removed service\n service = %@\n serviceID = %@",
+ service,
+ newServiceID);
+ _SC_crash_once("_SCNetworkServiceSetServiceID() w/removed service", NULL, NULL);
+ _SCErrorSet(kSCStatusInvalidArgument);
+ return FALSE;
+ }
+
+ newPath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
+ newServiceID, // service
+ NULL); // entity
+ entity = SCPreferencesPathGetValue(servicePrivate->prefs, newPath);
+ if (isA_CFDictionary(entity)) {
+ // if the new service already exists
+ _SCErrorSet(kSCStatusKeyExists);
+ goto done;
+ }
+
+ oldPath = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator
+ servicePrivate->serviceID, // service
+ NULL); // entity
+ entity = SCPreferencesPathGetValue(servicePrivate->prefs, oldPath);
+ if (!isA_CFDictionary(entity)) {
+ // if the service has already been removed
+ _SCErrorSet(kSCStatusNoKey);
+ goto done;
+ }
+
+ ok = SCPreferencesPathSetValue(servicePrivate->prefs, newPath, entity);
+ if (!ok) goto done;
+
+ ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, oldPath);
+ if (!ok) goto done;
+
+ allSets = SCNetworkSetCopyAll(servicePrivate->prefs);
+
+ service_context.newServiceID = newServiceID;
+ service_context.oldServiceID = servicePrivate->serviceID;
+
+ // find all sets w/oldServiceID and update
+ // ... and update the serviceOrder
+ CFArrayApplyFunction(allSets,
+ CFRangeMake(0, CFArrayGetCount(allSets)),
+ replaceServiceID,
+ &service_context);
+
+ if (servicePrivate->interface != NULL) {
+ SCNetworkInterfaceRef newInterface;
+
+ // duplicate the interface and associate the copy with the new service ID
+ newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL,
+ servicePrivate->interface,
+ servicePrivate->prefs,
+ newServiceID);
+ CFRelease(servicePrivate->interface);
+ servicePrivate->interface = newInterface;
+ }
+
+ SC_log(LOG_DEBUG, "_SCNetworkServiceSetServiceID(): %@ --> %@", service, newServiceID);
+
+ // replace serviceID with new one
+ CFRetain(newServiceID);
+ CFRelease(servicePrivate->serviceID);
+ servicePrivate->serviceID = newServiceID;
+
+ done:
+
+ if (oldPath != NULL) {
+ CFRelease(oldPath);
+ }
+ if (newPath != NULL) {
+ CFRelease(newPath);
+ }
+ if (allSets != NULL) {
+ CFRelease(allSets);
+ }
return ok;
}
+
+#define kVPNProtocolPayloadInfo CFSTR("com.apple.payload")
+#define kSCEntNetLoginWindowEAPOL CFSTR("EAPOL.LoginWindow")
+
+static void
+copyInterfaceConfiguration(SCNetworkServiceRef oldService, SCNetworkServiceRef newService)
+{
+ SCNetworkInterfaceRef oldInterface;
+ SCNetworkInterfaceRef newInterface;
+
+ oldInterface = SCNetworkServiceGetInterface(oldService);
+ newInterface = SCNetworkServiceGetInterface(newService);
+
+ while (oldInterface != NULL) {
+ CFDictionaryRef configuration;
+ CFStringRef interfaceType;
+
+ if (newInterface == NULL) {
+ // oops ... interface layering does not match
+ return;
+ }
+
+ // copy interface configuration
+ configuration = SCNetworkInterfaceGetConfiguration(oldInterface);
+
+ if ((configuration != NULL) ||
+ (SCError() == kSCStatusOK)) {
+ if (!SCNetworkInterfaceSetConfiguration(newInterface, configuration)) {
+ SC_log(LOG_INFO, "problem setting interface configuration");
+ }
+
+ }
+
+ // special case: PPP/L2TP + IPSec
+ interfaceType = SCNetworkInterfaceGetInterfaceType(oldInterface);
+ if (CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
+ SCNetworkInterfaceRef childInterface;
+
+ childInterface = SCNetworkInterfaceGetInterface(oldInterface);
+ if (childInterface != NULL) {
+ CFStringRef childInterfaceType;
+
+ childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface);
+
+ if (CFEqual(childInterfaceType, kSCNetworkInterfaceTypeL2TP)) {
+ configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetIPSec);
+ if ((configuration != NULL) ||
+ (SCError() == kSCStatusOK)) {
+ if (!SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetIPSec, configuration)) {
+ SC_log(LOG_INFO, "problem setting child interface configuration");
+ }
+ }
+ }
+ }
+ }
+
+ // special case: 802.1x
+ configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetEAPOL);
+ if ((configuration != NULL) ||
+ (SCError() == kSCStatusOK)) {
+ (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetEAPOL, configuration);
+ }
+
+ // special case: Managed Client
+ configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kVPNProtocolPayloadInfo);
+ if ((configuration != NULL) ||
+ (SCError() == kSCStatusOK)) {
+ (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kVPNProtocolPayloadInfo, configuration);
+ }
+
+ // special case: Network Pref
+ configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCValNetPPPAuthProtocolEAP);
+ if ((configuration != NULL) ||
+ (SCError() == kSCStatusOK)) {
+ (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCValNetPPPAuthProtocolEAP, configuration);
+ }
+
+ // special case: Remote Pref
+ configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCEntNetLoginWindowEAPOL);
+ if ((configuration != NULL) ||
+ (SCError() == kSCStatusOK)) {
+ (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCEntNetLoginWindowEAPOL, configuration);
+ }
+
+ // special case: Network Extension
+ configuration = SCNetworkInterfaceGetExtendedConfiguration(oldInterface, kSCNetworkInterfaceTypeIPSec);
+ if ((configuration != NULL) ||
+ (SCError() == kSCStatusOK)) {
+ (void) SCNetworkInterfaceSetExtendedConfiguration(newInterface, kSCNetworkInterfaceTypeIPSec, configuration);
+ }
+
+ oldInterface = SCNetworkInterfaceGetInterface(oldInterface);
+ newInterface = SCNetworkInterfaceGetInterface(newInterface);
+ }
+
+ return;
+}
+
+__private_extern__
+void
+__SCNetworkServiceAddProtocolToService(SCNetworkServiceRef service, CFStringRef protocolType, CFDictionaryRef configuration, Boolean enabled)
+{
+ Boolean ok;
+ SCNetworkProtocolRef protocol;
+
+ protocol = SCNetworkServiceCopyProtocol(service, protocolType);
+
+ if ((protocol == NULL) &&
+ (SCError() == kSCStatusNoKey)) {
+ ok = SCNetworkServiceAddProtocolType(service, protocolType);
+ if (ok) {
+ protocol = SCNetworkServiceCopyProtocol(service, protocolType);
+ }
+ }
+ if (protocol != NULL) {
+ SCNetworkProtocolSetConfiguration(protocol, configuration);
+ SCNetworkProtocolSetEnabled(protocol, enabled);
+ CFRelease(protocol);
+ }
+ return;
+}
+
+
+
+__private_extern__
+Boolean
+__SCNetworkServiceMigrateNew(SCPreferencesRef prefs,
+ SCNetworkServiceRef service,
+ CFDictionaryRef bsdMapping,
+ CFDictionaryRef setMapping,
+ CFDictionaryRef serviceSetMapping)
+{
+ CFStringRef deviceName = NULL;
+ Boolean enabled;
+ SCNetworkInterfaceRef interface = NULL;
+ CFDictionaryRef interfaceEntity = NULL;
+ CFMutableDictionaryRef interfaceEntityMutable = NULL;
+ SCNetworkSetRef newSet = NULL;
+ SCPreferencesRef ni_prefs = NULL;
+ SCNetworkInterfaceRef ni_interface = NULL;
+ SCNetworkInterfaceRef oldInterface = NULL;
+ SCNetworkSetRef oldSet = NULL;
+ SCNetworkServiceRef newService = NULL;
+ CFStringRef serviceID = NULL;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef) service;
+ CFArrayRef setList = NULL;
+ Boolean success = FALSE;
+ CFStringRef targetDeviceName = NULL;
+ CFStringRef userDefinedName = NULL;
+ CFStringRef userDefinedNameInterface = NULL;
+ CFArrayRef protocols = NULL;
+ CFStringRef subType;
+
+ if ((isA_SCNetworkService(service) == NULL) ||
+ (isA_SCNetworkInterface(servicePrivate->interface) == NULL) ||
+ (servicePrivate->prefs == NULL)) {
+ goto done;
+ }
+ serviceID = servicePrivate->serviceID;
+
+ newService = SCNetworkServiceCopy(prefs, serviceID);
+ if (newService != NULL) {
+ // Cannot add service if it already exists
+ SC_log(LOG_INFO, "Service already exists");
+ goto done;
+ }
+
+ oldInterface = SCNetworkServiceGetInterface(service);
+ interfaceEntity = __SCNetworkInterfaceCopyInterfaceEntity(oldInterface);
+ if (interfaceEntity == NULL) {
+ SC_log(LOG_INFO, "No interface entity");
+ goto done;
+ }
+ interfaceEntityMutable = CFDictionaryCreateMutableCopy(NULL, 0, interfaceEntity);
+
+ if (isA_CFDictionary(bsdMapping) != NULL) {
+ deviceName = CFDictionaryGetValue(interfaceEntityMutable, kSCPropNetInterfaceDeviceName);
+ if (isA_CFString(deviceName) != NULL) {
+ targetDeviceName = CFDictionaryGetValue(bsdMapping, deviceName);
+ if (targetDeviceName != NULL) {
+ // update mapping
+ CFDictionarySetValue(interfaceEntityMutable, kSCPropNetInterfaceDeviceName, targetDeviceName);
+ ni_prefs = __SCPreferencesCreateNIPrefsFromPrefs(prefs);
+ ni_interface = __SCNetworkInterfaceCreateWithNIPreferencesUsingBSDName(NULL, ni_prefs, targetDeviceName);
+ if (ni_interface != NULL) {
+ userDefinedNameInterface = __SCNetworkInterfaceGetUserDefinedName(ni_interface);
+ }
+ }
+ }
+ if (userDefinedNameInterface == NULL) {
+ userDefinedNameInterface = CFDictionaryGetValue(interfaceEntityMutable, kSCPropUserDefinedName);
+ }
+ }
+ subType = CFDictionaryGetValue(interfaceEntityMutable, kSCPropNetInterfaceSubType);
+ interface = _SCNetworkInterfaceCreateWithEntity(NULL, interfaceEntityMutable, NULL);
+ if (userDefinedNameInterface != NULL) {
+ __SCNetworkInterfaceSetUserDefinedName(interface, userDefinedNameInterface);
+ }
+ // Supporting PPPoE subtype
+ if (subType != NULL &&
+ CFEqual(subType, kSCValNetInterfaceSubTypePPPoE)) {
+ SCNetworkInterfaceRef childInterface = SCNetworkInterfaceGetInterface(interface);
+ if (childInterface != NULL) {
+ __SCNetworkInterfaceSetUserDefinedName(childInterface, userDefinedNameInterface);
+ }
+ }
+ newService = SCNetworkServiceCreate(prefs, interface);
+ if (newService == NULL) {
+ SC_log(LOG_INFO, "SCNetworkServiceCreate() failed");
+ goto done;
+ }
+
+ enabled = SCNetworkServiceGetEnabled(service);
+ if (!SCNetworkServiceSetEnabled(newService, enabled)) {
+ SCNetworkServiceRemove(newService);
+ SC_log(LOG_INFO, "SCNetworkServiceSetEnabled() failed");
+ goto done;
+ }
+
+ if (!SCNetworkServiceEstablishDefaultConfiguration(newService)) {
+ SCNetworkServiceRemove(newService);
+ SC_log(LOG_INFO, "SCNetworkServiceEstablishDefaultConfiguration() failed");
+ goto done;
+ }
+
+ // Set service ID
+ _SCNetworkServiceSetServiceID(newService, serviceID);
+
+ userDefinedName = SCNetworkServiceGetName(service);
+ if ((userDefinedName != NULL) &&
+ !SCNetworkServiceSetName(newService, userDefinedName)) {
+ SC_log(LOG_INFO, "SCNetworkServiceSetName(, %@) failed", userDefinedName);
+ }
+
+ // Determine which sets to add service
+ if (setMapping != NULL &&
+ serviceSetMapping != NULL) {
+ setList = CFDictionaryGetValue(serviceSetMapping, service);
+ if (setList != NULL) {
+ for (CFIndex idx = 0; idx < CFArrayGetCount(setList); idx++) {
+ oldSet = CFArrayGetValueAtIndex(setList, idx);
+ newSet = CFDictionaryGetValue(setMapping, oldSet);
+ if (newSet == NULL) {
+ continue;
+ }
+
+ if (!SCNetworkSetAddService(newSet, newService)) {
+ SC_log(LOG_INFO, "SCNetworkSetAddService() failed");
+ }
+ }
+ }
+ }
+
+ protocols = SCNetworkServiceCopyProtocols(service);
+ if (protocols != NULL) {
+
+ for (CFIndex idx = 0; idx < CFArrayGetCount(protocols); idx++) {
+ SCNetworkProtocolRef protocol = CFArrayGetValueAtIndex(protocols, idx);
+ CFDictionaryRef configuration = SCNetworkProtocolGetConfiguration(protocol);
+ CFStringRef protocolType = SCNetworkProtocolGetProtocolType(protocol);
+ enabled = SCNetworkProtocolGetEnabled(protocol);
+ __SCNetworkServiceAddProtocolToService(newService, protocolType, configuration, enabled);
+ }
+ CFRelease(protocols);
+ }
+
+ copyInterfaceConfiguration(service, newService);
+
+ success = TRUE;
+done:
+ if (interface != NULL) {
+ CFRelease(interface);
+ }
+ if (interfaceEntity != NULL) {
+ CFRelease(interfaceEntity);
+ }
+ if (interfaceEntityMutable != NULL) {
+ CFRelease(interfaceEntityMutable);
+ }
+ if (newService != NULL) {
+ CFRelease(newService);
+ }
+ if (ni_prefs != NULL) {
+ CFRelease(ni_prefs);
+ }
+ if (ni_interface != NULL) {
+ CFRelease(ni_interface);
+ }
+ return success;
+}
+
+
+__private_extern__
+Boolean
+__SCNetworkServiceCreate(SCPreferencesRef prefs,
+ SCNetworkInterfaceRef interface,
+ CFStringRef userDefinedName)
+{
+ SCNetworkSetRef currentSet = NULL;
+ Boolean ok = FALSE;
+ SCNetworkServiceRef service = NULL;
+
+ if (interface == NULL) {
+ goto done;
+ }
+
+ if (userDefinedName == NULL) {
+ userDefinedName = __SCNetworkInterfaceGetUserDefinedName(interface);
+ if (userDefinedName == NULL) {
+ SC_log(LOG_INFO, "No userDefinedName");
+ goto done;
+ }
+ }
+ service = SCNetworkServiceCreate(prefs, interface);
+ if (service == NULL) {
+ SC_log(LOG_INFO, "SCNetworkServiceCreate() failed: %s", SCErrorString(SCError()));
+ } else {
+ ok = SCNetworkServiceSetName(service, userDefinedName);
+ if (!ok) {
+ SC_log(LOG_INFO, "SCNetworkServiceSetName() failed: %s", SCErrorString(SCError()));
+ SCNetworkServiceRemove(service);
+ goto done;
+ }
+
+ ok = SCNetworkServiceEstablishDefaultConfiguration(service);
+ if (!ok) {
+ SC_log(LOG_INFO, "SCNetworkServiceEstablishDefaultConfiguration() failed: %s", SCErrorString(SCError()));
+ SCNetworkServiceRemove(service);
+ goto done;
+ }
+ }
+ currentSet = SCNetworkSetCopyCurrent(prefs);
+ if (currentSet == NULL) {
+ SC_log(LOG_INFO, "No current set");
+ if (service != NULL) {
+ SCNetworkServiceRemove(service);
+ }
+ goto done;
+ }
+ if (service != NULL) {
+ ok = SCNetworkSetAddService(currentSet, service);
+ if (!ok) {
+ SC_log(LOG_INFO, "Could not add service to the current set");
+ SCNetworkServiceRemove(service);
+ goto done;
+ }
+ }
+
+ done:
+ if (service != NULL) {
+ CFRelease(service);
+ }
+ if (currentSet != NULL) {
+ CFRelease(currentSet);
+ }
+ return ok;
+}
+
+__private_extern__ Boolean
+__SCNetworkServiceIsPPTP(SCNetworkServiceRef service)
+{
+ CFStringRef intfSubtype;
+ SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service;
+
+ if (servicePrivate == NULL || servicePrivate->interface == NULL) {
+ return FALSE;
+ }
+
+ intfSubtype = __SCNetworkInterfaceGetEntitySubType(servicePrivate->interface);
+ if (intfSubtype == NULL) {
+ return FALSE;
+ }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated"
+ if (CFEqual(intfSubtype, kSCValNetInterfaceSubTypePPTP)) {
+ return TRUE;
+ }
+#pragma GCC diagnostic pop
+
+ return FALSE;
+}