/* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ static Boolean hasEntitlement(audit_token_t audit_token, CFStringRef entitlement, CFStringRef vpntype) { Boolean hasEntitlement = FALSE; SecTaskRef task; /* Create the security task from the audit token. */ task = SecTaskCreateWithAuditToken(NULL, audit_token); if (task != NULL) { CFErrorRef error = NULL; CFTypeRef value; /* Get the value for the entitlement. */ value = SecTaskCopyValueForEntitlement(task, entitlement, &error); if (value != NULL) { if (isA_CFBoolean(value)) { if (CFBooleanGetValue(value)) { /* if client DOES have entitlement */ hasEntitlement = TRUE; } } else if (isA_CFArray(value)){ if (vpntype == NULL){ /* we don't care about subtype */ hasEntitlement = TRUE; }else { if (CFArrayContainsValue(value, CFRangeMake(0, CFArrayGetCount(value)), vpntype)) { // if client DOES have entitlement hasEntitlement = TRUE; } } } else { SCLog(TRUE, LOG_ERR, CFSTR("SCNC Controller: entitlement not valid: %@"), entitlement); } CFRelease(value); } else if (error != NULL) { SCLog(TRUE, LOG_ERR, CFSTR("SCNC Controller: SecTaskCopyValueForEntitlement() failed, error=%@: %@"), error, entitlement); CFRelease(error); } CFRelease(task); } else { SCLog(TRUE, LOG_ERR, CFSTR("SCNC Controller: SecTaskCreateWithAuditToken() failed: %@"), entitlement); } return hasEntitlement; }
__private_extern__ void proxy_configuration_init(CFBundleRef bundle) { CFDictionaryRef dict; dict = CFBundleGetInfoDictionary(bundle); if (isA_CFDictionary(dict)) { G_supplemental_proxies_follow_dns = CFDictionaryGetValue(dict, CFSTR("SupplementalProxiesFollowSupplementalDNS")); G_supplemental_proxies_follow_dns = isA_CFBoolean(G_supplemental_proxies_follow_dns); } return; }
/* * For rdar://problem/4685223 * * To keep MoreSCF happy we need to ensure that the first "Set" and * "NetworkService" have a [less than] unique identifier that can * be parsed as a numeric string. * * Note: this backwards compatibility code must be enabled using the * following command: * * sudo defaults write \ * /Library/Preferences/SystemConfiguration/preferences \ * MoreSCF \ * -bool true */ __private_extern__ CFStringRef __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(SCPreferencesRef prefs, CFStringRef prefix) { static int hack = -1; CFStringRef path = NULL; if (hack < 0) { CFBooleanRef enable; enable = SCPreferencesGetValue(prefs, CFSTR("MoreSCF")); hack = (isA_CFBoolean(enable) && CFBooleanGetValue(enable)) ? 1 : 0; } if (hack > 0) { CFDictionaryRef dict; Boolean ok; path = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), prefix, CFSTR("0")); dict = SCPreferencesPathGetValue(prefs, path); if (dict != NULL) { // if path "0" exists CFRelease(path); return NULL; } // unique child with path "0" does not exist, create dict = CFDictionaryCreate(NULL, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ok = SCPreferencesPathSetValue(prefs, path, dict); CFRelease(dict); if (!ok) { // if create failed CFRelease(path); return NULL; } } return path; }
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 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; }
/* 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; }
__private_extern__ kern_return_t _configopen(mach_port_t server, xmlData_t nameRef, /* raw XML bytes */ mach_msg_type_number_t nameLen, xmlData_t optionsRef, /* raw XML bytes */ mach_msg_type_number_t optionsLen, mach_port_t *newServer, int *sc_status, audit_token_t audit_token) { CFDictionaryRef info; serverSessionRef mySession; CFStringRef name = NULL; /* name (un-serialized) */ CFMutableDictionaryRef newInfo; mach_port_t oldNotify; CFDictionaryRef options = NULL; /* options (un-serialized) */ CFStringRef sessionKey; kern_return_t status; SCDynamicStorePrivateRef storePrivate; CFBooleanRef useSessionKeys = NULL; *sc_status = kSCStatusOK; /* un-serialize the name */ if (!_SCUnserializeString(&name, NULL, (void *)nameRef, nameLen)) { *sc_status = kSCStatusFailed; } if ((optionsRef != NULL) && (optionsLen > 0)) { /* un-serialize the [session] options */ if (!_SCUnserialize((CFPropertyListRef *)&options, NULL, (void *)optionsRef, optionsLen)) { *sc_status = kSCStatusFailed; } } if (*sc_status != kSCStatusOK) { goto done; } if (!isA_CFString(name)) { *sc_status = kSCStatusInvalidArgument; goto done; } if (options != NULL) { if (!isA_CFDictionary(options)) { *sc_status = kSCStatusInvalidArgument; goto done; } /* * [pre-]process any provided options */ useSessionKeys = CFDictionaryGetValue(options, kSCDynamicStoreUseSessionKeys); if (useSessionKeys != NULL) { if (!isA_CFBoolean(useSessionKeys)) { *sc_status = kSCStatusInvalidArgument; goto done; } } } /* * establish the new session */ mySession = addSession(server, openMPCopyDescription); if (mySession == NULL) { #ifdef DEBUG SCLog(TRUE, LOG_DEBUG, CFSTR("_configopen(): session is already open.")); #endif /* DEBUG */ *sc_status = kSCStatusFailed; /* you can't re-open an "open" session */ goto done; } *newServer = mySession->key; __MACH_PORT_DEBUG(TRUE, "*** _configopen (after addSession)", *newServer); /* save the audit_token in case we need to check the callers credentials */ mySession->auditToken = audit_token; /* Create and add a run loop source for the port */ mySession->serverRunLoopSource = CFMachPortCreateRunLoopSource(NULL, mySession->serverPort, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), mySession->serverRunLoopSource, kCFRunLoopDefaultMode); if (_configd_trace) { SCTrace(TRUE, _configd_trace, CFSTR("open : %5d : %@\n"), *newServer, name); } *sc_status = __SCDynamicStoreOpen(&mySession->store, name); storePrivate = (SCDynamicStorePrivateRef)mySession->store; /* * Make the server port accessible to the framework routines. * ... and be sure to clear before calling CFRelease(store) */ storePrivate->server = *newServer; /* * Process any provided [session] options */ if (useSessionKeys != NULL) { storePrivate->useSessionKeys = CFBooleanGetValue(useSessionKeys); } /* Request a notification when/if the client dies */ status = mach_port_request_notification(mach_task_self(), *newServer, MACH_NOTIFY_NO_SENDERS, 1, *newServer, MACH_MSG_TYPE_MAKE_SEND_ONCE, &oldNotify); if (status != KERN_SUCCESS) { SCLog(TRUE, LOG_ERR, CFSTR("_configopen() mach_port_request_notification() failed: %s"), mach_error_string(status)); cleanupSession(*newServer); *newServer = MACH_PORT_NULL; *sc_status = kSCStatusFailed; goto done; } __MACH_PORT_DEBUG(TRUE, "*** _configopen (after mach_port_request_notification)", *newServer); if (oldNotify != MACH_PORT_NULL) { SCLog(TRUE, LOG_ERR, CFSTR("_configopen(): oldNotify != MACH_PORT_NULL")); } /* * Save the name of the calling application / plug-in with the session data. */ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), *newServer); info = CFDictionaryGetValue(sessionData, sessionKey); if (info != NULL) { newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info); } else { newInfo = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } CFDictionarySetValue(newInfo, kSCDName, name); CFDictionarySetValue(sessionData, sessionKey, newInfo); CFRelease(newInfo); CFRelease(sessionKey); /* * Note: at this time we should be holding ONE send right and * ONE receive right to the server. The send right is * moved to the caller. */ done : if (name != NULL) CFRelease(name); if (options != NULL) CFRelease(options); return KERN_SUCCESS; }
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; }
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; }