]>
Commit | Line | Data |
---|---|---|
d8f41ccd | 1 | /* |
fa7225c8 A |
2 | * Copyright (c) 2000-2009,2012-2016 Apple Inc. All Rights Reserved. |
3 | * | |
d8f41ccd | 4 | * @APPLE_LICENSE_HEADER_START@ |
fa7225c8 | 5 | * |
d8f41ccd A |
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 | |
11 | * file. | |
fa7225c8 | 12 | * |
d8f41ccd A |
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. | |
fa7225c8 | 20 | * |
d8f41ccd A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
24 | ||
25 | // | |
26 | // acls - securityd ACL implementation | |
27 | // | |
28 | #include "acls.h" | |
29 | #include "connection.h" | |
30 | #include "server.h" | |
31 | #include "agentquery.h" | |
32 | #include "tokendatabase.h" | |
33 | #include "acl_keychain.h" | |
e3d460c9 | 34 | #include "acl_partition.h" |
d8f41ccd A |
35 | |
36 | // ACL subjects whose Environments we implement | |
37 | #include <security_cdsa_utilities/acl_any.h> | |
38 | #include <security_cdsa_utilities/acl_password.h> | |
e3d460c9 | 39 | #include "acl_keychain.h" |
d8f41ccd A |
40 | |
41 | #include <sys/sysctl.h> | |
42 | #include <security_utilities/logging.h> | |
e3d460c9 | 43 | #include <security_utilities/cfmunge.h> |
d8f41ccd A |
44 | |
45 | // | |
46 | // SecurityServerAcl is virtual | |
47 | // | |
48 | SecurityServerAcl::~SecurityServerAcl() | |
49 | { } | |
50 | ||
51 | ||
52 | // | |
53 | // The default implementation of the ACL interface simply uses the local ObjectAcl | |
54 | // data. You can customize this by implementing instantiateAcl() [from ObjectAcl] | |
55 | // or by overriding these methods as desired. | |
56 | // Note: While you can completely ignore the ObjectAcl personality if you wish, it's | |
57 | // usually smarter to adapt it. | |
58 | // | |
59 | void SecurityServerAcl::getOwner(AclOwnerPrototype &owner) | |
60 | { | |
61 | StLock<Mutex> _(aclSequence); | |
62 | ObjectAcl::cssmGetOwner(owner); | |
63 | } | |
64 | ||
65 | void SecurityServerAcl::getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls) | |
66 | { | |
67 | StLock<Mutex> _(aclSequence); | |
68 | ObjectAcl::cssmGetAcl(tag, count, acls); | |
69 | } | |
70 | ||
71 | void SecurityServerAcl::changeAcl(const AclEdit &edit, const AccessCredentials *cred, | |
72 | Database *db) | |
73 | { | |
74 | StLock<Mutex> _(aclSequence); | |
75 | SecurityServerEnvironment env(*this, db); | |
e3d460c9 A |
76 | |
77 | // if we're setting the INTEGRITY entry, check if you're in the partition list. | |
78 | if (const AclEntryInput* input = edit.newEntry()) { | |
79 | if (input->proto().authorization().containsOnly(CSSM_ACL_AUTHORIZATION_INTEGRITY)) { | |
80 | // Only prompt the user if these creds allow UI. | |
81 | bool ui = (!!cred) && cred->authorizesUI(); | |
82 | validatePartition(env, ui); // throws if fail | |
83 | ||
84 | // If you passed partition validation, bypass the owner ACL check entirely. | |
85 | env.forceSuccess = true; | |
86 | } | |
87 | } | |
88 | ||
89 | // If these access credentials, by themselves, protect this database, force success and don't | |
90 | // restrict changing PARTITION_ID | |
91 | if(db && db->checkCredentials(cred)) { | |
92 | env.forceSuccess = true; | |
93 | ObjectAcl::cssmChangeAcl(edit, cred, &env, NULL); | |
94 | } else { | |
95 | ObjectAcl::cssmChangeAcl(edit, cred, &env, CSSM_APPLE_ACL_TAG_PARTITION_ID); | |
96 | } | |
d8f41ccd A |
97 | } |
98 | ||
99 | void SecurityServerAcl::changeOwner(const AclOwnerPrototype &newOwner, | |
100 | const AccessCredentials *cred, Database *db) | |
101 | { | |
102 | StLock<Mutex> _(aclSequence); | |
103 | SecurityServerEnvironment env(*this, db); | |
104 | ObjectAcl::cssmChangeOwner(newOwner, cred, &env); | |
105 | } | |
106 | ||
107 | ||
108 | // | |
109 | // Modified validate() methods to connect all the conduits... | |
110 | // | |
111 | void SecurityServerAcl::validate(AclAuthorization auth, const AccessCredentials *cred, Database *db) | |
112 | { | |
113 | SecurityServerEnvironment env(*this, db); | |
fa7225c8 | 114 | |
d8f41ccd A |
115 | StLock<Mutex> objectSequence(aclSequence); |
116 | StLock<Mutex> processSequence(Server::process().aclSequence); | |
e3d460c9 A |
117 | ObjectAcl::validate(auth, cred, &env); |
118 | ||
119 | // partition validation happens outside the normal acl validation flow, in addition | |
120 | bool ui = (!!cred) && cred->authorizesUI(); | |
121 | ||
122 | // we should only offer the chance to extend the partition ID list on a "read" operation, so check the AclAuthorization | |
123 | bool readOperation = | |
124 | (auth == CSSM_ACL_AUTHORIZATION_CHANGE_ACL) || | |
125 | (auth == CSSM_ACL_AUTHORIZATION_DECRYPT) || | |
126 | (auth == CSSM_ACL_AUTHORIZATION_GENKEY) || | |
127 | (auth == CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED) || | |
128 | (auth == CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR) || | |
129 | (auth == CSSM_ACL_AUTHORIZATION_IMPORT_WRAPPED) || | |
130 | (auth == CSSM_ACL_AUTHORIZATION_IMPORT_CLEAR) || | |
131 | (auth == CSSM_ACL_AUTHORIZATION_SIGN) || | |
132 | (auth == CSSM_ACL_AUTHORIZATION_DECRYPT) || | |
133 | (auth == CSSM_ACL_AUTHORIZATION_MAC) || | |
134 | (auth == CSSM_ACL_AUTHORIZATION_DERIVE); | |
135 | ||
136 | validatePartition(env, ui && readOperation); | |
d8f41ccd A |
137 | } |
138 | ||
139 | void SecurityServerAcl::validate(AclAuthorization auth, const Context &context, Database *db) | |
140 | { | |
141 | validate(auth, | |
142 | context.get<AccessCredentials>(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS), db); | |
143 | } | |
144 | ||
145 | ||
e3d460c9 A |
146 | // |
147 | // Partitioning support | |
148 | // | |
149 | void SecurityServerAcl::validatePartition(SecurityServerEnvironment& env, bool prompt) | |
150 | { | |
79b9da22 A |
151 | // Avert your eyes! |
152 | StMaybeLock<Mutex> lock(env.database && env.database->hasCommon() ? &(env.database->common()) : NULL); | |
153 | ||
fa7225c8 A |
154 | // Calling checkAppleSigned() early at boot on a clean system install |
155 | // will end up trying to create the system keychain and causes a hang. | |
156 | // Avoid this by checking for the presence of the db first. | |
157 | if((!env.database) || env.database->dbVersion() < SecurityServer::CommonBlob::version_partition) { | |
b04fe171 | 158 | secinfo("integrity", "no db or old db version, skipping"); |
fa7225c8 A |
159 | return; |
160 | } | |
161 | ||
e3d460c9 A |
162 | // For the Keychain Migrator, don't even check the partition list |
163 | Process &process = Server::process(); | |
164 | if (process.checkAppleSigned() && process.hasEntitlement(migrationEntitlement)) { | |
fa7225c8 | 165 | secnotice("integrity", "bypassing partition check for keychain migrator"); |
e3d460c9 A |
166 | return; // migrator client -> automatic win |
167 | } | |
168 | ||
169 | if (CFRef<CFDictionaryRef> partition = this->createPartitionPayload()) { | |
170 | CFArrayRef partitionList; | |
171 | if (cfscan(partition, "{Partitions=%AO}", &partitionList)) { | |
172 | CFRef<CFStringRef> partitionDebug = CFCopyDescription(partitionList); // for debugging only | |
866f8763 | 173 | secinfo("integrity", "ACL partitionID = %s", cfString(partitionDebug).c_str()); |
e3d460c9 A |
174 | if (env.database) { |
175 | CFRef<CFStringRef> clientPartitionID = makeCFString(env.database->process().partitionId()); | |
176 | if (CFArrayContainsValue(partitionList, CFRangeMake(0, CFArrayGetCount(partitionList)), clientPartitionID)) { | |
866f8763 | 177 | secinfo("integrity", "ACL partitions match: %s", cfString(clientPartitionID).c_str()); |
e3d460c9 A |
178 | return; |
179 | } else { | |
fa7225c8 | 180 | secnotice("integrity", "ACL partition mismatch: client %s ACL %s", cfString(clientPartitionID).c_str(), cfString(partitionDebug).c_str()); |
e3d460c9 A |
181 | if (prompt && extendPartition(env)) |
182 | return; | |
183 | MacOSError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); | |
184 | } | |
185 | } | |
186 | } | |
fa7225c8 | 187 | secnotice("integrity", "failed to parse partition payload"); |
e3d460c9 A |
188 | MacOSError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); |
189 | } else { | |
fa7225c8 A |
190 | // There's no partition list. This keychain is recently upgraded. |
191 | Server::connection().overrideReturn(CSSMERR_CSP_APPLE_ADD_APPLICATION_ACL_SUBJECT); | |
192 | if(env.database->isRecoding()) { | |
193 | secnotice("integrity", "no partition ACL - database is recoding; skipping add"); | |
194 | // let this pass as well | |
e3d460c9 | 195 | } else { |
fa7225c8 | 196 | secnotice("integrity", "no partition ACL - adding"); |
e3d460c9 A |
197 | env.acl.instantiateAcl(); |
198 | this->createClientPartitionID(env.database->process()); | |
199 | env.acl.changedAcl(); | |
200 | Server::connection().overrideReturn(CSSMERR_CSP_APPLE_ADD_APPLICATION_ACL_SUBJECT); | |
201 | } | |
202 | } | |
203 | } | |
204 | ||
205 | ||
206 | bool SecurityServerAcl::extendPartition(SecurityServerEnvironment& env) | |
207 | { | |
208 | // brute-force find the KeychainAclSubject in the ACL | |
209 | KeychainPromptAclSubject *kcSubject = NULL; | |
210 | SecurityServerAcl& acl = env.acl; | |
211 | for (EntryMap::const_iterator it = acl.begin(); it != acl.end(); ++it) { | |
212 | AclSubjectPointer subject = it->second.subject; | |
213 | if (ThresholdAclSubject *threshold = dynamic_cast<ThresholdAclSubject *>(subject.get())) { | |
214 | unsigned size = threshold->count(); | |
215 | if (KeychainPromptAclSubject* last = dynamic_cast<KeychainPromptAclSubject *>(threshold->subject(size-1))) { | |
216 | // looks standard enough | |
217 | kcSubject = last; | |
218 | break; | |
219 | } | |
220 | } | |
221 | } | |
fa7225c8 | 222 | |
e3d460c9 A |
223 | if (kcSubject) { |
224 | BaseValidationContext ctx(NULL, CSSM_ACL_AUTHORIZATION_PARTITION_ID, &env); | |
fa7225c8 | 225 | kcSubject->addPromptAttempt(); |
e3d460c9 | 226 | return kcSubject->validateExplicitly(ctx, ^{ |
fa7225c8 | 227 | secnotice("integrity", "adding partition to list"); |
e3d460c9 A |
228 | env.acl.instantiateAcl(); |
229 | this->addClientPartitionID(env.database->process()); | |
230 | env.acl.changedAcl(); | |
231 | // trigger a special notification code on (otherwise successful) return | |
232 | Server::connection().overrideReturn(CSSMERR_CSP_APPLE_ADD_APPLICATION_ACL_SUBJECT); | |
233 | }); | |
234 | } | |
fa7225c8 | 235 | secnotice("integrity", "failure extending partition"); |
e3d460c9 A |
236 | return false; |
237 | } | |
238 | ||
239 | ||
240 | PartitionAclSubject* SecurityServerAcl::findPartitionSubject() | |
241 | { | |
242 | pair<EntryMap::const_iterator, EntryMap::const_iterator> range; | |
243 | switch (this->getRange(CSSM_APPLE_ACL_TAG_PARTITION_ID, range, true)) { | |
244 | case 0: | |
fa7225c8 | 245 | secnotice("integrity", "no partition tag on ACL"); |
e3d460c9 A |
246 | return NULL; |
247 | default: | |
fa7225c8 | 248 | secnotice("integrity", "multiple partition ACL entries"); |
e3d460c9 A |
249 | MacOSError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); |
250 | case 1: | |
251 | break; | |
252 | } | |
253 | const AclEntry& entry = range.first->second; | |
254 | if (!entry.authorizes(CSSM_ACL_AUTHORIZATION_PARTITION_ID)) { | |
fa7225c8 | 255 | secnotice("integrity", "partition entry does not authorize CSSM_ACL_AUTHORIZATION_PARTITION_ID"); |
e3d460c9 A |
256 | MacOSError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); |
257 | } | |
258 | if (PartitionAclSubject* partition = dynamic_cast<PartitionAclSubject*>(entry.subject.get())) { | |
259 | return partition; | |
260 | } else { | |
fa7225c8 | 261 | secnotice("integrity", "partition entry is not PartitionAclSubject"); |
e3d460c9 A |
262 | MacOSError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); |
263 | } | |
264 | } | |
265 | ||
266 | ||
267 | CFDictionaryRef SecurityServerAcl::createPartitionPayload() | |
268 | { | |
269 | if (PartitionAclSubject* subject = this->findPartitionSubject()) { | |
270 | if (CFDictionaryRef result = subject->createDictionaryPayload()) { | |
271 | return result; | |
272 | } else { | |
fa7225c8 | 273 | secnotice("integrity", "partition entry is malformed XML"); |
e3d460c9 A |
274 | MacOSError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); |
275 | } | |
276 | } else { | |
277 | return NULL; | |
278 | } | |
279 | } | |
280 | ||
281 | ||
d8f41ccd A |
282 | // |
283 | // This helper tries to add the (new) subject given to the ACL | |
284 | // whose validation is currently proceeding through context. | |
285 | // This will succeed if the ACL is in standard form, which means | |
286 | // a ThresholdAclSubject. | |
287 | // The new subject will be added at the front (so it is checked first | |
288 | // from now on), and as a side effect we'll notify the client side to | |
289 | // re-encode the object. | |
290 | // Returns true if the edit could be done, or false if the ACL wasn't | |
291 | // standard enough. May throw if the ACL is malformed or otherwise messed up. | |
292 | // | |
293 | // This is a self-contained helper that is here merely because it's "about" | |
294 | // ACLs and has no better home. | |
295 | // | |
296 | bool SecurityServerAcl::addToStandardACL(const AclValidationContext &context, AclSubject *subject) | |
297 | { | |
298 | if (SecurityServerEnvironment *env = context.environment<SecurityServerEnvironment>()) | |
299 | if (ThresholdAclSubject *threshold = env->standardSubject(context)) { | |
300 | unsigned size = threshold->count(); | |
301 | if (dynamic_cast<KeychainPromptAclSubject *>(threshold->subject(size-1))) { | |
302 | // looks standard enough | |
fa7225c8 | 303 | secinfo("acl", "adding new subject %p to from of threshold ACL", subject); |
d8f41ccd | 304 | threshold->add(subject, 0); |
fa7225c8 | 305 | |
d8f41ccd A |
306 | // tell the ACL it's been modified |
307 | context.acl()->changedAcl(); | |
308 | ||
309 | // trigger a special notification code on (otherwise successful) return | |
310 | Server::connection().overrideReturn(CSSMERR_CSP_APPLE_ADD_APPLICATION_ACL_SUBJECT); | |
311 | return true; | |
312 | } | |
313 | } | |
fa7225c8 | 314 | secinfo("acl", "ACL is not standard form; cannot edit"); |
d8f41ccd A |
315 | return false; |
316 | } | |
317 | ||
318 | ||
319 | // | |
320 | // Look at the ACL whose validation is currently proceeding through context. | |
321 | // If it LOOKS like a plausible version of a legacy "dot mac item" ACL. | |
322 | // We don't have access to the database attributes of the item up here in the | |
323 | // securityd sky, so we have to apply a heuristic based on which applications (by path) | |
324 | // are given access to the item. | |
325 | // So this is strictly a heuristic. The potential downside is that we may inadvertently | |
326 | // give access to new .Mac authorized Apple (only) applications when the user only intended | |
327 | // a limited set of extremely popular Apple (only) applications that just happen to all be | |
328 | // .Mac authorized today. We can live with that. | |
329 | // | |
330 | bool SecurityServerAcl::looksLikeLegacyDotMac(const AclValidationContext &context) | |
331 | { | |
332 | static const char * const prototypicalDotMacPath[] = { | |
333 | "/Applications/Mail.app", | |
334 | "/Applications/Safari.app", | |
335 | "/Applications/iSync.app", | |
336 | "/Applications/System Preferences.app", | |
337 | "/Applications/iCal.app", | |
338 | "/Applications/iChat.app", | |
339 | "/Applications/iTunes.app", | |
340 | "/Applications/Address Book.app", | |
341 | "/Applications/iSync.app", | |
342 | NULL // sentinel | |
343 | }; | |
fa7225c8 | 344 | |
d8f41ccd | 345 | static const unsigned threshold = 6; |
fa7225c8 | 346 | |
d8f41ccd A |
347 | if (SecurityServerEnvironment *env = context.environment<SecurityServerEnvironment>()) { |
348 | if (ThresholdAclSubject *list = env->standardSubject(context)) { | |
349 | unsigned count = list->count(); | |
350 | unsigned matches = 0; | |
351 | for (unsigned n = 0; n < count; ++n) { | |
352 | if (CodeSignatureAclSubject *app = dynamic_cast<CodeSignatureAclSubject *>(list->subject(n))) { | |
353 | for (const char * const *p = prototypicalDotMacPath; *p; p++) | |
354 | if (app->path() == *p) | |
355 | matches++; | |
356 | } | |
357 | } | |
fa7225c8 | 358 | secinfo("codesign", "matched %d of %zd candididates (threshold=%d)", |
d8f41ccd A |
359 | matches, sizeof(prototypicalDotMacPath) / sizeof(char *) - 1, threshold); |
360 | return matches >= threshold; | |
361 | } | |
362 | } | |
363 | return false; | |
364 | } | |
365 | ||
366 | ||
e3d460c9 A |
367 | // |
368 | // ACL manipulations related to keychain partitions | |
369 | // | |
370 | bool SecurityServerAcl::createClientPartitionID(Process& process) | |
371 | { | |
372 | // Make sure the ACL is ready for edits | |
373 | instantiateAcl(); | |
374 | ||
375 | // create partition payload | |
376 | std::string partitionID = process.partitionId(); | |
377 | CFTemp<CFDictionaryRef> payload("{Partitions=[%s]}", partitionID.c_str()); | |
378 | ObjectAcl::AclSubjectPointer subject = new PartitionAclSubject(); | |
379 | static_cast<PartitionAclSubject*>(subject.get())->setDictionaryPayload(Allocator::standard(), payload); | |
380 | ObjectAcl::AclEntry partition(subject); | |
381 | partition.addAuthorization(CSSM_ACL_AUTHORIZATION_PARTITION_ID); | |
382 | this->add(CSSM_APPLE_ACL_TAG_PARTITION_ID, partition); | |
866f8763 | 383 | secinfo("integrity", "added partition %s to new key", partitionID.c_str()); |
e3d460c9 A |
384 | return true; |
385 | } | |
386 | ||
387 | ||
388 | bool SecurityServerAcl::addClientPartitionID(Process& process) | |
389 | { | |
390 | if (PartitionAclSubject* subject = this->findPartitionSubject()) { | |
391 | std::string partitionID = process.partitionId(); | |
392 | if (CFRef<CFDictionaryRef> payload = subject->createDictionaryPayload()) { | |
393 | CFArrayRef partitionList; | |
394 | if (cfscan(payload, "{Partitions=%AO}", &partitionList)) { | |
395 | CFTemp<CFDictionaryRef> newPayload("{Partitions=[+%O,%s]}", partitionList, partitionID.c_str()); | |
396 | subject->setDictionaryPayload(Allocator::standard(), newPayload); | |
397 | } | |
398 | return true; | |
399 | } else { | |
400 | MacOSError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); | |
401 | } | |
402 | } else { | |
403 | return createClientPartitionID(process); | |
404 | } | |
405 | } | |
406 | ||
407 | ||
d8f41ccd A |
408 | // |
409 | // External storage interface | |
410 | // | |
411 | Adornable &SecurityServerEnvironment::store(const AclSubject *subject) | |
412 | { | |
413 | switch (subject->type()) { | |
414 | case CSSM_ACL_SUBJECT_TYPE_PREAUTH: | |
415 | { | |
416 | if (TokenDatabase *tokenDb = dynamic_cast<TokenDatabase *>(database)) | |
417 | return tokenDb->common().store(); | |
418 | } | |
419 | break; | |
420 | default: | |
421 | break; | |
422 | } | |
423 | CssmError::throwMe(CSSM_ERRCODE_ACL_SUBJECT_TYPE_NOT_SUPPORTED); | |
424 | } | |
425 | ||
426 | ||
427 | // | |
428 | // ProcessAclSubject personality: uid/gid/pid come from the active Process object | |
429 | // | |
430 | uid_t SecurityServerEnvironment::getuid() const | |
431 | { | |
432 | return Server::process().uid(); | |
433 | } | |
434 | ||
435 | gid_t SecurityServerEnvironment::getgid() const | |
436 | { | |
437 | return Server::process().gid(); | |
438 | } | |
439 | ||
440 | pid_t SecurityServerEnvironment::getpid() const | |
441 | { | |
442 | return Server::process().pid(); | |
443 | } | |
444 | ||
445 | ||
446 | // | |
447 | // CodeSignatureAclSubject personality: take code signature from active Process object | |
448 | // | |
449 | bool SecurityServerEnvironment::verifyCodeSignature(const OSXVerifier &verifier, | |
450 | const AclValidationContext &context) | |
451 | { | |
452 | return Server::codeSignatures().verify(Server::process(), verifier, context); | |
453 | } | |
454 | ||
455 | ||
456 | // | |
457 | // PromptedAclSubject personality: Get a secret by prompting through SecurityAgent | |
458 | // | |
459 | bool SecurityServerEnvironment::getSecret(CssmOwnedData &secret, const CssmData &prompt) const | |
460 | { | |
461 | //@@@ ignoring prompt - not used right now | |
462 | if (database) { | |
463 | QueryPIN query(*database); | |
464 | query.inferHints(Server::process()); | |
465 | if (!query()) { // success | |
466 | secret = query.pin(); | |
467 | return true; | |
468 | } | |
469 | } | |
470 | return false; | |
471 | } | |
472 | ||
473 | ||
474 | // | |
475 | // SecretAclSubject personality: externally validate a secret (passphrase etc.) | |
476 | // Right now, this always goes to the (Token)Database object, because that's where | |
477 | // the PIN ACL entries are. We could direct this at the ObjectAcl (database or key) | |
478 | // instead and rely on tokend to perform the PIN mapping, but the generic tokend | |
479 | // wrappers do not (currently) perform any ACL validation, so every tokend would have | |
480 | // to re-implement that. Perhaps in the next ACL revamp cycle... | |
481 | // | |
482 | bool SecurityServerEnvironment::validateSecret(const SecretAclSubject *me, | |
483 | const AccessCredentials *cred) | |
484 | { | |
485 | return database && database->validateSecret(me, cred); | |
486 | } | |
487 | ||
488 | ||
489 | // | |
490 | // PreAuthenticationAclSubject personality - refer to database (ObjectAcl) | |
491 | // | |
492 | ObjectAcl *SecurityServerEnvironment::preAuthSource() | |
493 | { | |
494 | return database ? &database->acl() : NULL; | |
495 | } | |
496 | ||
497 | ||
498 | // | |
499 | // Autonomous ACL editing support | |
500 | // | |
501 | ThresholdAclSubject *SecurityServerEnvironment::standardSubject(const AclValidationContext &context) | |
502 | { | |
503 | return dynamic_cast<ThresholdAclSubject *>(context.subject()); | |
504 | } | |
505 | ||
506 | ||
507 | // | |
508 | // The default AclSource denies having an ACL at all | |
509 | // | |
510 | AclSource::~AclSource() | |
511 | { /* virtual */ } | |
512 | ||
513 | SecurityServerAcl &AclSource::acl() | |
514 | { | |
515 | CssmError::throwMe(CSSM_ERRCODE_OBJECT_ACL_NOT_SUPPORTED); | |
516 | } | |
517 | ||
518 | Database *AclSource::relatedDatabase() | |
519 | { | |
520 | return NULL; | |
521 | } |