static bool is_valid_repeating_dictionary(CFDictionaryRef event) { CFNumberRef tmp_num; CFStringRef tmp_str; if(NULL == event) return true; if(!isA_CFDictionary(event)) return false; tmp_num = (CFNumberRef)CFDictionaryGetValue(event, CFSTR(kIOPMPowerEventTimeKey)); if(!isA_CFNumber(tmp_num)) return false; tmp_num = (CFNumberRef)CFDictionaryGetValue(event, CFSTR(kIOPMDaysOfWeekKey)); if(!isA_CFNumber(tmp_num)) return false; tmp_str = (CFStringRef)CFDictionaryGetValue(event, CFSTR(kIOPMPowerEventTypeKey)); if(!isA_CFString(tmp_str)) return false; if( !CFEqual(tmp_str, CFSTR(kIOPMAutoSleep)) && !CFEqual(tmp_str, CFSTR(kIOPMAutoShutdown)) && !CFEqual(tmp_str, CFSTR(kIOPMAutoWakeOrPowerOn)) && !CFEqual(tmp_str, CFSTR(kIOPMAutoPowerOn)) && !CFEqual(tmp_str, CFSTR(kIOPMAutoWake)) && !CFEqual(tmp_str, CFSTR(kIOPMAutoRestart)) ) { return false; } return true; }
static void add_configured_interface(const void *key, const void *value, void *context) { SCBondInterfaceRef bond; CFStringRef bond_if = (CFStringRef)key; CFDictionaryRef bond_info = (CFDictionaryRef)value; CFDictionaryRef bond_options; CFIndex i; CFArrayRef interfaces; SCNetworkInterfacePrivateRef interfacePrivate; CFMutableArrayRef members = NULL; CFNumberRef mode; addContextRef myContext = (addContextRef)context; CFStringRef name; CFIndex n; // create the bond interface bond = (SCBondInterfaceRef)_SCBondInterfaceCreatePrivate(NULL, bond_if); // add member interfaces interfaces = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondInterfaces); n = isA_CFArray(interfaces) ? CFArrayGetCount(interfaces) : 0; for (i = 0; i < n; i++) { CFStringRef member; member = CFArrayGetValueAtIndex(interfaces, i); if (isA_CFString(member)) { add_interface(&members, member); } } if (members != NULL) { _SCBondInterfaceSetMemberInterfaces(bond, members); CFRelease(members); } // set display name name = CFDictionaryGetValue(bond_info, kSCPropUserDefinedName); if (isA_CFString(name)) { SCBondInterfaceSetLocalizedDisplayName(bond, name); } // set options bond_options = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondOptions); if (isA_CFDictionary(bond_options)) { SCBondInterfaceSetOptions(bond, bond_options); } // set the mode mode = CFDictionaryGetValue(bond_info, kSCPropVirtualNetworkInterfacesBondMode); _SCBondInterfaceSetMode(bond, isA_CFNumber(mode)); // estabish link to the stored configuration interfacePrivate = (SCNetworkInterfacePrivateRef)bond; interfacePrivate->prefs = CFRetain(myContext->prefs); CFArrayAppendValue(myContext->bonds, bond); CFRelease(bond); return; }
__private_extern__ IOReturn GetPMSettingNumber(CFStringRef which, int64_t *value) { CFDictionaryRef current_settings; CFNumberRef n; CFStringRef pwrSrc; if (!energySettings || !which) return kIOReturnBadArgument; if (_getPowerSource() == kBatteryPowered) pwrSrc = CFSTR(kIOPMBatteryPowerKey); else pwrSrc = CFSTR(kIOPMACPowerKey); // Don't use 'currentPowerSource' here as that gets updated // little slowly after this function is called to get a setting // on new power source. current_settings = (CFDictionaryRef)isA_CFDictionary( CFDictionaryGetValue(energySettings, pwrSrc)); if (current_settings) { n = CFDictionaryGetValue(current_settings, which); if (isA_CFNumber(n)) { CFNumberGetValue(n, kCFNumberSInt64Type, value); return kIOReturnSuccess; } } return kIOReturnError; }
STATIC CFDataRef CGAModifierDictGetModifier(CFDictionaryRef dict, uint8_t * security_level) { CFDataRef modifier = NULL; *security_level = 0; if (isA_CFDictionary(dict) != NULL) { modifier = CFDictionaryGetValue(dict, kModifier); modifier = isA_CFData(modifier); if (modifier != NULL) { if (CFDataGetLength(modifier) != IN6_CGA_MODIFIER_LENGTH) { modifier = NULL; } else { CFNumberRef level; level = CFDictionaryGetValue(dict, kSecurityLevel); if (isA_CFNumber(level) != NULL) { CFNumberGetValue(level, kCFNumberSInt8Type, security_level); } } } } return (modifier); }
Boolean SCBondInterfaceSetMode(SCBondInterfaceRef bond, CFNumberRef mode) { int mode_num; if (!isA_SCBondInterface(bond) || !isA_CFNumber(mode)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } if (CFNumberGetValue(mode, kCFNumberIntType, &mode_num) == FALSE) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } switch (mode_num) { case IF_BOND_MODE_LACP: case IF_BOND_MODE_STATIC: break; default: _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } return (_SCBondInterfaceSetMode(bond, mode)); }
static int _threshValue(CFDictionaryRef dynamo) { int val = 0; CFNumberRef cfnum; cfnum = isA_CFNumber(CFDictionaryGetValue(dynamo, CFSTR(kIOUPSShutdownLevelValueKey))); if(cfnum) CFNumberGetValue(cfnum, kCFNumberIntType, &val); return val; }
static CFComparisonResult compareBySearchOrder(const void *val1, const void *val2, void *context) { CFDictionaryRef proxy1 = (CFDictionaryRef)val1; CFDictionaryRef proxy2 = (CFDictionaryRef)val2; CFNumberRef num1; CFNumberRef num2; uint32_t order1 = DEFAULT_MATCH_ORDER; uint32_t order2 = DEFAULT_MATCH_ORDER; num1 = CFDictionaryGetValue(proxy1, PROXY_MATCH_ORDER_KEY); if (!isA_CFNumber(num1) || !CFNumberGetValue(num1, kCFNumberIntType, &order1)) { order1 = DEFAULT_MATCH_ORDER; } num2 = CFDictionaryGetValue(proxy2, PROXY_MATCH_ORDER_KEY); if (!isA_CFNumber(num2) || !CFNumberGetValue(num2, kCFNumberIntType, &order2)) { order2 = DEFAULT_MATCH_ORDER; } if (order1 == order2) { // if same match "order", retain original ordering for configurations if (CFDictionaryGetValueIfPresent(proxy1, ORDER_KEY, (const void **)&num1) && CFDictionaryGetValueIfPresent(proxy2, ORDER_KEY, (const void **)&num2) && isA_CFNumber(num1) && isA_CFNumber(num2) && CFNumberGetValue(num1, kCFNumberIntType, &order1) && CFNumberGetValue(num2, kCFNumberIntType, &order2)) { if (order1 == order2) { return kCFCompareEqualTo; } else { return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan; } } return kCFCompareEqualTo; } return (order1 < order2) ? kCFCompareLessThan : kCFCompareGreaterThan; }
PRIVATE_EXTERN Boolean accept_types_valid(CFArrayRef accept) { int count; int i; if (isA_CFArray(accept) == NULL) { return (FALSE); } count = CFArrayGetCount(accept); if (count == 0) { return (FALSE); } for (i = 0; i < count; i++) { CFNumberRef type = CFArrayGetValueAtIndex(accept, i); if (isA_CFNumber(type) == NULL) { return (FALSE); } } return (TRUE); }
PRIVATE_EXTERN bool my_CFTypeToNumber(CFTypeRef element, uint32_t * l_p) { if (isA_CFString(element) != NULL) { if (my_CFStringToNumber(element, l_p) == FALSE) { return (FALSE); } } else if (isA_CFBoolean(element) != NULL) { *l_p = CFBooleanGetValue(element); } else if (isA_CFNumber(element) != NULL) { if (CFNumberGetValue(element, kCFNumberSInt32Type, l_p) == FALSE) { return (FALSE); } } else { return (FALSE); } return (TRUE); }
static void add_default_proxy(CFMutableArrayRef proxies, CFDictionaryRef defaultProxy, Boolean *orderAdded) { CFMutableDictionaryRef myDefault; uint32_t myOrder = DEFAULT_MATCH_ORDER; CFNumberRef order = NULL; if (defaultProxy == NULL) { myDefault = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } else { myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultProxy); CFDictionaryRemoveValue(myDefault, kSCPropInterfaceName); order = CFDictionaryGetValue(myDefault, PROXY_MATCH_ORDER_KEY); } // ensure that the default proxy has a search order if (!isA_CFNumber(order) || !CFNumberGetValue(order, kCFNumberIntType, &myOrder)) { myOrder = DEFAULT_MATCH_ORDER; order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder); CFDictionarySetValue(myDefault, PROXY_MATCH_ORDER_KEY, order); CFRelease(order); *orderAdded = TRUE; } // add the default proxy add_proxy(proxies, myDefault); CFRelease(myDefault); return; }
/* _doPowerEmergencyShutdown() * Performs a semi-complicated proecdure to get machines experiencing power failure to automatically power up when external power is restored. We do this to trigger the onboard "Restart Automatically after a power failure" feature; pulling the power from a mostly-shutdown machine simulates a "power failure." At the time we do the shutdown... The UPS has lost external power (presumably due to a power outage) and our backup power thresholds have been exceeded and we've decided to do a system shutdown. 1. Request that the UPS remove power from the system in kDelayedRemovePowerMinutes 2. Set the StallSystemAtHalt root domain property that will cause the machine to hang at shutdown (after the OS has been shutdown). 3. We run the emergency shutdown script (/usr/libexec/upsshutdown) and shutdown to the point of stalling. 4. OS hangs there at the endpoint, waiting for UPS to remove power to its AC plugs. Later... 1. External power is restored to the UPS 2. The UPS restores power to its outlets, the CPU's "Restart Automatically after a power failure" switch is triggered. System boots up and resumes operation. * */ static void _doPowerEmergencyShutdown(CFNumberRef ups_id) { static int _alreadyShuttingDown = 0; CFDictionaryRef _ESSettings = NULL; char *shutdown_argv[3]; CFNumberRef auto_restart; IOReturn error; bool upsRestart = false; int restart_setting; if(_alreadyShuttingDown) return; _alreadyShuttingDown = 1; syslog(LOG_INFO, "Performing emergency UPS low power shutdown now"); _ESSettings = PMSettings_CopyActivePMSettings(); if(!_ESSettings) goto shutdown; auto_restart = isA_CFNumber(CFDictionaryGetValue(_ESSettings, CFSTR(kIOPMRestartOnPowerLossKey))); if(auto_restart) { CFNumberGetValue(auto_restart, kCFNumberIntType, &restart_setting); } else { restart_setting = 0; } upsRestart = restart_setting ? true:false; if(!upsRestart) { // Automatic Restart On Power Loss checkbox is disabled - // just do a plain old shutdown // and don't attempt to auto-restart. goto shutdown; } // Does the attached UPS support RemovePowerDelayed? if(_upsSupports(ups_id, CFSTR(kIOPSCommandDelayedRemovePowerKey))) { syslog(LOG_INFO, "System will restart when external power is restored to UPS."); error = _upsCommand(ups_id, CFSTR(kIOPSCommandStartupDelayKey), _delayBeforeStartupMinutes); if(kIOReturnSuccess != error) { // Attempt to set "startup when power restored" delay failed syslog(LOG_INFO, "UPS Emergency shutdown: error 0x%08x requesting UPS startup delay of %d minutes\n", error, _delayBeforeStartupMinutes); goto shutdown; } error = _upsCommand(ups_id, CFSTR(kIOPSCommandDelayedRemovePowerKey), _delayedRemovePowerMinutes); if(kIOReturnSuccess != error) { // We tried telling the UPS to auto-restart us, but since that's // failing we're just going to do an old school shutdown that // requires human intervention to power on. syslog(LOG_INFO, "UPS Emergency shutdown: error 0x%08x communicating shutdown time to UPS\n", error); goto shutdown; } } shutdown: if (_ESSettings) { CFRelease(_ESSettings); } shutdown_argv[0] = (char *)"/usr/libexec/upsshutdown"; if(upsRestart) { shutdown_argv[1] = (char *)"WaitForUPS"; shutdown_argv[2] = NULL; } else { shutdown_argv[1] = NULL; } _SCDPluginExecCommand(0, 0, 0, 0, "/usr/libexec/upsshutdown", shutdown_argv); }
/* PSLowPowerPSChange * * Is the handler that gets notified when power source (battery or UPS) * state changes. We might respond to this by posting a user notification * or performing emergency shutdown. */ __private_extern__ void PSLowPowerPSChange(CFTypeRef ps_blob) { CFTypeRef ups = NULL; CFDictionaryRef ups_info = 0; int t1, t2; CFNumberRef n1, n2; int minutes_remaining; int percent_remaining; CFBooleanRef isPresent; static int last_ups_power_source = _kIOUPSExternalPowerBit; CFStringRef power_source = 0; CFNumberRef ups_id = 0; // Bail immediately if another application (like APC's PowerChute) // is managing emergency UPS shutdown if(!_weManageUPSPower()) { goto _exit_PowerSourcesHaveChanged_; } // *** Inspect UPS power levels // We assume we're only dealing with 1 UPS for simplicity. // The "more than one UPS attached " case is undefined. if((ups = IOPSGetActiveUPS(ps_blob))) { ups_info = isA_CFDictionary(IOPSGetPowerSourceDescription(ps_blob, ups)); if(!ups_info) goto _exit_PowerSourcesHaveChanged_; ups_id = isA_CFNumber(CFDictionaryGetValue(ups_info, CFSTR(kIOPSPowerSourceIDKey))); if(!ups_id) goto _exit_PowerSourcesHaveChanged_; // Check UPS "Is Present" key isPresent = isA_CFBoolean(CFDictionaryGetValue(ups_info, CFSTR(kIOPSIsPresentKey))); if(!isPresent || !CFBooleanGetValue(isPresent)) { #if HAVE_CF_USER_NOTIFICATION if(_UPSAlert) { CFUserNotificationCancel(_UPSAlert); _UPSAlert = 0; } #endif // If UPS isn't active or connected we shouldn't base policy decisions on it goto _exit_PowerSourcesHaveChanged_; } // Check Power Source power_source = isA_CFString(CFDictionaryGetValue(ups_info, CFSTR(kIOPSPowerSourceStateKey))); if(!power_source || !CFEqual(power_source, CFSTR(kIOPSBatteryPowerValue))) { #if HAVE_CF_USER_NOTIFICATION // Running off of AC Power if(_UPSAlert) { CFUserNotificationCancel(_UPSAlert); _UPSAlert = 0; } #endif // we have to be draining the internal battery to do a shutdown, so we'll just exit from here. goto _exit_PowerSourcesHaveChanged_; } // UPS is running off of internal battery power. Show warning if we just switched from AC to battery. if(_kIOUPSExternalPowerBit == last_ups_power_source) { _switchedToUPSPowerTime = CFAbsoluteTimeGetCurrent(); if( _thresh->haltafter[kHaltEnabled] ) { // If there's a "shutdown after X minutes on UPS power" threshold, // set a timer to remind us to check UPS state again after X minutes _reEvaluatePowerSourcesLater(5 + (60*_thresh->haltafter[kHaltValue])); } #if HAVE_CF_USER_NOTIFICATION if(!_UPSAlert) _UPSAlert = _copyUPSWarning(); #endif } // TODO: switch this battery-present check for the IOKit // private API IOPMSystemSupportsUPSShutdown // Is an internal battery present? if(kCFBooleanTrue == IOPSPowerSourceSupported(ps_blob, CFSTR(kIOPMBatteryPowerKey))) { // Do not do UPS shutdown if internal battery is present. // Internal battery may still be providing power. // Don't do any further UPS shutdown processing. // PMU will cause an emergency sleep when the battery runs out - we fall back on that // in the battery case. goto _exit_PowerSourcesHaveChanged_; } // ****** // ****** Perform emergency shutdown if any of the shutdown thresholds is true // Check to make sure that the UPS has been on battery power for a full 10 seconds before initiating a shutdown. // Certain UPS's have reported transient "on battery power with 0% capacity remaining" states for 3-5 seconds. // So we make sure not to heed this shutdown notice unless we've been on battery power for 10 seconds. if(_secondsSpentOnUPSPower() < 10) { _reEvaluatePowerSourcesLater(10); goto _exit_PowerSourcesHaveChanged_; } // Calculate battery percentage remaining n1 = isA_CFNumber(CFDictionaryGetValue(ups_info, CFSTR(kIOPSCurrentCapacityKey))); n2 = isA_CFNumber(CFDictionaryGetValue(ups_info, CFSTR(kIOPSMaxCapacityKey))); if(n1 && n2) { if( CFNumberGetValue(n1, kCFNumberIntType, &t1) && CFNumberGetValue(n2, kCFNumberIntType, &t2)) { percent_remaining = (int)(100.0* ((double)t1) / ((double)t2) ); if( _thresh->haltpercent[kHaltEnabled] ) { if( percent_remaining <= _thresh->haltpercent[kHaltValue] ) { _doPowerEmergencyShutdown(ups_id); } } } } // Get UPS's estimated time remaining n1 = isA_CFNumber(CFDictionaryGetValue(ups_info, CFSTR(kIOPSTimeToEmptyKey))); if(n1) { if(CFNumberGetValue(n1, kCFNumberIntType, &minutes_remaining)) { if( _thresh->haltremain[kHaltEnabled] ) { if( minutes_remaining <= _thresh->haltremain[kHaltValue] ) { _doPowerEmergencyShutdown(ups_id); } } } } // Determine how long we've been running on UPS power if( _thresh->haltafter[kHaltEnabled] ) { if(_minutesSpentOnUPSPower() >= _thresh->haltafter[kHaltValue]) { _doPowerEmergencyShutdown(ups_id); } } } else { // No "active UPS" detected. // One could have just disappeared - if we're showing an alert, clear it. #if HAVE_CF_USER_NOTIFICATION if(_UPSAlert) { CFUserNotificationCancel(_UPSAlert); _UPSAlert = 0; } #endif } // exit point _exit_PowerSourcesHaveChanged_: if(power_source && CFEqual(power_source, CFSTR(kIOPSBatteryPowerValue))) { last_ups_power_source = _kIOUPSInternalPowerBit; } else { last_ups_power_source = _kIOUPSExternalPowerBit; } return; }
CFStringRef _SCCopyDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { #ifdef ENABLE_SC_FORMATTING CFMutableDictionaryRef nFormatOptions; CFStringRef prefix1; CFStringRef prefix2; CFTypeID type = CFGetTypeID(cf); if (!formatOptions || !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX1"), (const void **)&prefix1)) { prefix1 = CFSTR(""); } if (type == CFStringGetTypeID()) { return CFStringCreateWithFormat(NULL, formatOptions, CFSTR("%@%@"), prefix1, cf); } if (type == CFBooleanGetTypeID()) { return CFStringCreateWithFormat(NULL, formatOptions, CFSTR("%@%s"), prefix1, CFBooleanGetValue(cf) ? "TRUE" : "FALSE"); } if (type == CFDataGetTypeID()) { const uint8_t *data; CFIndex dataLen; CFIndex i; CFMutableStringRef str; str = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(str, formatOptions, CFSTR("%@<data> 0x"), prefix1); data = CFDataGetBytePtr(cf); dataLen = CFDataGetLength(cf); for (i = 0; i < dataLen; i++) { CFStringAppendFormat(str, NULL, CFSTR("%02x"), data[i]); } return str; } if (type == CFNumberGetTypeID()) { return CFStringCreateWithFormat(NULL, formatOptions, CFSTR("%@%@"), prefix1, cf); } if (type == CFDateGetTypeID()) { CFCalendarRef calendar; CFStringRef str; CFTimeZoneRef tz; int MM, DD, YYYY, hh, mm, ss; calendar = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar); tz = CFTimeZoneCopySystem(); CFCalendarSetTimeZone(calendar, tz); CFRelease(tz); CFCalendarDecomposeAbsoluteTime(calendar, CFDateGetAbsoluteTime(cf), "MdyHms", &MM, &DD, &YYYY, &hh, &mm, &ss); CFRelease(calendar); str = CFStringCreateWithFormat(NULL, formatOptions, CFSTR("%@%02d/%02d/%04d %02d:%02d:%02d"), prefix1, MM, DD, YYYY, hh, mm, ss); return str; } if ((formatOptions == NULL) || !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX2"), (const void **)&prefix2)) { prefix2 = prefix1; } if (formatOptions != NULL) { nFormatOptions = CFDictionaryCreateMutableCopy(NULL, 0, formatOptions); } else { nFormatOptions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } assert(nFormatOptions != NULL); #define N_QUICK 32 if (type == CFArrayGetTypeID()) { const void * elements_q[N_QUICK]; const void ** elements = elements_q; CFIndex i; CFIndex nElements; CFMutableStringRef str; str = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(str, formatOptions, CFSTR("%@<array> {"), prefix1); nElements = CFArrayGetCount(cf); if (nElements > 0) { if (nElements > (CFIndex)(sizeof(elements_q)/sizeof(CFTypeRef))) elements = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); CFArrayGetValues(cf, CFRangeMake(0, nElements), elements); for (i = 0; i < nElements; i++) { CFMutableStringRef nPrefix1; CFMutableStringRef nPrefix2; CFStringRef nStr; CFStringRef vStr; nStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%ld"), i); nPrefix1 = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(nPrefix1, formatOptions, CFSTR("%@ %@ : "), prefix2, nStr); nPrefix2 = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(nPrefix2, formatOptions, CFSTR("%@ "), prefix2); CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1); CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2); CFRelease(nPrefix1); CFRelease(nPrefix2); CFRelease(nStr); vStr = _SCCopyDescription((CFTypeRef)elements[i], nFormatOptions); CFStringAppendFormat(str, formatOptions, CFSTR("\n%@"), vStr); CFRelease(vStr); } if (elements != elements_q) CFAllocatorDeallocate(NULL, elements); } CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2); CFRelease(nFormatOptions); return str; } if (type == CFDictionaryGetTypeID()) { const void * keys_q[N_QUICK]; const void ** keys = keys_q; CFIndex i; CFIndex nElements; CFMutableStringRef nPrefix1; CFMutableStringRef nPrefix2; CFMutableStringRef str; str = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(str, formatOptions, CFSTR("%@<dictionary> {"), prefix1); nElements = CFDictionaryGetCount(cf); if (nElements > 0) { CFComparatorFunction compFunc = NULL; CFMutableArrayRef sortedKeys; if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); } CFDictionaryGetKeysAndValues(cf, keys, NULL); sortedKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); for (i = 0; i < nElements; i++) { CFArrayAppendValue(sortedKeys, (CFStringRef)keys[i]); } if (isA_CFString(keys[0])) { compFunc = (CFComparatorFunction)CFStringCompare; } else if (isA_CFNumber(keys[0])) { compFunc = (CFComparatorFunction)CFNumberCompare; } else if (isA_CFDate(keys[0])) { compFunc = (CFComparatorFunction)CFDateCompare; } if (compFunc != NULL) { CFArraySortValues(sortedKeys, CFRangeMake(0, nElements), compFunc, NULL); } for (i = 0; i < nElements; i++) { CFStringRef key; CFStringRef kStr; CFTypeRef val; CFStringRef vStr; key = CFArrayGetValueAtIndex(sortedKeys, i); kStr = _SCCopyDescription((CFTypeRef)key, NULL); nPrefix1 = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(nPrefix1, formatOptions, CFSTR("%@ %@ : "), prefix2, kStr); nPrefix2 = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(nPrefix2, formatOptions, CFSTR("%@ "), prefix2); CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1); CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2); CFRelease(nPrefix1); CFRelease(nPrefix2); CFRelease(kStr); val = CFDictionaryGetValue(cf, key); vStr = _SCCopyDescription((CFTypeRef)val, nFormatOptions); CFStringAppendFormat(str, formatOptions, CFSTR("\n%@"), vStr); CFRelease(vStr); } CFRelease(sortedKeys); if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); } } CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2); CFRelease(nFormatOptions); return str; } CFRelease(nFormatOptions); #endif /* ENABLE_SC_FORMATTING */ return CFStringCreateWithFormat(NULL, formatOptions, CFSTR("%@%@"), prefix1, cf); }
static void booter(kickeeRef target) { char **argv = NULL; char *cmd = NULL; CFStringRef execCommand = CFDictionaryGetValue(target->dict, CFSTR("execCommand")); int i; CFArrayRef keys = NULL; CFStringRef name = CFDictionaryGetValue(target->dict, CFSTR("name")); int nKeys = 0; Boolean ok = FALSE; CFStringRef postName = CFDictionaryGetValue(target->dict, CFSTR("postName")); SCLog(_verbose, LOG_DEBUG, CFSTR("Kicker callback, target=%@"), name); if (!isA_CFString(postName) && !isA_CFString(execCommand)) { goto error; /* if no notifications to post nor commands to execute */ } if (isA_CFString(postName)) { uint32_t status; /* * post a notification */ cmd = _SC_cfstring_to_cstring(postName, NULL, 0, kCFStringEncodingASCII); if (!cmd) { SCLog(TRUE, LOG_DEBUG, CFSTR(" could not convert post name to C string")); goto error; } SCLog(TRUE, LOG_NOTICE, CFSTR("posting notification %s"), cmd); status = notify_post(cmd); if (status != NOTIFY_STATUS_OK) { SCLog(TRUE, LOG_DEBUG, CFSTR(" notify_post() failed: error=%ld"), status); goto error; } CFAllocatorDeallocate(NULL, cmd); /* clean up */ cmd = NULL; } /* * get the arguments for the kickee */ keys = target->changedKeys; target->changedKeys = NULL; if (isA_CFString(execCommand)) { CFRange bpr; CFNumberRef execGID = CFDictionaryGetValue(target->dict, CFSTR("execGID")); CFNumberRef execUID = CFDictionaryGetValue(target->dict, CFSTR("execUID")); CFBooleanRef passKeys = CFDictionaryGetValue(target->dict, CFSTR("changedKeysAsArguments")); gid_t reqGID = 0; uid_t reqUID = 0; CFMutableStringRef str; /* * build the kickee command */ str = CFStringCreateMutableCopy(NULL, 0, execCommand); bpr = CFStringFind(str, CFSTR("$BUNDLE"), 0); if (bpr.location != kCFNotFound) { CFStringRef bundlePath; bundlePath = CFURLCopyFileSystemPath(myBundleURL, kCFURLPOSIXPathStyle); CFStringReplace(str, bpr, bundlePath); CFRelease(bundlePath); } cmd = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingASCII); CFRelease(str); if (!cmd) { SCLog(TRUE, LOG_DEBUG, CFSTR(" could not convert command to C string")); goto error; } /* * get the UID/GID for the kickee */ if (isA_CFNumber(execUID)) { CFNumberGetValue(execUID, kCFNumberIntType, &reqUID); } if (isA_CFNumber(execGID)) { CFNumberGetValue(execGID, kCFNumberIntType, &reqGID); } nKeys = CFArrayGetCount(keys); argv = CFAllocatorAllocate(NULL, (nKeys + 2) * sizeof(char *), 0); for (i = 0; i < (nKeys + 2); i++) { argv[i] = NULL; } /* create command name argument */ if ((argv[0] = rindex(cmd, '/')) != NULL) { argv[0]++; } else { argv[0] = cmd; } /* create changed key arguments */ if (isA_CFBoolean(passKeys) && CFBooleanGetValue(passKeys)) { for (i = 0; i < nKeys; i++) { CFStringRef key = CFArrayGetValueAtIndex(keys, i); argv[i+1] = _SC_cfstring_to_cstring(key, NULL, 0, kCFStringEncodingASCII); if (!argv[i+1]) { SCLog(TRUE, LOG_DEBUG, CFSTR(" could not convert argument to C string")); goto error; } } } SCLog(TRUE, LOG_NOTICE, CFSTR("executing %s"), cmd); SCLog(_verbose, LOG_DEBUG, CFSTR(" current uid = %d, requested = %d"), geteuid(), reqUID); /* this kicker is now "running" */ target->active = TRUE; (void)_SCDPluginExecCommand(booterExit, target, reqUID, reqGID, cmd, argv); // CFAllocatorDeallocate(NULL, cmd); /* clean up */ // cmd = NULL; } else { target->active = FALSE; } target->needsKick = FALSE; /* allow additional requests to be queued */ ok = TRUE; error : if (keys) CFRelease(keys); if (cmd) CFAllocatorDeallocate(NULL, cmd); if (argv) { for (i = 0; i < nKeys; i++) { if (argv[i+1]) { CFAllocatorDeallocate(NULL, argv[i+1]); } } CFAllocatorDeallocate(NULL, argv); } if (!ok) { /* * If the target action can't be performed this time then * there's not much point in trying again. As such, I close * the session and the kickee target released. */ cleanupKicker(target); } return; }
static boolean_t updateConfiguration(int *newState) { boolean_t changed = FALSE; CFStringRef computerName; CFStringEncoding computerNameEncoding; CFArrayRef configuredServices = NULL; CFDictionaryRef dict; CFIndex i; CFIndex ifCount = 0; CFMutableArrayRef info = NULL; CFArrayRef interfaces = NULL; CFStringRef key; CFArrayRef keys; CFIndex n; CFMutableArrayRef newConfigFile; CFMutableDictionaryRef newDefaults; CFMutableDictionaryRef newDict; CFMutableDictionaryRef newGlobals; CFMutableDictionaryRef newGlobalsX; /* newGlobals without ServiceID */ CFMutableDictionaryRef newStartup; CFMutableDictionaryRef newZones; CFNumberRef num; CFMutableDictionaryRef curGlobalsX; /* curGlobals without ServiceID */ CFStringRef pattern; boolean_t postGlobals = FALSE; CFStringRef primaryPort = NULL; /* primary interface */ CFStringRef primaryZone = NULL; CFArrayRef serviceOrder = NULL; CFDictionaryRef setGlobals = NULL; cache_open(); /* * establish the "new" AppleTalk configuration */ *newState = curState; newConfigFile = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); newGlobals = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); newDefaults = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); newStartup = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); newZones = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); /* initialize overall state */ CFDictionarySetValue(newStartup, CFSTR("APPLETALK"), CFSTR("-NO-")); /* * get the global settings (ServiceOrder, ComputerName, ...) */ key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainSetup, kSCEntNetAppleTalk); setGlobals = cache_SCDynamicStoreCopyValue(store, key); CFRelease(key); if (setGlobals) { if (isA_CFDictionary(setGlobals)) { /* get service order */ serviceOrder = CFDictionaryGetValue(setGlobals, kSCPropNetServiceOrder); serviceOrder = isA_CFArray(serviceOrder); if (serviceOrder) { CFRetain(serviceOrder); } } else { CFRelease(setGlobals); setGlobals = NULL; } } /* * if we don't have an AppleTalk ServiceOrder, use IPv4's (if defined) */ if (!serviceOrder) { key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainSetup, kSCEntNetIPv4); dict = cache_SCDynamicStoreCopyValue(store, key); CFRelease(key); if (dict) { if (isA_CFDictionary(dict)) { serviceOrder = CFDictionaryGetValue(dict, kSCPropNetServiceOrder); serviceOrder = isA_CFArray(serviceOrder); if (serviceOrder) { CFRetain(serviceOrder); } } CFRelease(dict); } } /* * get the list of ALL configured services */ configuredServices = entity_all(store, kSCEntNetAppleTalk, serviceOrder); if (configuredServices) { ifCount = CFArrayGetCount(configuredServices); } if (serviceOrder) CFRelease(serviceOrder); /* * get the list of ALL active interfaces */ key = SCDynamicStoreKeyCreateNetworkInterface(NULL, kSCDynamicStoreDomainState); dict = cache_SCDynamicStoreCopyValue(store, key); CFRelease(key); if (dict) { if (isA_CFDictionary(dict)) { interfaces = CFDictionaryGetValue(dict, kSCDynamicStorePropNetInterfaces); interfaces = isA_CFArray(interfaces); if (interfaces) { CFRetain(interfaces); } } CFRelease(dict); } /* * get the list of previously configured services */ pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetAppleTalk); keys = SCDynamicStoreCopyKeyList(store, pattern); CFRelease(pattern); if (keys) { info = CFArrayCreateMutableCopy(NULL, 0, keys); CFRelease(keys); } /* * iterate over each configured service to establish the new * configuration. */ for (i = 0; i < ifCount; i++) { CFDictionaryRef service; CFStringRef ifName; CFStringRef configMethod; CFMutableStringRef portConfig = NULL; CFArrayRef networkRange; /* for seed ports, CFArray[2] of CFNumber (lo, hi) */ int sNetwork; int eNetwork; CFArrayRef zoneList; /* for seed ports, CFArray[] of CFString (zones names) */ CFIndex zCount; CFIndex j; CFMutableDictionaryRef ifDefaults = NULL; CFNumberRef defaultNetwork; CFNumberRef defaultNode; CFStringRef defaultZone; /* get AppleTalk service dictionary */ service = CFArrayGetValueAtIndex(configuredServices, i); /* get interface name */ ifName = CFDictionaryGetValue(service, kSCPropNetInterfaceDeviceName); /* check inteface availability */ if (!interfaces || !CFArrayContainsValue(interfaces, CFRangeMake(0, CFArrayGetCount(interfaces)), ifName)) { /* if interface not available */ goto nextIF; } /* check interface link status */ key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, ifName, kSCEntNetLink); dict = cache_SCDynamicStoreCopyValue(store, key); CFRelease(key); if (dict) { Boolean linkStatus = TRUE; /* assume the link is "up" */ Boolean ifDetaching = FALSE; /* assume link is not detaching */ /* the link key for this interface is available */ if (isA_CFDictionary(dict)) { CFBooleanRef bVal; bVal = CFDictionaryGetValue(dict, kSCPropNetLinkActive); if (isA_CFBoolean(bVal)) { linkStatus = CFBooleanGetValue(bVal); } /* check if interface is detaching - value doesn't really matter, only that it exists */ ifDetaching = CFDictionaryContainsKey(dict, kSCPropNetLinkDetaching); } CFRelease(dict); if (!linkStatus || ifDetaching) { /* if link status down or the interface is detaching */ goto nextIF; } } /* * Determine configuration method for this service */ configMethod = CFDictionaryGetValue(service, kSCPropNetAppleTalkConfigMethod); if (!isA_CFString(configMethod)) { /* if no ConfigMethod */ goto nextIF; } if (!CFEqual(configMethod, kSCValNetAppleTalkConfigMethodNode ) && !CFEqual(configMethod, kSCValNetAppleTalkConfigMethodRouter ) && !CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) { /* if not one of the expected values, disable */ SCLog(TRUE, LOG_NOTICE, CFSTR("Unexpected AppleTalk ConfigMethod: %@"), configMethod); goto nextIF; } /* * the first service to be defined will always be "primary" */ if (CFArrayGetCount(newConfigFile) == 0) { CFDictionaryRef active; CFDictionarySetValue(newGlobals, kSCDynamicStorePropNetPrimaryService, CFDictionaryGetValue(service, CFSTR("ServiceID"))); CFDictionarySetValue(newGlobals, kSCDynamicStorePropNetPrimaryInterface, ifName); /* and check if AT newtorking is active on the primary interface */ key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, ifName, kSCEntNetAppleTalk); active = cache_SCDynamicStoreCopyValue(store, key); CFRelease(key); if (active) { if (isA_CFDictionary(active)) { postGlobals = TRUE; } CFRelease(active); } } /* * define the port */ portConfig = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(portConfig, NULL, CFSTR("%@:"), ifName); if (CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) { CFNumberRef num; /* * we have been asked to configure this interface as a * seed port. Ensure that we have been provided at least * one network number, have been provided with at least * one zonename, ... */ networkRange = CFDictionaryGetValue(service, kSCPropNetAppleTalkSeedNetworkRange); if (!isA_CFArray(networkRange) || (CFArrayGetCount(networkRange) == 0)) { SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk configuration error (%@)"), kSCPropNetAppleTalkSeedNetworkRange); goto nextIF; } /* * establish the starting and ending network numbers */ num = CFArrayGetValueAtIndex(networkRange, 0); if (!isA_CFNumber(num)) { SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk configuration error (%@)"), kSCPropNetAppleTalkSeedNetworkRange); goto nextIF; } CFNumberGetValue(num, kCFNumberIntType, &sNetwork); eNetwork = sNetwork; if (CFArrayGetCount(networkRange) > 1) { num = CFArrayGetValueAtIndex(networkRange, 1); if (!isA_CFNumber(num)) { SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk configuration error (%@)"), kSCPropNetAppleTalkSeedNetworkRange); goto nextIF; } CFNumberGetValue(num, kCFNumberIntType, &eNetwork); } CFStringAppendFormat(portConfig, NULL, CFSTR("%d:%d:"), sNetwork, eNetwork); /* * establish the zones associated with this port */ zoneList = CFDictionaryGetValue(service, kSCPropNetAppleTalkSeedZones); if (!isA_CFArray(zoneList)) { SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk configuration error (%@)"), kSCPropNetAppleTalkSeedZones); goto nextIF; } zCount = CFArrayGetCount(zoneList); for (j = 0; j < zCount; j++) { CFStringRef zone; CFArrayRef ifList; CFMutableArrayRef newIFList; zone = CFArrayGetValueAtIndex(zoneList, j); if (!isA_CFString(zone)) { continue; } if (CFDictionaryGetValueIfPresent(newZones, zone, (const void **)&ifList)) { /* known zone */ newIFList = CFArrayCreateMutableCopy(NULL, 0, ifList); } else { /* new zone */ newIFList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } CFArrayAppendValue(newIFList, ifName); CFArraySortValues(newIFList, CFRangeMake(0, CFArrayGetCount(newIFList)), (CFComparatorFunction)CFStringCompare, NULL); CFDictionarySetValue(newZones, zone, newIFList); CFRelease(newIFList); /* * flag the default zone */ if (!primaryZone) { primaryZone = CFRetain(zone); } } if (!primaryZone) { SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk configuration error (%@)"), kSCPropNetAppleTalkSeedZones); goto nextIF; } } /* get the (per-interface) "Computer Name" */ computerName = CFDictionaryGetValue(service, kSCPropNetAppleTalkComputerName); if (CFDictionaryGetValueIfPresent(service, kSCPropNetAppleTalkComputerNameEncoding, (const void **)&num) && isA_CFNumber(num)) { CFNumberGetValue(num, kCFNumberIntType, &computerNameEncoding); } else { computerNameEncoding = CFStringGetSystemEncoding(); } encodeName(computerName, computerNameEncoding, newStartup, newGlobals); /* * declare the first configured AppleTalk service / interface * as the "home port". */ if (CFArrayGetCount(newConfigFile) == 0) { CFStringAppend(portConfig, CFSTR("*")); primaryPort = CFRetain(ifName); } CFArrayAppendValue(newConfigFile, portConfig); /* * get the per-interface defaults */ ifDefaults = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); defaultNetwork = CFDictionaryGetValue(service, kSCPropNetAppleTalkNetworkID); defaultNode = CFDictionaryGetValue(service, kSCPropNetAppleTalkNodeID); if (isA_CFNumber(defaultNetwork) && isA_CFNumber(defaultNode)) { /* * set the default node and network */ CFDictionarySetValue(ifDefaults, kSCPropNetAppleTalkNetworkID, defaultNetwork); CFDictionarySetValue(ifDefaults, kSCPropNetAppleTalkNodeID, defaultNode); } if ((CFDictionaryGetValueIfPresent(service, kSCPropNetAppleTalkDefaultZone, (const void **)&defaultZone) == TRUE)) { /* * set the default zone for this interface */ CFDictionarySetValue(ifDefaults, kSCPropNetAppleTalkDefaultZone, defaultZone); } CFDictionarySetValue(newDefaults, ifName, ifDefaults); CFRelease(ifDefaults); switch (CFArrayGetCount(newConfigFile)) { case 1: /* * first AppleTalk interface */ CFDictionarySetValue(newStartup, CFSTR("APPLETALK"), ifName); break; case 2: /* second AppleTalk interface */ if (!CFEqual(CFDictionaryGetValue(newStartup, CFSTR("APPLETALK")), CFSTR("-ROUTER-"))) { /* * if not routing (yet), configure as multi-home */ CFDictionarySetValue(newStartup, CFSTR("APPLETALK"), CFSTR("-MULTIHOME-")); } break; } if (CFEqual(configMethod, kSCValNetAppleTalkConfigMethodRouter) || CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) { /* if not a simple node, enable routing */ CFDictionarySetValue(newStartup, CFSTR("APPLETALK"), CFSTR("-ROUTER-")); } /* * establish the State:/Network/Service/nnn/AppleTalk key info */ key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, CFDictionaryGetValue(service, CFSTR("ServiceID")), kSCEntNetAppleTalk); newDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(newDict, kSCPropInterfaceName, ifName); cache_SCDynamicStoreSetValue(store, key, newDict); CFRelease(newDict); if (info) { j = CFArrayGetFirstIndexOfValue(info, CFRangeMake(0, CFArrayGetCount(info)), key); if (j != kCFNotFound) { CFArrayRemoveValueAtIndex(info, j); } } CFRelease(key); nextIF : if (portConfig) CFRelease(portConfig); } if (primaryZone) { CFArrayRef ifList; CFMutableArrayRef newIFList; ifList = CFDictionaryGetValue(newZones, primaryZone); if (CFArrayContainsValue(ifList, CFRangeMake(0, CFArrayGetCount(ifList)), primaryPort)) { newIFList = CFArrayCreateMutableCopy(NULL, 0, ifList); CFArrayAppendValue(newIFList, CFSTR("*")); CFDictionarySetValue(newZones, primaryZone, newIFList); CFRelease(newIFList); } CFRelease(primaryZone); } if (primaryPort) { CFRelease(primaryPort); } /* sort the ports */ i = CFArrayGetCount(newConfigFile); CFArraySortValues(newConfigFile, CFRangeMake(0, i), (CFComparatorFunction)CFStringCompare, NULL); /* add the zones to the configuration */ CFDictionaryApplyFunction(newZones, addZoneToPorts, newConfigFile); CFRelease(newZones); /* sort the zones */ CFArraySortValues(newConfigFile, CFRangeMake(i, CFArrayGetCount(newConfigFile)-i), (CFComparatorFunction)CFStringCompare, NULL); /* ensure that the last line of the configuration file is terminated */ CFArrayAppendValue(newConfigFile, CFSTR("")); /* * Check if we have a "ComputerName" and look elsewhere if we don't have * one yet. */ if (!CFDictionaryContainsKey(newStartup, CFSTR("APPLETALK_HOSTNAME")) && (setGlobals != NULL)) { computerName = CFDictionaryGetValue(setGlobals, kSCPropNetAppleTalkComputerName); if (CFDictionaryGetValueIfPresent(setGlobals, kSCPropNetAppleTalkComputerNameEncoding, (const void **)&num) && isA_CFNumber(num)) { CFNumberGetValue(num, kCFNumberIntType, &computerNameEncoding); } else { computerNameEncoding = CFStringGetSystemEncoding(); } encodeName(computerName, computerNameEncoding, newStartup, newGlobals); } if (!CFDictionaryContainsKey(newStartup, CFSTR("APPLETALK_HOSTNAME"))) { computerName = SCDynamicStoreCopyComputerName(store, &computerNameEncoding); if (computerName) { encodeName(computerName, computerNameEncoding, newStartup, newGlobals); CFRelease(computerName); } } if (!CFDictionaryContainsKey(newStartup, CFSTR("APPLETALK_HOSTNAME"))) { struct utsname name; if (uname(&name) == 0) { computerName = CFStringCreateWithCString(NULL, name.nodename, kCFStringEncodingASCII); if (computerName) { encodeName(computerName, kCFStringEncodingASCII, NULL, newGlobals); CFRelease(computerName); } } } /* compare the previous and current configurations */ curGlobalsX = CFDictionaryCreateMutableCopy(NULL, 0, curGlobals); CFDictionaryRemoveValue(curGlobalsX, kSCDynamicStorePropNetPrimaryService); newGlobalsX = CFDictionaryCreateMutableCopy(NULL, 0, newGlobals); CFDictionaryRemoveValue(newGlobalsX, kSCDynamicStorePropNetPrimaryService); key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetAppleTalk); if (CFEqual(curGlobalsX , newGlobalsX ) && CFEqual(curConfigFile , newConfigFile) && CFEqual(curDefaults , newDefaults ) && CFEqual(curStartup , newStartup ) ) { /* * the configuration has not changed. */ if (postGlobals) { /* * the requested configuration hasn't changed but we * now need to tell everyone that AppleTalk is active. */ if (!SCDynamicStoreSetValue(store, key, newGlobals)) { SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetValue() failed: %s"), SCErrorString(SCError())); } } CFRelease(newGlobals); CFRelease(newConfigFile); CFRelease(newDefaults); CFRelease(newStartup); } else if (CFArrayGetCount(newConfigFile) <= 1) { /* * the configuration has changed but there are no * longer any interfaces configured for AppleTalk * networking. */ /* * remove the global (State:/Network/Global/AppleTalk) key. * * Note: it will be restored later after AT networking has * been activated. */ /* remove the (/etc/appletalk.cfg) configuration file */ (void)unlink(AT_CFG_FILE); /* * update the per-service (and global) state */ cache_SCDynamicStoreRemoveValue(store, key); // remove State:/Network/Global/AppleTalk n = CFArrayGetCount(info); for (i = 0; i < n; i++) { CFStringRef xKey = CFArrayGetValueAtIndex(info, i); cache_SCDynamicStoreRemoveValue(store, xKey); } cache_write(store); /* flag this as a new configuration */ *newState = -(abs(curState) + 1); changed = TRUE; } else { /* * the configuration has changed. */ /* update the (/etc/appletalk.cfg) configuration file */ configWrite(AT_CFG_FILE, newConfigFile); /* * update the per-service (and global) state * * Note: if present, we remove any existing global state key and allow it * to be restored after the stack has been re-started. */ CFDictionaryApplyFunction(newDefaults, updateDefaults, NULL); cache_SCDynamicStoreRemoveValue(store, key); // remove State:/Network/Global/AppleTalk n = CFArrayGetCount(info); for (i = 0; i < n; i++) { CFStringRef xKey = CFArrayGetValueAtIndex(info, i); cache_SCDynamicStoreRemoveValue(store, xKey); } cache_write(store); /* flag this as a new configuration */ *newState = abs(curState) + 1; changed = TRUE; } CFRelease(curGlobalsX); CFRelease(newGlobalsX); CFRelease(key); if (changed) { CFRelease(curGlobals); curGlobals = newGlobals; CFRelease(curConfigFile); curConfigFile = newConfigFile; CFRelease(curDefaults); curDefaults = newDefaults; CFRelease(curStartup); curStartup = newStartup; } if (info) CFRelease(info); if (interfaces) CFRelease(interfaces); if (configuredServices) CFRelease(configuredServices); if (setGlobals) CFRelease(setGlobals); cache_close(); return changed; }
static void smb_set_configuration(SCDynamicStoreRef store, CFDictionaryRef dict) { CFArrayRef array; Boolean changed = FALSE; UInt32 dosCodepage = 0; CFStringEncoding dosEncoding = 0; CFStringEncoding macEncoding = kCFStringEncodingMacRoman; uint32_t macRegion = 0; Boolean ok; SCPreferencesRef prefs; CFStringRef str; prefs = SCPreferencesCreate(NULL, CFSTR("smb-configuration"), CFSTR(kSMBPreferencesAppID)); if (prefs == NULL) { my_log(LOG_ERR, "smb_set_configuration: SCPreferencesCreate() failed: %s", SCErrorString(SCError())); return; } ok = SCPreferencesLock(prefs, TRUE); if (!ok) { my_log(LOG_ERR, "smb_set_configuration: SCPreferencesLock() failed: %s", SCErrorString(SCError())); goto done; } // Server description str = SCDynamicStoreCopyComputerName(store, &macEncoding); update_pref(prefs, CFSTR(kSMBPrefServerDescription), str, &changed); // DOS code page if (str != NULL) { if (macEncoding == kCFStringEncodingMacRoman) { CFStringRef key; CFDictionaryRef dict; // get region key = SCDynamicStoreKeyCreateComputerName(NULL); dict = SCDynamicStoreCopyValue(store, key); CFRelease(key); if (dict != NULL) { if (isA_CFDictionary(dict)) { CFNumberRef num; SInt32 val; num = CFDictionaryGetValue(dict, kSCPropSystemComputerNameRegion); if (isA_CFNumber(num) && CFNumberGetValue(num, kCFNumberSInt32Type, &val)) { macRegion = (uint32_t)val; } } CFRelease(dict); } } CFRelease(str); } else { // Important: must have root acccess (eUID==0) to access the config file! __CFStringGetInstallationEncodingAndRegion((uint32_t *)&macEncoding, &macRegion); } _SC_dos_encoding_and_codepage(macEncoding, macRegion, &dosEncoding, &dosCodepage); str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), (unsigned int)dosCodepage); assert(str != NULL); update_pref(prefs, CFSTR(kSMBPrefDOSCodePage), str, &changed); CFRelease(str); // NetBIOS name str = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSName); str = isA_CFString(str); update_pref(prefs, CFSTR(kSMBPrefNetBIOSName), str, &changed); // NetBIOS node type str = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSNodeType); str = isA_CFString(str); if (str != NULL) { if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypeBroadcast)) { // B-node str = CFSTR(kSMBPrefNetBIOSNodeBroadcast); } else if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypePeer)) { // P-node str = CFSTR(kSMBPrefNetBIOSNodePeer); } else if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypeMixed)) { // M-node str = CFSTR(kSMBPrefNetBIOSNodeMixed); } else if (CFEqual(str, kSCValNetSMBNetBIOSNodeTypeHybrid)) { // H-node str = CFSTR(kSMBPrefNetBIOSNodeHybrid); } else { str = NULL; } } update_pref(prefs, CFSTR(kSMBPrefNetBIOSNodeType), str, &changed); #ifdef ADD_NETBIOS_SCOPE // NetBIOS scope str = CFDictionaryGetValue(dict, kSCPropNetSMBNetBIOSScope); str = isA_CFString(str); update_pref(prefs, CFSTR(kSMBPrefNetBIOSScope), str, &changed); #endif // ADD_NETBIOS_SCOPE // WINS addresses array = CFDictionaryGetValue(dict, kSCPropNetSMBWINSAddresses); array = isA_CFArray(array); update_pref(prefs, CFSTR(kSMBPrefWINSServerAddressList), array, &changed); // Workgroup (or domain) str = CFDictionaryGetValue(dict, kSCPropNetSMBWorkgroup); str = isA_CFString(str); update_pref(prefs, CFSTR(kSMBPrefWorkgroup), str, &changed); if (changed) { ok = SCPreferencesCommitChanges(prefs); if (!ok) { if ((SCError() != EROFS)) { my_log(LOG_ERR, "smb_set_configuration: SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError())); } goto done; } ok = SCPreferencesApplyChanges(prefs); if (!ok) { my_log(LOG_ERR, "smb_set_configuration: SCPreferencesApplyChanges() failed: %s", SCErrorString(SCError())); goto done; } } done : (void) SCPreferencesUnlock(prefs); CFRelease(prefs); return; }
SCVLANInterfaceRef SCVLANInterfaceCreate(SCPreferencesRef prefs, SCNetworkInterfaceRef physical, CFNumberRef tag) { CFAllocatorRef allocator; CFIndex i; SCNetworkInterfacePrivateRef interfacePrivate; SCVLANInterfaceRef vlan; if (prefs == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } if (!isA_SCNetworkInterface(physical)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } interfacePrivate = (SCNetworkInterfacePrivateRef)physical; if (!interfacePrivate->supportsVLAN) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } if (isA_CFNumber(tag)) { int tag_val; CFNumberGetValue(tag, kCFNumberIntType, &tag_val); if ((tag_val < 1) || (tag_val > 4094)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } } else { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } // make sure that physical interface and tag are not used vlan = findVLANInterfaceAndTag(prefs, physical, tag); if (vlan != NULL) { CFRelease(vlan); _SCErrorSet(kSCStatusKeyExists); return NULL; } allocator = CFGetAllocator(prefs); // create a new VLAN using an unused interface name for (i = 0; vlan == NULL; i++) { CFDictionaryRef dict; CFStringRef vlan_if; Boolean ok; CFStringRef path; vlan_if = CFStringCreateWithFormat(allocator, NULL, CFSTR("vlan%ld"), i); path = CFStringCreateWithFormat(allocator, NULL, CFSTR("/%@/%@/%@"), kSCPrefVirtualNetworkInterfaces, kSCNetworkInterfaceTypeVLAN, vlan_if); dict = SCPreferencesPathGetValue(prefs, path); if (dict != NULL) { // if VLAN interface name not available CFRelease(path); CFRelease(vlan_if); continue; } // add the VLAN to the stored preferences dict = CFDictionaryCreate(allocator, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ok = SCPreferencesPathSetValue(prefs, path, dict); CFRelease(dict); CFRelease(path); if (!ok) { // if the VLAN could not be saved CFRelease(vlan_if); _SCErrorSet(kSCStatusFailed); break; } // create the SCVLANInterfaceRef vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(allocator, vlan_if); CFRelease(vlan_if); // estabish link to the stored configuration interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; interfacePrivate->prefs = CFRetain(prefs); // set physical interface and tag SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, physical, tag); } return vlan; }
Boolean SCVLANInterfaceSetPhysicalInterfaceAndTag(SCVLANInterfaceRef vlan, SCNetworkInterfaceRef physical, CFNumberRef tag) { SCNetworkInterfacePrivateRef interfacePrivate; Boolean ok = TRUE; if (!isA_SCVLANInterface(vlan)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } if (!isA_SCNetworkInterface(physical)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } interfacePrivate = (SCNetworkInterfacePrivateRef)physical; if (!interfacePrivate->supportsVLAN) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } if (isA_CFNumber(tag)) { int tag_val; CFNumberGetValue(tag, kCFNumberIntType, &tag_val); if ((tag_val < 1) || (tag_val > 4094)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } } else { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; if (interfacePrivate->prefs != NULL) { SCVLANInterfaceRef config_vlan; CFDictionaryRef dict; CFMutableDictionaryRef newDict; CFStringRef path; // make sure that physical interface and tag are not used config_vlan = findVLANInterfaceAndTag(interfacePrivate->prefs, physical, tag); if (config_vlan != NULL) { if (!CFEqual(vlan, config_vlan)) { CFRelease(config_vlan); _SCErrorSet(kSCStatusKeyExists); return FALSE; } CFRelease(config_vlan); } // set interface/tag in the stored preferences path = CFStringCreateWithFormat(NULL, NULL, CFSTR("/%@/%@/%@"), kSCPrefVirtualNetworkInterfaces, kSCNetworkInterfaceTypeVLAN, interfacePrivate->entity_device); dict = SCPreferencesPathGetValue(interfacePrivate->prefs, path); if (!isA_CFDictionary(dict)) { // if the prefs are confused CFRelease(path); _SCErrorSet(kSCStatusFailed); return FALSE; } newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANInterface, SCNetworkInterfaceGetBSDName(physical)); CFDictionarySetValue(newDict, kSCPropVirtualNetworkInterfacesVLANTag, tag); if (!CFEqual(dict, newDict)) { ok = SCPreferencesPathSetValue(interfacePrivate->prefs, path, newDict); } CFRelease(newDict); CFRelease(path); } if (ok) { SCNetworkInterfacePrivateRef newInterface; CFTypeRef save; // set physical interface newInterface = __SCNetworkInterfaceCreateCopy(NULL, physical, interfacePrivate->prefs, interfacePrivate->serviceID); save = interfacePrivate->vlan.interface; interfacePrivate->vlan.interface = (SCNetworkInterfaceRef)newInterface; if (save != NULL) CFRelease(save); // set tag save = interfacePrivate->vlan.tag; interfacePrivate->vlan.tag = CFRetain(tag); if (save != NULL) CFRelease(save); } return ok; }
static void add_configured_interface(const void *key, const void *value, void *context) { SCNetworkInterfacePrivateRef interfacePrivate; addContextRef myContext = (addContextRef)context; SCVLANInterfaceRef vlan; CFStringRef vlan_if = (CFStringRef)key; CFDictionaryRef vlan_info = (CFDictionaryRef)value; CFStringRef vlan_name; CFDictionaryRef vlan_options; SCNetworkInterfaceRef vlan_physical; CFStringRef vlan_physical_if; CFNumberRef vlan_tag; vlan_physical_if = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANInterface); if (!isA_CFString(vlan_physical_if)) { // if prefs are confused return; } vlan_tag = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANTag); if (!isA_CFNumber(vlan_tag)) { // if prefs are confused return; } // create the VLAN interface vlan = (SCVLANInterfaceRef)_SCVLANInterfaceCreatePrivate(NULL, vlan_if); assert(vlan != NULL); // set physical interface and tag vlan_physical = _SCNetworkInterfaceCreateWithBSDName(NULL, vlan_physical_if, kIncludeBondInterfaces); assert(vlan_physical != NULL); // since we KNOW that the physical interface supported VLANs when // it was first established it's OK to force that state here ... // and this is needed for the case when the interface (e.g. a // dongle) is not currently attached to the system interfacePrivate = (SCNetworkInterfacePrivateRef)vlan_physical; interfacePrivate->supportsVLAN = TRUE; // and now we associate the physical interface and tag SCVLANInterfaceSetPhysicalInterfaceAndTag(vlan, vlan_physical, vlan_tag); CFRelease(vlan_physical); // set display name vlan_name = CFDictionaryGetValue(vlan_info, kSCPropUserDefinedName); if (isA_CFString(vlan_name)) { SCVLANInterfaceSetLocalizedDisplayName(vlan, vlan_name); } // set options vlan_options = CFDictionaryGetValue(vlan_info, kSCPropVirtualNetworkInterfacesVLANOptions); if (isA_CFDictionary(vlan_options)) { SCVLANInterfaceSetOptions(vlan, vlan_options); } // estabish link to the stored configuration interfacePrivate = (SCNetworkInterfacePrivateRef)vlan; interfacePrivate->prefs = CFRetain(myContext->prefs); CFArrayAppendValue(myContext->vlans, vlan); CFRelease(vlan); return; }
static void add_supplemental(CFMutableArrayRef proxies, CFDictionaryRef proxy, uint32_t defaultOrder) { CFArrayRef domains; CFIndex i; CFIndex n_domains; CFArrayRef orders; domains = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchDomains); n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0; if (n_domains == 0) { return; } orders = CFDictionaryGetValue(proxy, kSCPropNetProxiesSupplementalMatchOrders); if (orders != NULL) { if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) { return; } } /* * yes, this is a "supplemental" proxy configuration, expand * the match domains and add each to the proxies list. */ for (i = 0; i < n_domains; i++) { CFStringRef match_domain; CFNumberRef match_order; CFMutableDictionaryRef match_proxy; match_domain = CFArrayGetValueAtIndex(domains, i); if (!isA_CFString(match_domain)) { continue; } match_proxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); // set supplemental proxy match "domain" match_domain = _SC_trimDomain(match_domain); if (match_domain != NULL) { CFDictionarySetValue(match_proxy, kSCPropNetProxiesSupplementalMatchDomain, match_domain); CFRelease(match_domain); } else { CFDictionaryRemoveValue(match_proxy, kSCPropNetProxiesSupplementalMatchDomain); } // set supplemental proxy match "order" match_order = (orders != NULL) ? CFArrayGetValueAtIndex(orders, i) : NULL; if (isA_CFNumber(match_order)) { CFDictionarySetValue(match_proxy, PROXY_MATCH_ORDER_KEY, match_order); } else { CFNumberRef num; num = CFNumberCreate(NULL, kCFNumberIntType, &defaultOrder); CFDictionarySetValue(match_proxy, PROXY_MATCH_ORDER_KEY, num); CFRelease(num); defaultOrder++; // if multiple domains, maintain ordering } // remove keys we don't want in a supplemental proxy CFDictionaryRemoveValue(match_proxy, kSCPropNetProxiesSupplementalMatchDomains); CFDictionaryRemoveValue(match_proxy, kSCPropNetProxiesSupplementalMatchOrders); CFDictionaryRemoveValue(match_proxy, kSCPropInterfaceName); add_proxy(proxies, match_proxy); CFRelease(match_proxy); } return; }
int checkVPNInterfaceOrServiceBlocked (const char *location, char *interface_buf) { // check to see if interface is captive: if so, bail if the interface is not ready. if (check_interface_captive_and_not_ready(gDynamicStore, interface_buf)) { // TODO: perhaps we should wait for a few seconds? return true; } // return 1, if this is a delete event, and; // TODO: add support for IPv6 <rdar://problem/5920237> // walk Setup:/Network/Service/* and check if there are service entries referencing this interface. e.g. Setup:/Network/Service/44DB8790-0177-4F17-8D4E-37F9413D1D87/Interface:DeviceName == interface, other_serv_found = 1 // Setup:/Network/Interface/"interface"/AirPort:'PowerEnable' == 0 || Setup:/Network/Interface/"interface"/IPv4 is missing, interf_down = 1 if (gDynamicStore) { CFStringRef interf_key; CFMutableArrayRef interf_keys; CFStringRef pattern; CFMutableArrayRef patterns; CFDictionaryRef dict = NULL; CFIndex i; const void * keys_q[128]; const void ** keys = keys_q; const void * values_q[128]; const void ** values = values_q; CFIndex n; CFStringRef vpn_if; int other_serv_found = 0, interf_down = 0; vpn_if = CFStringCreateWithCStringNoCopy(NULL, interface_buf, kCFStringEncodingASCII, kCFAllocatorNull); if (!vpn_if) { // if we could not initialize interface CFString syslog(LOG_NOTICE, "%s: failed to initialize interface CFString", location); goto done; } interf_keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); // get Setup:/Network/Interface/<vpn_if>/Airport interf_key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainSetup, vpn_if, kSCEntNetAirPort); CFArrayAppendValue(interf_keys, interf_key); CFRelease(interf_key); // get State:/Network/Interface/<vpn_if>/Airport interf_key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, vpn_if, kSCEntNetAirPort); CFArrayAppendValue(interf_keys, interf_key); CFRelease(interf_key); // get Setup:/Network/Service/*/Interface pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface); CFArrayAppendValue(patterns, pattern); CFRelease(pattern); // get Setup:/Network/Service/*/IPv4 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4); CFArrayAppendValue(patterns, pattern); CFRelease(pattern); dict = SCDynamicStoreCopyMultiple(gDynamicStore, interf_keys, patterns); CFRelease(interf_keys); CFRelease(patterns); if (!dict) { // if we could not access the SCDynamicStore syslog(LOG_NOTICE, "%s: failed to initialize SCDynamicStore dictionary", location); CFRelease(vpn_if); goto done; } // look for the service which matches the provided prefixes n = CFDictionaryGetCount(dict); if (n <= 0) { syslog(LOG_NOTICE, "%s: empty SCDynamicStore dictionary", location); CFRelease(vpn_if); goto done; } if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); values = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); } CFDictionaryGetKeysAndValues(dict, keys, values); for (i=0; i < n; i++) { CFStringRef s_key = (CFStringRef)keys[i]; CFDictionaryRef s_dict = (CFDictionaryRef)values[i]; CFStringRef s_if; if (!isA_CFString(s_key) || !isA_CFDictionary(s_dict)) { continue; } if (CFStringHasSuffix(s_key, kSCEntNetInterface)) { // is a Service Interface entity s_if = CFDictionaryGetValue(s_dict, kSCPropNetInterfaceDeviceName); if (isA_CFString(s_if) && CFEqual(vpn_if, s_if)) { CFArrayRef components; CFStringRef serviceIDRef = NULL, serviceKey = NULL; other_serv_found = 1; // extract service ID components = CFStringCreateArrayBySeparatingStrings(NULL, s_key, CFSTR("/")); if (CFArrayGetCount(components) > 3) { serviceIDRef = CFArrayGetValueAtIndex(components, 3); //if (new key) Setup:/Network/Service/service_id/IPv4 is missing, then interf_down = 1 serviceKey = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainSetup, serviceIDRef, kSCEntNetIPv4); if (!serviceKey || !CFDictionaryGetValue(dict, serviceKey)) { syslog(LOG_NOTICE, "%s: detected disabled IPv4 Config", location); interf_down = 1; } if (serviceKey) CFRelease(serviceKey); } if (components) CFRelease(components); if (interf_down) break; } continue; } else if (CFStringHasSuffix(s_key, kSCEntNetAirPort)) { // Interface/<vpn_if>/Airport entity if (CFStringHasPrefix(s_key, kSCDynamicStoreDomainSetup)) { CFBooleanRef powerEnable = CFDictionaryGetValue(s_dict, kSCPropNetAirPortPowerEnabled); if (isA_CFBoolean(powerEnable) && CFEqual(powerEnable, kCFBooleanFalse)) { syslog(LOG_NOTICE, "%s: detected AirPort, PowerEnable == FALSE", location); interf_down = 1; break; } } else if (CFStringHasPrefix(s_key, kSCDynamicStoreDomainState)) { UInt16 temp; CFNumberRef airStatus = CFDictionaryGetValue(s_dict, CFSTR("Power Status")); if (isA_CFNumber(airStatus) && CFNumberGetValue(airStatus, kCFNumberShortType, &temp)) { if (temp ==0) { syslog(LOG_NOTICE, "%s: detected AirPort, PowerStatus == 0", location); } } } continue; } } if (vpn_if) CFRelease(vpn_if); if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); CFAllocatorDeallocate(NULL, values); } done : if (dict) CFRelease(dict); return (other_serv_found == 0 || interf_down == 1); } return 0; }