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 default Access object.
33 // This construct an Access with "default form", whatever that happens to be
36 Access::Access(const string
&descriptor
, const ACL::ApplicationList
&trusted
)
38 makeStandard(descriptor
, trusted
);
41 Access::Access(const string
&descriptor
)
43 ACL::ApplicationList trusted
;
44 trusted
.push_back(new TrustedApplication
);
45 makeStandard(descriptor
, trusted
);
48 void Access::makeStandard(const string
&descriptor
, const ACL::ApplicationList
&trusted
)
51 RefPointer
<ACL
> owner
= new ACL(*this, descriptor
, ACL::defaultSelector
);
52 owner
->setAuthorization(CSSM_ACL_AUTHORIZATION_CHANGE_ACL
);
56 RefPointer
<ACL
> encrypt
= new ACL(*this, descriptor
, ACL::defaultSelector
);
57 encrypt
->setAuthorization(CSSM_ACL_AUTHORIZATION_ENCRYPT
);
58 encrypt
->form(ACL::allowAllForm
);
62 RefPointer
<ACL
> decrypt
= new ACL(*this, descriptor
, ACL::defaultSelector
);
63 decrypt
->setAuthorization(CSSM_ACL_AUTHORIZATION_DECRYPT
);
64 decrypt
->applications() = trusted
;
70 // Create an Access object whose initial value is taken
71 // from a CSSM ACL bearing object.
73 Access::Access(AclBearer
&source
)
76 AutoAclOwnerPrototype owner
;
77 source
.getOwner(owner
);
78 AutoAclEntryInfoList acls
;
80 compile(*owner
, acls
.count(), acls
.entries());
85 // Create an Access object from CSSM-layer access controls
87 Access::Access(const CSSM_ACL_OWNER_PROTOTYPE
&owner
,
88 uint32 aclCount
, const CSSM_ACL_ENTRY_INFO
*acls
)
90 compile(owner
, aclCount
, acls
);
100 // Return all ACL components in a newly-made CFArray.
102 CFArrayRef
Access::copySecACLs() const
104 return makeCFArray(gTypes().acl
, mAcls
);
107 CFArrayRef
Access::copySecACLs(CSSM_ACL_AUTHORIZATION_TAG action
) const
110 for (Map::const_iterator it
= mAcls
.begin(); it
!= mAcls
.end(); it
++)
111 if (it
->second
->authorizations().find(action
) != it
->second
->authorizations().end())
112 choices
.push_back(it
->second
);
113 return choices
.empty() ? NULL
: makeCFArray(gTypes().acl
, choices
);
118 // Enter the complete access configuration into a AclBearer.
119 // If update, skip any part marked unchanged. (If not update, skip
120 // any part marked deleted.)
122 void Access::setAccess(AclBearer
&target
, bool update
= false)
125 editAccess(target
, update
, factory
.promptCred());
128 void Access::setAccess(AclBearer
&target
, Maker
&maker
)
130 // remove initial-setup ACL
131 target
.deleteAcl(Maker::creationEntryTag
, maker
.cred());
133 // insert our own ACL entries
134 editAccess(target
, false, maker
.cred());
137 void Access::editAccess(AclBearer
&target
, bool update
, const AccessCredentials
*cred
)
139 assert(mAcls
[ownerHandle
]); // have owner
141 // apply all non-owner ACLs first
142 for (Map::iterator it
= mAcls
.begin(); it
!= mAcls
.end(); it
++)
143 if (!it
->second
->isOwner())
144 it
->second
->setAccess(target
, update
, cred
);
146 // finally, apply owner
147 mAcls
[ownerHandle
]->setAccess(target
, update
, cred
);
152 // A convenience function to add one application to a standard ("simple") form
153 // ACL entry. This will only work if
154 // -- there is exactly one ACL entry authorizing the right
155 // -- that entry is in simple form
157 void Access::addApplicationToRight(AclAuthorization right
, TrustedApplication
*app
)
160 findAclsForRight(right
, acls
);
161 if (acls
.size() != 1)
162 MacOSError::throwMe(errSecACLNotSimple
); // let's not guess here...
163 (*acls
.begin())->addApplication(app
);
168 // Add a new ACL to the resident set. The ACL must have been
169 // newly made for this Access.
171 void Access::add(ACL
*newAcl
)
173 if (&newAcl
->access
!= this)
174 MacOSError::throwMe(paramErr
);
175 assert(!mAcls
[newAcl
->entryHandle()]);
176 mAcls
[newAcl
->entryHandle()] = newAcl
;
181 // Add the owner ACL to the resident set. The ACL must have been
182 // newly made for this Access.
183 // Since an Access must have exactly one owner ACL, this call
184 // should only be made (exactly once) for a newly created Access.
186 void Access::addOwner(ACL
*newAcl
)
189 assert(mAcls
.find(ownerHandle
) == mAcls
.end()); // no owner yet
195 // Compile a set of ACL entries and owner into internal form.
197 void Access::compile(const CSSM_ACL_OWNER_PROTOTYPE
&owner
,
198 uint32 aclCount
, const CSSM_ACL_ENTRY_INFO
*acls
)
201 mAcls
[ownerHandle
] = new ACL(*this, AclOwnerPrototype::overlay(owner
));
204 const AclEntryInfo
*acl
= AclEntryInfo::overlay(acls
);
205 for (uint32 n
= 0; n
< aclCount
; n
++) {
206 debug("SecAccess", "%p compiling entry %ld", this, acl
[n
].handle());
207 mAcls
[acl
[n
].handle()] = new ACL(*this, acl
[n
]);
209 debug("SecAccess", "%p %ld entries compiled", this, mAcls
.size());
214 // Creation helper objects
216 const char Access::Maker::creationEntryTag
[] = "___setup___";
218 Access::Maker::Maker(CssmAllocator
&alloc
)
219 : allocator(alloc
), mKey(alloc
), mCreds(allocator
)
221 // generate random key
222 mKey
.malloc(keySize
);
223 UniformRandomBlobs
<DevRandomGenerator
>().random(mKey
.get());
225 // create entry info for resource creation
226 mInput
= AclEntryPrototype(TypedList(allocator
, CSSM_ACL_SUBJECT_TYPE_PASSWORD
,
227 new(allocator
) ListElement(mKey
.get())));
228 mInput
.proto().tag(creationEntryTag
);
230 // create credential sample for access
231 mCreds
+= TypedList(allocator
, CSSM_SAMPLE_TYPE_PASSWORD
, new(allocator
) ListElement(mKey
.get()));
234 void Access::Maker::initialOwner(ResourceControlContext
&ctx
, const AccessCredentials
*creds
)
236 //@@@ make up ctx.entry-info
237 ctx
.input() = mInput
;
238 ctx
.credentials(creds
);
241 const AccessCredentials
*Access::Maker::cred()