CFStringRef EAPOLClientItemIDGetProfileID(EAPOLClientItemIDRef itemID) { switch (itemID->type) { case kEAPOLClientItemIDTypeProfileID: return (itemID->u.profileID); case kEAPOLClientItemIDTypeProfile: return (EAPOLClientProfileGetID(itemID->u.profile)); default: break; } return (NULL); }
/** ** Internal SPI **/ PRIVATE_EXTERN void EAPOLClientConfigurationSetProfileForSSID(EAPOLClientConfigurationRef cfg, CFDataRef ssid, EAPOLClientProfileRef profile) { if (profile == NULL) { CFDictionaryRemoveValue(cfg->ssids, ssid); } else { CFDictionarySetValue(cfg->ssids, ssid, EAPOLClientProfileGetID(profile)); } return; }
PRIVATE_EXTERN void EAPOLClientConfigurationSetProfileForWLANDomain(EAPOLClientConfigurationRef cfg, CFStringRef domain, EAPOLClientProfileRef profile) { if (profile == NULL) { CFDictionaryRemoveValue(cfg->domains, domain); } else { CFDictionarySetValue(cfg->domains, domain, EAPOLClientProfileGetID(profile)); } return; }
/* * Function: EAPOLClientConfigurationRemoveProfile * * Purpose: * Remove the specified profile from the configuration. * * Returns: * FALSE if the profile is invalid or not in the configuration, * TRUE otherwise. */ Boolean EAPOLClientConfigurationRemoveProfile(EAPOLClientConfigurationRef cfg, EAPOLClientProfileRef profile) { CFStringRef profileID = EAPOLClientProfileGetID(profile); CFDataRef ssid; if (EAPOLClientConfigurationGetProfileWithID(cfg, profileID) != profile) { /* trying to remove profile that isn't part of the configuration */ return (FALSE); } ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(profile, NULL); if (ssid != NULL) { CFDictionaryRemoveValue(cfg->ssids, ssid); } CFDictionaryRemoveValue(cfg->profiles, profileID); return (TRUE); }
/* * Function: EAPOLClientConfigurationAddProfile * * Purpose: * Add the specified profile to the configuration. * * Returns: * FALSE if the profile could not be added, either because: * - the profile is already in the configuration, or * - the profile conflicts with an existing profile (profileID or WLAN SSID) * TRUE if the profile was added successfully. */ Boolean EAPOLClientConfigurationAddProfile(EAPOLClientConfigurationRef cfg, EAPOLClientProfileRef profile) { CFStringRef domain = NULL; CFStringRef profileID = EAPOLClientProfileGetID(profile); CFDataRef ssid; if (profile->cfg != NULL) { /* profile is already part of the configuration */ return (FALSE); } if (EAPOLClientConfigurationGetProfileWithID(cfg, profileID) != NULL) { /* profile already present with that profileID */ return (FALSE); } ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(profile, NULL); if (ssid != NULL) { if (EAPOLClientConfigurationGetProfileWithWLANSSID(cfg, ssid) != NULL) { /* profile already present with that SSID */ return (FALSE); } } else { domain = EAPOLClientProfileGetWLANDomain(profile); if (domain != NULL) { if (EAPOLClientConfigurationGetProfileWithWLANDomain(cfg, domain) != NULL) { /* profile already exists with that domain */ return (FALSE); } } } CFDictionarySetValue(cfg->profiles, profileID, profile); if (ssid != NULL) { CFDictionarySetValue(cfg->ssids, ssid, profileID); } else if (domain != NULL) { CFDictionarySetValue(cfg->domains, domain, profileID); } EAPOLClientProfileSetConfiguration(profile, cfg); return (TRUE); }
STATIC CFStringRef __EAPOLClientItemIDCopyDebugDesc(CFTypeRef cf) { CFAllocatorRef allocator = CFGetAllocator(cf); EAPOLClientItemIDRef itemID = (EAPOLClientItemIDRef)cf; CFStringRef profileID; CFMutableStringRef result; CFStringRef ssid_str; result = CFStringCreateMutable(allocator, 0); CFStringAppendFormat(result, NULL, CFSTR("<EAPOLClientItemID %p [%p]> {"), cf, allocator); switch (itemID->type) { case kEAPOLClientItemIDTypeWLANSSID: ssid_str = my_CFStringCreateWithData(itemID->u.ssid); CFStringAppendFormat(result, NULL, CFSTR("WLAN SSID = %@"), ssid_str); CFRelease(ssid_str); break; case kEAPOLClientItemIDTypeWLANDomain: CFStringAppendFormat(result, NULL, CFSTR("WLAN domain = %@"), itemID->u.domain); break; case kEAPOLClientItemIDTypeProfileID: CFStringAppendFormat(result, NULL, CFSTR("ProfileID = %@"), itemID->u.profileID); break; case kEAPOLClientItemIDTypeProfile: profileID = EAPOLClientProfileGetID(itemID->u.profile); CFStringAppendFormat(result, NULL, CFSTR("Profile = %@"), profileID); break; case kEAPOLClientItemIDTypeDefault: CFStringAppend(result, CFSTR("Default")); break; default: break; } CFStringAppend(result, CFSTR("}")); return result; }
/* * Function: EAPOLClientConfigurationCopyMatchingProfiles * * Purpose: * Find the profile(s) matching the specified profile. * A profile is matched based on the profileID, the WLAN SSID, and * the WLAN domain, all of which must be unique in the configuration. * * Usually invoked after calling * EAPOLClientProfileCreateWithPropertyList() to instantiate a profile * from an external format. * * Returns: * NULL if no matching profile is part of the configuration, * non-NULL CFArrayRef of EAPOLClientProfileRef if found. */ CFArrayRef /* of EAPOLClientProfileRef */ EAPOLClientConfigurationCopyMatchingProfiles(EAPOLClientConfigurationRef cfg, EAPOLClientProfileRef profile) { int count; EAPOLClientProfileRef matching_profile; CFStringRef profileID = EAPOLClientProfileGetID(profile); CFDataRef ssid; const void * values[2] = { NULL, NULL }; count = 0; matching_profile = EAPOLClientConfigurationGetProfileWithID(cfg, profileID); if (matching_profile != NULL) { values[count] = matching_profile; count++; } matching_profile = NULL; ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(profile, NULL); if (ssid != NULL) { matching_profile = EAPOLClientConfigurationGetProfileWithWLANSSID(cfg, ssid); } else { CFStringRef domain; domain = EAPOLClientProfileGetWLANDomain(profile); if (domain != NULL) { matching_profile = EAPOLClientConfigurationGetProfileWithWLANDomain(cfg, domain); } } if (matching_profile != NULL && values[0] != matching_profile) { values[count] = matching_profile; count++; } if (count == 0) { return (NULL); } return (CFArrayCreate(CFGetAllocator(cfg), values, count, &kCFTypeArrayCallBacks)); }
/* * Function: EAPOLClientItemIDSetPasswordItem * * Purpose: * Set the password item in secure storage for the specified itemID * in the specified domain. * * Passing an empty 'username' or 'password' removes the corresponding * attribute. If both 'username' and 'password' are empty, the item is * also removed. An empty value is a non-NULL CFDataRef of length 0. * * Passing NULL for 'username' or 'password' means that the corresponding * item attribute is left alone. If both 'username" and 'password' are * NULL, the call has no effect, but TRUE is still returned. * * Passing non-NULL, non-empty 'username' or 'password' sets the * corresponding item attribute to the specified value. If the item * does not exist, it will be created. * * Returns: * FALSE if the operation did not succeed, TRUE otherwise. */ Boolean EAPOLClientItemIDSetPasswordItem(EAPOLClientItemIDRef itemID, EAPOLClientDomain domain, CFDataRef name, CFDataRef password) { CFMutableDictionaryRef attrs = NULL; CFDataRef data; SecKeychainRef keychain = NULL; CFDataRef ssid; OSStatus status = errSecParam; CFStringRef unique_string; if (name == NULL && password == NULL) { return (TRUE); } switch (domain) { case kEAPOLClientDomainUser: status = SecKeychainCopyDomainDefault(kSecPreferencesDomainUser, &keychain); if (status != noErr) { fprintf(stderr, "EAPOLClientItemIDSetPasswordItem can't get" " User keychain, %s (%d)\n", EAPSecurityErrorString(status), (int)status); return (FALSE); } break; case kEAPOLClientDomainSystem: if (EAPOLClientItemIDGetAuthorizationExternalForm(itemID) != NULL) { return (authEAPOLClientItemIDSetPasswordItem(itemID, name, password)); } status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain); if (status != noErr) { fprintf(stderr, "EAPOLClientItemIDSetPasswordItem can't get" " System keychain, %s (%d)\n", EAPSecurityErrorString(status), (int)status); return (FALSE); } break; default: return (FALSE); } /* populate an attributes dictionary */ attrs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); /* Description */ data = CFDataCreate(NULL, (UInt8 *)kItemDescription, kItemDescriptionLength); CFDictionarySetValue(attrs, kEAPSecKeychainPropDescription, data); CFRelease(data); /* Label */ switch (itemID->type) { case kEAPOLClientItemIDTypeWLANSSID: CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, itemID->u.ssid); break; case kEAPOLClientItemIDTypeWLANDomain: { CFDataRef label_data; label_data = my_CFDataCreateWithString(itemID->u.domain); CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, label_data); CFRelease(label_data); break; } case kEAPOLClientItemIDTypeProfileID: { CFDataRef label_data; label_data = my_CFDataCreateWithString(itemID->u.profileID); CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, label_data); CFRelease(label_data); break; } case kEAPOLClientItemIDTypeProfile: ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(itemID->u.profile, NULL); if (ssid != NULL) { CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, ssid); } else { CFStringRef label; CFDataRef label_data; label = EAPOLClientProfileGetUserDefinedName(itemID->u.profile); if (label == NULL) { label = EAPOLClientProfileGetWLANDomain(itemID->u.profile); if (label == NULL) { label = EAPOLClientProfileGetID(itemID->u.profile); } } label_data = my_CFDataCreateWithString(label); CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, label_data); CFRelease(label_data); } break; case kEAPOLClientItemIDTypeDefault: { CFDataRef label_data; /* XXX localize? */ label_data = my_CFDataCreateWithString(CFSTR("Default")); CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, label_data); CFRelease(label_data); break; } default: goto done; } /* Account */ if (name != NULL) { CFDictionarySetValue(attrs, kEAPSecKeychainPropAccount, name); } /* Password */ if (password != NULL) { CFDictionarySetValue(attrs, kEAPSecKeychainPropPassword, password); }; if (domain == kEAPOLClientDomainUser) { CFArrayRef trusted_apps; /* Trusted Applications */ trusted_apps = copy_trusted_applications(FALSE); if (trusted_apps != NULL) { CFDictionarySetValue(attrs, kEAPSecKeychainPropTrustedApplications, trusted_apps); CFRelease(trusted_apps); } } else { CFDictionarySetValue(attrs, kEAPSecKeychainPropAllowRootAccess, kCFBooleanTrue); } unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, TRUE); status = EAPSecKeychainPasswordItemSet2(keychain, unique_string, attrs); if (status == errSecItemNotFound) { status = EAPSecKeychainPasswordItemCreate(keychain, unique_string, attrs); } my_CFRelease(&unique_string); if (status != noErr) { EAPLOG(LOG_NOTICE, "EAPOLClientItemID: failed to set keychain item, %d", (int)status); } done: my_CFRelease(&attrs); my_CFRelease(&keychain); return (status == noErr); }
STATIC CFStringRef EAPOLClientItemIDCopyUniqueString(EAPOLClientItemIDRef itemID, EAPOLClientDomain domain, bool is_item) { const char * domain_str; CFStringRef result = NULL; CFStringRef profileID; CFDataRef ssid; CFStringRef ssid_str; const char * type_str; type_str = is_item ? "item" : "identity"; domain_str = (domain == kEAPOLClientDomainSystem) ? "system" : "user"; switch (itemID->type) { case kEAPOLClientItemIDTypeWLANSSID: ssid_str = my_CFStringCreateWithData(itemID->u.ssid); result = create_item_format(domain_str, type_str, WLAN_SSID_STR, ssid_str); if (ssid_str != NULL) { CFRelease(ssid_str); } break; case kEAPOLClientItemIDTypeWLANDomain: result = create_item_format(domain_str, type_str, WLAN_DOMAIN_STR, itemID->u.domain); break; case kEAPOLClientItemIDTypeProfileID: result = create_item_format(domain_str, type_str, PROFILEID_STR, itemID->u.profileID); break; case kEAPOLClientItemIDTypeProfile: ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(itemID->u.profile, NULL); if (ssid != NULL) { ssid_str = my_CFStringCreateWithData(ssid); result = create_item_format(domain_str, type_str, WLAN_SSID_STR, ssid_str); if (ssid_str != NULL) { CFRelease(ssid_str); } } else { CFStringRef wlan_domain; wlan_domain = EAPOLClientProfileGetWLANDomain(itemID->u.profile); if (wlan_domain != NULL) { result = create_item_format(domain_str, type_str, WLAN_DOMAIN_STR, wlan_domain); } else { profileID = EAPOLClientProfileGetID(itemID->u.profile); result = create_item_format(domain_str, type_str, PROFILEID_STR, profileID); } } break; case kEAPOLClientItemIDTypeDefault: result = create_item_format(domain_str, type_str, DEFAULT_STR, NULL); break; default: break; } return (result); }
PRIVATE_EXTERN CFMutableDictionaryRef EAPOLClientProfileCreateDictAndProfileID(EAPOLClientProfileRef profile, CFStringRef * ret_profileID) { CFArrayRef accept_types = NULL; CFMutableDictionaryRef dict; if (profile->auth_props != NULL) { accept_types = CFDictionaryGetValue(profile->auth_props, kEAPClientPropAcceptEAPTypes); } if (accept_types_valid(accept_types) == FALSE) { SCLog(TRUE, LOG_NOTICE, CFSTR("EAPOLClientConfiguration: profile %@" " missing/invalid AuthenticationProperties"), EAPOLClientProfileGetID(profile)); return (NULL); } dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (ret_profileID != NULL) { *ret_profileID = CFRetain(profile->uuid); } CFDictionarySetValue(dict, kProfileKeyAuthenticationProperties, profile->auth_props); if (profile->user_defined_name != NULL) { CFDictionarySetValue(dict, kProfileKeyUserDefinedName, profile->user_defined_name); } if (profile->information != NULL && CFDictionaryGetCount(profile->information) != 0) { CFDictionarySetValue(dict, kProfileKeyInformation, profile->information); } if (profile->WLAN.ssid != NULL || profile->WLAN.domain != NULL) { int count; const void * keys[2]; CFDictionaryRef WLAN; const void * values[2]; if (profile->WLAN.ssid != NULL) { keys[0] = kProfileKeyWLANSSID; values[0] = profile->WLAN.ssid; keys[1] = kProfileKeyWLANSecurityType; values[1] = profile->WLAN.security_type; count = 2; } else { keys[0] = kProfileKeyWLANDomain; values[0] = profile->WLAN.domain; count = 1; } WLAN = CFDictionaryCreate(NULL, keys, values, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(dict, kProfileKeyWLAN, WLAN); CFRelease(WLAN); } return (dict); }
/* * 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: 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); }