/ OSX / libsecurity_keychain / lib / SecAccess.cpp
SecAccess.cpp
  1  /*
  2   * Copyright (c) 2002-2004,2011-2014 Apple Inc. All Rights Reserved.
  3   *
  4   * @APPLE_LICENSE_HEADER_START@
  5   * 
  6   * This file contains Original Code and/or Modifications of Original Code
  7   * as defined in and that are subject to the Apple Public Source License
  8   * Version 2.0 (the 'License'). You may not use this file except in
  9   * compliance with the License. Please obtain a copy of the License at
 10   * http://www.opensource.apple.com/apsl/ and read it before using this
 11   * file.
 12   * 
 13   * The Original Code and all software distributed under the License are
 14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18   * Please see the License for the specific language governing rights and
 19   * limitations under the License.
 20   * 
 21   * @APPLE_LICENSE_HEADER_END@
 22   */
 23  
 24  #include <Security/SecBase.h>
 25  #include <Security/SecAccess.h>
 26  #include <Security/SecAccessPriv.h>
 27  #include <Security/SecTrustedApplication.h>
 28  #include <Security/SecTrustedApplicationPriv.h>
 29  #include <security_keychain/Access.h>
 30  #include <security_utilities/casts.h>
 31  #include <utilities/SecCFRelease.h>
 32  #include "SecBridge.h"
 33  #include <sys/param.h>
 34  
 35  #include <utilities/SecCFWrappers.h>
 36  
 37  #include "LegacyAPICounts.h"
 38  
 39  /* No restrictions. Permission to perform all operations on
 40     the resource or available to an ACL owner.  */
 41  
 42  
 43  const CFStringRef kSecACLAuthorizationAny = CFSTR("ACLAuthorizationAny");
 44  
 45  const CFStringRef kSecACLAuthorizationLogin = CFSTR("ACLAuthorizationLogin");
 46  const CFStringRef kSecACLAuthorizationGenKey = CFSTR("ACLAuthorizationGenKey");
 47  const CFStringRef kSecACLAuthorizationDelete = CFSTR("ACLAuthorizationDelete");
 48  const CFStringRef kSecACLAuthorizationExportWrapped = CFSTR("ACLAuthorizationExportWrapped");
 49  const CFStringRef kSecACLAuthorizationExportClear = CFSTR("ACLAuthorizationExportClear");
 50  const CFStringRef kSecACLAuthorizationImportWrapped = CFSTR("ACLAuthorizationImportWrapped");
 51  const CFStringRef kSecACLAuthorizationImportClear = CFSTR("ACLAuthorizationImportClear");
 52  const CFStringRef kSecACLAuthorizationSign = CFSTR("ACLAuthorizationSign");
 53  const CFStringRef kSecACLAuthorizationEncrypt = CFSTR("ACLAuthorizationEncrypt");
 54  const CFStringRef kSecACLAuthorizationDecrypt = CFSTR("ACLAuthorizationDecrypt");
 55  const CFStringRef kSecACLAuthorizationMAC = CFSTR("ACLAuthorizationMAC");
 56  const CFStringRef kSecACLAuthorizationDerive = CFSTR("ACLAuthorizationDerive");
 57  
 58  /* Defined authorization tag values for Keychain */
 59  
 60  
 61  
 62  const CFStringRef kSecACLAuthorizationKeychainCreate = CFSTR("ACLAuthorizationKeychainCreate");
 63  const CFStringRef kSecACLAuthorizationKeychainDelete = CFSTR("ACLAuthorizationKeychainDelete");
 64  const CFStringRef kSecACLAuthorizationKeychainItemRead = CFSTR("ACLAuthorizationKeychainItemRead");
 65  const CFStringRef kSecACLAuthorizationKeychainItemInsert = CFSTR("ACLAuthorizationKeychainItemInsert");
 66  const CFStringRef kSecACLAuthorizationKeychainItemModify = CFSTR("ACLAuthorizationKeychainItemModify");
 67  const CFStringRef kSecACLAuthorizationKeychainItemDelete = CFSTR("ACLAuthorizationKeychainItemDelete");
 68  
 69  const CFStringRef kSecACLAuthorizationChangeACL = CFSTR("ACLAuthorizationChangeACL");
 70  const CFStringRef kSecACLAuthorizationChangeOwner = CFSTR("ACLAuthorizationChangeOwner");
 71  const CFStringRef kSecACLAuthorizationPartitionID = CFSTR("ACLAuthorizationPartitionID");
 72  const CFStringRef kSecACLAuthorizationIntegrity = CFSTR("ACLAuthorizationIntegrity");
 73  
 74  
 75  static CFArrayRef copyTrustedAppListFromBundle(CFStringRef bundlePath, CFStringRef trustedAppListFileName);
 76  
 77  static CFStringRef gKeys[] =
 78  {
 79  	kSecACLAuthorizationAny,
 80  	kSecACLAuthorizationLogin,
 81  	kSecACLAuthorizationGenKey,
 82  	kSecACLAuthorizationDelete,
 83  	kSecACLAuthorizationExportWrapped,
 84  	kSecACLAuthorizationExportClear,
 85  	kSecACLAuthorizationImportWrapped,
 86  	kSecACLAuthorizationImportClear,
 87  	kSecACLAuthorizationSign,
 88  	kSecACLAuthorizationEncrypt,
 89  	kSecACLAuthorizationDecrypt,
 90  	kSecACLAuthorizationMAC,
 91  	kSecACLAuthorizationDerive,
 92  
 93  	/* Defined authorization tag values for Keychain */
 94  	kSecACLAuthorizationKeychainCreate,
 95  	kSecACLAuthorizationKeychainDelete,
 96  	kSecACLAuthorizationKeychainItemRead,
 97  	kSecACLAuthorizationKeychainItemInsert,
 98  	kSecACLAuthorizationKeychainItemModify,
 99  	kSecACLAuthorizationKeychainItemDelete,
100  
101  	kSecACLAuthorizationChangeACL,
102  	kSecACLAuthorizationChangeOwner,
103      kSecACLAuthorizationPartitionID,
104      kSecACLAuthorizationIntegrity
105  };
106  
107  static sint32 gValues[] =
108  {
109  	CSSM_ACL_AUTHORIZATION_ANY,
110  	CSSM_ACL_AUTHORIZATION_LOGIN,
111  	CSSM_ACL_AUTHORIZATION_GENKEY,
112  	CSSM_ACL_AUTHORIZATION_DELETE,
113  	CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED,
114  	CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR,
115  	CSSM_ACL_AUTHORIZATION_IMPORT_WRAPPED,
116  	CSSM_ACL_AUTHORIZATION_IMPORT_CLEAR,
117  	CSSM_ACL_AUTHORIZATION_SIGN,
118  	CSSM_ACL_AUTHORIZATION_ENCRYPT,
119  	CSSM_ACL_AUTHORIZATION_DECRYPT,
120  	CSSM_ACL_AUTHORIZATION_MAC,
121  	CSSM_ACL_AUTHORIZATION_DERIVE,
122  	CSSM_ACL_AUTHORIZATION_DBS_CREATE,
123  	CSSM_ACL_AUTHORIZATION_DBS_DELETE,
124  	CSSM_ACL_AUTHORIZATION_DB_READ,
125  	CSSM_ACL_AUTHORIZATION_DB_INSERT,
126  	CSSM_ACL_AUTHORIZATION_DB_MODIFY,
127  	CSSM_ACL_AUTHORIZATION_DB_DELETE,
128  	CSSM_ACL_AUTHORIZATION_CHANGE_ACL,
129  	CSSM_ACL_AUTHORIZATION_CHANGE_OWNER,
130      CSSM_ACL_AUTHORIZATION_PARTITION_ID,
131      CSSM_ACL_AUTHORIZATION_INTEGRITY
132  };
133  
134  static
135  CFDictionaryRef CreateStringToNumDictionary()
136  {
137  	int numItems = (sizeof(gValues) / sizeof(sint32));
138  	CFMutableDictionaryRef tempDict = CFDictionaryCreateMutable(kCFAllocatorDefault, numItems, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
139  
140  	for (int iCnt = 0; iCnt < numItems; iCnt++)
141  	{
142  		sint32 aNumber = gValues[iCnt];
143  		CFNumberRef aNum = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &aNumber);
144  
145  		CFStringRef aString = gKeys[iCnt];
146  		CFDictionaryAddValue(tempDict, aString, aNum);
147  		CFRelease(aNum);
148  	}
149  
150  	CFDictionaryRef result = CFDictionaryCreateCopy(kCFAllocatorDefault, tempDict);
151  	CFRelease(tempDict);
152  	return result;
153  
154  }
155  
156  static
157  CFDictionaryRef CreateNumToStringDictionary()
158  {
159  	int numItems = (sizeof(gValues) / sizeof(sint32));
160  
161  	CFMutableDictionaryRef tempDict = CFDictionaryCreateMutable(kCFAllocatorDefault, numItems, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
162  
163  	for (int iCnt = 0; iCnt < numItems; iCnt++)
164  	{
165  		sint32 aNumber = gValues[iCnt];
166  		CFNumberRef aNum = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &aNumber);
167  
168  		CFStringRef aString = gKeys[iCnt];
169  		CFDictionaryAddValue(tempDict, aNum, aString);
170  		CFRelease(aNum);
171  
172  	}
173  
174  	CFDictionaryRef result = CFDictionaryCreateCopy(kCFAllocatorDefault, tempDict);
175  	CFRelease(tempDict);
176  	return result;
177  }
178  
179  
180  /* TODO: This should be in some header */
181  sint32 GetACLAuthorizationTagFromString(CFStringRef aclStr);
182  sint32 GetACLAuthorizationTagFromString(CFStringRef aclStr)
183  {
184  	if (NULL == aclStr)
185  	{
186  #ifndef NDEBUG
187  		CFShow(CFSTR("GetACLAuthorizationTagFromString aclStr is NULL"));
188  #endif
189  		return 0;
190  	}
191  
192  	static CFDictionaryRef gACLMapping = NULL;
193  
194  	if (NULL == gACLMapping)
195  	{
196  		gACLMapping = CreateStringToNumDictionary();
197  	}
198  
199  	sint32 result = 0;
200  	CFNumberRef valueResult = (CFNumberRef)CFDictionaryGetValue(gACLMapping, aclStr);
201  	if (NULL != valueResult)
202  	{
203  		if (!CFNumberGetValue(valueResult, kCFNumberSInt32Type, &result))
204  		{
205  			return 0;
206  		}
207  
208  	}
209  	else
210  	{
211  		return 0;
212  	}
213  
214  	return result;
215  
216  }
217  
218  /* TODO: This should be in some header */
219  CFStringRef GetAuthStringFromACLAuthorizationTag(sint32 tag);
220  CFStringRef GetAuthStringFromACLAuthorizationTag(sint32 tag)
221  {
222  	static CFDictionaryRef gTagMapping = NULL;
223  	CFNumberRef aNum = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &tag);
224  
225  	if (NULL == gTagMapping)
226  	{
227  		gTagMapping = CreateNumToStringDictionary();
228  	}
229  
230  	CFStringRef result = (CFStringRef)kSecACLAuthorizationAny;
231  
232  	if (NULL != gTagMapping && CFDictionaryContainsKey(gTagMapping, aNum))
233  	{
234  		result = (CFStringRef)CFDictionaryGetValue(gTagMapping, aNum);
235  	}
236      CFReleaseSafe(aNum);
237  	return result;
238  }
239  
240  //
241  // CF boilerplate
242  //
243  CFTypeID SecAccessGetTypeID(void)
244  {
245  	BEGIN_SECAPI
246  	return gTypes().Access.typeID;
247  	END_SECAPI1(_kCFRuntimeNotATypeID)
248  }
249  
250  
251  //
252  // API bridge calls
253  //
254  /*!
255   *	Create a new SecAccessRef that is set to the default configuration
256   *	of a (newly created) security object.
257   */
258  OSStatus SecAccessCreate(CFStringRef descriptor, CFArrayRef trustedList, SecAccessRef *accessRef)
259  {
260  	BEGIN_SECAPI
261  	Required(descriptor);
262  	SecPointer<Access> access;
263  	if (trustedList) {
264  		CFIndex length = CFArrayGetCount(trustedList);
265  		ACL::ApplicationList trusted;
266  		for (CFIndex n = 0; n < length; n++)
267  			trusted.push_back(TrustedApplication::required(
268  				SecTrustedApplicationRef(CFArrayGetValueAtIndex(trustedList, n))));
269  		access = new Access(cfString(descriptor), trusted);
270  	} else {
271  		access = new Access(cfString(descriptor));
272  	}
273  	Required(accessRef) = access->handle();
274  	END_SECAPI
275  }
276  
277  
278  /*!
279   */
280  OSStatus SecAccessCreateFromOwnerAndACL(const CSSM_ACL_OWNER_PROTOTYPE *owner,
281  	uint32 aclCount, const CSSM_ACL_ENTRY_INFO *acls,
282  	SecAccessRef *accessRef)
283  {
284  	BEGIN_SECAPI
285  	Required(accessRef);	// preflight
286  	SecPointer<Access> access = new Access(Required(owner), aclCount, &Required(acls));
287  	*accessRef = access->handle();
288  	END_SECAPI
289  }
290  
291  SecAccessRef SecAccessCreateWithOwnerAndACL(uid_t userId, gid_t groupId, SecAccessOwnerType ownerType, CFArrayRef acls, CFErrorRef *error)
292  {
293  	COUNTLEGACYAPI
294  	SecAccessRef result = NULL;
295  
296  	CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector =
297  	{
298  		CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION,	// selector version
299  		int_cast<UInt32, uint16>(ownerType),
300  		userId,
301  		groupId
302  	};
303  
304  	CSSM_LIST_ELEMENT subject2 = { NULL, 0 };
305  	subject2.Element.Word.Data = (UInt8 *)&selector;
306  	subject2.Element.Word.Length = sizeof(selector);
307  	CSSM_LIST_ELEMENT subject1 =
308  	{
309  		&subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID
310  	};
311  
312  	CFIndex numAcls = 0;
313  
314  	if (NULL != acls)
315  	{
316  		numAcls = CFArrayGetCount(acls);
317  	}
318  
319  #ifndef NDEBUG
320  	CFStringRef debugStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
321  		CFSTR("SecAccessCreateWithOwnerAndACL: processing %d acls"), (int)numAcls);
322  	CFShow(debugStr);
323  	CFRelease(debugStr);
324  #endif
325  
326  	std::vector<CSSM_ACL_AUTHORIZATION_TAG> rights(numAcls);
327  
328  	for (CFIndex iCnt = 0; iCnt < numAcls; iCnt++)
329  	{
330  		CFStringRef aclStr = (CFStringRef)CFArrayGetValueAtIndex(acls, iCnt);
331  
332  #ifndef NDEBUG
333  		debugStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
334  			CFSTR("SecAccessCreateWithOwnerAndACL: acls[%d] = %@"), (int)iCnt, aclStr);
335  
336  		CFShow(debugStr);
337  		CFRelease(debugStr);
338  #endif
339  
340  		CSSM_ACL_AUTHORIZATION_TAG aTag = GetACLAuthorizationTagFromString(aclStr);
341  
342  #ifndef NDEBUG
343  		debugStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
344  			CFSTR("SecAccessCreateWithOwnerAndACL: rights[%d] = %d"), (int)iCnt, aTag);
345  
346  		CFShow(debugStr);
347  		CFRelease(debugStr);
348  #endif
349  
350  		rights[iCnt] = aTag;
351  	}
352  
353  
354  	for (CFIndex iCnt = 0; iCnt < numAcls; iCnt++)
355  	{
356  #ifndef NDEBUG
357  		debugStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
358  			CFSTR("SecAccessCreateWithOwnerAndACL: rights[%d]  = %d"), (int)iCnt, rights[iCnt]);
359  
360  		CFShow(debugStr);
361  		CFRelease(debugStr);
362  #endif
363  
364  
365  	}
366  
367  	CSSM_ACL_OWNER_PROTOTYPE owner =
368  	{
369  		// TypedSubject
370  		{ CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
371  		// Delegate
372  		false
373  	};
374  
375  
376  	// ACL entries (any number, just one here)
377  	CSSM_ACL_ENTRY_INFO acl_rights[] =
378  	{
379  		{
380  			// prototype
381  			{
382  				// TypedSubject
383  				{ CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
384  				false,	// Delegate
385  				// rights for this entry
386  				{ (uint32)numAcls, rights.data() },
387  				// rest is defaulted
388  			}
389  		}
390  	};
391  
392  	OSStatus err = SecAccessCreateFromOwnerAndACL(&owner,
393  		sizeof(acl_rights) / sizeof(acl_rights[0]), acl_rights, &result);
394  
395  	if (errSecSuccess != err)
396  	{
397  		result = NULL;
398  		if (NULL != error)
399  		{
400  			*error  = CFErrorCreate(kCFAllocatorDefault, CFSTR("FIX ME"), err, NULL);
401     		}
402  	}
403  	return result;
404  }
405  
406  
407  /*!
408   */
409  OSStatus SecAccessGetOwnerAndACL(SecAccessRef accessRef,
410  	CSSM_ACL_OWNER_PROTOTYPE_PTR *owner,
411  	uint32 *aclCount, CSSM_ACL_ENTRY_INFO_PTR *acls)
412  {
413  	BEGIN_SECAPI
414  	Access::required(accessRef)->copyOwnerAndAcl(
415  		Required(owner), Required(aclCount), Required(acls));
416  	END_SECAPI
417  }
418  
419  OSStatus SecAccessCopyOwnerAndACL(SecAccessRef accessRef, uid_t* userId, gid_t* groupId, SecAccessOwnerType* ownerType, CFArrayRef* aclList)
420  {
421  	COUNTLEGACYAPI
422  	CSSM_ACL_OWNER_PROTOTYPE_PTR owner = NULL;
423  	CSSM_ACL_ENTRY_INFO_PTR acls = NULL;
424  	uint32 aclCount = 0;
425  	OSStatus result = SecAccessGetOwnerAndACL(accessRef, &owner, &aclCount, &acls);
426  	if (errSecSuccess != result )
427  	{
428  		return result;
429  	}
430  
431  	if (NULL != owner)
432  	{
433  		CSSM_LIST_ELEMENT_PTR listHead = owner->TypedSubject.Head;
434  		if (listHead != NULL && listHead->ElementType == CSSM_LIST_ELEMENT_WORDID)
435  		{
436  			CSSM_LIST_ELEMENT_PTR nextElement = listHead->NextElement;
437  			if (listHead->WordID == CSSM_ACL_SUBJECT_TYPE_PROCESS && listHead->ElementType == CSSM_LIST_ELEMENT_WORDID)
438  			{
439  				// nextElement contains the required data
440  				CSSM_ACL_PROCESS_SUBJECT_SELECTOR* selectorPtr = (CSSM_ACL_PROCESS_SUBJECT_SELECTOR*)nextElement->Element.Word.Data;
441  				if (NULL != selectorPtr)
442  				{
443  					if (NULL != userId)
444  					{
445  						*userId = (uid_t)selectorPtr->uid;
446  					}
447  
448  					if (NULL != groupId)
449  					{
450  						*groupId = (gid_t)selectorPtr->gid;
451  					}
452  
453  					if (NULL != ownerType)
454  					{
455  						*ownerType = (SecAccessOwnerType)selectorPtr->mask;
456  					}
457  				}
458  			}
459  
460  		}
461  
462  	}
463  
464  	if (NULL != aclList)
465  	{
466  #ifndef NDEBUG
467  		CFShow(CFSTR("SecAccessCopyOwnerAndACL: processing the ACL list"));
468  #endif
469  
470  		CFMutableArrayRef stringArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
471  		CSSM_ACL_OWNER_PROTOTYPE_PTR protoPtr = NULL;
472  		uint32 numAcls = 0L;
473  		CSSM_ACL_ENTRY_INFO_PTR aclEntry = NULL;
474  
475  		result = SecAccessGetOwnerAndACL(accessRef, &protoPtr, &numAcls, &aclEntry);
476  		if (errSecSuccess == result)
477  		{
478  #ifndef NDEBUG
479  			CFStringRef tempStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("SecAccessCopyOwnerAndACL: numAcls = %d"), numAcls);
480  			CFShow(tempStr);
481  			CFRelease(tempStr);
482  #endif
483  
484  			for (uint32 iCnt = 0; iCnt < numAcls; iCnt++)
485  			{
486  				CSSM_ACL_ENTRY_PROTOTYPE prototype = aclEntry[iCnt].EntryPublicInfo;
487  				CSSM_AUTHORIZATIONGROUP authGroup = prototype.Authorization;
488  				int numAuthTags = (int)authGroup.NumberOfAuthTags;
489  
490  				for (int jCnt = 0; jCnt < numAuthTags; jCnt++)
491  				{
492  
493  					sint32 aTag = authGroup.AuthTags[jCnt];
494  					CFStringRef aString = GetAuthStringFromACLAuthorizationTag(aTag);
495  
496  					CFArrayAppendValue(stringArray, aString);
497  				}
498  			}
499  		}
500  
501  		if (NULL != stringArray)
502  		{
503  			if (0 < CFArrayGetCount(stringArray))
504  			{
505  				*aclList = CFArrayCreateCopy(kCFAllocatorDefault, stringArray);
506  			}
507  			CFRelease(stringArray);
508  		}
509  	}
510  
511  	return result;
512  }
513  
514  /*!
515   */
516  OSStatus SecAccessCopyACLList(SecAccessRef accessRef,
517  	CFArrayRef *aclList)
518  {
519  	BEGIN_SECAPI
520  	Required(aclList) = Access::required(accessRef)->copySecACLs();
521  	END_SECAPI
522  }
523  
524  
525  /*!
526   */
527  OSStatus SecAccessCopySelectedACLList(SecAccessRef accessRef,
528  	CSSM_ACL_AUTHORIZATION_TAG action,
529  	CFArrayRef *aclList)
530  {
531  	BEGIN_SECAPI
532  	Required(aclList) = Access::required(accessRef)->copySecACLs(action);
533  	END_SECAPI
534  }
535  
536  CFArrayRef SecAccessCopyMatchingACLList(SecAccessRef accessRef, CFTypeRef authorizationTag)
537  {
538  	COUNTLEGACYAPI
539  	CFArrayRef result = NULL;
540  	CSSM_ACL_AUTHORIZATION_TAG tag = GetACLAuthorizationTagFromString((CFStringRef)authorizationTag);
541  	OSStatus err = SecAccessCopySelectedACLList(accessRef, tag, &result);
542  	if (errSecSuccess != err)
543  	{
544  		result = NULL;
545  	}
546  	return result;
547  }
548  
549  CFArrayRef copyTrustedAppListFromBundle(CFStringRef bundlePath, CFStringRef trustedAppListFileName)
550  {
551  	CFStringRef errorString = nil;
552      CFURLRef bundleURL,trustedAppsURL = NULL;
553      CFBundleRef secBundle = NULL;
554  	CFPropertyListRef trustedAppsPlist = NULL;
555  	CFDataRef xmlDataRef = NULL;
556  	SInt32 errorCode;
557      CFArrayRef trustedAppList = NULL;
558  	CFMutableStringRef trustedAppListFileNameWithoutExtension = NULL;
559  
560      // Make a CFURLRef from the CFString representation of the bundle�s path.
561      bundleURL = CFURLCreateWithFileSystemPath(
562          kCFAllocatorDefault,bundlePath,kCFURLPOSIXPathStyle,true);
563  
564  	CFRange wholeStrRange;
565  
566  	if (!bundleURL)
567          goto xit;
568  
569      // Make a bundle instance using the URLRef.
570      secBundle = CFBundleCreate(kCFAllocatorDefault,bundleURL);
571      if (!secBundle) {
572          goto xit;
573      }
574  
575  	trustedAppListFileNameWithoutExtension =
576  		CFStringCreateMutableCopy(NULL,CFStringGetLength(trustedAppListFileName),trustedAppListFileName);
577  	wholeStrRange = CFStringFind(trustedAppListFileName,CFSTR(".plist"),0);
578  
579  	CFStringDelete(trustedAppListFileNameWithoutExtension,wholeStrRange);
580  
581      // Look for a resource in the bundle by name and type
582      trustedAppsURL = CFBundleCopyResourceURL(secBundle,trustedAppListFileNameWithoutExtension,CFSTR("plist"),NULL);
583      if (!trustedAppsURL) {
584          goto xit;
585      }
586  
587      if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,trustedAppsURL,&xmlDataRef,NULL,NULL,&errorCode)) {
588          goto xit;
589      }
590  
591  	trustedAppsPlist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,xmlDataRef,kCFPropertyListImmutable,&errorString);
592      trustedAppList = (CFArrayRef)trustedAppsPlist;
593  
594  xit:
595      CFReleaseNull(trustedAppListFileNameWithoutExtension);
596      if (bundleURL)
597          CFRelease(bundleURL);
598      if (secBundle)
599          CFRelease(secBundle);
600      if (trustedAppsURL)
601          CFRelease(trustedAppsURL);
602      if (xmlDataRef)
603          CFRelease(xmlDataRef);
604      if (errorString)
605          CFRelease(errorString);
606  
607      return trustedAppList;
608  }
609  
610  OSStatus SecAccessCreateWithTrustedApplications(CFStringRef trustedApplicationsPListPath, CFStringRef accessLabel, Boolean allowAny, SecAccessRef* returnedAccess)
611  {
612  	COUNTLEGACYAPI
613  	OSStatus err = errSecSuccess;
614  	SecAccessRef accessToReturn=nil;
615  	CFMutableArrayRef trustedApplications=nil;
616  
617  	if (!allowAny) // use default access ("confirm access")
618  	{
619  		// make an exception list of applications you want to trust,
620  		// which are allowed to access the item without requiring user confirmation
621  		SecTrustedApplicationRef myself=NULL, someOther=NULL;
622          CFArrayRef trustedAppListFromBundle=NULL;
623  
624          trustedApplications=CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks);
625          err = SecTrustedApplicationCreateFromPath(NULL, &myself);
626          if (!err)
627              CFArrayAppendValue(trustedApplications,myself);
628  
629  		CFURLRef url = CFURLCreateWithFileSystemPath(NULL, trustedApplicationsPListPath, kCFURLPOSIXPathStyle, 0);
630  		CFStringRef leafStr = NULL;
631  		leafStr = CFURLCopyLastPathComponent(url);
632  
633  		CFURLRef bndlPathURL = NULL;
634  		bndlPathURL = CFURLCreateCopyDeletingLastPathComponent(NULL, url);
635  		CFStringRef bndlPath = NULL;
636  		bndlPath = CFURLCopyFileSystemPath(bndlPathURL, kCFURLPOSIXPathStyle);
637          trustedAppListFromBundle=copyTrustedAppListFromBundle(bndlPath, leafStr);
638  		if ( leafStr )
639  			CFRelease(leafStr);
640  		if ( bndlPath )
641  			CFRelease(bndlPath);
642  		if ( url )
643  			CFRelease(url);
644  		if ( bndlPathURL )
645  			CFRelease(bndlPathURL);
646          if (trustedAppListFromBundle)
647          {
648              CFIndex ix,top;
649              char buffer[MAXPATHLEN];
650              top = CFArrayGetCount(trustedAppListFromBundle);
651              for (ix=0;ix<top;ix++)
652              {
653                  CFStringRef filename = (CFStringRef)CFArrayGetValueAtIndex(trustedAppListFromBundle,ix);
654                  CFIndex stringLength = CFStringGetLength(filename);
655                  CFIndex usedBufLen;
656  
657                  if (stringLength != CFStringGetBytes(filename,CFRangeMake(0,stringLength),kCFStringEncodingUTF8,0,
658                      false,(UInt8 *)&buffer,MAXPATHLEN, &usedBufLen))
659                      break;
660                  buffer[usedBufLen] = 0;
661  				//
662  				// Support specification of trusted applications by either
663  				// a full pathname or a code requirement string.
664  				//
665  				if (buffer[0]=='/')
666  				{
667  					err = SecTrustedApplicationCreateFromPath(buffer,&someOther);
668  				}
669  				else
670  				{
671  					char *buf = NULL;
672  					CFStringRef reqStr = filename;
673  					CFArrayRef descArray = CFStringCreateArrayBySeparatingStrings(NULL, reqStr, CFSTR("\""));
674  					if (descArray && (CFArrayGetCount(descArray) > 1))
675  					{
676  						CFStringRef descStr = (CFStringRef) CFArrayGetValueAtIndex(descArray, 1);
677  						if (descStr)
678  							buf = CFStringToCString(descStr);
679  					}
680  					SecRequirementRef reqRef = NULL;
681  					err = SecRequirementCreateWithString(reqStr, kSecCSDefaultFlags, &reqRef);
682  					if (!err)
683  						err = SecTrustedApplicationCreateFromRequirement((const char *)buf, reqRef, &someOther);
684  					if (buf)
685  						free(buf);
686  					CFReleaseSafe(reqRef);
687  					CFReleaseSafe(descArray);
688  				}
689                  if (!err)
690                      CFArrayAppendValue(trustedApplications,someOther);
691  
692  				if (someOther)
693  					CFReleaseNull(someOther);
694              }
695              CFRelease(trustedAppListFromBundle);
696          }
697  	}
698  
699  	err = SecAccessCreate((CFStringRef)accessLabel, (CFArrayRef)trustedApplications, &accessToReturn);
700      if (!err)
701  	{
702  		if (allowAny) // change access to be wide-open for decryption ("always allow access")
703  		{
704  			// get the access control list for decryption operations
705  			CFArrayRef aclList=nil;
706  			err = SecAccessCopySelectedACLList(accessToReturn, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
707  			if (!err)
708  			{
709  				// get the first entry in the access control list
710  				SecACLRef aclRef=(SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
711  				CFArrayRef appList=nil;
712  				CFStringRef promptDescription=nil;
713  				CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
714  				err = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector);
715  
716  				// modify the default ACL to not require the passphrase, and have a nil application list
717  				promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
718  				err = SecACLSetSimpleContents(aclRef, NULL, promptDescription, &promptSelector);
719  
720  				if (appList) CFRelease(appList);
721  				if (promptDescription) CFRelease(promptDescription);
722  			}
723  		}
724  	}
725  	*returnedAccess = accessToReturn;
726  	return err;
727  }