#include "access_utils.h"
#include "security_tool.h"
#include <stdio.h>
#include <Security/SecKeychainItem.h>
#include <Security/SecAccess.h>
#include <Security/SecACL.h>
int
create_access(const char *accessName, Boolean allowAny, CFArrayRef trustedApps, SecAccessRef *access)
{
int result = 0;
CFArrayRef appList = NULL;
CFArrayRef aclList = NULL;
CFStringRef description = NULL;
const char *descriptionLabel = (accessName) ? accessName : "<unlabeled key>";
CFStringRef promptDescription = NULL;
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
SecACLRef aclRef;
OSStatus status;
if (accessName) {
description = CFStringCreateWithCString(NULL, descriptionLabel, kCFStringEncodingUTF8);
}
status = SecAccessCreate(description, trustedApps, access);
if (status)
{
sec_perror("SecAccessCreate", status);
result = 1;
goto cleanup;
}
status = SecAccessCopySelectedACLList(*access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
if (status)
{
sec_perror("SecAccessCopySelectedACLList", status);
result = 1;
goto cleanup;
}
aclRef = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
status = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);
if (status)
{
sec_perror("SecACLCopySimpleContents", status);
result = 1;
goto cleanup;
}
if (allowAny) {
promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
status = SecACLSetSimpleContents(aclRef, NULL, promptDescription, &promptSelector);
}
else {
status = SecACLSetSimpleContents(aclRef, trustedApps, promptDescription, &promptSelector);
}
if (status)
{
sec_perror("SecACLSetSimpleContents", status);
result = 1;
goto cleanup;
}
cleanup:
if (description)
CFRelease(description);
if (promptDescription)
CFRelease(promptDescription);
if (appList)
CFRelease(appList);
if (aclList)
CFRelease(aclList);
return result;
}
int
merge_access(SecAccessRef access, SecAccessRef otherAccess)
{
OSStatus status;
CFArrayRef aclList, newAclList;
status = SecAccessCopySelectedACLList(access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
if (status) {
return status;
}
status = SecAccessCopySelectedACLList(otherAccess, CSSM_ACL_AUTHORIZATION_DECRYPT, &newAclList);
if (status) {
newAclList = nil;
} else {
SecACLRef aclRef=(SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
SecACLRef newAclRef=(SecACLRef)CFArrayGetValueAtIndex(newAclList, 0);
CFArrayRef appList=nil;
CFArrayRef newAppList=nil;
CFMutableArrayRef mergedAppList = nil;
CFStringRef promptDescription=nil;
CFStringRef newPromptDescription=nil;
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR newPromptSelector;
status = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);
if (!status) {
status = SecACLCopySimpleContents(newAclRef, &newAppList, &newPromptDescription, &newPromptSelector);
}
if (!status) {
if (appList) {
mergedAppList = CFArrayCreateMutableCopy(NULL, 0, appList);
}
if (newAppList) {
if (mergedAppList) {
CFArrayAppendArray(mergedAppList, newAppList, CFRangeMake(0, CFArrayGetCount(newAppList)));
} else {
mergedAppList = CFArrayCreateMutableCopy(NULL, 0, newAppList);
}
}
promptSelector.flags = newPromptSelector.flags;
status = SecACLSetSimpleContents(aclRef, mergedAppList, newPromptDescription, &newPromptSelector);
}
if (appList) CFRelease(appList);
if (newAppList) CFRelease(newAppList);
if (mergedAppList) CFRelease(mergedAppList);
if (promptDescription) CFRelease(promptDescription);
if (newPromptDescription) CFRelease(newPromptDescription);
}
if (aclList) CFRelease(aclList);
if (newAclList) CFRelease(newAclList);
return status;
}
int
modify_access(SecKeychainItemRef itemRef, SecAccessRef access)
{
OSStatus status;
SecAccessRef curAccess = NULL;
status = SecKeychainItemCopyAccess(itemRef, &curAccess);
if (status) {
sec_error("SecKeychainItemCopyAccess: %s", sec_errstr(status));
} else {
status = merge_access(curAccess, access); if (!status) {
status = SecKeychainItemSetAccess(itemRef, curAccess); if (status) {
sec_error("SecKeychainItemSetAccess: %s", sec_errstr(status));
}
}
}
if (curAccess) {
CFRelease(curAccess);
}
return status;
}