STATIC Boolean
__EAPOLClientProfileEqual(CFTypeRef cf1, CFTypeRef cf2)
{
    EAPOLClientProfileRef 	prof1 = (EAPOLClientProfileRef)cf1;
    EAPOLClientProfileRef	prof2 = (EAPOLClientProfileRef)cf2;

    if (CFEqual(prof1->uuid, prof2->uuid) == FALSE) {
	return (FALSE);
    }
    if (my_CFEqual(prof1->auth_props, prof2->auth_props) == FALSE) {
	return (FALSE);
    }
    if (my_CFEqual(prof1->user_defined_name,
		   prof2->user_defined_name) == FALSE) {
	return (FALSE);
    }
    if (my_CFEqual(prof1->WLAN.ssid, prof2->WLAN.ssid) == FALSE) {
	return (FALSE);
    }
    if (my_CFEqual(prof1->WLAN.security_type, prof2->WLAN.security_type)
	== FALSE) {
	return (FALSE);
    }
    if (my_CFEqual(prof1->information, prof2->information) == FALSE) {
	return (FALSE);
    }
    return (TRUE);
}
/*
 * Function: EAPOLClientConfigurationSetLoginWindowProfiles
 *
 * Purpose:
 *   Set the list of profiles configured for LoginWindow mode on the
 *   specified BSD network interface (e.g. "en0", "en1").
 *
 *   If you pass NULL for the "profiles" argument, the LoginWindow profile
 *   list is cleared.
 */
Boolean
EAPOLClientConfigurationSetLoginWindowProfiles(EAPOLClientConfigurationRef cfg,
					       CFStringRef if_name,
					       CFArrayRef profiles)
{
    CFDictionaryRef		dict;
    CFArrayRef			existing_profile_ids = NULL;
    SCNetworkInterfaceRef	net_if = NULL;
    CFMutableDictionaryRef	new_dict = NULL;
    CFMutableArrayRef		profile_ids = NULL;
    Boolean			ret = FALSE;

    dict = get_eapol_configuration(get_sc_prefs(cfg), if_name, &net_if);
    if (net_if == NULL) {
	goto done;
    }
    if (dict != NULL) {
	existing_profile_ids
	    = CFDictionaryGetValue(dict, kLoginWindowProfileIDs);
	existing_profile_ids = isA_CFArray(existing_profile_ids);
    }
    if (profiles == NULL || CFArrayGetCount(profiles) == 0) {
	profile_ids = NULL;
    }
    else {
	int				count;
	int				i;
	CFRange				r = { 0, 0 };

	count = CFArrayGetCount(profiles);
	profile_ids = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
	for (i = 0; i < count; i++) {
	    EAPOLClientProfileRef	profile;
	    CFStringRef			profileID;

	    profile = (EAPOLClientProfileRef)
		CFArrayGetValueAtIndex(profiles, i);
	    profileID = EAPOLClientProfileGetID(profile);
	    if (CFArrayContainsValue(profile_ids, r, profileID) == FALSE) {
		CFArrayAppendValue(profile_ids, profileID);
		r.length++;
	    }
	}
    }
    if (my_CFEqual(existing_profile_ids, profile_ids)) {
	ret = TRUE;
	goto done;
    }
    if (dict != NULL) {
	/*
	 * remove the AcceptEAPTypes array to give EAPOLController a way to
	 * know whether we're using new configuration or the old
	 */
	new_dict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
	CFDictionaryRemoveValue(new_dict, kEAPClientPropAcceptEAPTypes);
	CFDictionaryRemoveValue(new_dict, kSCResvInactive);
    }
    else {
	new_dict = CFDictionaryCreateMutable(NULL, 0,
					     &kCFTypeDictionaryKeyCallBacks,
					     &kCFTypeDictionaryValueCallBacks);
    }
    if (profile_ids == NULL) {
	CFDictionaryRemoveValue(new_dict, kLoginWindowProfileIDs);
	if (CFDictionaryGetCount(new_dict) == 0) {
	    my_CFRelease(&new_dict);
	}
    }
    else {
	CFDictionarySetValue(new_dict, kLoginWindowProfileIDs, profile_ids);
    }
    if (setInterfaceEAPOLConfiguration(cfg, net_if, new_dict)
	== FALSE) {
	goto done;
    }
    ret = TRUE;

 done:
    my_CFRelease(&new_dict);
    my_CFRelease(&profile_ids);
    my_CFRelease(&net_if);
    return (ret);
}
/*
 * Function: EAPOLClientConfigurationSetSystemProfile
 *
 * Purpose:
 *   Set the profile configured for System mode on the specified
 *   BSD network interface (e.g. "en0", "en1").
 *
 *   If you pass NULL for the "profile" argument, the System profile
 *   list is cleared.
 */
