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/SecRandom.h>
31 #include <security_cdsa_client/aclclient.h>
33 #include <Security/SecBase.h>
34 using namespace KeychainCore
;
35 using namespace CssmClient
;
39 // Access static constants
41 const CSSM_ACL_HANDLE
Access::ownerHandle
;
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.
49 Access::Access() : mMutex(Mutex::recursive
)
51 SecPointer
<ACL
> owner
= new ACL();
52 owner
->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL
);
55 SecPointer
<ACL
> any
= new ACL();
61 // Create a default Access object.
62 // This construct an Access with "default form", whatever that happens to be
65 Access::Access(const string
&descriptor
, const ACL::ApplicationList
&trusted
) : mMutex(Mutex::recursive
)
67 makeStandard(descriptor
, trusted
);
70 Access::Access(const string
&descriptor
) : mMutex(Mutex::recursive
)
72 ACL::ApplicationList trusted
;
73 trusted
.push_back(new TrustedApplication
);
74 makeStandard(descriptor
, trusted
);
77 Access::Access(const string
&descriptor
, const ACL::ApplicationList
&trusted
,
78 const AclAuthorizationSet
&limitedRights
, const AclAuthorizationSet
&freeRights
) : mMutex(Mutex::recursive
)
80 makeStandard(descriptor
, trusted
, limitedRights
, freeRights
);
83 void Access::makeStandard(const string
&descriptor
, const ACL::ApplicationList
&trusted
,
84 const AclAuthorizationSet
&limitedRights
, const AclAuthorizationSet
&freeRights
)
86 StLock
<Mutex
>_(mMutex
);
89 SecPointer
<ACL
> owner
= new ACL(descriptor
, ACL::defaultSelector
);
90 owner
->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL
);
94 SecPointer
<ACL
> unlimited
= new ACL(descriptor
, ACL::defaultSelector
);
95 if (freeRights
.empty()) {
96 unlimited
->authorizations().clear();
97 unlimited
->authorizations().insert(CSSM_ACL_AUTHORIZATION_ENCRYPT
);
99 unlimited
->authorizations() = freeRights
;
100 unlimited
->form(ACL::allowAllForm
);
104 SecPointer
<ACL
> limited
= new ACL(descriptor
, ACL::defaultSelector
);
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
);
114 limited
->authorizations() = limitedRights
;
115 limited
->applications() = trusted
;
121 // Create an Access object whose initial value is taken
122 // from a CSSM ACL bearing object.
124 Access::Access(AclBearer
&source
) : mMutex(Mutex::recursive
)
127 AutoAclOwnerPrototype owner
;
128 source
.getOwner(owner
);
129 AutoAclEntryInfoList acls
;
131 compile(*owner
, acls
.count(), acls
.entries());
136 // Create an Access object from CSSM-layer access controls
138 Access::Access(const CSSM_ACL_OWNER_PROTOTYPE
&owner
,
139 uint32 aclCount
, const CSSM_ACL_ENTRY_INFO
*acls
) : mMutex(Mutex::recursive
)
141 compile(owner
, aclCount
, acls
);
150 // Convert a SecPointer to a SecACLRef.
152 convert(const SecPointer
<ACL
> &acl
)
158 // Return all ACL components in a newly-made CFArray.
160 CFArrayRef
Access::copySecACLs() const
162 return makeCFArrayFrom(convert
, mAcls
);
165 CFArrayRef
Access::copySecACLs(CSSM_ACL_AUTHORIZATION_TAG action
) const
168 for (Map::const_iterator it
= mAcls
.begin(); it
!= mAcls
.end(); it
++)
169 if (it
->second
->authorizes(action
))
170 choices
.push_back(it
->second
);
171 return choices
.empty() ? NULL
: makeCFArrayFrom(convert
, choices
);
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.)
180 void Access::setAccess(AclBearer
&target
, bool update
/* = false */)
182 StLock
<Mutex
>_(mMutex
);
184 editAccess(target
, update
, factory
.promptCred());
187 void Access::setAccess(AclBearer
&target
, Maker
&maker
)
189 StLock
<Mutex
>_(mMutex
);
190 if (maker
.makerType() == Maker::kStandardMakerType
)
192 // remove initial-setup ACL
193 target
.deleteAcl(Maker::creationEntryTag
, maker
.cred());
195 // insert our own ACL entries
196 editAccess(target
, false, maker
.cred());
200 void Access::editAccess(AclBearer
&target
, bool update
, const AccessCredentials
*cred
)
202 StLock
<Mutex
>_(mMutex
);
203 assert(mAcls
[ownerHandle
]); // have owner
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
);
210 // finally, apply owner
211 mAcls
[ownerHandle
]->setAccess(target
, update
, cred
);
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
221 void Access::addApplicationToRight(AclAuthorization right
, TrustedApplication
*app
)
223 StLock
<Mutex
>_(mMutex
);
225 findAclsForRight(right
, acls
);
226 if (acls
.size() != 1)
227 MacOSError::throwMe(errSecACLNotSimple
); // let's not guess here...
228 (*acls
.begin())->addApplication(app
);
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.
237 void Access::copyOwnerAndAcl(CSSM_ACL_OWNER_PROTOTYPE
* &ownerResult
,
238 uint32
&aclCount
, CSSM_ACL_ENTRY_INFO
* &aclsResult
)
240 StLock
<Mutex
>_(mMutex
);
241 Allocator
& alloc
= Allocator::standard();
242 unsigned long count
= mAcls
.size() - 1; // one will be owner, others are acls
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
);
251 aclp
->handle() = acl
->entryHandle();
252 acl
->copyAclEntry(*aclp
, alloc
);
256 assert((aclp
- acls
) == count
); // all ACL elements filled
259 ownerResult
= new(alloc
) AclOwnerPrototype(owner
);
260 aclCount
= (uint32
)count
;
261 aclsResult
= acls
.release();
266 // Remove all ACLs that confer this right.
268 void 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
);
272 secinfo("SecAccess", "%p removed an acl, %lu left", this, mAcls
.size());
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.
284 string
Access::promptDescription() const
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
:
292 string descr
= acl
->promptDescription();
300 // couldn't find suitable ACL (no description anywhere)
301 CssmError::throwMe(errSecACLNotSimple
);
306 // Add a new ACL to the resident set. The ACL must have been
307 // newly made for this Access.
309 void Access::add(ACL
*newAcl
)
311 StLock
<Mutex
>_(mMutex
);
312 assert(!mAcls
[newAcl
->entryHandle()]);
313 mAcls
[newAcl
->entryHandle()] = newAcl
;
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.
323 void Access::addOwner(ACL
*newAcl
)
325 StLock
<Mutex
>_(mMutex
);
327 assert(mAcls
.find(ownerHandle
) == mAcls
.end()); // no owner yet
333 // Compile a set of ACL entries and owner into internal form.
335 void Access::compile(const CSSM_ACL_OWNER_PROTOTYPE
&owner
,
336 uint32 aclCount
, const CSSM_ACL_ENTRY_INFO
*acls
)
338 StLock
<Mutex
>_(mMutex
);
340 mAcls
[ownerHandle
] = new ACL(AclOwnerPrototype::overlay(owner
));
341 secinfo("SecAccess", "form of owner is: %d", mAcls
[ownerHandle
]->form());
344 const AclEntryInfo
*acl
= AclEntryInfo::overlay(acls
);
345 for (uint32 n
= 0; n
< aclCount
; n
++) {
346 secinfo("SecAccess", "%p compiling entry %ld", this, acl
[n
].handle());
347 mAcls
[acl
[n
].handle()] = new ACL(acl
[n
]);
348 secinfo("SecAccess", "form is: %d", mAcls
[acl
[n
].handle()]->form());
350 secinfo("SecAccess", "%p %ld entries compiled", this, mAcls
.size());
355 // Creation helper objects
357 const char Access::Maker::creationEntryTag
[] = "___setup___";
359 Access::Maker::Maker(Allocator
&alloc
, MakerType makerType
)
360 : allocator(alloc
), mKey(alloc
), mCreds(allocator
), mMakerType(makerType
)
362 if (makerType
== kStandardMakerType
)
364 // generate random key
365 mKey
.malloc(keySize
);
366 CssmData data
= mKey
.get();
367 MacOSError::check(SecRandomCopyBytes(kSecRandomDefault
, data
.length(), data
.data()));
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()