2 * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved.
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
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.
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>
29 using namespace KeychainCore
;
30 using namespace CssmClient
;
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.
40 SecPointer
<ACL
> owner
= new ACL(*this);
41 owner
->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL
);
44 SecPointer
<ACL
> any
= new ACL(*this);
50 // Create a default Access object.
51 // This construct an Access with "default form", whatever that happens to be
54 Access::Access(const string
&descriptor
, const ACL::ApplicationList
&trusted
)
56 makeStandard(descriptor
, trusted
);
59 Access::Access(const string
&descriptor
)
61 ACL::ApplicationList trusted
;
62 trusted
.push_back(new TrustedApplication
);
63 makeStandard(descriptor
, trusted
);
66 Access::Access(const string
&descriptor
, const ACL::ApplicationList
&trusted
,
67 const AclAuthorizationSet
&limitedRights
, const AclAuthorizationSet
&freeRights
)
69 makeStandard(descriptor
, trusted
, limitedRights
, freeRights
);
72 void Access::makeStandard(const string
&descriptor
, const ACL::ApplicationList
&trusted
,
73 const AclAuthorizationSet
&limitedRights
, const AclAuthorizationSet
&freeRights
)
76 SecPointer
<ACL
> owner
= new ACL(*this, descriptor
, ACL::defaultSelector
);
77 owner
->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL
);
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
);
86 unlimited
->authorizations() = freeRights
;
87 unlimited
->form(ACL::allowAllForm
);
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
);
101 limited
->authorizations() = limitedRights
;
102 limited
->applications() = trusted
;
108 // Create an Access object whose initial value is taken
109 // from a CSSM ACL bearing object.
111 Access::Access(AclBearer
&source
)
114 AutoAclOwnerPrototype owner
;
115 source
.getOwner(owner
);
116 AutoAclEntryInfoList acls
;
118 compile(*owner
, acls
.count(), acls
.entries());
123 // Create an Access object from CSSM-layer access controls
125 Access::Access(const CSSM_ACL_OWNER_PROTOTYPE
&owner
,
126 uint32 aclCount
, const CSSM_ACL_ENTRY_INFO
*acls
)
128 compile(owner
, aclCount
, acls
);
132 Access::~Access() throw()
137 // Convert a SecPointer to a SecACLRef.
139 convert(const SecPointer
<ACL
> &acl
)
145 // Return all ACL components in a newly-made CFArray.
147 CFArrayRef
Access::copySecACLs() const
149 return makeCFArray(convert
, mAcls
);
152 CFArrayRef
Access::copySecACLs(CSSM_ACL_AUTHORIZATION_TAG action
) const
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
);
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.)
167 void Access::setAccess(AclBearer
&target
, bool update
/* = false */)
170 editAccess(target
, update
, factory
.promptCred());
173 void Access::setAccess(AclBearer
&target
, Maker
&maker
)
175 // remove initial-setup ACL
176 target
.deleteAcl(Maker::creationEntryTag
, maker
.cred());
178 // insert our own ACL entries
179 editAccess(target
, false, maker
.cred());
182 void Access::editAccess(AclBearer
&target
, bool update
, const AccessCredentials
*cred
)
184 assert(mAcls
[ownerHandle
]); // have owner
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
);
191 // finally, apply owner
192 mAcls
[ownerHandle
]->setAccess(target
, update
, cred
);
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
202 void Access::addApplicationToRight(AclAuthorization right
, TrustedApplication
*app
)
205 findAclsForRight(right
, acls
);
206 if (acls
.size() != 1)
207 MacOSError::throwMe(errSecACLNotSimple
); // let's not guess here...
208 (*acls
.begin())->addApplication(app
);
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.
217 void Access::copyOwnerAndAcl(CSSM_ACL_OWNER_PROTOTYPE
* &ownerResult
,
218 uint32
&aclCount
, CSSM_ACL_ENTRY_INFO
* &aclsResult
)
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
);
230 aclp
->handle() = acl
->entryHandle();
231 acl
->copyAclEntry(*aclp
, alloc
);
235 assert((aclp
- acls
) == count
); // all ACL elements filled
238 ownerResult
= new(alloc
) AclOwnerPrototype(owner
);
240 aclsResult
= acls
.release();
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.
249 string
Access::promptDescription() const
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
:
257 string descr
= acl
->promptDescription();
265 // couldn't find suitable ACL (no description anywhere)
266 CssmError::throwMe(errSecACLNotSimple
);
271 // Add a new ACL to the resident set. The ACL must have been
272 // newly made for this Access.
274 void Access::add(ACL
*newAcl
)
276 if (&newAcl
->access
!= this)
277 MacOSError::throwMe(paramErr
);
278 assert(!mAcls
[newAcl
->entryHandle()]);
279 mAcls
[newAcl
->entryHandle()] = newAcl
;
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.
289 void Access::addOwner(ACL
*newAcl
)
292 assert(mAcls
.find(ownerHandle
) == mAcls
.end()); // no owner yet
298 // Compile a set of ACL entries and owner into internal form.
300 void Access::compile(const CSSM_ACL_OWNER_PROTOTYPE
&owner
,
301 uint32 aclCount
, const CSSM_ACL_ENTRY_INFO
*acls
)
304 mAcls
[ownerHandle
] = new ACL(*this, AclOwnerPrototype::overlay(owner
));
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
]);
312 secdebug("SecAccess", "%p %ld entries compiled", this, mAcls
.size());
317 // Creation helper objects
319 const char Access::Maker::creationEntryTag
[] = "___setup___";
321 Access::Maker::Maker(CssmAllocator
&alloc
)
322 : allocator(alloc
), mKey(alloc
), mCreds(allocator
)
324 // generate random key
325 mKey
.malloc(keySize
);
326 UniformRandomBlobs
<DevRandomGenerator
>().random(mKey
.get());
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
);
333 // create credential sample for access
334 mCreds
+= TypedList(allocator
, CSSM_SAMPLE_TYPE_PASSWORD
, new(allocator
) ListElement(mKey
.get()));
337 void Access::Maker::initialOwner(ResourceControlContext
&ctx
, const AccessCredentials
*creds
)
339 //@@@ make up ctx.entry-info
340 ctx
.input() = mInput
;
341 ctx
.credentials(creds
);
344 const AccessCredentials
*Access::Maker::cred()