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