static Boolean
__bond_remove_interface(int s, CFStringRef bond_if, CFStringRef interface_if)
{
	struct if_bond_req	breq;
	struct ifreq		ifr;

	// bond interface
	bzero(&ifr, sizeof(ifr));
	(void) _SC_cfstring_to_cstring(bond_if,
				       ifr.ifr_name,
				       sizeof(ifr.ifr_name),
				       kCFStringEncodingASCII);
	ifr.ifr_data = (caddr_t)&breq;

	// bond member to remove
	bzero(&breq, sizeof(breq));
	breq.ibr_op = IF_BOND_OP_REMOVE_INTERFACE;
	(void) _SC_cfstring_to_cstring(interface_if,
				       breq.ibr_ibru.ibru_if_name,
				       sizeof(breq.ibr_ibru.ibru_if_name),
				       kCFStringEncodingASCII);

	// remove bond member
	if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
		_SCErrorSet(errno);
		SCLog(TRUE, LOG_ERR,
		      CFSTR("could not remove interface \"%@\" from bond \"%@\": %s"),
		      interface_if,
		      bond_if,
		      strerror(errno));
		return FALSE;
	}

	return TRUE;
}
Example #2
0
static uid_t
uid_from_odrecord(ODRecordRef record)
{
    uid_t		uid = -2;
    CFArrayRef		values	= NULL;

    values = ODRecordCopyValues(record, CFSTR(kDS1AttrUniqueID), NULL);
    if ((values != NULL) && (CFArrayGetCount(values) > 0)) {
	char		buf[64];
	char *		end;
	CFStringRef	uidStr;
	unsigned long	val;

	uidStr = CFArrayGetValueAtIndex(values, 0);
	(void) _SC_cfstring_to_cstring(uidStr, buf, sizeof(buf),
				       kCFStringEncodingASCII);
	errno = 0;
	val = strtoul(buf, &end, 0);
	if ((buf[0] != '\0') && (*end == '\0') && (errno == 0)) {
	    uid = (uid_t)val;
	}
    }
    my_CFRelease(&values);
    return (uid);
}
static Boolean
__vlan_clear(int s, CFStringRef interface_if)
{
	struct ifreq	ifr;
	struct vlanreq	vreq;

	bzero(&ifr, sizeof(ifr));
	bzero(&vreq, sizeof(vreq));

	// interface
	(void) _SC_cfstring_to_cstring(interface_if,
				       ifr.ifr_name,
				       sizeof(ifr.ifr_name),
				       kCFStringEncodingASCII);
	ifr.ifr_data = (caddr_t)&vreq;

	// clear physical interface
	bzero(&vreq.vlr_parent, sizeof(vreq.vlr_parent));

	// clear tag
	vreq.vlr_tag = 0;

	// update physical interface and tag
	if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
		SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
		_SCErrorSet(kSCStatusFailed);
		return FALSE;
	}

	return TRUE;
}
static Boolean
__bond_set_mode(int s, CFStringRef bond_if, CFNumberRef mode)
{
	struct if_bond_req	breq;
	struct ifreq		ifr;
	int					mode_num;

	mode_num = IF_BOND_MODE_LACP;
	if (mode != NULL) {
		CFNumberGetValue(mode, kCFNumberIntType, &mode_num);
	}

	// bond interface
	bzero(&ifr, sizeof(ifr));
	(void) _SC_cfstring_to_cstring(bond_if,
				       ifr.ifr_name,
				       sizeof(ifr.ifr_name),
				       kCFStringEncodingASCII);
	ifr.ifr_data = (caddr_t)&breq;
	bzero(&breq, sizeof(breq));
	breq.ibr_op = IF_BOND_OP_SET_MODE;
	breq.ibr_ibru.ibru_int_val = mode_num;
	if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1) {
		_SCErrorSet(errno);
		SCLog(TRUE, LOG_ERR,
		      CFSTR("could not set mode to %d on bond \"%@\": %s"),
		      mode,
		      bond_if,
		      strerror(errno));
		return FALSE;
	}

	return TRUE;
}
Example #5
0
char *
AFPUser_get_user(AFPUserRef user, char *buf, size_t buf_len)
{
    CFStringRef	name;
    ODRecordRef	record;

    record = (ODRecordRef)CFDictionaryGetValue(user, kAFPUserODRecord);
    name = ODRecordGetRecordName(record);
    (void) _SC_cfstring_to_cstring(name, buf, buf_len, kCFStringEncodingASCII);
    return buf;
}
static Boolean
__vlan_set(int s, CFStringRef interface_if, CFStringRef physical_if, CFNumberRef tag)
{
	struct ifreq	ifr;
	int		tag_val;
	struct vlanreq	vreq;

	bzero(&ifr, sizeof(ifr));
	bzero(&vreq, sizeof(vreq));

	// interface
	(void) _SC_cfstring_to_cstring(interface_if,
				       ifr.ifr_name,
				       sizeof(ifr.ifr_name),
				       kCFStringEncodingASCII);
	ifr.ifr_data = (caddr_t)&vreq;

	// physical interface
	(void) _SC_cfstring_to_cstring(physical_if,
				       vreq.vlr_parent,
				       sizeof(vreq.vlr_parent),
				       kCFStringEncodingASCII);

	// tag
	CFNumberGetValue(tag, kCFNumberIntType, &tag_val);
	vreq.vlr_tag = tag_val;

	// update physical interface and tag
	if (ioctl(s, SIOCSIFVLAN, (caddr_t)&ifr) == -1) {
		SCLog(TRUE, LOG_ERR, CFSTR("ioctl(SIOCSIFVLAN) failed: %s"), strerror(errno));
		_SCErrorSet(kSCStatusFailed);
		return FALSE;
	}

	return TRUE;
}
Example #7
0
/*
 * Function: AFPUser_set_random_password
 * Purpose:
 *   Set a random password for the user and returns it in passwd.
 *   Do not change the password again until AFPUSER_PASSWORD_CHANGE_INTERVAL
 *   has elapsed.  This overcomes the problem where every client
 *   request packet is duplicated. In that case, the client tries to use
 *   a password that subsequently gets changed when the duplicate arrives.
 */
