1/*
2 * Copyright (c) 2000-2001,2007 Apple Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19//
20// aclclient
21//
22#include <security_cdsa_client/cssmclient.h>
23#include <security_cdsa_client/aclclient.h>
24#include <security_cdsa_client/keychainacl.h>
25#include <security_cdsa_utilities/cssmwalkers.h>
26#include <security_cdsa_utilities/cssmdata.h>
27
28
29namespace Security {
30namespace CssmClient {
31
32static inline void check(CSSM_RETURN rc)
33{
34	ObjectImpl::check(rc);
35}
36
37
38//
39// AclBearer methods (trivial)
40//
41AclBearer::~AclBearer()
42{ }
43
44
45//
46// Variant forms of AclBearer implemented in terms of its canonical virtual methods
47//
48void AclBearer::addAcl(const AclEntryInput &input, const CSSM_ACCESS_CREDENTIALS *cred)
49{
50	changeAcl(AclEdit(input), cred);
51}
52
53void AclBearer::changeAcl(CSSM_ACL_HANDLE handle, const AclEntryInput &input,
54	const CSSM_ACCESS_CREDENTIALS *cred)
55{
56	changeAcl(AclEdit(handle, input), cred);
57}
58
59void AclBearer::deleteAcl(CSSM_ACL_HANDLE handle, const CSSM_ACCESS_CREDENTIALS *cred)
60{
61	changeAcl(AclEdit(handle), cred);
62}
63
64void AclBearer::deleteAcl(const char *tag, const CSSM_ACCESS_CREDENTIALS *cred)
65{
66	AutoAclEntryInfoList entries;
67	getAcl(entries, tag);
68	for (uint32 n = 0; n < entries.count(); n++)
69		deleteAcl(entries[n].handle(), cred);
70}
71
72
73//
74// KeyAclBearer implementation
75//
76void KeyAclBearer::getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag) const
77{
78	aclInfos.allocator(allocator);
79	check(CSSM_GetKeyAcl(csp, &key, reinterpret_cast<const CSSM_STRING *>(selectionTag), aclInfos, aclInfos));
80}
81
82void KeyAclBearer::changeAcl(const CSSM_ACL_EDIT &aclEdit, const CSSM_ACCESS_CREDENTIALS *cred)
83{
84	check(CSSM_ChangeKeyAcl(csp, AccessCredentials::needed(cred), &aclEdit, &key));
85}
86
87void KeyAclBearer::getOwner(AutoAclOwnerPrototype &owner) const
88{
89	owner.allocator(allocator);
90	check(CSSM_GetKeyOwner(csp, &key, owner));
91}
92
93void KeyAclBearer::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
94	const CSSM_ACCESS_CREDENTIALS *cred)
95{
96	check(CSSM_ChangeKeyOwner(csp, AccessCredentials::needed(cred), &key, &newOwner));
97}
98
99
100//
101// A single global structure containing pseudo-static data
102//
103struct Statics {
104	Statics();
105	Allocator &alloc;
106
107	AutoCredentials nullCred;
108	AutoCredentials promptCred;
109	AutoCredentials unlockCred;
110	AutoCredentials cancelCred;
111	AutoCredentials promptedPINCred;
112	AutoCredentials promptedPINItemCred;
113
114	AclOwnerPrototype anyOwner;
115	AclEntryInfo anyAcl;
116};
117
118namespace {
119	ModuleNexus<Statics> statics;
120}
121
122
123//
124// Make pseudo-statics.
125// Note: This is an eternal object. It is not currently destroyed
126// if the containing code is unloaded.
127//
128Statics::Statics()
129	: alloc(Allocator::standard()),
130	  nullCred(alloc, 1),
131	  promptCred(alloc, 3),
132	  unlockCred(alloc, 1),
133	  cancelCred(alloc, 1),
134	  promptedPINCred(alloc, 1),
135	  promptedPINItemCred(alloc, 1),
136	  anyOwner(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_ANY)),
137	  anyAcl(AclEntryPrototype(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_ANY), 1))
138{
139	// nullCred: nothing at all
140	// contains:
141	//  an empty THRESHOLD sample to match threshold subjects with "free" subjects
142	nullCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD);
143
144	// promptCred: a credential permitting user prompt confirmations
145	// contains:
146	//  a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD
147	//  a PROMPTED_PASSWORD sample
148	promptCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT);
149	promptCred.sample(1) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD,
150		new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT)));
151	promptCred.sample(2) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
152		new(alloc) ListElement(alloc, CssmData()));
153
154	// unlockCred: ???
155	unlockCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
156		new(alloc) ListElement(CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT));
157
158	cancelCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
159									 new(alloc) ListElement(CSSM_WORDID_CANCELED));
160
161	/*
162		We don't set this:
163
164			promptedPINCred.tag("PIN1");
165
166		here to avoid triggering code in TokenDatabase::getAcl in securityd that
167		would always show a PIN unlock dialog. This credential is used for an
168		unlock of the database, i.e. a dbauthenticate call to unlock the card.
169	*/
170	promptedPINCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
171										  new(alloc) ListElement(alloc, CssmData()));
172
173	/*
174		This credential is used for items like non-repudiation keys that always
175		require an explicit entry of the PIN. We set this so that Token::authenticate
176		will recognize the number of the PIN we need to unlock.
177	*/
178	promptedPINItemCred.tag("PIN1");
179	promptedPINItemCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
180										  new(alloc) ListElement(alloc, CssmData()));
181}
182
183
184//
185// Make and break AclFactories
186//
187AclFactory::AclFactory()
188{ }
189
190AclFactory::~AclFactory()
191{ }
192
193
194//
195// Return basic pseudo-static values
196//
197const AccessCredentials *AclFactory::nullCred() const
198{ return &statics().nullCred; }
199
200const AccessCredentials *AclFactory::promptCred() const
201{ return &statics().promptCred; }
202
203const AccessCredentials *AclFactory::unlockCred() const
204{ return &statics().unlockCred; }
205
206
207const AccessCredentials *AclFactory::cancelCred() const
208{ return &statics().cancelCred; }
209
210const AccessCredentials *AclFactory::promptedPINCred() const
211{ return &statics().promptedPINCred; }
212
213const AccessCredentials *AclFactory::promptedPINItemCred() const
214{ return &statics().promptedPINItemCred; }
215
216
217//
218// Manage the (pseudo) credentials used to explicitly provide a passphrase to a keychain.
219// Use the eternal unlockCred() for normal (protected prompt) unlocking.
220//
221AclFactory::KeychainCredentials::~KeychainCredentials ()
222{
223    DataWalkers::chunkFree(mCredentials, allocator);
224}
225
226AclFactory::PassphraseUnlockCredentials::PassphraseUnlockCredentials (const CssmData& password,
227	Allocator& allocator) : KeychainCredentials(allocator)
228{
229    mCredentials->sample(0) = TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
230		new (allocator) ListElement (CSSM_SAMPLE_TYPE_PASSWORD),
231		new (allocator) ListElement (CssmAutoData(allocator, password).release()));
232}
233
234
235//
236// Manage the (pseudo) credentials used to explicitly change a keychain's passphrase
237//
238AclFactory::PasswordChangeCredentials::PasswordChangeCredentials (const CssmData& password,
239	Allocator& allocator) : KeychainCredentials(allocator)
240{
241    mCredentials->sample(0) = TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
242		new (allocator) ListElement (CSSM_SAMPLE_TYPE_PASSWORD),
243		new (allocator) ListElement (CssmAutoData(allocator, password).release()));
244}
245
246
247//
248// Wide open ("ANY") CSSM forms for owner and ACL entry
249//
250const AclOwnerPrototype &AclFactory::anyOwner() const
251{ return statics().anyOwner; }
252
253const AclEntryInfo &AclFactory::anyAcl() const
254{ return statics().anyAcl; }
255
256
257//
258// Create an ANY style AclEntryInput.
259// This can be used to explicitly request wide-open authorization on a new CSSM object.
260//
261AclFactory::AnyResourceContext::AnyResourceContext(const CSSM_ACCESS_CREDENTIALS *cred)
262	: mAny(CSSM_ACL_SUBJECT_TYPE_ANY), mTag(CSSM_ACL_AUTHORIZATION_ANY)
263{
264	// set up an ANY/EVERYTHING AclEntryInput
265	input().proto().subject() += &mAny;
266	AuthorizationGroup &authGroup = input().proto().authorization();
267	authGroup.NumberOfAuthTags = 1;
268	authGroup.AuthTags = &mTag;
269
270	// install the cred (not copied)
271	credentials(cred);
272}
273
274
275//
276// CSSM ACL makers
277//
278AclFactory::Subject::Subject(Allocator &alloc, CSSM_ACL_SUBJECT_TYPE type)
279	: TypedList(alloc, type)
280{ }
281
282
283AclFactory::PWSubject::PWSubject(Allocator &alloc)
284	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD)
285{ }
286
287AclFactory::PWSubject::PWSubject(Allocator &alloc, const CssmData &secret)
288	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD)
289{
290	append(new(alloc) ListElement(alloc, secret));
291}
292
293AclFactory::PromptPWSubject::PromptPWSubject(Allocator &alloc, const CssmData &prompt)
294	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD)
295{
296	append(new(alloc) ListElement(alloc, prompt));
297}
298
299AclFactory::PromptPWSubject::PromptPWSubject(Allocator &alloc, const CssmData &prompt, const CssmData &secret)
300	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD)
301{
302	append(new(alloc) ListElement(alloc, prompt));
303	append(new(alloc) ListElement(alloc, secret));
304}
305
306AclFactory::ProtectedPWSubject::ProtectedPWSubject(Allocator &alloc)
307	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROTECTED_PASSWORD)
308{ }
309
310AclFactory::PinSubject::PinSubject(Allocator &alloc, uint32 slot)
311	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH)
312{
313	append(new(alloc) ListElement(CSSM_ACL_AUTHORIZATION_PREAUTH(slot)));
314}
315
316AclFactory::PinSourceSubject::PinSourceSubject(Allocator &alloc, const TypedList &form)
317	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH_SOURCE)
318{
319	append(new(alloc) ListElement(form));
320}
321
322
323} // end namespace CssmClient
324} // end namespace Security
325