CFDataRef EAPOLClientItemIDGetWLANSSID(EAPOLClientItemIDRef itemID) { switch (itemID->type) { case kEAPOLClientItemIDTypeWLANSSID: return (itemID->u.ssid); case kEAPOLClientItemIDTypeProfile: return (EAPOLClientProfileGetWLANSSIDAndSecurityType(itemID->u.profile, NULL)); default: break; } return (NULL); }
/* * 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); }
/* * 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); }
STATIC void import_profiles(EAPOLClientConfigurationRef cfg) { int count = 0; CFMutableDictionaryRef domains_dict; int i; const void * * keys; CFDictionaryRef prefs_dict; CFMutableDictionaryRef profiles_dict; CFMutableDictionaryRef ssids_dict; const void * * values; profiles_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ssids_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); domains_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); prefs_dict = SCPreferencesGetValue(cfg->eap_prefs, kConfigurationKeyProfiles); if (isA_CFDictionary(prefs_dict) != NULL) { count = CFDictionaryGetCount(prefs_dict); } if (count == 0) { goto done; } /* allocate a single array, half for keys, half for values */ keys = (const void * *)malloc(sizeof(*keys) * count * 2); values = keys + count; CFDictionaryGetKeysAndValues(prefs_dict, keys, values); for (i = 0; i < count; i++) { EAPOLClientProfileRef profile; CFDictionaryRef profile_dict = values[i]; CFStringRef profileID = keys[i]; CFDataRef ssid; if (isA_CFDictionary(profile_dict) == NULL) { SCLog(TRUE, LOG_NOTICE, CFSTR("EAPOLClientConfiguration: invalid profile with id %@"), profileID); continue; } profile = EAPOLClientProfileCreateWithDictAndProfileID(profile_dict, profileID); if (profile == NULL) { continue; } ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(profile, NULL); if (ssid != NULL) { CFStringRef conflicting_profileID; conflicting_profileID = CFDictionaryGetValue(ssids_dict, ssid); if (conflicting_profileID != NULL) { CFStringRef ssid_str = my_CFStringCreateWithData(ssid); SCLog(TRUE, LOG_NOTICE, CFSTR("EAPOLClientConfiguration: ignoring profile %@:" " SSID '%@' already used by %@"), profileID, ssid_str, conflicting_profileID); CFRelease(ssid_str); CFRelease(profile); continue; } CFDictionarySetValue(ssids_dict, ssid, profileID); } else { CFStringRef domain; domain = EAPOLClientProfileGetWLANDomain(profile); if (domain != NULL) { CFStringRef conflicting_profileID; conflicting_profileID = CFDictionaryGetValue(profiles_dict, domain); if (conflicting_profileID != NULL) { SCLog(TRUE, LOG_NOTICE, CFSTR("EAPOLClientConfiguration: ignoring profile %@:" " WLAN domain '%@' already used by %@"), profileID, domain, conflicting_profileID); CFRelease(profile); continue; } CFDictionarySetValue(domains_dict, domain, profileID); } } CFDictionarySetValue(profiles_dict, profileID, profile); EAPOLClientProfileSetConfiguration(profile, cfg); CFRelease(profile); } free(keys); done: cfg->ssids = ssids_dict; cfg->profiles = profiles_dict; cfg->domains = domains_dict; return; }