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//
25// Access.cpp
26//
27#include <security_keychain/Access.h>
28#include <Security/SecBase.h>
29#include "SecBridge.h"
30#include <security_utilities/devrandom.h>
31#include <security_cdsa_utilities/uniformrandom.h>
32#include <security_cdsa_client/aclclient.h>
33#include <vector>
34#include <SecBase.h>
35using namespace KeychainCore;
36using namespace CssmClient;
37
38
39//
40// Access static constants
41//
42const CSSM_ACL_HANDLE Access::ownerHandle;
43
44
45//
46// Create a completely open Access (anyone can do anything)
47// Note that this means anyone can *change* the ACL at will, too.
48// These ACL entries contain no descriptor names.
49//
50Access::Access() : mMutex(Mutex::recursive)
51{
52	SecPointer<ACL> owner = new ACL(*this);
53	owner->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL);
54	addOwner(owner);
55
56	SecPointer<ACL> any = new ACL(*this);
57	add(any);
58}
59
60
61//
62// Create a default Access object.
63// This construct an Access with "default form", whatever that happens to be
64// in this release.
65//
66Access::Access(const string &descriptor, const ACL::ApplicationList &trusted) : mMutex(Mutex::recursive)
67{
68	makeStandard(descriptor, trusted);
69}
70
71Access::Access(const string &descriptor) : mMutex(Mutex::recursive)
72{
73	ACL::ApplicationList trusted;
74	trusted.push_back(new TrustedApplication);
75	makeStandard(descriptor, trusted);
76}
77
78Access::Access(const string &descriptor, const ACL::ApplicationList &trusted,
79	const AclAuthorizationSet &limitedRights, const AclAuthorizationSet &freeRights) : mMutex(Mutex::recursive)
80{
81	makeStandard(descriptor, trusted, limitedRights, freeRights);
82}
83
84void Access::makeStandard(const string &descriptor, const ACL::ApplicationList &trusted,
85	const AclAuthorizationSet &limitedRights, const AclAuthorizationSet &freeRights)
86{
87	StLock<Mutex>_(mMutex);
88
89	// owner "entry"
90	SecPointer<ACL> owner = new ACL(*this, descriptor, ACL::defaultSelector);
91	owner->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL);
92	addOwner(owner);
93
94	// unlimited entry
95	SecPointer<ACL> unlimited = new ACL(*this, descriptor, ACL::defaultSelector);
96	if (freeRights.empty()) {
97		unlimited->authorizations().clear();
98		unlimited->authorizations().insert(CSSM_ACL_AUTHORIZATION_ENCRYPT);
99	} else
100		unlimited->authorizations() = freeRights;
101	unlimited->form(ACL::allowAllForm);
102	add(unlimited);
103
104	// limited entry
105	SecPointer<ACL> limited = new ACL(*this, descriptor, ACL::defaultSelector);
106	if (limitedRights.empty()) {
107		limited->authorizations().clear();
108		limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_DECRYPT);
109		limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_SIGN);
110		limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_MAC);
111		limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_DERIVE);
112		limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR);
113		limited->authorizations().insert(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED);
114	} else
115		limited->authorizations() = limitedRights;
116	limited->applications() = trusted;
117	add(limited);
118}
119
120
121//
122// Create an Access object whose initial value is taken
123// from a CSSM ACL bearing object.
124//
125Access::Access(AclBearer &source) : mMutex(Mutex::recursive)
126{
127	// retrieve and set
128	AutoAclOwnerPrototype owner;
129	source.getOwner(owner);
130	AutoAclEntryInfoList acls;
131	source.getAcl(acls);
132	compile(*owner, acls.count(), acls.entries());
133}
134
135
136//
137// Create an Access object from CSSM-layer access controls
138//
139Access::Access(const CSSM_ACL_OWNER_PROTOTYPE &owner,
140	uint32 aclCount, const CSSM_ACL_ENTRY_INFO *acls) : mMutex(Mutex::recursive)
141{
142	compile(owner, aclCount, acls);
143}
144
145
146Access::~Access()
147{
148}
149
150
151// Convert a SecPointer to a SecACLRef.
152static SecACLRef
153convert(const SecPointer<ACL> &acl)
154{
155	return *acl;
156}
157
158//
159// Return all ACL components in a newly-made CFArray.
160//
161CFArrayRef Access::copySecACLs() const
162{
163	return makeCFArray(convert, mAcls);
164}
165
166CFArrayRef Access::copySecACLs(CSSM_ACL_AUTHORIZATION_TAG action) const
167{
168	list<ACL *> choices;
169	for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); it++)
170		if (it->second->authorizes(action))
171			choices.push_back(it->second);
172	return choices.empty() ? NULL : makeCFArray(convert, choices);
173}
174
175
176//
177// Enter the complete access configuration into a AclBearer.
178// If update, skip any part marked unchanged. (If not update, skip
179// any part marked deleted.)
180//
181void Access::setAccess(AclBearer &target, bool update /* = false */)
182{
183	StLock<Mutex>_(mMutex);
184	AclFactory factory;
185	editAccess(target, update, factory.promptCred());
186}
187
188void Access::setAccess(AclBearer &target, Maker &maker)
189{
190	StLock<Mutex>_(mMutex);
191	if (maker.makerType() == Maker::kStandardMakerType)
192	{
193		// remove initial-setup ACL
194		target.deleteAcl(Maker::creationEntryTag, maker.cred());
195
196		// insert our own ACL entries
197		editAccess(target, false, maker.cred());
198	}
199}
200
201void Access::editAccess(AclBearer &target, bool update, const AccessCredentials *cred)
202{
203	StLock<Mutex>_(mMutex);
204	assert(mAcls[ownerHandle]);	// have owner
205
206	// apply all non-owner ACLs first
207	for (Map::iterator it = mAcls.begin(); it != mAcls.end(); it++)
208		if (!it->second->isOwner())
209			it->second->setAccess(target, update, cred);
210
211	// finally, apply owner
212	mAcls[ownerHandle]->setAccess(target, update, cred);
213}
214
215
216//
217// A convenience function to add one application to a standard ("simple") form
218// ACL entry. This will only work if
219//  -- there is exactly one ACL entry authorizing the right
220//  -- that entry is in simple form
221//
222void Access::addApplicationToRight(AclAuthorization right, TrustedApplication *app)
223{
224	StLock<Mutex>_(mMutex);
225	vector<ACL *> acls;
226	findAclsForRight(right, acls);
227	if (acls.size() != 1)
228		MacOSError::throwMe(errSecACLNotSimple);	// let's not guess here...
229	(*acls.begin())->addApplication(app);
230}
231
232
233//
234// Yield new (copied) CSSM level owner and acls values, presumably
235// for use at CSSM layer operations.
236// Caller is responsible for releasing the beasties when done.
237//
238void Access::copyOwnerAndAcl(CSSM_ACL_OWNER_PROTOTYPE * &ownerResult,
239	uint32 &aclCount, CSSM_ACL_ENTRY_INFO * &aclsResult)
240{
241	StLock<Mutex>_(mMutex);
242	Allocator& alloc = Allocator::standard();
243	unsigned long count = mAcls.size() - 1;	// one will be owner, others are acls
244	AclOwnerPrototype owner;
245	CssmAutoPtr<AclEntryInfo> acls = new(alloc) AclEntryInfo[count];
246	AclEntryInfo *aclp = acls;	// -> next unfilled acl element
247	for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); it++) {
248		SecPointer<ACL> acl = it->second;
249		if (acl->isOwner()) {
250			acl->copyAclOwner(owner, alloc);
251		} else {
252			aclp->handle() = acl->entryHandle();
253			acl->copyAclEntry(*aclp, alloc);
254			++aclp;
255		}
256	}
257	assert((aclp - acls) == count);	// all ACL elements filled
258
259	// commit output
260	ownerResult = new(alloc) AclOwnerPrototype(owner);
261	aclCount = (uint32)count;
262	aclsResult = acls.release();
263}
264
265
266//
267// Retrieve the description from a randomly chosen ACL within this Access.
268// In the conventional case where all ACLs have the same descriptor, this
269// is deterministic. But you have been warned.
270//
271string Access::promptDescription() const
272{
273	for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); it++) {
274		ACL *acl = it->second;
275		switch (acl->form()) {
276		case ACL::allowAllForm:
277		case ACL::appListForm:
278			{
279				string descr = acl->promptDescription();
280				if (!descr.empty())
281					return descr;
282			}
283		default:
284			break;
285		}
286	}
287	// couldn't find suitable ACL (no description anywhere)
288	CssmError::throwMe(errSecACLNotSimple);
289}
290
291
292//
293// Add a new ACL to the resident set. The ACL must have been
294// newly made for this Access.
295//
296void Access::add(ACL *newAcl)
297{
298	StLock<Mutex>_(mMutex);
299	if (&newAcl->access != this)
300		MacOSError::throwMe(errSecParam);
301	assert(!mAcls[newAcl->entryHandle()]);
302	mAcls[newAcl->entryHandle()] = newAcl;
303}
304
305
306//
307// Add the owner ACL to the resident set. The ACL must have been
308// newly made for this Access.
309// Since an Access must have exactly one owner ACL, this call
310// should only be made (exactly once) for a newly created Access.
311//
312void Access::addOwner(ACL *newAcl)
313{
314	StLock<Mutex>_(mMutex);
315	newAcl->makeOwner();
316	assert(mAcls.find(ownerHandle) == mAcls.end());	// no owner yet
317	add(newAcl);
318}
319
320
321//
322// Compile a set of ACL entries and owner into internal form.
323//
324void Access::compile(const CSSM_ACL_OWNER_PROTOTYPE &owner,
325	uint32 aclCount, const CSSM_ACL_ENTRY_INFO *acls)
326{
327	StLock<Mutex>_(mMutex);
328	// add owner acl
329	mAcls[ownerHandle] = new ACL(*this, AclOwnerPrototype::overlay(owner));
330
331	// add acl entries
332	const AclEntryInfo *acl = AclEntryInfo::overlay(acls);
333	for (uint32 n = 0; n < aclCount; n++) {
334		secdebug("SecAccess", "%p compiling entry %ld", this, acl[n].handle());
335		mAcls[acl[n].handle()] = new ACL(*this, acl[n]);
336	}
337	secdebug("SecAccess", "%p %ld entries compiled", this, mAcls.size());
338}
339
340
341//
342// Creation helper objects
343//
344const char Access::Maker::creationEntryTag[] = "___setup___";
345
346Access::Maker::Maker(Allocator &alloc, MakerType makerType)
347	: allocator(alloc), mKey(alloc), mCreds(allocator), mMakerType(makerType)
348{
349	if (makerType == kStandardMakerType)
350	{
351		// generate random key
352		mKey.malloc(keySize);
353		UniformRandomBlobs<DevRandomGenerator>().random(mKey.get());
354
355		// create entry info for resource creation
356		mInput = AclEntryPrototype(TypedList(allocator, CSSM_ACL_SUBJECT_TYPE_PASSWORD,
357			new(allocator) ListElement(mKey.get())));
358		mInput.proto().tag(creationEntryTag);
359
360		// create credential sample for access
361		mCreds += TypedList(allocator, CSSM_SAMPLE_TYPE_PASSWORD, new(allocator) ListElement(mKey.get()));
362	}
363	else
364	{
365		// just make it an CSSM_ACL_SUBJECT_TYPE_ANY list
366		mInput = AclEntryPrototype(TypedList(allocator, CSSM_ACL_SUBJECT_TYPE_ANY));
367	}
368}
369
370void Access::Maker::initialOwner(ResourceControlContext &ctx, const AccessCredentials *creds)
371{
372	//@@@ make up ctx.entry-info
373	ctx.input() = mInput;
374	ctx.credentials(creds);
375}
376
377const AccessCredentials *Access::Maker::cred()
378{
379	return &mCreds;
380}
381