/* * Copyright (c) 2004 Apple Computer, 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 * - initial revision */ #include #include #include #include #include #include #include static CFStringRef __SCNetworkServiceCopyDescription (CFTypeRef cf); static void __SCNetworkServiceDeallocate (CFTypeRef cf); static Boolean __SCNetworkServiceEqual (CFTypeRef cf1, CFTypeRef cf2); static CFTypeID __kSCNetworkServiceTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __SCNetworkServiceClass = { 0, // version "SCNetworkService", // className NULL, // init NULL, // copy __SCNetworkServiceDeallocate, // dealloc __SCNetworkServiceEqual, // equal NULL, // 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 CFStringRef __SCNetworkServiceCopyDescription(CFTypeRef cf) { CFAllocatorRef allocator = CFGetAllocator(cf); CFMutableStringRef result; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf; result = CFStringCreateMutable(allocator, 0); CFStringAppendFormat(result, NULL, CFSTR(" { "), cf, allocator); CFStringAppendFormat(result, NULL, CFSTR("id=%@"), servicePrivate->serviceID); // CFStringAppendFormat(result, NULL, CFSTR(", prefs=%@"), servicePrivate->prefs); CFStringAppendFormat(result, NULL, CFSTR(" }")); return result; } static void __SCNetworkServiceDeallocate(CFTypeRef cf) { SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)cf; /* release resources */ CFRelease(servicePrivate->serviceID); if (servicePrivate->interface != NULL) CFRelease(servicePrivate->interface); CFRelease(servicePrivate->prefs); return; } static Boolean __SCNetworkServiceEqual(CFTypeRef cf1, CFTypeRef cf2) { SCNetworkServicePrivateRef s1 = (SCNetworkServicePrivateRef)cf1; SCNetworkServicePrivateRef s2 = (SCNetworkServicePrivateRef)cf2; if (s1 == s2) return TRUE; if (s1->prefs != s2->prefs) return FALSE; // if not the same prefs if (!CFEqual(s1->serviceID, s2->serviceID)) return FALSE; // if not the same service identifier return TRUE; } static void __SCNetworkServiceInitialize(void) { __kSCNetworkServiceTypeID = _CFRuntimeRegisterClass(&__SCNetworkServiceClass); return; } __private_extern__ SCNetworkServicePrivateRef __SCNetworkServiceCreatePrivate(CFAllocatorRef allocator, CFStringRef serviceID, SCNetworkInterfaceRef interface, SCPreferencesRef prefs) { SCNetworkServicePrivateRef servicePrivate; uint32_t size; /* initialize runtime */ pthread_once(&initialized, __SCNetworkServiceInitialize); /* allocate target */ size = sizeof(SCNetworkServicePrivate) - sizeof(CFRuntimeBase); servicePrivate = (SCNetworkServicePrivateRef)_CFRuntimeCreateInstance(allocator, __kSCNetworkServiceTypeID, size, NULL); if (servicePrivate == NULL) { return NULL; } servicePrivate->prefs = CFRetain(prefs); servicePrivate->serviceID = CFStringCreateCopy(NULL, serviceID); servicePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL; return servicePrivate; } /* ---------- SCNetworkService APIs ---------- */ #define N_QUICK 64 Boolean SCNetworkServiceAddProtocolType(SCNetworkServiceRef service, CFStringRef protocolType) { CFDictionaryRef entity; CFDictionaryRef newEntity = NULL; Boolean ok = FALSE; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (!__SCNetworkProtocolIsValidType(protocolType)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service protocolType); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); if (entity != NULL) { // if "protocol" already exists _SCErrorSet(kSCStatusKeyExists); goto done; } if (servicePrivate->interface != NULL) { SCNetworkInterfaceRef childInterface; CFStringRef childInterfaceType = NULL; CFStringRef interfaceType; interfaceType = SCNetworkInterfaceGetInterfaceType(servicePrivate->interface); childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface); if (childInterface != NULL) { childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface); } newEntity = __copyProtocolTemplate(interfaceType, childInterfaceType, protocolType); } if (newEntity == NULL) { newEntity = CFDictionaryCreate(NULL, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity); CFRelease(newEntity); done : CFRelease(path); return ok; } CFArrayRef /* of SCNetworkServiceRef's */ SCNetworkServiceCopyAll(SCPreferencesRef prefs) { CFMutableArrayRef array; CFIndex n; CFStringRef path; CFDictionaryRef services; path = SCPreferencesPathKeyCreateNetworkServices(NULL); services = SCPreferencesPathGetValue(prefs, path); CFRelease(path); if ((services != NULL) && !isA_CFDictionary(services)) { return NULL; } array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); n = (services != NULL) ? CFDictionaryGetCount(services) : 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(services, keys, vals); for (i = 0; i < n; i++) { CFDictionaryRef entity; SCNetworkServicePrivateRef servicePrivate; if (!isA_CFDictionary(vals[i])) { SCLog(TRUE, LOG_INFO, CFSTR("SCNetworkServiceCopyAll(): error w/service \"%@\"\n"), 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]); continue; } servicePrivate = __SCNetworkServiceCreatePrivate(NULL, keys[i], NULL, prefs); CFArrayAppendValue(array, (SCNetworkServiceRef)servicePrivate); CFRelease(servicePrivate); } if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); CFAllocatorDeallocate(NULL, vals); } } return array; } /* * build a list of all of a servives entity types that are associated * with the services interface. The list will include : * * - entity types associated with the interface type (Ethernet, FireWire, PPP, ...) * - entity types associated with the interface sub-type (PPPSerial, PPPoE, L2TP, PPTP, ...) * - entity types associated with the hardware device (Ethernet, AirPort, FireWire, Modem, ...) */ static CFSetRef _copyInterfaceEntityTypes(CFDictionaryRef protocols) { CFDictionaryRef interface; CFMutableSetRef interface_entity_types; interface_entity_types = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); interface = CFDictionaryGetValue(protocols, kSCEntNetInterface); if (isA_CFDictionary(interface)) { 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++) { CFStringRef entity; entity = CFDictionaryGetValue(interface, entities[i]); if (isA_CFString(entity)) { CFSetAddValue(interface_entity_types, entity); } } /* * and, because we've found some misguided network preference code * developers leaving [PPP] entity dictionaries around even though * they are unused and/or unneeded... */ CFSetAddValue(interface_entity_types, kSCEntNetPPP); } return interface_entity_types; } SCNetworkServiceRef SCNetworkServiceCopy(SCPreferencesRef prefs, CFStringRef serviceID) { CFDictionaryRef entity; CFStringRef path; SCNetworkServicePrivateRef servicePrivate; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator serviceID, // service kSCEntNetInterface); // entity entity = SCPreferencesPathGetValue(prefs, path); CFRelease(path); if (!isA_CFDictionary(entity)) { // a "service" must have an "interface" _SCErrorSet(kSCStatusNoKey); return NULL; } servicePrivate = __SCNetworkServiceCreatePrivate(NULL, serviceID, NULL, prefs); return (SCNetworkServiceRef)servicePrivate; } SCNetworkProtocolRef SCNetworkServiceCopyProtocol(SCNetworkServiceRef service, CFStringRef protocolType) { CFSetRef non_protocol_entities; CFStringRef path; CFDictionaryRef protocols; SCNetworkProtocolPrivateRef protocolPrivate = NULL; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); if ((protocols != NULL) && !isA_CFDictionary(protocols)) { // if corrupt prefs _SCErrorSet(kSCStatusFailed); return NULL; } non_protocol_entities = _copyInterfaceEntityTypes(protocols); if (CFSetContainsValue(non_protocol_entities, protocolType)) { // if the "protocolType" matches an interface entity type _SCErrorSet(kSCStatusInvalidArgument); goto done; } if (!CFDictionaryContainsKey(protocols, protocolType)) { // if the "protocolType" entity does not exist _SCErrorSet(kSCStatusNoKey); goto done; } protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, protocolType, service); done : CFRelease(non_protocol_entities); return (SCNetworkProtocolRef)protocolPrivate; } CFArrayRef /* of SCNetworkProtocolRef's */ SCNetworkServiceCopyProtocols(SCNetworkServiceRef service) { CFMutableArrayRef array; CFIndex n; CFSetRef non_protocol_entities; CFStringRef path; CFDictionaryRef protocols; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity protocols = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); if (!isA_CFDictionary(protocols)) { return NULL; } non_protocol_entities = _copyInterfaceEntityTypes(protocols); array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); n = CFDictionaryGetCount(protocols); 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(protocols, keys, vals); for (i = 0; i < n; i++) { SCNetworkProtocolPrivateRef protocolPrivate; if (!isA_CFDictionary(vals[i])) { // if it's not a dictionary then it can't be a protocol entity continue; } if (CFSetContainsValue(non_protocol_entities, keys[i])) { // skip any non-protocol (interface) entities continue; } protocolPrivate = __SCNetworkProtocolCreatePrivate(NULL, keys[i], service); CFArrayAppendValue(array, (SCNetworkProtocolRef)protocolPrivate); CFRelease(protocolPrivate); } if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); CFAllocatorDeallocate(NULL, vals); } } CFRelease(non_protocol_entities); return array; } static Boolean __SCNetworkServiceSetInterfaceEntity(SCNetworkServiceRef service, SCNetworkInterfaceRef interface) { CFMutableDictionaryRef entity; SCNetworkInterfacePrivateRef interfacePrivate = (SCNetworkInterfacePrivateRef)interface; Boolean ok; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service kSCEntNetInterface); // entity entity = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (interfacePrivate->entity_type != NULL) { CFDictionarySetValue(entity, kSCPropNetInterfaceType, interfacePrivate->entity_type); } if (interfacePrivate->entity_subtype != NULL) { CFDictionarySetValue(entity, kSCPropNetInterfaceSubType, interfacePrivate->entity_subtype); } if (interfacePrivate->entity_device != NULL) { CFDictionarySetValue(entity, kSCPropNetInterfaceDeviceName, interfacePrivate->entity_device); } if (interfacePrivate->entity_hardware != NULL) { CFDictionarySetValue(entity, kSCPropNetInterfaceHardware, interfacePrivate->entity_hardware); } if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeModem) && interfacePrivate->supportsDeviceOnHold) { int one = 1; CFNumberRef num; num = CFNumberCreate(NULL, kCFNumberIntType, &one); CFDictionarySetValue(entity, kSCPropNetInterfaceSupportsModemOnHold, num); CFRelease(num); } ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, entity); CFRelease(entity); CFRelease(path); return ok; } SCNetworkServiceRef SCNetworkServiceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef interface) { CFArrayRef components; CFArrayRef interface_config; SCNetworkInterfaceRef newInterface; CFStringRef path; CFStringRef prefix; CFStringRef serviceID; SCNetworkServicePrivateRef servicePrivate; // establish the service prefix = SCPreferencesPathKeyCreateNetworkServices(NULL); path = SCPreferencesPathCreateUniqueChild(prefs, prefix); CFRelease(prefix); if (path == NULL) { return NULL; } components = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/")); CFRelease(path); serviceID = CFArrayGetValueAtIndex(components, 2); servicePrivate = __SCNetworkServiceCreatePrivate(NULL, serviceID, NULL, prefs); CFRelease(components); // duplicate the interface and associate the copy with the new service newInterface = (SCNetworkInterfaceRef)__SCNetworkInterfaceCreateCopy(NULL, interface, (SCNetworkServiceRef)servicePrivate); servicePrivate->interface = newInterface; // establish "default" configuration(s) for the interface for (interface = newInterface; interface != NULL; interface = SCNetworkInterfaceGetInterface(interface)) { SCNetworkInterfaceRef childInterface; CFStringRef childInterfaceType = NULL; CFDictionaryRef config; CFStringRef interfaceType; interfaceType = SCNetworkInterfaceGetInterfaceType(interface); childInterface = SCNetworkInterfaceGetInterface(servicePrivate->interface); if (childInterface != NULL) { childInterfaceType = SCNetworkInterfaceGetInterfaceType(childInterface); } config = __copyInterfaceTemplate(interfaceType, childInterfaceType); if (config != NULL) { (void) __SCNetworkInterfaceSetConfiguration(interface, config, TRUE); CFRelease(config); } } // add the interface [entity] to the service (void) __SCNetworkServiceSetInterfaceEntity((SCNetworkServiceRef)servicePrivate, servicePrivate->interface); // push the [deep] interface configuration into into the service. interface_config = __SCNetworkInterfaceCopyDeepConfiguration(servicePrivate->interface); __SCNetworkInterfaceSetDeepConfiguration(servicePrivate->interface, interface_config); return (SCNetworkServiceRef)servicePrivate; } Boolean SCNetworkServiceGetEnabled(SCNetworkServiceRef service) { Boolean enabled; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity enabled = __getPrefsEnabled(servicePrivate->prefs, path); CFRelease(path); return enabled; } SCNetworkInterfaceRef SCNetworkServiceGetInterface(SCNetworkServiceRef service) { SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; if (servicePrivate->interface == NULL) { CFDictionaryRef entity; CFStringRef path; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service kSCEntNetInterface); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); if (isA_CFDictionary(entity)) { servicePrivate->interface = __SCNetworkInterfaceCreateWithEntity(NULL, entity, service); } } return servicePrivate->interface; } CFStringRef SCNetworkServiceGetName(SCNetworkServiceRef service) { CFDictionaryRef entity; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; CFStringRef name = NULL; CFStringRef path; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); CFRelease(path); if (isA_CFDictionary(entity)) { name = CFDictionaryGetValue(entity, kSCPropUserDefinedName); } return isA_CFString(name) ? name : NULL; } CFStringRef SCNetworkServiceGetServiceID(SCNetworkServiceRef service) { SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; return servicePrivate->serviceID; } CFTypeID SCNetworkServiceGetTypeID(void) { pthread_once(&initialized, __SCNetworkServiceInitialize); /* initialize runtime */ return __kSCNetworkServiceTypeID; } Boolean SCNetworkServiceRemove(SCNetworkServiceRef service) { Boolean ok = FALSE; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; CFArrayRef sets; CFStringRef path; // 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++) { SCNetworkSetRef set; set = CFArrayGetValueAtIndex(sets, i); ok = SCNetworkSetRemoveService(set, service); if (!ok && (SCError() != kSCStatusNoKey)) { break; } } CFRelease(sets); } // remove service path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path); CFRelease(path); return ok; } Boolean SCNetworkServiceRemoveProtocolType(SCNetworkServiceRef service, CFStringRef protocolType) { CFDictionaryRef entity; Boolean ok = FALSE; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service protocolType); // entity entity = SCPreferencesPathGetValue(servicePrivate->prefs, path); if (entity == NULL) { // if "protocol" does not exist _SCErrorSet(kSCStatusNoKey); goto done; } ok = SCPreferencesPathRemoveValue(servicePrivate->prefs, path); done : CFRelease(path); return ok; } Boolean SCNetworkServiceSetEnabled(SCNetworkServiceRef service, Boolean enabled) { Boolean ok; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator servicePrivate->serviceID, // service NULL); // entity ok = __setPrefsEnabled(servicePrivate->prefs, path, enabled); CFRelease(path); return ok; } Boolean SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) { CFDictionaryRef entity; Boolean ok = FALSE; CFStringRef path; SCNetworkServicePrivateRef servicePrivate = (SCNetworkServicePrivateRef)service; #define PREVENT_DUPLICATE_SERVICE_NAMES #ifdef PREVENT_DUPLICATE_SERVICE_NAMES if (isA_CFString(name)) { CFArrayRef sets; // ensure that each service is uniquely named within its sets sets = SCNetworkSetCopyAll(servicePrivate->prefs); if (sets != NULL) { CFIndex set_index; CFIndex set_count; set_count = CFArrayGetCount(sets); for (set_index = 0; set_index < set_count; set_index++) { CFIndex service_index; Boolean isDup = FALSE; Boolean isMember = FALSE; CFIndex service_count; CFArrayRef services; SCNetworkSetRef set = CFArrayGetValueAtIndex(sets, set_index); services = SCNetworkSetCopyServices(set); service_count = CFArrayGetCount(services); for (service_index = 0; service_index < service_count; service_index++) { CFStringRef otherID; CFStringRef otherName; SCNetworkServiceRef otherService; otherService = CFArrayGetValueAtIndex(services, service_index); otherID = SCNetworkServiceGetServiceID(otherService); if (CFEqual(servicePrivate->serviceID, otherID)) { // if the service is a member of this set isMember = TRUE; continue; } otherName = SCNetworkServiceGetName(otherService); if ((otherName != NULL) && CFEqual(name, otherName)) { isDup = TRUE; continue; } } CFRelease(services); if (isMember && isDup) { /* * if this service is a member of the set and * the "name" is not unique. */ CFRelease(sets); _SCErrorSet(kSCStatusKeyExists); return FALSE; } } CFRelease(sets); } } #endif /* PREVENT_DUPLICATE_SERVICE_NAMES */ path = SCPreferencesPathKeyCreateNetworkServiceEntity(NULL, // allocator 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)) { CFMutableDictionaryRef newEntity; newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity); if (isA_CFString(name)) { CFDictionarySetValue(newEntity, kSCPropUserDefinedName, name); } else { CFDictionaryRemoveValue(newEntity, kSCPropUserDefinedName); } ok = SCPreferencesPathSetValue(servicePrivate->prefs, path, newEntity); CFRelease(newEntity); } CFRelease(path); return ok; }