Boolean
EAPOLClientConfigurationSetSystemProfile(EAPOLClientConfigurationRef cfg,
					 CFStringRef if_name,
					 EAPOLClientProfileRef profile)
{
    CFDictionaryRef		dict;
    CFStringRef			existing_profileID = NULL;
    CFMutableDictionaryRef	new_dict = NULL;
    SCNetworkInterfaceRef	net_if = NULL;
    CFStringRef			profileID = NULL;
    Boolean			ret = FALSE;

    if (profile != NULL) {
	profileID = EAPOLClientProfileGetID(profile);
    }
    dict = get_eapol_configuration(get_sc_prefs(cfg), if_name, &net_if);
    if (net_if == NULL) {
	goto done;
    }
    if (CFEqual(SCNetworkInterfaceGetInterfaceType(net_if),
		kSCNetworkInterfaceTypeIEEE80211)) {
	/* disallow setting static System Mode on AirPort interfaces */
	goto done;
    }

    if (dict != NULL) {
	existing_profileID 
	    = CFDictionaryGetValue(dict, kSystemProfileID);
    }
    if (my_CFEqual(existing_profileID, profileID)) {
	/* nothing to do */
	ret = TRUE;
	goto done;
    }
    if (dict != NULL) {
	/*
	 * remove the AcceptEAPTypes array to give EAPOLController a way to
	 * know whether we're using new configuration or the old
	 */
	new_dict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
	CFDictionaryRemoveValue(new_dict, kEAPClientPropAcceptEAPTypes);
	CFDictionaryRemoveValue(new_dict, kSCResvInactive);
    }
    else {
	new_dict = CFDictionaryCreateMutable(NULL, 0,
					     &kCFTypeDictionaryKeyCallBacks,
					     &kCFTypeDictionaryValueCallBacks);
    }

    if (profileID == NULL) {
	CFDictionaryRemoveValue(new_dict, kSystemProfileID);
	if (CFDictionaryGetCount(new_dict) == 0) {
	    my_CFRelease(&new_dict);
	}
    }
    else {
	CFDictionarySetValue(new_dict, kSystemProfileID, profileID);
    }
    if (setInterfaceEAPOLConfiguration(cfg, net_if, new_dict)
	== FALSE) {
	goto done;
    }
    ret = TRUE;

 done:
    my_CFRelease(&new_dict);
    my_CFRelease(&net_if);
    return (ret);
}
/*
 * Function: EAPOLClientConfigurationSave
 * 
 * Purpose:
 *   Write the configuration to persistent storage.
 *
 * Returns:
 *   TRUE if successfully written, FALSE otherwise.
 */	
Boolean
EAPOLClientConfigurationSave(EAPOLClientConfigurationRef cfg)
{
    Boolean		changed = FALSE;
    CFDictionaryRef	existing_prefs_dict;
    CFDictionaryRef	prefs_dict;
    Boolean		ret = FALSE;

    /* save the 802.1X prefs */
    prefs_dict = export_profiles(cfg);
    if (prefs_dict == NULL) {
	EAPLOG(LOG_NOTICE,
	       "EAPOLClientConfigurationSave export_profiles() failed");
	goto done;
    }
    existing_prefs_dict = SCPreferencesGetValue(cfg->eap_prefs,
						kConfigurationKeyProfiles);
    if (cfg->def_auth_props_changed == FALSE
	&& my_CFEqual(existing_prefs_dict, prefs_dict)) {
	/* configuration is the same, no need to save */
    }
    else {
	if (cfg->def_auth_props_changed) {
	    ret = SCPreferencesSetValue(cfg->eap_prefs,
					kConfigurationKeyDefaultAuthenticationProperties,
					cfg->def_auth_props);
	    if (ret == FALSE) {
		EAPLOG(LOG_NOTICE,
		       "EAPOLClientConfigurationSave SCPreferencesSetValue"
		       " failed %s",
		       SCErrorString(SCError()));
		goto done;
	    }
	}
	ret = SCPreferencesSetValue(cfg->eap_prefs, kConfigurationKeyProfiles,
				    prefs_dict);
	if (ret == FALSE) {
	    EAPLOG(LOG_NOTICE,
		   "EAPOLClientConfigurationSave SCPreferencesSetValue"
		   " failed %s",
		   SCErrorString(SCError()));
	    goto done;
	}
	ret = SCPreferencesCommitChanges(cfg->eap_prefs);
	if (ret == FALSE) {
	    EAPLOG(LOG_NOTICE,
		   "EAPOLClientConfigurationSave SCPreferencesCommitChanges"
		   " failed %s", SCErrorString(SCError()));
	    return (FALSE);
	}
	cfg->def_auth_props_changed = FALSE;
	SCPreferencesApplyChanges(cfg->eap_prefs);
	changed = TRUE;
    }

    /* save the network prefs */
    {
	Boolean		this_changed = FALSE;

	ret = saveInterfaceEAPOLConfiguration(cfg, &this_changed);
	if (ret == FALSE) {
	    goto done;
	}
	if (this_changed) {
	    changed = TRUE;
	}
    }
    my_CFRelease(&cfg->sc_prefs); /* force a refresh */

 done:
    my_CFRelease(&prefs_dict);
    if (changed) {
	notify_post(kEAPOLClientConfigurationChangedNotifyKey);
    }
    return (ret);
}