--- /dev/null
+/*
+ * Copyright (c) 2002-2004,2011-2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SecBase.h>
+#include <Security/SecAccess.h>
+#include <Security/SecAccessPriv.h>
+#include <Security/SecTrustedApplication.h>
+#include <Security/SecTrustedApplicationPriv.h>
+#include <security_keychain/Access.h>
+#include "SecBridge.h"
+#include <sys/param.h>
+
+#undef secdebug
+#include <utilities/SecCFWrappers.h>
+
+
+/* No restrictions. Permission to perform all operations on
+ the resource or available to an ACL owner. */
+
+
+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"));
+
+/* Defined authorization tag values for Keychain */
+
+
+
+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,
+
+ /* Defined authorization tag values for Keychain */
+ (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
+};
+
+static
+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;
+
+}
+
+static
+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;
+}
+
+
+/* TODO: This should be in some header */
+sint32 GetACLAuthorizationTagFromString(CFStringRef aclStr);
+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;
+
+}
+
+/* TODO: This should be in some header */
+CFStringRef GetAuthStringFromACLAuthorizationTag(sint32 tag);
+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;
+}
+
+//
+// CF boilerplate
+//
+CFTypeID SecAccessGetTypeID(void)
+{
+ BEGIN_SECAPI
+ return gTypes().Access.typeID;
+ END_SECAPI1(_kCFRuntimeNotATypeID)
+}
+
+
+//
+// API bridge calls
+//
+/*!
+ * Create a new SecAccessRef that is set to the default configuration
+ * of a (newly created) security object.
+ */
+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); // preflight
+ 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, // selector 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"), (int)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] = %@"), (int)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"), (int)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"), (int)iCnt, rights[iCnt]);
+
+ CFShow(debugStr);
+ CFRelease(debugStr);
+#endif
+
+
+ }
+
+ CSSM_ACL_OWNER_PROTOTYPE owner =
+ {
+ // TypedSubject
+ { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
+ // Delegate
+ false
+ };
+
+
+ // ACL entries (any number, just one here)
+ CSSM_ACL_ENTRY_INFO acl_rights[] =
+ {
+ {
+ // prototype
+ {
+ // TypedSubject
+ { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
+ false, // Delegate
+ // rights for this entry
+ { (uint32)(sizeof(rights) / sizeof(rights[0])), rights },
+ // rest is defaulted
+ }
+ }
+ };
+
+ OSStatus err = SecAccessCreateFromOwnerAndACL(&owner,
+ sizeof(acl_rights) / sizeof(acl_rights[0]), acl_rights, &result);
+
+ if (errSecSuccess != 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 (errSecSuccess != 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)
+ {
+ // nextElement contains the required data
+ 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 (errSecSuccess == 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 (errSecSuccess != 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;
+
+ // Make a CFURLRef from the CFString representation of the bundleĆs path.
+ bundleURL = CFURLCreateWithFileSystemPath(
+ kCFAllocatorDefault,bundlePath,kCFURLPOSIXPathStyle,true);
+
+ CFRange wholeStrRange;
+
+ if (!bundleURL)
+ goto xit;
+
+ // Make a bundle instance using the URLRef.
+ secBundle = CFBundleCreate(kCFAllocatorDefault,bundleURL);
+ if (!secBundle)
+ goto xit;
+
+ trustedAppListFileNameWithoutExtension =
+ CFStringCreateMutableCopy(NULL,CFStringGetLength(trustedAppListFileName),trustedAppListFileName);
+ wholeStrRange = CFStringFind(trustedAppListFileName,CFSTR(".plist"),0);
+
+ CFStringDelete(trustedAppListFileNameWithoutExtension,wholeStrRange);
+
+ // Look for a resource in the bundle by name and type
+ 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 = errSecSuccess;
+ SecAccessRef accessToReturn=nil;
+ CFMutableArrayRef trustedApplications=nil;
+
+ if (!allowAny) // use default access ("confirm access")
+ {
+ // make an exception list of applications you want to trust,
+ // which are allowed to access the item without requiring user confirmation
+ 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)
+ {
+ CFIndex 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;
+ //
+ // Support specification of trusted applications by either
+ // a full pathname or a code requirement string.
+ //
+ if (buffer[0]=='/')
+ {
+ err = SecTrustedApplicationCreateFromPath(buffer,&someOther);
+ }
+ else
+ {
+ char *buf = NULL;
+ CFStringRef reqStr = filename;
+ CFArrayRef descArray = CFStringCreateArrayBySeparatingStrings(NULL, reqStr, CFSTR("\""));
+ if (descArray && (CFArrayGetCount(descArray) > 1))
+ {
+ CFStringRef descStr = (CFStringRef) CFArrayGetValueAtIndex(descArray, 1);
+ if (descStr)
+ buf = CFStringToCString(descStr);
+ }
+ SecRequirementRef reqRef = NULL;
+ err = SecRequirementCreateWithString(reqStr, kSecCSDefaultFlags, &reqRef);
+ if (!err)
+ err = SecTrustedApplicationCreateFromRequirement((const char *)buf, reqRef, &someOther);
+ if (buf)
+ free(buf);
+ CFReleaseSafe(reqRef);
+ CFReleaseSafe(descArray);
+ }
+ if (!err)
+ CFArrayAppendValue(trustedApplications,someOther);
+
+ if (someOther)
+ CFReleaseNull(someOther);
+ }
+ CFRelease(trustedAppListFromBundle);
+ }
+ }
+
+ err = SecAccessCreate((CFStringRef)accessLabel, (CFArrayRef)trustedApplications, &accessToReturn);
+ if (!err)
+ {
+ if (allowAny) // change access to be wide-open for decryption ("always allow access")
+ {
+ // get the access control list for decryption operations
+ CFArrayRef aclList=nil;
+ err = SecAccessCopySelectedACLList(accessToReturn, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
+ if (!err)
+ {
+ // get the first entry in the access control list
+ SecACLRef aclRef=(SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
+ CFArrayRef appList=nil;
+ CFStringRef promptDescription=nil;
+ CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
+ err = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);
+
+ // modify the default ACL to not require the passphrase, and have a nil application list
+ 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;
+}