#include <Security/SecACL.h>
#include <security_keychain/ACL.h>
#include <security_keychain/Access.h>
#include <security_keychain/SecAccessPriv.h>
#include <os/activity.h>
#include "SecBridge.h"
#include "LegacyAPICounts.h"
sint32 GetACLAuthorizationTagFromString(CFStringRef aclStr);
CFStringRef GetAuthStringFromACLAuthorizationTag(sint32 tag);
static void setApplications(ACL *acl, CFArrayRef applicationList);
CFTypeID
SecACLGetTypeID(void)
{
BEGIN_SECAPI
return gTypes().ACL.typeID;
END_SECAPI1(_kCFRuntimeNotATypeID)
}
OSStatus SecACLCreateFromSimpleContents(SecAccessRef accessRef,
CFArrayRef applicationList,
CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector,
SecACLRef *newAcl)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecACLCreateFromSimpleContents", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
SecPointer<Access> access = Access::required(accessRef);
SecPointer<ACL> acl = new ACL(cfString(description), *promptSelector);
if (applicationList) {
acl->form(ACL::appListForm);
setApplications(acl, applicationList);
} else {
acl->form(ACL::allowAllForm);
}
access->add(acl.get());
Required(newAcl) = acl->handle();
END_SECAPI
}
OSStatus SecACLCreateWithSimpleContents(SecAccessRef access,
CFArrayRef applicationList,
CFStringRef description,
SecKeychainPromptSelector promptSelector,
SecACLRef *newAcl)
{
COUNTLEGACYAPI
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
cdsaPromptSelector.version = CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION;
cdsaPromptSelector.flags = promptSelector;
return SecACLCreateFromSimpleContents(access, applicationList, description, &cdsaPromptSelector, newAcl);
}
OSStatus SecACLRemove(SecACLRef aclRef)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecACLRemove", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
ACL::required(aclRef)->remove();
END_SECAPI
}
static SecTrustedApplicationRef
convert(const SecPointer<TrustedApplication> &trustedApplication)
{
return *trustedApplication;
}
OSStatus SecACLCopySimpleContents(SecACLRef aclRef,
CFArrayRef *applicationList,
CFStringRef *promptDescription, CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector)
{
BEGIN_SECAPI
SecPointer<ACL> acl = ACL::required(aclRef);
switch (acl->form()) {
case ACL::allowAllForm:
Required(applicationList) = NULL;
Required(promptDescription) =
acl->promptDescription().empty() ? NULL
: makeCFString(acl->promptDescription());
Required(promptSelector) = acl->promptSelector();
break;
case ACL::appListForm:
Required(applicationList) =
makeCFArrayFrom(convert, acl->applications());
Required(promptDescription) = makeCFString(acl->promptDescription());
Required(promptSelector) = acl->promptSelector();
break;
case ACL::integrityForm:
Required(applicationList) = NULL;
Required(promptDescription) = makeCFString(acl->integrity().toHex());
Required(promptSelector).version = CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION;
Required(promptSelector).flags = 0;
break;
default:
return errSecACLNotSimple; }
END_SECAPI
}
OSStatus SecACLCopyContents(SecACLRef acl,
CFArrayRef *applicationList,
CFStringRef *description,
SecKeychainPromptSelector *promptSelector)
{
COUNTLEGACYAPI
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
memset(&cdsaPromptSelector, 0, sizeof(cdsaPromptSelector));
OSStatus err = errSecSuccess;
err = SecACLCopySimpleContents(acl, applicationList, description, &cdsaPromptSelector);
*promptSelector = cdsaPromptSelector.flags;
return err;
}
OSStatus SecACLSetSimpleContents(SecACLRef aclRef,
CFArrayRef applicationList,
CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecACLSetSimpleContents", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
SecPointer<ACL> acl = ACL::required(aclRef);
if(acl->form() == ACL::integrityForm) {
string hex = cfString(description);
if(hex.length() %2 == 0) {
CssmAutoData data(Allocator::standard());
data.malloc(hex.length() / 2);
data.get().fromHex(hex.c_str());
acl->setIntegrity(data);
}
} else {
acl->promptDescription() = description ? cfString(description) : "";
}
acl->promptSelector() = promptSelector ? *promptSelector : ACL::defaultSelector;
if(acl->form() != ACL::integrityForm) {
if (applicationList) {
acl->form(ACL::appListForm);
setApplications(acl, applicationList);
} else {
acl->form(ACL::allowAllForm);
}
}
acl->modify();
END_SECAPI
}
OSStatus SecACLSetContents(SecACLRef acl,
CFArrayRef applicationList,
CFStringRef description,
SecKeychainPromptSelector promptSelector)
{
COUNTLEGACYAPI
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
cdsaPromptSelector.version = CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION;
cdsaPromptSelector.flags = promptSelector;
return SecACLSetSimpleContents(acl, applicationList, description, &cdsaPromptSelector);
}
static void setApplications(ACL *acl, CFArrayRef applicationList)
{
ACL::ApplicationList &appList = acl->applications();
appList.clear();
CFIndex count = CFArrayGetCount(applicationList);
for (CFIndex n = 0; n < count; n++)
appList.push_back(TrustedApplication::required(
SecTrustedApplicationRef(CFArrayGetValueAtIndex(applicationList, n))));
}
OSStatus SecACLGetAuthorizations(SecACLRef acl,
CSSM_ACL_AUTHORIZATION_TAG *tags, uint32 *tagCount)
{
BEGIN_SECAPI
AclAuthorizationSet auths = ACL::required(acl)->authorizations();
if (Required(tagCount) < auths.size()) { *tagCount = (uint32)auths.size(); CssmError::throwMe(errSecParam);
}
*tagCount = (uint32)auths.size();
copy(auths.begin(), auths.end(), tags);
END_SECAPI
}
CFArrayRef SecACLCopyAuthorizations(SecACLRef acl)
{
COUNTLEGACYAPI
CFArrayRef result = NULL;
if (NULL == acl)
{
return result;
}
AclAuthorizationSet auths = ACL::required(acl)->authorizations();
uint32 numAuths = (uint32)auths.size();
CSSM_ACL_AUTHORIZATION_TAG* tags = new CSSM_ACL_AUTHORIZATION_TAG[numAuths];
int i;
for (i = 0; i < numAuths; ++i)
{
tags[i] = NULL;
}
OSStatus err = SecACLGetAuthorizations(acl, tags, &numAuths);
if (errSecSuccess != err)
{
return result;
}
CFTypeRef* strings = new CFTypeRef[numAuths];
for (i = 0; i < numAuths; ++i)
{
strings[i] = NULL;
}
for (size_t iCnt = 0; iCnt < numAuths; iCnt++)
{
strings[iCnt] = (CFTypeRef)GetAuthStringFromACLAuthorizationTag(tags[iCnt]);
}
result = CFArrayCreate(kCFAllocatorDefault, (const void **)strings, numAuths, &kCFTypeArrayCallBacks);
delete[] strings;
delete[] tags;
return result;
}
OSStatus SecACLSetAuthorizations(SecACLRef aclRef,
CSSM_ACL_AUTHORIZATION_TAG *tags, uint32 tagCount)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecACLSetAuthorizations", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
SecPointer<ACL> acl = ACL::required(aclRef);
if (acl->isOwner()) MacOSError::throwMe(errSecInvalidOwnerEdit);
AclAuthorizationSet &auths = acl->authorizations();
auths.clear();
copy(tags, tags + tagCount, insert_iterator<AclAuthorizationSet>(auths, auths.begin()));
acl->modify();
END_SECAPI
}
OSStatus SecACLUpdateAuthorizations(SecACLRef acl, CFArrayRef authorizations)
{
COUNTLEGACYAPI
if (NULL == acl || NULL == authorizations)
{
return errSecParam;
}
uint32 tagCount = (uint32)CFArrayGetCount(authorizations);
size_t tagSize = (tagCount * sizeof(CSSM_ACL_AUTHORIZATION_TAG));
CSSM_ACL_AUTHORIZATION_TAG* tags = (CSSM_ACL_AUTHORIZATION_TAG*)malloc(tagSize);
memset(tags, 0, tagSize);
for (uint32 iCnt = 0; iCnt < tagCount; iCnt++)
{
tags[iCnt] = GetACLAuthorizationTagFromString((CFStringRef)CFArrayGetValueAtIndex(authorizations, iCnt));
}
OSStatus result = SecACLSetAuthorizations(acl, tags, tagCount);
free(tags);
return result;
}