SecSharedCredential.c [plain text]
#include <Security/SecSharedCredential.h>
#include <Security/SecBasePriv.h>
#include <utilities/SecCFError.h>
#include <utilities/SecCFWrappers.h>
#include "SecItemInternal.h"
#include <ipc/securityd_client.h>
#include "SecPasswordGenerate.h"
OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn, CFStringRef account, CFStringRef password, CFErrorRef *error);
OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn, CFStringRef account, CFArrayRef *credentials, CFErrorRef *error);
OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn,
CFStringRef account,
CFStringRef password,
CFErrorRef *error)
{
OSStatus status;
__block CFErrorRef* outError = error;
__block CFMutableDictionaryRef args = CFDictionaryCreateMutable(kCFAllocatorDefault,
0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (fqdn) {
CFDictionaryAddValue(args, kSecAttrServer, fqdn);
}
if (account) {
CFDictionaryAddValue(args, kSecAttrAccount, account);
}
if (password) {
#if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
CFDictionaryAddValue(args, kSecSharedPassword, password);
#else
CFDictionaryAddValue(args, CFSTR("spwd"), password);
#endif
}
status = SecOSStatusWith(^bool (CFErrorRef *error) {
CFTypeRef raw_result = NULL;
bool xpc_result;
bool internal_spi = false; if(internal_spi && gSecurityd && gSecurityd->sec_add_shared_web_credential) {
xpc_result = gSecurityd->sec_add_shared_web_credential(args, NULL, NULL, SecAccessGroupsGetCurrent(), &raw_result, error);
} else {
xpc_result = cftype_ag_to_bool_cftype_error_request(sec_add_shared_web_credential_id, args, SecAccessGroupsGetCurrent(), &raw_result, error);
}
CFReleaseSafe(args);
if (!xpc_result) {
if (NULL == *error) {
SecError(errSecInternal, error, CFSTR("Internal error (XPC failure)"));
}
}
if (outError) {
*outError = (error) ? *error : NULL;
CFRetainSafe(*outError);
} else {
CFReleaseNull(*error);
}
CFReleaseNull(raw_result);
return xpc_result;
});
return status;
}
void SecAddSharedWebCredential(CFStringRef fqdn,
CFStringRef account,
CFStringRef password,
void (^completionHandler)(CFErrorRef error))
{
__block CFErrorRef error = NULL;
__block dispatch_queue_t dst_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_retain(dst_queue);
CFStringRef errStr = NULL;
if (!fqdn || CFGetTypeID(fqdn) != CFStringGetTypeID() || !CFStringGetLength(fqdn) ||
!account || CFGetTypeID(account) != CFStringGetTypeID() || !CFStringGetLength(account) ) {
errStr = CFSTR("fqdn or account was not of type CFString, or not provided");
}
else if (password && CFGetTypeID(password) != CFStringGetTypeID()) {
errStr = CFSTR("non-nil password was not of type CFString");
}
if (errStr) {
SecError(errSecParam, &error, errStr);
dispatch_async(dst_queue, ^{
if (completionHandler) {
completionHandler(error);
}
CFReleaseSafe(error);
dispatch_release(dst_queue);
});
return;
}
__block CFStringRef serverStr = CFRetainSafe(fqdn);
__block CFStringRef accountStr = CFRetainSafe(account);
__block CFStringRef passwordStr = CFRetainSafe(password);
dispatch_async(dst_queue, ^{
OSStatus status = SecAddSharedWebCredentialSync(serverStr, accountStr, passwordStr, &error);
CFReleaseSafe(serverStr);
CFReleaseSafe(accountStr);
CFReleaseSafe(passwordStr);
if (status && !error) {
SecError(status, &error, CFSTR("Error adding shared password"));
}
dispatch_async(dst_queue, ^{
if (completionHandler) {
completionHandler(error);
}
CFReleaseSafe(error);
dispatch_release(dst_queue);
});
});
}
OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn,
CFStringRef account,
CFArrayRef *credentials,
CFErrorRef *error)
{
OSStatus status;
__block CFErrorRef* outError = error;
__block CFMutableDictionaryRef args = CFDictionaryCreateMutable(kCFAllocatorDefault,
0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (fqdn) {
CFDictionaryAddValue(args, kSecAttrServer, fqdn);
}
if (account) {
CFDictionaryAddValue(args, kSecAttrAccount, account);
}
status = SecOSStatusWith(^bool (CFErrorRef *error) {
CFTypeRef raw_result = NULL;
bool xpc_result;
bool internal_spi = false; if(internal_spi && gSecurityd && gSecurityd->sec_copy_shared_web_credential) {
xpc_result = gSecurityd->sec_copy_shared_web_credential(args, NULL, NULL, SecAccessGroupsGetCurrent(), &raw_result, error);
} else {
xpc_result = cftype_ag_to_bool_cftype_error_request(sec_copy_shared_web_credential_id, args, SecAccessGroupsGetCurrent(), &raw_result, error);
}
CFReleaseSafe(args);
if (!xpc_result) {
if (NULL == *error) {
SecError(errSecInternal, error, CFSTR("Internal error (XPC failure)"));
}
}
if (outError) {
*outError = (error) ? *error : NULL;
CFRetainSafe(*outError);
} else {
CFReleaseNull(*error);
}
if (!raw_result) {
raw_result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
}
*credentials = raw_result;
return xpc_result;
});
return status;
}
void SecRequestSharedWebCredential(CFStringRef fqdn,
CFStringRef account,
void (^completionHandler)(CFArrayRef credentials, CFErrorRef error))
{
__block CFArrayRef result = NULL;
__block CFErrorRef error = NULL;
__block dispatch_queue_t dst_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_retain(dst_queue);
CFStringRef errStr = NULL;
if (fqdn && (CFGetTypeID(fqdn) != CFStringGetTypeID() || !CFStringGetLength(fqdn))) {
errStr = CFSTR("fqdn was empty or not a CFString");
}
else if (account && (CFGetTypeID(account) != CFStringGetTypeID() || !CFStringGetLength(account))) {
errStr = CFSTR("account was empty or not a CFString");
}
if (errStr) {
SecError(errSecParam, &error, errStr);
dispatch_async(dst_queue, ^{
if (completionHandler) {
completionHandler(result, error);
}
CFReleaseSafe(error);
CFReleaseSafe(result);
dispatch_release(dst_queue);
});
return;
}
__block CFStringRef serverStr = CFRetainSafe(fqdn);
__block CFStringRef accountStr = CFRetainSafe(account);
dispatch_async(dst_queue, ^{
OSStatus status = SecCopySharedWebCredentialSync(serverStr, accountStr, &result, &error);
CFReleaseSafe(serverStr);
CFReleaseSafe(accountStr);
if (status && !error) {
SecError(status, &error, CFSTR("Error copying shared password"));
}
dispatch_async(dst_queue, ^{
if (completionHandler) {
completionHandler(result, error);
}
CFReleaseSafe(error);
CFReleaseSafe(result);
dispatch_release(dst_queue);
});
});
}
CFStringRef SecCreateSharedWebCredentialPassword(void)
{
CFStringRef password = NULL;
CFErrorRef error = NULL;
CFMutableDictionaryRef passwordRequirements = NULL;
CFStringRef allowedCharacters = CFSTR("abcdefghkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789");
CFCharacterSetRef requiredCharactersLower = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("abcdefghkmnopqrstuvwxyz"));
CFCharacterSetRef requiredCharactersUppder = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("ABCDEFGHJKLMNPQRSTUVWXYZ"));
CFCharacterSetRef requiredCharactersNumbers = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("3456789"));
int groupSize = 3;
int groupCount = 4;
int totalLength = (groupSize * groupCount);
CFNumberRef groupSizeRef = CFNumberCreate(NULL, kCFNumberIntType, &groupSize);
CFNumberRef groupCountRef = CFNumberCreate(NULL, kCFNumberIntType, &groupCount);
CFNumberRef totalLengthRef = CFNumberCreate(NULL, kCFNumberIntType, &totalLength);
CFStringRef separator = CFSTR("-");
CFMutableArrayRef requiredCharacterSets = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(requiredCharacterSets, requiredCharactersLower);
CFArrayAppendValue(requiredCharacterSets, requiredCharactersUppder);
CFArrayAppendValue(requiredCharacterSets, requiredCharactersNumbers);
passwordRequirements = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
CFDictionaryAddValue(passwordRequirements, kSecPasswordAllowedCharactersKey, allowedCharacters);
CFDictionaryAddValue(passwordRequirements, kSecPasswordRequiredCharactersKey, requiredCharacterSets);
CFDictionaryAddValue(passwordRequirements, kSecPasswordGroupSize, groupSizeRef );
CFDictionaryAddValue(passwordRequirements, kSecPasswordNumberOfGroups, groupCountRef);
CFDictionaryAddValue(passwordRequirements, kSecPasswordSeparator, separator);
CFDictionaryAddValue(passwordRequirements, kSecPasswordMaxLengthKey, totalLengthRef);
CFDictionaryAddValue(passwordRequirements, kSecPasswordMinLengthKey, totalLengthRef);
CFDictionaryAddValue(passwordRequirements, kSecPasswordDefaultForType, CFSTR("false"));
CFRelease(requiredCharactersLower);
CFRelease(requiredCharactersUppder);
CFRelease(requiredCharactersNumbers);
CFRelease(groupSizeRef);
CFRelease(groupCountRef);
CFRelease(totalLengthRef);
password = SecPasswordGenerate(kSecPasswordTypeSafari, &error, passwordRequirements);
CFRelease(requiredCharacterSets);
CFRelease(passwordRequirements);
if ((error && error != errSecSuccess) || !password)
{
if (password) CFRelease(password);
secwarning("SecPasswordGenerate failed to generate a password for SecCreateSharedWebCredentialPassword.");
return NULL;
} else {
return password;
}
}