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;
}
Exemple #3
0
__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;
}
Exemple #4
0
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);
}
Exemple #9
0
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;
}
Exemple #13
0
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);
}
Exemple #14
0
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;
}
Exemple #15
0
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;
}
Exemple #16
0
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;
}
Exemple #21
0
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;
}