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