]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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 | // | |
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> | |
427c49bc | 34 | #include <SecBase.h> |
b1ab9ed8 A |
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(*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 | // | |
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(*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 | // | |
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 makeCFArray(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 : 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 | // | |
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(); | |
427c49bc | 243 | unsigned long count = mAcls.size() - 1; // one will be owner, others are acls |
b1ab9ed8 A |
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); | |
427c49bc | 261 | aclCount = (uint32)count; |
b1ab9ed8 A |
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 | // | |
271 | string 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 | // | |
296 | void Access::add(ACL *newAcl) | |
297 | { | |
298 | StLock<Mutex>_(mMutex); | |
299 | if (&newAcl->access != this) | |
427c49bc | 300 | MacOSError::throwMe(errSecParam); |
b1ab9ed8 A |
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 | // | |
312 | void 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 | // | |
324 | void 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 | // | |
344 | const char Access::Maker::creationEntryTag[] = "___setup___"; | |
345 | ||
346 | Access::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 | ||
370 | void 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 | ||
377 | const AccessCredentials *Access::Maker::cred() | |
378 | { | |
379 | return &mCreds; | |
380 | } |