1/*
2 * Copyright (c) 2002-2004 Apple Computer, 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/SecACL.h>
25#include <security_keychain/ACL.h>
26#include <security_keychain/Access.h>
27#include <security_keychain/SecAccessPriv.h>
28
29#include "SecBridge.h"
30
31// Forward reference
32/*!
33	@function GetACLAuthorizationTagFromString
34	@abstract Get the CSSM ACL item from the CFString
35    @param aclStr The String name of the ACL
36	@result The CSSM ACL value
37*/
38sint32 GetACLAuthorizationTagFromString(CFStringRef aclStr);
39
40CFStringRef GetAuthStringFromACLAuthorizationTag(sint32 tag);
41
42//
43// Local functions
44//
45static void setApplications(ACL *acl, CFArrayRef applicationList);
46
47CFTypeID
48SecACLGetTypeID(void)
49{
50	BEGIN_SECAPI
51
52	return gTypes().ACL.typeID;
53
54	END_SECAPI1(_kCFRuntimeNotATypeID)
55}
56
57
58/*!
59 */
60OSStatus SecACLCreateFromSimpleContents(SecAccessRef accessRef,
61	CFArrayRef applicationList,
62	CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector,
63	SecACLRef *newAcl)
64{
65	BEGIN_SECAPI
66	SecPointer<Access> access = Access::required(accessRef);
67	SecPointer<ACL> acl = new ACL(*access, cfString(description), *promptSelector);
68	if (applicationList) {
69		// application-list + prompt
70		acl->form(ACL::appListForm);
71		setApplications(acl, applicationList);
72	} else {
73		// allow-any
74		acl->form(ACL::allowAllForm);
75	}
76	access->add(acl.get());
77	Required(newAcl) = acl->handle();
78	END_SECAPI
79}
80
81OSStatus SecACLCreateWithSimpleContents(SecAccessRef access,
82										CFArrayRef applicationList,
83										CFStringRef description,
84										SecKeychainPromptSelector promptSelector,
85										SecACLRef *newAcl)
86{
87	CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
88	cdsaPromptSelector.version = CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION;
89	cdsaPromptSelector.flags = promptSelector;
90	return SecACLCreateFromSimpleContents(access, applicationList, description, &cdsaPromptSelector, newAcl);
91}
92
93
94/*!
95 */
96OSStatus SecACLRemove(SecACLRef aclRef)
97{
98	BEGIN_SECAPI
99	ACL::required(aclRef)->remove();
100	END_SECAPI
101}
102
103
104static SecTrustedApplicationRef
105convert(const SecPointer<TrustedApplication> &trustedApplication)
106{
107	return *trustedApplication;
108}
109
110/*!
111 */
112OSStatus SecACLCopySimpleContents(SecACLRef aclRef,
113	CFArrayRef *applicationList,
114	CFStringRef *promptDescription, CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector)
115{
116	BEGIN_SECAPI
117	SecPointer<ACL> acl = ACL::required(aclRef);
118	switch (acl->form()) {
119	case ACL::allowAllForm:
120		Required(applicationList) = NULL;
121		Required(promptDescription) =
122			acl->promptDescription().empty() ? NULL
123				: makeCFString(acl->promptDescription());
124		Required(promptSelector) = acl->promptSelector();
125		break;
126	case ACL::appListForm:
127		Required(applicationList) =
128			makeCFArray(convert, acl->applications());
129		Required(promptDescription) = makeCFString(acl->promptDescription());
130		Required(promptSelector) = acl->promptSelector();
131		break;
132	default:
133		return errSecACLNotSimple;		// custom or unknown
134	}
135	END_SECAPI
136}
137
138OSStatus SecACLCopyContents(SecACLRef acl,
139							CFArrayRef *applicationList,
140							CFStringRef *description,
141							SecKeychainPromptSelector *promptSelector)
142{
143	CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
144	memset(&cdsaPromptSelector, 0, sizeof(cdsaPromptSelector));
145	OSStatus err = errSecSuccess;
146
147	err = SecACLCopySimpleContents(acl, applicationList, description, &cdsaPromptSelector);
148	*promptSelector = cdsaPromptSelector.flags;
149	return err;
150}
151
152OSStatus SecACLSetSimpleContents(SecACLRef aclRef,
153	CFArrayRef applicationList,
154	CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector)
155{
156	BEGIN_SECAPI
157	SecPointer<ACL> acl = ACL::required(aclRef);
158	acl->promptDescription() = description ? cfString(description) : "";
159	acl->promptSelector() = promptSelector ? *promptSelector : ACL::defaultSelector;
160	if (applicationList) {
161		// application-list + prompt
162		acl->form(ACL::appListForm);
163		setApplications(acl, applicationList);
164	} else {
165		// allow-any
166		acl->form(ACL::allowAllForm);
167	}
168	acl->modify();
169	END_SECAPI
170}
171
172OSStatus SecACLSetContents(SecACLRef acl,
173						   CFArrayRef applicationList,
174						   CFStringRef description,
175						   SecKeychainPromptSelector promptSelector)
176{
177	CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
178	cdsaPromptSelector.version = CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION;
179	cdsaPromptSelector.flags = promptSelector;
180	return SecACLSetSimpleContents(acl, applicationList, description, &cdsaPromptSelector);
181}
182
183//
184// Stuff a CFArray-of-SecTrustedApplications into an ACL object
185//
186static void setApplications(ACL *acl, CFArrayRef applicationList)
187{
188	ACL::ApplicationList &appList = acl->applications();
189	appList.clear();
190	//@@@ should really use STL iterator overlay on CFArray. By hand...
191	CFIndex count = CFArrayGetCount(applicationList);
192	for (CFIndex n = 0; n < count; n++)
193		appList.push_back(TrustedApplication::required(
194			SecTrustedApplicationRef(CFArrayGetValueAtIndex(applicationList, n))));
195}
196
197
198//
199// Set and get the authorization tags of an ACL entry
200//
201OSStatus SecACLGetAuthorizations(SecACLRef acl,
202	CSSM_ACL_AUTHORIZATION_TAG *tags, uint32 *tagCount)
203{
204	BEGIN_SECAPI
205	AclAuthorizationSet auths = ACL::required(acl)->authorizations();
206	if (Required(tagCount) < auths.size()) {	// overflow
207		*tagCount = (uint32)auths.size();				// report size required
208		CssmError::throwMe(errSecParam);
209	}
210	*tagCount = (uint32)auths.size();
211	copy(auths.begin(), auths.end(), tags);
212	END_SECAPI
213}
214
215CFArrayRef SecACLCopyAuthorizations(SecACLRef acl)
216{
217	CFArrayRef result = NULL;
218	if (NULL == acl)
219	{
220		return result;
221	}
222
223	AclAuthorizationSet auths = ACL::required(acl)->authorizations();
224	uint32 numAuths = (uint32)auths.size();
225
226    CSSM_ACL_AUTHORIZATION_TAG* tags = new CSSM_ACL_AUTHORIZATION_TAG[numAuths];
227    int i;
228    for (i = 0; i < numAuths; ++i)
229    {
230        tags[i] = NULL;
231    }
232
233	OSStatus err = SecACLGetAuthorizations(acl, tags, &numAuths);
234	if (errSecSuccess != err)
235	{
236
237		return result;
238	}
239
240	CFTypeRef* strings = new CFTypeRef[numAuths];
241    for (i = 0; i < numAuths; ++i)
242    {
243        strings[i] = NULL;
244    }
245
246	for (size_t iCnt = 0; iCnt < numAuths; iCnt++)
247	{
248		strings[iCnt] = (CFTypeRef)GetAuthStringFromACLAuthorizationTag(tags[iCnt]);
249	}
250
251	result = CFArrayCreate(kCFAllocatorDefault, (const void **)strings, numAuths, NULL);
252
253	delete[] strings;
254    delete[] tags;
255
256	return result;
257
258}
259
260OSStatus SecACLSetAuthorizations(SecACLRef aclRef,
261	CSSM_ACL_AUTHORIZATION_TAG *tags, uint32 tagCount)
262{
263	BEGIN_SECAPI
264	SecPointer<ACL> acl = ACL::required(aclRef);
265	if (acl->isOwner())		// can't change rights of the owner ACL
266		MacOSError::throwMe(errSecInvalidOwnerEdit);
267	AclAuthorizationSet &auths = acl->authorizations();
268	auths.clear();
269	copy(tags, tags + tagCount, insert_iterator<AclAuthorizationSet>(auths, auths.begin()));
270	acl->modify();
271	END_SECAPI
272}
273
274OSStatus SecACLUpdateAuthorizations(SecACLRef acl, CFArrayRef authorizations)
275{
276	if (NULL == acl || NULL == authorizations)
277	{
278		return errSecParam;
279	}
280	uint32 tagCount = (uint32)CFArrayGetCount(authorizations);
281
282	size_t tagSize = (tagCount * sizeof(CSSM_ACL_AUTHORIZATION_TAG));
283
284	CSSM_ACL_AUTHORIZATION_TAG* tags = (CSSM_ACL_AUTHORIZATION_TAG*)malloc(tagSize);
285	memset(tags, 0, tagSize);
286	for (uint32 iCnt = 0; iCnt < tagCount; iCnt++)
287	{
288		tags[iCnt] = GetACLAuthorizationTagFromString((CFStringRef)CFArrayGetValueAtIndex(authorizations, iCnt));
289	}
290
291	OSStatus result = SecACLSetAuthorizations(acl, tags, tagCount);
292	free(tags);
293	return result;
294}
295