]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/Access.cpp
Security-58286.251.4.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / Access.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 //
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>
35 using namespace KeychainCore;
36 using namespace CssmClient;
37
38
39 //
40 // Access static constants
41 //
42 const 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 //
50 Access::Access() : mMutex(Mutex::recursive)
51 {
52 SecPointer<ACL> owner = new ACL();
53 owner->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL);
54 addOwner(owner);
55
56 SecPointer<ACL> any = new ACL();
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 //
66 Access::Access(const string &descriptor, const ACL::ApplicationList &trusted) : mMutex(Mutex::recursive)
67 {
68 makeStandard(descriptor, trusted);
69 }
70
71 Access::Access(const string &descriptor) : mMutex(Mutex::recursive)
72 {
73 ACL::ApplicationList trusted;
74 trusted.push_back(new TrustedApplication);
75 makeStandard(descriptor, trusted);
76 }
77
78 Access::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
84 void 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(descriptor, ACL::defaultSelector);
91 owner->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL);
92 addOwner(owner);
93
94 // unlimited entry
95 SecPointer<ACL> unlimited = new ACL(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(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 //
125 Access::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 //
139 Access::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
146 Access::~Access()
147 {
148 }
149
150
151 // Convert a SecPointer to a SecACLRef.
152 static SecACLRef
153 convert(const SecPointer<ACL> &acl)
154 {
155 return *acl;
156 }
157
158 //
159 // Return all ACL components in a newly-made CFArray.
160 //
161 CFArrayRef Access::copySecACLs() const
162 {
163 return makeCFArrayFrom(convert, mAcls);
164 }
165
166 CFArrayRef 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 : makeCFArrayFrom(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 //
181 void Access::setAccess(AclBearer &target, bool update /* = false */)
182 {
183 StLock<Mutex>_(mMutex);
184 AclFactory factory;
185 editAccess(target, update, factory.promptCred());
186 }
187
188 void 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
201 void 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 //
222 void 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 //
238 void 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 // Remove all ACLs that confer this right.
268 //
269 void Access::removeAclsForRight(AclAuthorization right) {
270 for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); ) {
271 if (it->second->authorizesSpecifically(right)) {
272 it = mAcls.erase(it);
273 secinfo("SecAccess", "%p removed an acl, %lu left", this, mAcls.size());
274 } else {
275 it++;
276 }
277 }
278 }
279
280 //
281 // Retrieve the description from a randomly chosen ACL within this Access.
282 // In the conventional case where all ACLs have the same descriptor, this
283 // is deterministic. But you have been warned.
284 //
285 string Access::promptDescription() const
286 {
287 for (Map::const_iterator it = mAcls.begin(); it != mAcls.end(); it++) {
288 ACL *acl = it->second;
289 switch (acl->form()) {
290 case ACL::allowAllForm:
291 case ACL::appListForm:
292 {
293 string descr = acl->promptDescription();
294 if (!descr.empty())
295 return descr;
296 }
297 default:
298 break;
299 }
300 }
301 // couldn't find suitable ACL (no description anywhere)
302 CssmError::throwMe(errSecACLNotSimple);
303 }
304
305
306 //
307 // Add a new ACL to the resident set. The ACL must have been
308 // newly made for this Access.
309 //
310 void Access::add(ACL *newAcl)
311 {
312 StLock<Mutex>_(mMutex);
313 assert(!mAcls[newAcl->entryHandle()]);
314 mAcls[newAcl->entryHandle()] = newAcl;
315 }
316
317
318 //
319 // Add the owner ACL to the resident set. The ACL must have been
320 // newly made for this Access.
321 // Since an Access must have exactly one owner ACL, this call
322 // should only be made (exactly once) for a newly created Access.
323 //
324 void Access::addOwner(ACL *newAcl)
325 {
326 StLock<Mutex>_(mMutex);
327 newAcl->makeOwner();
328 assert(mAcls.find(ownerHandle) == mAcls.end()); // no owner yet
329 add(newAcl);
330 }
331
332
333 //
334 // Compile a set of ACL entries and owner into internal form.
335 //
336 void Access::compile(const CSSM_ACL_OWNER_PROTOTYPE &owner,
337 uint32 aclCount, const CSSM_ACL_ENTRY_INFO *acls)
338 {
339 StLock<Mutex>_(mMutex);
340 // add owner acl
341 mAcls[ownerHandle] = new ACL(AclOwnerPrototype::overlay(owner));
342 secinfo("SecAccess", "form of owner is: %d", mAcls[ownerHandle]->form());
343
344 // add acl entries
345 const AclEntryInfo *acl = AclEntryInfo::overlay(acls);
346 for (uint32 n = 0; n < aclCount; n++) {
347 secinfo("SecAccess", "%p compiling entry %ld", this, acl[n].handle());
348 mAcls[acl[n].handle()] = new ACL(acl[n]);
349 secinfo("SecAccess", "form is: %d", mAcls[acl[n].handle()]->form());
350 }
351 secinfo("SecAccess", "%p %ld entries compiled", this, mAcls.size());
352 }
353
354
355 //
356 // Creation helper objects
357 //
358 const char Access::Maker::creationEntryTag[] = "___setup___";
359
360 Access::Maker::Maker(Allocator &alloc, MakerType makerType)
361 : allocator(alloc), mKey(alloc), mCreds(allocator), mMakerType(makerType)
362 {
363 if (makerType == kStandardMakerType)
364 {
365 // generate random key
366 mKey.malloc(keySize);
367 UniformRandomBlobs<DevRandomGenerator>().random(mKey.get());
368
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);
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));
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));
383 secinfo("SecAccess", "made a CSSM_ACL_SUBJECT_TYPE_ANY ACL entry for %p", this);
384 }
385 }
386
387 void 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
394 const AccessCredentials *Access::Maker::cred()
395 {
396 return &mCreds;
397 }