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>
28 using namespace KeychainCore
;
32 // Create a completely open Access (anyone can do anything)
33 // Note that this means anyone can *change* the ACL at will, too.
34 // These ACL entries contain no descriptor names.
38 RefPointer
<ACL
> owner
= new ACL(*this);
39 owner
->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL
);
42 RefPointer
<ACL
> any
= new ACL(*this);
48 // Create a default Access object.
49 // This construct an Access with "default form", whatever that happens to be
52 Access::Access(const string
&descriptor
, const ACL::ApplicationList
&trusted
)
54 makeStandard(descriptor
, trusted
);
57 Access::Access(const string
&descriptor
)
59 ACL::ApplicationList trusted
;
60 trusted
.push_back(new TrustedApplication
);
61 makeStandard(descriptor
, trusted
);
64 Access::Access(const string
&descriptor
, const ACL::ApplicationList
&trusted
,
65 const AclAuthorizationSet
&limitedRights
, const AclAuthorizationSet
&freeRights
)
67 makeStandard(descriptor
, trusted
, limitedRights
, freeRights
);
70 void Access::makeStandard(const string
&descriptor
, const ACL::ApplicationList
&trusted
,
71 const AclAuthorizationSet
&limitedRights
, const AclAuthorizationSet
&freeRights
)
74 RefPointer
<ACL
> owner
= new ACL(*this, descriptor
, ACL::defaultSelector
);
75 owner
->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL
);
79 RefPointer
<ACL
> unlimited
= new ACL(*this, descriptor
, ACL::defaultSelector
);
80 if (freeRights
.empty()) {
81 unlimited
->authorizations().clear();
82 unlimited
->authorizations().insert(CSSM_ACL_AUTHORIZATION_ENCRYPT
);
84 unlimited
->authorizations() = freeRights
;
85 unlimited
->form(ACL::allowAllForm
);
89 RefPointer
<ACL
> limited
= new ACL(*this, descriptor
, ACL::defaultSelector
);
90 if (limitedRights
.empty()) {
91 limited
->authorizations().clear();
92 limited
->authorizations().insert(CSSM_ACL_AUTHORIZATION_DECRYPT
);
93 limited
->authorizations().insert(CSSM_ACL_AUTHORIZATION_SIGN
);
94 limited
->authorizations().insert(CSSM_ACL_AUTHORIZATION_MAC
);
95 limited
->authorizations().insert(CSSM_ACL_AUTHORIZATION_DERIVE
);
96 limited
->authorizations().insert(CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR
);
97 limited
->authorizations().insert(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
);
99 limited
->authorizations() = limitedRights
;
100 limited
->applications() = trusted
;
106 // Create an Access object whose initial value is taken
107 // from a CSSM ACL bearing object.
109 Access::Access(AclBearer
&source
)
112 AutoAclOwnerPrototype owner
;
113 source
.getOwner(owner
);
114 AutoAclEntryInfoList acls
;
116 compile(*owner
, acls
.count(), acls
.entries());
121 // Create an Access object from CSSM-layer access controls
123 Access::Access(const CSSM_ACL_OWNER_PROTOTYPE
&owner
,
124 uint32 aclCount
, const CSSM_ACL_ENTRY_INFO
*acls
)
126 compile(owner
, aclCount
, acls
);
136 // Return all ACL components in a newly-made CFArray.
138 CFArrayRef
Access::copySecACLs() const
140 return makeCFArray(gTypes().acl
, mAcls
);
143 CFArrayRef
Access::copySecACLs(CSSM_ACL_AUTHORIZATION_TAG action
) const
146 for (Map::const_iterator it
= mAcls
.begin(); it
!= mAcls
.end(); it
++)
147 if (it
->second
->authorizes(action
))
148 choices
.push_back(it
->second
);
149 return choices
.empty() ? NULL
: makeCFArray(gTypes().acl
, choices
);
154 // Enter the complete access configuration into a AclBearer.
155 // If update, skip any part marked unchanged. (If not update, skip
156 // any part marked deleted.)
158 void Access::setAccess(AclBearer
&target
, bool update
/* = false */)
161 editAccess(target
, update
, factory
.promptCred());
164 void Access::setAccess(AclBearer
&target
, Maker
&maker
)
166 // remove initial-setup ACL
167 target
.deleteAcl(Maker::creationEntryTag
, maker
.cred());
169 // insert our own ACL entries
170 editAccess(target
, false, maker
.cred());
173 void Access::editAccess(AclBearer
&target
, bool update
, const AccessCredentials
*cred
)
175 assert(mAcls
[ownerHandle
]); // have owner
177 // apply all non-owner ACLs first
178 for (Map::iterator it
= mAcls
.begin(); it
!= mAcls
.end(); it
++)
179 if (!it
->second
->isOwner())
180 it
->second
->setAccess(target
, update
, cred
);
182 // finally, apply owner
183 mAcls
[ownerHandle
]->setAccess(target
, update
, cred
);
188 // A convenience function to add one application to a standard ("simple") form
189 // ACL entry. This will only work if
190 // -- there is exactly one ACL entry authorizing the right
191 // -- that entry is in simple form
193 void Access::addApplicationToRight(AclAuthorization right
, TrustedApplication
*app
)
196 findAclsForRight(right
, acls
);
197 if (acls
.size() != 1)
198 MacOSError::throwMe(errSecACLNotSimple
); // let's not guess here...
199 (*acls
.begin())->addApplication(app
);
204 // Retrieve the description from a randomly chosen ACL within this Access.
205 // In the conventional case where all ACLs have the same descriptor, this
206 // is deterministic. But you have been warned.
208 string
Access::promptDescription() const
210 for (Map::const_iterator it
= mAcls
.begin(); it
!= mAcls
.end(); it
++) {
211 ACL
*acl
= it
->second
;
212 switch (acl
->form()) {
213 case ACL::allowAllForm
:
214 case ACL::appListForm
:
216 string descr
= acl
->promptDescription();
224 // couldn't find suitable ACL (no description anywhere)
225 CssmError::throwMe(errSecACLNotSimple
);
230 // Add a new ACL to the resident set. The ACL must have been
231 // newly made for this Access.
233 void Access::add(ACL
*newAcl
)
235 if (&newAcl
->access
!= this)
236 MacOSError::throwMe(paramErr
);
237 assert(!mAcls
[newAcl
->entryHandle()]);
238 mAcls
[newAcl
->entryHandle()] = newAcl
;
243 // Add the owner ACL to the resident set. The ACL must have been
244 // newly made for this Access.
245 // Since an Access must have exactly one owner ACL, this call
246 // should only be made (exactly once) for a newly created Access.
248 void Access::addOwner(ACL
*newAcl
)
251 assert(mAcls
.find(ownerHandle
) == mAcls
.end()); // no owner yet
257 // Compile a set of ACL entries and owner into internal form.
259 void Access::compile(const CSSM_ACL_OWNER_PROTOTYPE
&owner
,
260 uint32 aclCount
, const CSSM_ACL_ENTRY_INFO
*acls
)
263 mAcls
[ownerHandle
] = new ACL(*this, AclOwnerPrototype::overlay(owner
));
266 const AclEntryInfo
*acl
= AclEntryInfo::overlay(acls
);
267 for (uint32 n
= 0; n
< aclCount
; n
++) {
268 debug("SecAccess", "%p compiling entry %ld", this, acl
[n
].handle());
269 mAcls
[acl
[n
].handle()] = new ACL(*this, acl
[n
]);
271 debug("SecAccess", "%p %ld entries compiled", this, mAcls
.size());
276 // Creation helper objects
278 const char Access::Maker::creationEntryTag
[] = "___setup___";
280 Access::Maker::Maker(CssmAllocator
&alloc
)
281 : allocator(alloc
), mKey(alloc
), mCreds(allocator
)
283 // generate random key
284 mKey
.malloc(keySize
);
285 UniformRandomBlobs
<DevRandomGenerator
>().random(mKey
.get());
287 // create entry info for resource creation
288 mInput
= AclEntryPrototype(TypedList(allocator
, CSSM_ACL_SUBJECT_TYPE_PASSWORD
,
289 new(allocator
) ListElement(mKey
.get())));
290 mInput
.proto().tag(creationEntryTag
);
292 // create credential sample for access
293 mCreds
+= TypedList(allocator
, CSSM_SAMPLE_TYPE_PASSWORD
, new(allocator
) ListElement(mKey
.get()));
296 void Access::Maker::initialOwner(ResourceControlContext
&ctx
, const AccessCredentials
*creds
)
298 //@@@ make up ctx.entry-info
299 ctx
.input() = mInput
;
300 ctx
.credentials(creds
);
303 const AccessCredentials
*Access::Maker::cred()