Boolean
AFPUser_set_random_password(AFPUserRef user,
			    char * passwd, size_t passwd_len)
{
    CFDateRef		last_set;
    Boolean		ok = TRUE;
    CFDateRef		now;
    CFStringRef		pw;
    ODRecordRef		record;

    now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
    pw = CFDictionaryGetValue(user, kAFPUserPassword);
    last_set = CFDictionaryGetValue(user, kAFPUserDatePasswordLastSet);
    if (pw != NULL && last_set != NULL
	&& (CFDateGetTimeIntervalSinceDate(now, last_set) 
	    < AFPUSER_PASSWORD_CHANGE_INTERVAL)) {
	/* return what we have */
#ifdef TEST_AFPUSERS
	printf("No need to change the password %d < %d\n",
	       (int)CFDateGetTimeIntervalSinceDate(now, last_set),
	       AFPUSER_PASSWORD_CHANGE_INTERVAL);
#endif /* TEST_AFPUSERS */
	(void)_SC_cfstring_to_cstring(pw, passwd, passwd_len,
				      kCFStringEncodingASCII);
	CFDictionarySetValue(user, kAFPUserDatePasswordLastSet, now);
    }
    else {
	generate_random_password(passwd, passwd_len);

	record = (ODRecordRef)CFDictionaryGetValue(user, kAFPUserODRecord);
	pw = CFStringCreateWithCString(NULL, passwd, kCFStringEncodingASCII);
	ok = ODRecordChangePassword(record, NULL, pw, NULL);
	if (ok) {
	    CFDictionarySetValue(user, kAFPUserPassword, pw);
	    CFDictionarySetValue(user, kAFPUserDatePasswordLastSet, now);
	}
	else {
	    my_log(LOG_NOTICE, "AFPUser_set_random_password:"******" ODRecordChangePassword() failed");
	    CFDictionaryRemoveValue(user, kAFPUserPassword);
	    CFDictionaryRemoveValue(user, kAFPUserDatePasswordLastSet);
	}
	CFRelease(pw);
    }
    CFRelease(now);
    return ok;
}
Example #8
0
static Boolean
ptr_query_start(CFStringRef address)
{
	union {
		struct sockaddr         sa;
		struct sockaddr_in      sin;
		struct sockaddr_in6     sin6;
	} addr;
	char				buf[64];
	CFDataRef			data;
	CFMutableDictionaryRef		options;

	if (_SC_cfstring_to_cstring(address, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
		my_log(LOG_ERR, "could not convert [primary] address string");
		return FALSE;
	}

	if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
		my_log(LOG_ERR, "could not convert [primary] address");
		return FALSE;
	}

	options = CFDictionaryCreateMutable(NULL,
					    0,
					    &kCFTypeDictionaryKeyCallBacks,
					    &kCFTypeDictionaryValueCallBacks);
	data = CFDataCreate(NULL, (const UInt8 *)&addr.sa, addr.sa.sa_len);
	CFDictionarySetValue(options, kSCNetworkReachabilityOptionPTRAddress, data);
	CFRelease(data);
	ptrTarget = SCNetworkReachabilityCreateWithOptions(NULL, options);
	CFRelease(options);
	if (ptrTarget == NULL) {
		my_log(LOG_ERR, "could not resolve [primary] address");
		return FALSE;
	}

	my_log(LOG_INFO, "NetBIOS name: ptr query start");

	(void) SCNetworkReachabilitySetCallback(ptrTarget, ptr_query_callback, NULL);
	(void) SCNetworkReachabilityScheduleWithRunLoop(ptrTarget, rl, kCFRunLoopDefaultMode);

	return TRUE;
}
__private_extern__ Boolean
__destroyInterface(int s, CFStringRef interface)
{
	struct ifreq	ifr;

	bzero(&ifr, sizeof(ifr));
	(void) _SC_cfstring_to_cstring(interface,
				       ifr.ifr_name,
				       sizeof(ifr.ifr_name),
				       kCFStringEncodingASCII);

	if (ioctl(s, SIOCIFDESTROY, &ifr) == -1) {
		SCLog(TRUE,
		      LOG_ERR,
		      CFSTR("could not destroy interface \"%@\": %s"),
		      interface,
		      strerror(errno));
		return FALSE;
	}

	return TRUE;
}
static CFDictionaryRef
copy_scoped_proxies(CFDictionaryRef services, CFArrayRef order)
{
	CFIndex			i;
	CFIndex			n_order;
	CFMutableDictionaryRef	scoped	= NULL;

	// iterate over services

	n_order = isA_CFArray(order) ? CFArrayGetCount(order) : 0;
	for (i = 0; i < n_order; i++) {
		char			if_name[IF_NAMESIZE];
		CFStringRef		interface;
		CFMutableDictionaryRef	newProxy;
		CFDictionaryRef		proxy;
		CFDictionaryRef		service;
		CFStringRef		serviceID;

		serviceID = CFArrayGetValueAtIndex(order, i);
		service = CFDictionaryGetValue(services, serviceID);
		if (!isA_CFDictionary(service)) {
			// if no service
			continue;
		}

		proxy = CFDictionaryGetValue(service, kSCEntNetProxies);
		if (!isA_CFDictionary(proxy)) {
			// if no proxy
			continue;
		}

		interface = CFDictionaryGetValue(proxy, kSCPropInterfaceName);
		if (interface == NULL) {
			// if no [scoped] interface
			continue;
		}
		if ((scoped != NULL) &&
		    CFDictionaryContainsKey(scoped, interface)) {
			// if we've already processed this [scoped] interface
			continue;
		}

		if ((_SC_cfstring_to_cstring(interface,
					     if_name,
					     sizeof(if_name),
					     kCFStringEncodingASCII) == NULL) ||
		    ((if_nametoindex(if_name)) == 0)) {
			// if interface index not available
			continue;
		}

		// add [scoped] proxy entry
		// ... and remove keys we don't want in a [scoped] proxy
		CFRetain(interface);
		newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
		CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains);
		CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders);
		CFDictionaryRemoveValue(newProxy, kSCPropInterfaceName);
		if (scoped == NULL) {
			scoped = CFDictionaryCreateMutable(NULL,
							   0,
							   &kCFTypeDictionaryKeyCallBacks,
							   &kCFTypeDictionaryValueCallBacks);
		}
		CFDictionarySetValue(scoped, interface, newProxy);
		CFRelease(newProxy);
		CFRelease(interface);
	}

	return scoped;
}
Example #11
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;
}
static void
updateDefaults(const void *key, const void *val, void *context)
{
	CFStringRef		ifName		= (CFStringRef)key;
	CFDictionaryRef		oldDict;
	CFDictionaryRef		newDict		= (CFDictionaryRef)val;
	CFNumberRef		defaultNode;
	CFNumberRef		defaultNetwork;
	CFStringRef		defaultZone;

	if (!CFDictionaryGetValueIfPresent(curDefaults, ifName, (const void **)&oldDict) ||
	    !CFEqual(oldDict, newDict)) {
		char		ifr_name[IFNAMSIZ+1];

		bzero(&ifr_name, sizeof(ifr_name));
		if (!_SC_cfstring_to_cstring(ifName, ifr_name, sizeof(ifr_name), kCFStringEncodingASCII)) {
			SCLog(TRUE, LOG_ERR, CFSTR("could not convert interface name to C string"));
			return;
		}

		/*
		 * Set preferred Network and Node ID
		 */
		if (CFDictionaryGetValueIfPresent(newDict,
						  kSCPropNetAppleTalkNetworkID,
						  (const void **)&defaultNetwork) &&
		    CFDictionaryGetValueIfPresent(newDict,
						  kSCPropNetAppleTalkNodeID,
						  (const void **)&defaultNode)
		    ) {
			struct at_addr	init_address;
			int		status;

			/*
			 * set the default node and network
			 */
			CFNumberGetValue(defaultNetwork, kCFNumberShortType, &init_address.s_net);
			CFNumberGetValue(defaultNode,    kCFNumberCharType,  &init_address.s_node);
			status = at_setdefaultaddr(ifr_name, &init_address);
			if (status == -1) {
				SCLog(TRUE, LOG_ERR, CFSTR("at_setdefaultaddr() failed"));
				return;
			}
		}

		/*
		 * Set default zone
		 */
		if (CFDictionaryGetValueIfPresent(newDict,
						  kSCPropNetAppleTalkDefaultZone,
						  (const void **)&defaultZone)
		    ) {
			int		status;
			at_nvestr_t	zone;

			/*
			 * set the "default zone" for this interface
			 */
			bzero(&zone, sizeof(zone));
			if (!_SC_cfstring_to_cstring(defaultZone, zone.str, sizeof(zone.str), kCFStringEncodingASCII)) {
				SCLog(TRUE, LOG_ERR, CFSTR("could not convert default zone to C string"));
				return;
			}

			zone.len = strlen(zone.str);
			status = at_setdefaultzone(ifr_name, &zone);
			if (status == -1) {
				SCLog(TRUE, LOG_ERR, CFSTR("at_setdefaultzone() failed"));
				return;
			}
		}
	}

	return;
}
static void
startAppleTalk(CFRunLoopTimerRef timer, void *info)
{
	int		argc		= 0;
	char		*argv[8];
	char		*computerName	= NULL;
	char		*interface	= NULL;
	CFStringRef	mode		= CFDictionaryGetValue(curStartup, CFSTR("APPLETALK"));
	CFStringRef	name		= CFDictionaryGetValue(curStartup, CFSTR("APPLETALK_HOSTNAME"));

	SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk startup"));

	if (!mode) {
		// Huh?
		return;
	}

	// set command name
	argv[argc++] = "appletalk";

	// set hostname
	if (name) {
		computerName = _SC_cfstring_to_cstring(name, NULL, 0, kCFStringEncodingASCII);
		if (computerName) {
			argv[argc++] = "-C";
			argv[argc++] = computerName;
		} else {
			// could not convert name
			goto done;
		}
	}

	// set mode
	if (CFEqual(mode, CFSTR("-ROUTER-"))) {
		argv[argc++] = "-r";
	} else if (CFEqual(mode, CFSTR("-MULTIHOME-"))) {
		argv[argc++] = "-x";
	} else {
		interface = _SC_cfstring_to_cstring(mode, NULL, 0, kCFStringEncodingASCII);
		if (interface) {
			argv[argc++] = "-u";
			argv[argc++] = interface;
		} else {
			// could not convert interface
			goto done;
		}
	}

	// set non-interactive
	argv[argc++] = "-q";

	// close argument list
	argv[argc++] = NULL;

	execCommand = _SCDPluginExecCommand(startComplete,		// callback
					    info,			// context
					    0,				// uid
					    0,				// gid
					    "/usr/sbin/appletalk",	// path
					    argv);			// argv

	if (!timer) {
		execRetry = 5;	// initialize retry count
	}

    done :

	if (computerName)	CFAllocatorDeallocate(NULL, computerName);
	if (interface)		CFAllocatorDeallocate(NULL, interface);

	return;
}
SCBondStatusRef
SCBondInterfaceCopyStatus(SCBondInterfaceRef bond)
{
	int				bond_if_active;
	int				bond_if_status;
	CFIndex				i;
	struct if_bond_status_req	*ibsr_p		= NULL;
	char				if_name[IFNAMSIZ];
	CFIndex				n;
	CFNumberRef			num;
	int				s;
	struct if_bond_status		*scan_p;
	SCBondStatusRef			status		= NULL;
	CFMutableDictionaryRef		status_bond;
	CFMutableDictionaryRef		status_interfaces;

	if (!isA_SCBondInterface(bond)) {
		_SCErrorSet(kSCStatusInvalidArgument);
		return NULL;
	}

	s = inet_dgram_socket();
	if (s == -1) {
		_SCErrorSet(errno);
		goto done;
	}

	_SC_cfstring_to_cstring(SCNetworkInterfaceGetBSDName(bond),
				if_name,
				sizeof(if_name),
				kCFStringEncodingASCII);
	if (siocgifmedia(s, if_name, &bond_if_status, &bond_if_active) == -1) {
		_SCErrorSet(errno);
		switch (errno) {
			case EBUSY :
			case ENXIO :
				break;
			default :
				SCLog(TRUE, LOG_ERR,
				      CFSTR("siocgifmedia(%s) failed: %s"),
				      if_name,
				      strerror(errno));
		}
		goto done;
	}
	ibsr_p = if_bond_status_req_copy(s, if_name);
	if (ibsr_p == NULL) {
		_SCErrorSet(errno);
		goto done;
	}

	status_bond = CFDictionaryCreateMutable(NULL,
						0,
						&kCFTypeDictionaryKeyCallBacks,
						&kCFTypeDictionaryValueCallBacks);

	status_interfaces = CFDictionaryCreateMutable(NULL,
						      0,
						      &kCFTypeDictionaryKeyCallBacks,
						      &kCFTypeDictionaryValueCallBacks);
	n = ibsr_p->ibsr_total;
	for (i = 0, scan_p = (struct if_bond_status *)ibsr_p->ibsr_buffer; i < n; i++, scan_p++) {
		int				collecting	= 0;
		int				distributing	= 0;
		SCNetworkInterfaceRef		interface;
		CFStringRef			interface_name;
		struct if_bond_partner_state *	ps;
		CFMutableDictionaryRef		status_interface;
		int				status_val;

		ps = &scan_p->ibs_partner_state;

		if (lacp_actor_partner_state_in_sync(scan_p->ibs_state)) {
			/* we're in-sync */
			status_val = kSCBondStatusOK;
			if (lacp_actor_partner_state_in_sync(ps->ibps_state)) {
				/* partner is also in-sync */
				if (lacp_actor_partner_state_collecting(scan_p->ibs_state)
				    && lacp_actor_partner_state_distributing(ps->ibps_state)) {
					/* we're able to collect (receive) frames */
					collecting = 1;
				}
				if (lacp_actor_partner_state_distributing(scan_p->ibs_state)
				    && lacp_actor_partner_state_collecting(ps->ibps_state)) {
					/* we're able to distribute (transmit) frames */
					distributing = 1;
				}
			}
		} else {
			int			active = 0;
			int			status = 0;
			static lacp_system	zeroes = { {0, 0, 0, 0, 0, 0}};

			if (siocgifmedia(s, scan_p->ibs_if_name, &status, &active) == -1) {
				switch (errno) {
					case EBUSY :
					case ENXIO :
						break;
					default :
						SCLog(TRUE, LOG_ERR,
						      CFSTR("siocgifmedia(%s) failed: %s"),
						      if_name,
						      strerror(errno));
						break;
				}
			}
			if (((status & IFM_AVALID) == 0) ||
			    ((status & IFM_ACTIVE) == 0) ||
			    ((active & IFM_FDX   ) == 0)) {
				/* link down or not full-duplex */
				status_val = kSCBondStatusLinkInvalid;
			} else if ((ps->ibps_system_priority == 0) &&
				   (bcmp(&zeroes, &ps->ibps_system, sizeof(zeroes)) == 0)) {
				/* no one on the other end of the link */
				status_val = kSCBondStatusNoPartner;
			} else if (active != bond_if_active) {
				/* the link speed was different */
				status_val = kSCBondStatusLinkInvalid;
			} else {
				/* partner is not in the active group */
				status_val = kSCBondStatusNotInActiveGroup;
			}
		}

		// interface
		strlcpy(if_name, scan_p->ibs_if_name, sizeof(if_name));
		interface_name = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingASCII);
		interface = _SCNetworkInterfaceCreateWithBSDName(NULL, interface_name,
								 kIncludeNoVirtualInterfaces);
		CFRelease(interface_name);

		// interface status
		status_interface = CFDictionaryCreateMutable(NULL,
							     0,
							     &kCFTypeDictionaryKeyCallBacks,
							     &kCFTypeDictionaryValueCallBacks);
		num = CFNumberCreate(NULL, kCFNumberIntType, &status_val);
		CFDictionarySetValue(status_interface, kSCBondStatusDeviceAggregationStatus, num);
		CFRelease(num);
		num = CFNumberCreate(NULL, kCFNumberIntType, &collecting);
		CFDictionarySetValue(status_interface, kSCBondStatusDeviceCollecting, num);
		CFRelease(num);
		num = CFNumberCreate(NULL, kCFNumberIntType, &distributing);
		CFDictionarySetValue(status_interface, kSCBondStatusDeviceDistributing, num);
		CFRelease(num);

		CFDictionarySetValue(status_interfaces, interface, status_interface);
		CFRelease(interface);
		CFRelease(status_interface);
	}

	status = __SCBondStatusCreatePrivate(NULL, bond, status_bond, status_interfaces);
	CFRelease(status_bond);
	CFRelease(status_interfaces);

    done:

	if (s != -1) {
		close(s);
	}
	if (ibsr_p != NULL) {
		free(ibsr_p);
	}
	return (SCBondStatusRef)status;
}