+
+
+#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 void
+add_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_IPHONE
+static SCBridgeInterfaceRef
+copyAutoBridgeInterface(SCPreferencesRef prefs, CFStringRef bridgeName)
+{
+ SCBridgeInterfaceRef bridge = NULL;
+ CFArrayRef interfaces;
+
+ // exclude Bridge [member] interfaces
+ interfaces = SCBridgeInterfaceCopyAll(prefs);
+ if (interfaces != NULL) {
+ CFIndex i;
+ CFIndex n;
+
+ n = CFArrayGetCount(interfaces);
+ for (i = 0; i < n; i++) {
+ SCBridgeInterfaceRef interface;
+ CFStringRef name = NULL;
+ CFDictionaryRef options;
+
+ interface = CFArrayGetValueAtIndex(interfaces, i);
+ options = SCBridgeInterfaceGetOptions(interface);
+ if ((options != NULL) &&
+ CFDictionaryGetValueIfPresent(options,
+ CFSTR("__AUTO__"),
+ (const void **)&name) &&
+ _SC_CFEqual(name, bridgeName)) {
+ bridge = interface;
+ CFRetain(bridge);
+ break;
+ }
+ }
+
+ CFRelease(interfaces);
+ }
+
+ if (bridge == NULL) {
+ bridge = SCBridgeInterfaceCreate(prefs);
+ if (bridge != NULL) {
+ CFMutableDictionaryRef newOptions;
+ Boolean ok;
+
+ newOptions = CFDictionaryCreateMutable(NULL, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFDictionarySetValue(newOptions, CFSTR("__AUTO__"), bridgeName);
+ ok = SCBridgeInterfaceSetOptions(bridge, newOptions);
+ CFRelease(newOptions);
+ if (!ok) {
+ CFRelease(bridge);
+ bridge = NULL;
+ }
+ }
+ }
+
+ return bridge;
+}
+#endif // !TARGET_OS_IPHONE
+
+
+static CFArrayRef
+copyServices(SCNetworkSetRef set)
+{
+ CFArrayRef services;
+ SCNetworkSetPrivateRef setPrivate = (SCNetworkSetPrivateRef)set;
+
+ // first, assume that we only want to add new services
+ // for those interfaces that are not represented in the
+ // current set.
+ services = SCNetworkSetCopyServices(set);
+ if ((services != NULL) && setPrivate->established) {
+ // but, if we are given an existing (or "established") set
+ // than we only want to add new services for those interfaces
+ // that are not represented in *any* set.
+ CFRelease(services);
+ services = SCNetworkServiceCopyAll(setPrivate->prefs);
+ }
+
+ return services;
+}
+
+
+#if !TARGET_OS_IPHONE
+static CF_RETURNS_RETAINED CFArrayRef
+updateServices(CFArrayRef services, SCNetworkInterfaceRef interface)
+{
+ CFStringRef bsdName;
+ CFIndex i;
+ CFIndex n;
+ CFMutableArrayRef newServices;
+
+ if (services == NULL) {
+ return NULL;
+ }
+
+ bsdName = SCNetworkInterfaceGetBSDName(interface);
+
+ newServices = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ n = CFArrayGetCount(services);
+ for (i = 0; i < n; i++) {
+ SCNetworkInterfaceRef interface;
+ CFStringRef interfaceName;
+ SCNetworkServiceRef newService;
+ SCNetworkServiceRef service;
+ CFStringRef serviceID;
+ SCNetworkServicePrivateRef servicePrivate;
+
+ service = CFArrayGetValueAtIndex(services, i);
+ interface = SCNetworkServiceGetInterface(service);
+ interfaceName = SCNetworkInterfaceGetBSDName(interface);
+ if (!_SC_CFEqual(interfaceName, bsdName)) {
+ // if not a match, retain
+ CFArrayAppendValue(newServices, service);
+ continue;
+ }
+
+ // if a match, update
+ serviceID = SCNetworkServiceGetServiceID(service);
+ servicePrivate = (SCNetworkServicePrivateRef)service;
+ newService = SCNetworkServiceCopy(servicePrivate->prefs, serviceID);
+ if (newService != NULL) {
+ CFArrayAppendValue(newServices, newService);
+ CFRelease(newService);
+ }
+ }
+
+ return newServices;
+}
+#endif // !TARGET_OS_IPHONE
+
+
+static __inline__ Boolean
+skipInterface(SCNetworkInterfaceRef interface)
+{
+ CFStringRef action;
+
+ action = _SCNetworkInterfaceGetConfigurationAction(interface);
+ if (isA_CFString(action) &&
+ CFEqual(action, kSCNetworkInterfaceConfigurationActionValueNone)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+CFComparisonResult
+_SCNetworkSetCompare(const void *val1, const void *val2, void *context)
+{
+#pragma unused(context)
+ CFStringRef id1;
+ CFStringRef id2;
+ CFStringRef name1;
+ CFStringRef name2;
+ SCNetworkSetRef s1 = (SCNetworkSetRef)val1;
+ SCNetworkSetRef s2 = (SCNetworkSetRef)val2;
+
+ name1 = SCNetworkSetGetName(s1);
+ name2 = SCNetworkSetGetName(s2);
+
+ if (name1 != NULL) {
+ if (name2 != NULL) {
+ return CFStringCompare(name1, name2, 0);
+ } else {
+ return kCFCompareLessThan;
+ }
+ }
+
+ if (name2 != NULL) {
+ return kCFCompareGreaterThan;
+ }
+
+ id1 = SCNetworkSetGetSetID(s1);
+ id2 = SCNetworkSetGetSetID(s2);
+ return CFStringCompare(id1, id2, 0);
+}
+
+
+static Boolean
+__SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CFArrayRef interfaces, 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;
+}
+
+
+Boolean
+SCNetworkSetEstablishDefaultConfiguration(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;
+}
+
+
+Boolean
+SCNetworkSetEstablishDefaultInterfaceConfiguration(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;
+}
+
+
+SCNetworkServiceRef
+SCNetworkSetCopySelectedVPNService(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;
+}
+
+
+Boolean
+SCNetworkSetSetSelectedVPNService(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;
+}