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