2 * Copyright (c) 2002-2004,2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
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>
35 using namespace KeychainCore
;
36 using namespace CssmClient
;
40 // Access static constants
42 const CSSM_ACL_HANDLE
Access::ownerHandle
;
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.
50 Access::Access() : mMutex(Mutex::recursive
)
52 SecPointer
<ACL
> owner
= new ACL();
53 owner
->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL
);
56 SecPointer
<ACL
> any
= new ACL();
62 // Create a default Access object.
63 // This construct an Access with "default form", whatever that happens to be
66 Access::Access(const string
&descriptor
, const ACL::ApplicationList
&trusted
) : mMutex(Mutex::recursive
)
68 makeStandard(descriptor
, trusted
);
71 Access::Access(const string
&descriptor
) : mMutex(Mutex::recursive
)
73 ACL::ApplicationList trusted
;
74 trusted
.push_back(new TrustedApplication
);
75 makeStandard(descriptor
, trusted
);
78 Access::Access(const string
&descriptor
, const ACL::ApplicationList
&trusted
,
79 const AclAuthorizationSet
&limitedRights
, const AclAuthorizationSet
&freeRights
) : mMutex(Mutex::recursive
)
81 makeStandard(descriptor
, trusted
, limitedRights
, freeRights
);
84 void Access::makeStandard(const string
&descriptor
, const ACL::ApplicationList
&trusted
,
85 const AclAuthorizationSet
&limitedRights
, const AclAuthorizationSet
&freeRights
)
87 StLock
<Mutex
>_(mMutex
);
90 SecPointer
<ACL
> owner
= new ACL(descriptor
, ACL::defaultSelector
);
91 owner
->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL
);
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
);
100 unlimited
->authorizations() = freeRights
;
101 unlimited
->form(ACL::allowAllForm
);
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
);
115 limited
->authorizations() = limitedRights
;
116 limited
->applications() = trusted
;
122 // Create an Access object whose initial value is taken
123 // from a CSSM ACL bearing object.
125 Access::Access(AclBearer
&source
) : mMutex(Mutex::recursive
)
128 AutoAclOwnerPrototype owner
;
129 source
.getOwner(owner
);
130 AutoAclEntryInfoList acls
;
132 compile(*owner
, acls
.count(), acls
.entries());
137 // Create an Access object from CSSM-layer access controls
139 Access::Access(const CSSM_ACL_OWNER_PROTOTYPE
&owner
,
140 uint32 aclCount
, const CSSM_ACL_ENTRY_INFO
*acls
) : mMutex(Mutex::recursive
)
142 compile(owner
, aclCount
, acls
);
151 // Convert a SecPointer to a SecACLRef.
153 convert(const SecPointer
<ACL
> &acl
)
159 // Return all ACL components in a newly-made CFArray.
161 CFArrayRef
Access::copySecACLs() const
163 return makeCFArrayFrom(convert
, mAcls
);
166 CFArrayRef
Access::copySecACLs(CSSM_ACL_AUTHORIZATION_TAG action
) const
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
);
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.)
181 void Access::setAccess(AclBearer
&target
, bool update
/* = false */)
183 StLock
<Mutex
>_(mMutex
);
185 editAccess(target
, update
, factory
.promptCred());
188 void Access::setAccess(AclBearer
&target
, Maker
&maker
)
190 StLock
<Mutex
>_(mMutex
);
191 if (maker
.makerType() == Maker::kStandardMakerType
)
193 // remove initial-setup ACL
194 target
.deleteAcl(Maker::creationEntryTag
, maker
.cred());
196 // insert our own ACL entries
197 editAccess(target
, false, maker
.cred());
201 void Access::editAccess(AclBearer
&target
, bool update
, const AccessCredentials
*cred
)
203 StLock
<Mutex
>_(mMutex
);
204 assert(mAcls
[ownerHandle
]); // have owner
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
);
211 // finally, apply owner
212 mAcls
[ownerHandle
]->setAccess(target
, update
, cred
);
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
222 void Access::addApplicationToRight(AclAuthorization right
, TrustedApplication
*app
)
224 StLock
<Mutex
>_(mMutex
);
226 findAclsForRight(right
, acls
);
227 if (acls
.size() != 1)
228 MacOSError::throwMe(errSecACLNotSimple
); // let's not guess here...
229 (*acls
.begin())->addApplication(app
);
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.
238 void Access::copyOwnerAndAcl(CSSM_ACL_OWNER_PROTOTYPE
* &ownerResult
,
239 uint32
&aclCount
, CSSM_ACL_ENTRY_INFO
* &aclsResult
)
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
);
252 aclp
->handle() = acl
->entryHandle();
253 acl
->copyAclEntry(*aclp
, alloc
);
257 assert((aclp
- acls
) == count
); // all ACL elements filled
260 ownerResult
= new(alloc
) AclOwnerPrototype(owner
);
261 aclCount
= (uint32
)count
;
262 aclsResult
= acls
.release();
267 // Remove all ACLs that confer this right.
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());
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.
285 string
Access::promptDescription() const
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
:
293 string descr
= acl
->promptDescription();
301 // couldn't find suitable ACL (no description anywhere)
302 CssmError::throwMe(errSecACLNotSimple
);
307 // Add a new ACL to the resident set. The ACL must have been
308 // newly made for this Access.
310 void Access::add(ACL
*newAcl
)
312 StLock
<Mutex
>_(mMutex
);
313 assert(!mAcls
[newAcl
->entryHandle()]);
314 mAcls
[newAcl
->entryHandle()] = newAcl
;
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.
324 void Access::addOwner(ACL
*newAcl
)
326 StLock
<Mutex
>_(mMutex
);
328 assert(mAcls
.find(ownerHandle
) == mAcls
.end()); // no owner yet
334 // Compile a set of ACL entries and owner into internal form.
336 void Access::compile(const CSSM_ACL_OWNER_PROTOTYPE
&owner
,
337 uint32 aclCount
, const CSSM_ACL_ENTRY_INFO
*acls
)
339 StLock
<Mutex
>_(mMutex
);
341 mAcls
[ownerHandle
] = new ACL(AclOwnerPrototype::overlay(owner
));
342 secinfo("SecAccess", "form of owner is: %d", mAcls
[ownerHandle
]->form());
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());
351 secinfo("SecAccess", "%p %ld entries compiled", this, mAcls
.size());
356 // Creation helper objects
358 const char Access::Maker::creationEntryTag
[] = "___setup___";
360 Access::Maker::Maker(Allocator
&alloc
, MakerType makerType
)
361 : allocator(alloc
), mKey(alloc
), mCreds(allocator
), mMakerType(makerType
)
363 if (makerType
== kStandardMakerType
)
365 // generate random key
366 mKey
.malloc(keySize
);
367 UniformRandomBlobs
<DevRandomGenerator
>().random(mKey
.get());
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
));
376 // create credential sample for access
377 mCreds
+= TypedList(allocator
, CSSM_SAMPLE_TYPE_PASSWORD
, new(allocator
) ListElement(mKey
.get()));
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);
387 void Access::Maker::initialOwner(ResourceControlContext
&ctx
, const AccessCredentials
*creds
)
389 //@@@ make up ctx.entry-info
390 ctx
.input() = mInput
;
391 ctx
.credentials(creds
);
394 const AccessCredentials
*Access::Maker::cred()