#include <Security/SecAccess.h>
#include <Security/SecAccessPriv.h>
#include <security_keychain/Access.h>
#include "SecBridge.h"
#include <sys/param.h>
CFTypeRef kSecACLAuthorizationAny = (CFTypeRef)(CFSTR("ACLAuthorizationAny"));
CFTypeRef kSecACLAuthorizationLogin = (CFTypeRef)(CFSTR("ACLAuthorizationLogin"));
CFTypeRef kSecACLAuthorizationGenKey = (CFTypeRef)(CFSTR("ACLAuthorizationGenKey"));
CFTypeRef kSecACLAuthorizationDelete = (CFTypeRef)(CFSTR("ACLAuthorizationDelete"));
CFTypeRef kSecACLAuthorizationExportWrapped = (CFTypeRef)(CFSTR("ACLAuthorizationExportWrapped"));
CFTypeRef kSecACLAuthorizationExportClear = (CFTypeRef)(CFSTR("ACLAuthorizationExportClear"));
CFTypeRef kSecACLAuthorizationImportWrapped = (CFTypeRef)(CFSTR("ACLAuthorizationImportWrapped"));
CFTypeRef kSecACLAuthorizationImportClear = (CFTypeRef)(CFSTR("ACLAuthorizationImportClear"));
CFTypeRef kSecACLAuthorizationSign = (CFTypeRef)(CFSTR("ACLAuthorizationSign"));
CFTypeRef kSecACLAuthorizationEncrypt = (CFTypeRef)(CFSTR("ACLAuthorizationEncrypt"));
CFTypeRef kSecACLAuthorizationDecrypt = (CFTypeRef)(CFSTR("ACLAuthorizationDecrypt"));
CFTypeRef kSecACLAuthorizationMAC = (CFTypeRef)(CFSTR("ACLAuthorizationMAC"));
CFTypeRef kSecACLAuthorizationDerive = (CFTypeRef)(CFSTR("ACLAuthorizationDerive"));
CFTypeRef kSecACLAuthorizationKeychainCreate = (CFTypeRef)(CFSTR("ACLAuthorizationKeychainCreate"));
CFTypeRef kSecACLAuthorizationKeychainDelete = (CFTypeRef)(CFSTR("ACLAuthorizationKeychainDelete"));
CFTypeRef kSecACLAuthorizationKeychainItemRead = (CFTypeRef)(CFSTR("ACLAuthorizationKeychainItemRead"));
CFTypeRef kSecACLAuthorizationKeychainItemInsert = (CFTypeRef)(CFSTR("ACLAuthorizationKeychainItemInsert"));
CFTypeRef kSecACLAuthorizationKeychainItemModify = (CFTypeRef)(CFSTR("ACLAuthorizationKeychainItemModify"));
CFTypeRef kSecACLAuthorizationKeychainItemDelete = (CFTypeRef)(CFSTR("ACLAuthorizationKeychainItemDelete"));
CFTypeRef kSecACLAuthorizationChangeACL = (CFTypeRef)(CFSTR("ACLAuthorizationChangeACL"));
CFTypeRef kSecACLAuthorizationChangeOwner = (CFTypeRef)(CFSTR("ACLAuthorizationChangeOwner"));
static CFArrayRef copyTrustedAppListFromBundle(CFStringRef bundlePath, CFStringRef trustedAppListFileName);
static CFStringRef gKeys[] =
{
(CFStringRef)kSecACLAuthorizationAny,
(CFStringRef)kSecACLAuthorizationLogin,
(CFStringRef)kSecACLAuthorizationGenKey,
(CFStringRef)kSecACLAuthorizationDelete,
(CFStringRef)kSecACLAuthorizationExportWrapped,
(CFStringRef)kSecACLAuthorizationExportClear,
(CFStringRef)kSecACLAuthorizationImportWrapped,
(CFStringRef)kSecACLAuthorizationImportClear,
(CFStringRef)kSecACLAuthorizationSign,
(CFStringRef)kSecACLAuthorizationEncrypt,
(CFStringRef)kSecACLAuthorizationDecrypt,
(CFStringRef)kSecACLAuthorizationMAC,
(CFStringRef)kSecACLAuthorizationDerive,
(CFStringRef)kSecACLAuthorizationKeychainCreate,
(CFStringRef)kSecACLAuthorizationKeychainDelete,
(CFStringRef)kSecACLAuthorizationKeychainItemRead,
(CFStringRef)kSecACLAuthorizationKeychainItemInsert,
(CFStringRef)kSecACLAuthorizationKeychainItemModify,
(CFStringRef)kSecACLAuthorizationKeychainItemDelete,
(CFStringRef)kSecACLAuthorizationChangeACL,
(CFStringRef)kSecACLAuthorizationChangeOwner
};
static sint32 gValues[] =
{
CSSM_ACL_AUTHORIZATION_ANY,
CSSM_ACL_AUTHORIZATION_LOGIN,
CSSM_ACL_AUTHORIZATION_GENKEY,
CSSM_ACL_AUTHORIZATION_DELETE,
CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED,
CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR,
CSSM_ACL_AUTHORIZATION_IMPORT_WRAPPED,
CSSM_ACL_AUTHORIZATION_IMPORT_CLEAR,
CSSM_ACL_AUTHORIZATION_SIGN,
CSSM_ACL_AUTHORIZATION_ENCRYPT,
CSSM_ACL_AUTHORIZATION_DECRYPT,
CSSM_ACL_AUTHORIZATION_MAC,
CSSM_ACL_AUTHORIZATION_DERIVE,
CSSM_ACL_AUTHORIZATION_DBS_CREATE,
CSSM_ACL_AUTHORIZATION_DBS_DELETE,
CSSM_ACL_AUTHORIZATION_DB_READ,
CSSM_ACL_AUTHORIZATION_DB_INSERT,
CSSM_ACL_AUTHORIZATION_DB_MODIFY,
CSSM_ACL_AUTHORIZATION_DB_DELETE,
CSSM_ACL_AUTHORIZATION_CHANGE_ACL,
CSSM_ACL_AUTHORIZATION_CHANGE_OWNER
};
CFDictionaryRef CreateStringToNumDictionary()
{
int numItems = (sizeof(gValues) / sizeof(sint32));
CFMutableDictionaryRef tempDict = CFDictionaryCreateMutable(kCFAllocatorDefault, numItems, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
for (int iCnt = 0; iCnt < numItems; iCnt++)
{
sint32 aNumber = gValues[iCnt];
CFNumberRef aNum = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &aNumber);
CFStringRef aString = gKeys[iCnt];
CFDictionaryAddValue(tempDict, aString, aNum);
CFRelease(aNum);
}
CFDictionaryRef result = CFDictionaryCreateCopy(kCFAllocatorDefault, tempDict);
CFRelease(tempDict);
return result;
}
CFDictionaryRef CreateNumToStringDictionary()
{
int numItems = (sizeof(gValues) / sizeof(sint32));
CFMutableDictionaryRef tempDict = CFDictionaryCreateMutable(kCFAllocatorDefault, numItems, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
for (int iCnt = 0; iCnt < numItems; iCnt++)
{
sint32 aNumber = gValues[iCnt];
CFNumberRef aNum = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &aNumber);
CFStringRef aString = gKeys[iCnt];
CFDictionaryAddValue(tempDict, aNum, aString);
CFRelease(aNum);
}
CFDictionaryRef result = CFDictionaryCreateCopy(kCFAllocatorDefault, tempDict);
CFRelease(tempDict);
return result;
}
sint32 GetACLAuthorizationTagFromString(CFStringRef aclStr)
{
if (NULL == aclStr)
{
#ifndef NDEBUG
CFShow(CFSTR("GetACLAuthorizationTagFromString aclStr is NULL"));
#endif
return 0;
}
static CFDictionaryRef gACLMapping = NULL;
if (NULL == gACLMapping)
{
gACLMapping = CreateStringToNumDictionary();
}
sint32 result = 0;
CFNumberRef valueResult = (CFNumberRef)CFDictionaryGetValue(gACLMapping, aclStr);
if (NULL != valueResult)
{
if (!CFNumberGetValue(valueResult, kCFNumberSInt32Type, &result))
{
return 0;
}
}
else
{
return 0;
}
return result;
}
CFStringRef GetAuthStringFromACLAuthorizationTag(sint32 tag)
{
static CFDictionaryRef gTagMapping = NULL;
CFNumberRef aNum = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &tag);
if (NULL == gTagMapping)
{
gTagMapping = CreateNumToStringDictionary();
}
CFStringRef result = (CFStringRef)kSecACLAuthorizationAny;
if (NULL != gTagMapping && CFDictionaryContainsKey(gTagMapping, aNum))
{
result = (CFStringRef)CFDictionaryGetValue(gTagMapping, aNum);
}
return result;
}
CFTypeID SecAccessGetTypeID(void)
{
BEGIN_SECAPI
return gTypes().Access.typeID;
END_SECAPI1(_kCFRuntimeNotATypeID)
}
OSStatus SecAccessCreate(CFStringRef descriptor, CFArrayRef trustedList, SecAccessRef *accessRef)
{
BEGIN_SECAPI
Required(descriptor);
SecPointer<Access> access;
if (trustedList) {
CFIndex length = CFArrayGetCount(trustedList);
ACL::ApplicationList trusted;
for (CFIndex n = 0; n < length; n++)
trusted.push_back(TrustedApplication::required(
SecTrustedApplicationRef(CFArrayGetValueAtIndex(trustedList, n))));
access = new Access(cfString(descriptor), trusted);
} else {
access = new Access(cfString(descriptor));
}
Required(accessRef) = access->handle();
END_SECAPI
}
OSStatus SecAccessCreateFromOwnerAndACL(const CSSM_ACL_OWNER_PROTOTYPE *owner,
uint32 aclCount, const CSSM_ACL_ENTRY_INFO *acls,
SecAccessRef *accessRef)
{
BEGIN_SECAPI
Required(accessRef); SecPointer<Access> access = new Access(Required(owner), aclCount, &Required(acls));
*accessRef = access->handle();
END_SECAPI
}
SecAccessRef SecAccessCreateWithOwnerAndACL(uid_t userId, gid_t groupId, SecAccessOwnerType ownerType, CFArrayRef acls, CFErrorRef *error)
{
SecAccessRef result = NULL;
CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector =
{
CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION, ownerType,
userId,
groupId
};
CSSM_LIST_ELEMENT subject2 = { NULL, 0 };
subject2.Element.Word.Data = (UInt8 *)&selector;
subject2.Element.Word.Length = sizeof(selector);
CSSM_LIST_ELEMENT subject1 =
{
&subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID
};
CFIndex numAcls = 0;
if (NULL != acls)
{
numAcls = CFArrayGetCount(acls);
}
#ifndef NDEBUG
CFStringRef debugStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
CFSTR("SecAccessCreateWithOwnerAndACL: processing %d acls"), numAcls);
CFShow(debugStr);
CFRelease(debugStr);
#endif
CSSM_ACL_AUTHORIZATION_TAG rights[numAcls];
memset(rights, 0, sizeof(rights));
for (CFIndex iCnt = 0; iCnt < numAcls; iCnt++)
{
CFStringRef aclStr = (CFStringRef)CFArrayGetValueAtIndex(acls, iCnt);
#ifndef NDEBUG
debugStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
CFSTR("SecAccessCreateWithOwnerAndACL: acls[%d] = %@"), iCnt, aclStr);
CFShow(debugStr);
CFRelease(debugStr);
#endif
CSSM_ACL_AUTHORIZATION_TAG aTag = GetACLAuthorizationTagFromString(aclStr);
#ifndef NDEBUG
debugStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
CFSTR("SecAccessCreateWithOwnerAndACL: rights[%d] = %d"), iCnt, aTag);
CFShow(debugStr);
CFRelease(debugStr);
#endif
rights[iCnt] = aTag;
}
for (CFIndex iCnt = 0; iCnt < numAcls; iCnt++)
{
#ifndef NDEBUG
debugStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
CFSTR("SecAccessCreateWithOwnerAndACL: rights[%d] = %d"), iCnt, rights[iCnt]);
CFShow(debugStr);
CFRelease(debugStr);
#endif
}
CSSM_ACL_OWNER_PROTOTYPE owner =
{
{ CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
false
};
CSSM_ACL_ENTRY_INFO acl_rights[] =
{
{
{
{ CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
false, { sizeof(rights) / sizeof(rights[0]), rights },
}
}
};
OSStatus err = SecAccessCreateFromOwnerAndACL(&owner,
sizeof(acl_rights) / sizeof(acl_rights[0]), acl_rights, &result);
if (noErr != err)
{
result = NULL;
if (NULL != error)
{
*error = CFErrorCreate(kCFAllocatorDefault, CFSTR("FIX ME"), err, NULL);
}
}
return result;
}
OSStatus SecAccessGetOwnerAndACL(SecAccessRef accessRef,
CSSM_ACL_OWNER_PROTOTYPE_PTR *owner,
uint32 *aclCount, CSSM_ACL_ENTRY_INFO_PTR *acls)
{
BEGIN_SECAPI
Access::required(accessRef)->copyOwnerAndAcl(
Required(owner), Required(aclCount), Required(acls));
END_SECAPI
}
OSStatus SecAccessCopyOwnerAndACL(SecAccessRef accessRef, uid_t* userId, gid_t* groupId, SecAccessOwnerType* ownerType, CFArrayRef* aclList)
{
CSSM_ACL_OWNER_PROTOTYPE_PTR owner = NULL;
CSSM_ACL_ENTRY_INFO_PTR acls = NULL;
uint32 aclCount = 0;
OSStatus result = SecAccessGetOwnerAndACL(accessRef, &owner, &aclCount, &acls);
if (noErr != result )
{
return result;
}
if (NULL != owner)
{
CSSM_LIST_ELEMENT_PTR listHead = owner->TypedSubject.Head;
if (listHead != NULL && listHead->ElementType == CSSM_LIST_ELEMENT_WORDID)
{
CSSM_LIST_ELEMENT_PTR nextElement = listHead->NextElement;
if (listHead->WordID == CSSM_ACL_SUBJECT_TYPE_PROCESS && listHead->ElementType == CSSM_LIST_ELEMENT_WORDID)
{
CSSM_ACL_PROCESS_SUBJECT_SELECTOR* selectorPtr = (CSSM_ACL_PROCESS_SUBJECT_SELECTOR*)nextElement->Element.Word.Data;
if (NULL != selectorPtr)
{
if (NULL != userId)
{
*userId = (uid_t)selectorPtr->uid;
}
if (NULL != groupId)
{
*groupId = (gid_t)selectorPtr->gid;
}
if (NULL != ownerType)
{
*ownerType = (SecAccessOwnerType)selectorPtr->mask;
}
}
}
}
}
if (NULL != aclList)
{
#ifndef NDEBUG
CFShow(CFSTR("SecAccessCopyOwnerAndACL: processing the ACL list"));
#endif
CFMutableArrayRef stringArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
CSSM_ACL_OWNER_PROTOTYPE_PTR protoPtr = NULL;
uint32 numAcls = 0L;
CSSM_ACL_ENTRY_INFO_PTR aclEntry = NULL;
result = SecAccessGetOwnerAndACL(accessRef, &protoPtr, &numAcls, &aclEntry);
if (noErr == result)
{
#ifndef NDEBUG
CFStringRef tempStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("SecAccessCopyOwnerAndACL: numAcls = %d"), numAcls);
CFShow(tempStr);
CFRelease(tempStr);
#endif
for (uint32 iCnt = 0; iCnt < numAcls; iCnt++)
{
CSSM_ACL_ENTRY_PROTOTYPE prototype = aclEntry[iCnt].EntryPublicInfo;
CSSM_AUTHORIZATIONGROUP authGroup = prototype.Authorization;
int numAuthTags = (int)authGroup.NumberOfAuthTags;
for (int jCnt = 0; jCnt < numAuthTags; jCnt++)
{
sint32 aTag = authGroup.AuthTags[jCnt];
CFStringRef aString = GetAuthStringFromACLAuthorizationTag(aTag);
CFArrayAppendValue(stringArray, aString);
}
}
}
if (NULL != stringArray)
{
if (0 < CFArrayGetCount(stringArray))
{
*aclList = CFArrayCreateCopy(kCFAllocatorDefault, stringArray);
}
CFRelease(stringArray);
}
}
return result;
}
OSStatus SecAccessCopyACLList(SecAccessRef accessRef,
CFArrayRef *aclList)
{
BEGIN_SECAPI
Required(aclList) = Access::required(accessRef)->copySecACLs();
END_SECAPI
}
OSStatus SecAccessCopySelectedACLList(SecAccessRef accessRef,
CSSM_ACL_AUTHORIZATION_TAG action,
CFArrayRef *aclList)
{
BEGIN_SECAPI
Required(aclList) = Access::required(accessRef)->copySecACLs(action);
END_SECAPI
}
CFArrayRef SecAccessCopyMatchingACLList(SecAccessRef accessRef, CFTypeRef authorizationTag)
{
CFArrayRef result = NULL;
CSSM_ACL_AUTHORIZATION_TAG tag = GetACLAuthorizationTagFromString((CFStringRef)authorizationTag);
OSStatus err = SecAccessCopySelectedACLList(accessRef, tag, &result);
if (noErr != err)
{
result = NULL;
}
return result;
}
CFArrayRef copyTrustedAppListFromBundle(CFStringRef bundlePath, CFStringRef trustedAppListFileName)
{
CFStringRef errorString = nil;
CFURLRef bundleURL,trustedAppsURL = NULL;
CFBundleRef secBundle = NULL;
CFPropertyListRef trustedAppsPlist = NULL;
CFDataRef xmlDataRef = NULL;
SInt32 errorCode;
CFArrayRef trustedAppList = NULL;
CFMutableStringRef trustedAppListFileNameWithoutExtension = NULL;
bundleURL = CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,bundlePath,kCFURLPOSIXPathStyle,true);
CFRange wholeStrRange;
if (!bundleURL)
goto xit;
secBundle = CFBundleCreate(kCFAllocatorDefault,bundleURL);
if (!secBundle)
goto xit;
trustedAppListFileNameWithoutExtension =
CFStringCreateMutableCopy(NULL,CFStringGetLength(trustedAppListFileName),trustedAppListFileName);
wholeStrRange = CFStringFind(trustedAppListFileName,CFSTR(".plist"),0);
CFStringDelete(trustedAppListFileNameWithoutExtension,wholeStrRange);
trustedAppsURL = CFBundleCopyResourceURL(secBundle,trustedAppListFileNameWithoutExtension,CFSTR("plist"),NULL);
if (!trustedAppsURL)
goto xit;
if ( trustedAppListFileNameWithoutExtension )
CFRelease(trustedAppListFileNameWithoutExtension);
if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,trustedAppsURL,&xmlDataRef,NULL,NULL,&errorCode))
goto xit;
trustedAppsPlist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,xmlDataRef,kCFPropertyListImmutable,&errorString);
trustedAppList = (CFArrayRef)trustedAppsPlist;
xit:
if (bundleURL)
CFRelease(bundleURL);
if (secBundle)
CFRelease(secBundle);
if (trustedAppsURL)
CFRelease(trustedAppsURL);
if (xmlDataRef)
CFRelease(xmlDataRef);
if (errorString)
CFRelease(errorString);
return trustedAppList;
}
OSStatus SecAccessCreateWithTrustedApplications(CFStringRef trustedApplicationsPListPath, CFStringRef accessLabel, Boolean allowAny, SecAccessRef* returnedAccess)
{
OSStatus err = noErr;
SecAccessRef accessToReturn=nil;
CFMutableArrayRef trustedApplications=nil;
if (!allowAny) {
SecTrustedApplicationRef myself=NULL, someOther=NULL;
CFArrayRef trustedAppListFromBundle=NULL;
trustedApplications=CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks);
err = SecTrustedApplicationCreateFromPath(NULL, &myself);
if (!err)
CFArrayAppendValue(trustedApplications,myself);
CFURLRef url = CFURLCreateWithFileSystemPath(NULL, trustedApplicationsPListPath, kCFURLPOSIXPathStyle, 0);
CFStringRef leafStr = NULL;
leafStr = CFURLCopyLastPathComponent(url);
CFURLRef bndlPathURL = NULL;
bndlPathURL = CFURLCreateCopyDeletingLastPathComponent(NULL, url);
CFStringRef bndlPath = NULL;
bndlPath = CFURLCopyFileSystemPath(bndlPathURL, kCFURLPOSIXPathStyle);
trustedAppListFromBundle=copyTrustedAppListFromBundle(bndlPath, leafStr);
if ( leafStr )
CFRelease(leafStr);
if ( bndlPath )
CFRelease(bndlPath);
if ( url )
CFRelease(url);
if ( bndlPathURL )
CFRelease(bndlPathURL);
if (trustedAppListFromBundle)
{
int ix,top;
char buffer[MAXPATHLEN];
top = CFArrayGetCount(trustedAppListFromBundle);
for (ix=0;ix<top;ix++)
{
CFStringRef filename = (CFStringRef)CFArrayGetValueAtIndex(trustedAppListFromBundle,ix);
CFIndex stringLength = CFStringGetLength(filename);
CFIndex usedBufLen;
if (stringLength != CFStringGetBytes(filename,CFRangeMake(0,stringLength),kCFStringEncodingUTF8,0,
false,(UInt8 *)&buffer,MAXPATHLEN, &usedBufLen))
break;
buffer[usedBufLen] = 0;
err = SecTrustedApplicationCreateFromPath(buffer,&someOther);
if (!err)
CFArrayAppendValue(trustedApplications,someOther);
}
CFRelease(trustedAppListFromBundle);
}
}
err = SecAccessCreate((CFStringRef)accessLabel, (CFArrayRef)trustedApplications, &accessToReturn);
if (!err)
{
if (allowAny) {
CFArrayRef aclList=nil;
err = SecAccessCopySelectedACLList(accessToReturn, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
if (!err)
{
SecACLRef aclRef=(SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
CFArrayRef appList=nil;
CFStringRef promptDescription=nil;
CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
err = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);
promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
err = SecACLSetSimpleContents(aclRef, NULL, promptDescription, &promptSelector);
if (appList) CFRelease(appList);
if (promptDescription) CFRelease(promptDescription);
}
}
}
*returnedAccess = accessToReturn;
return err;
}