]> git.saurik.com Git - apple/securityd.git/blob - src/tokendatabase.cpp
securityd-32597.tar.gz
[apple/securityd.git] / src / tokendatabase.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // tokendatabase - software database container implementation.
27 //
28 #include "tokendatabase.h"
29 #include "tokenkey.h"
30 #include "tokenaccess.h"
31 #include "process.h"
32 #include "server.h"
33 #include "localkey.h" // to retrieve local raw keys
34 #include <security_cdsa_client/wrapkey.h>
35
36
37 //
38 // Construct a TokenDbCommon
39 //
40 TokenDbCommon::TokenDbCommon(Session &ssn, Token &tk, const char *name)
41 : DbCommon(ssn), mDbName(name ? name : ""), mResetLevel(0)
42 {
43 secdebug("tokendb", "creating tokendbcommon %p: with token %p", this, &tk);
44 parent(tk);
45 }
46
47 TokenDbCommon::~TokenDbCommon()
48 {
49 secdebug("tokendb", "destroying tokendbcommon %p", this);
50 token().removeCommon(*this); // unregister from Token
51 }
52
53 Token &TokenDbCommon::token() const
54 {
55 return parent<Token>();
56 }
57
58 const std::string &TokenDbCommon::dbName() const
59 {
60 return token().printName();
61 }
62
63
64 //
65 // A TokenDbCommon holds per-session adornments for the ACL machine
66 //
67 Adornable &TokenDbCommon::store()
68 {
69 StLock<Mutex> _(*this);
70
71 // if this is the first one, hook for lifetime
72 if (mAdornments.empty()) {
73 session().addReference(*this); // hold and slave to SSN lifetime
74 token().addCommon(*this); // register with Token
75 }
76
77 // return our (now active) adornments
78 return mAdornments;
79 }
80
81 void TokenDbCommon::resetAcls()
82 {
83 StLock<Mutex> _(*this);
84 if (!mAdornments.empty()) {
85 mAdornments.clearAdornments(); // clear ACL state
86 session().removeReference(*this); // unhook from SSN
87 }
88 token().removeCommon(*this); // unregister from Token
89 }
90
91 // Send out a "keychain" notification for this database
92 //
93 void TokenDbCommon::notify(NotificationEvent event)
94 {
95 DbCommon::notify(event, DLDbIdentifier(dbName().c_str(), gGuidAppleSdCSPDL,
96 subservice(), CSSM_SERVICE_DL | CSSM_SERVICE_CSP));
97 }
98
99
100 //
101 // Process (our part of) a "lock all" request.
102 // Smartcard tokens interpret a "lock" as a forced card reset, transmitted
103 // to tokend as an authenticate request.
104 // @@@ Virtual reset for multi-session tokens. Right now, we're using the sledge hammer.
105 //
106 void TokenDbCommon::lockProcessing()
107 {
108 Access access(token());
109 access().authenticate(CSSM_DB_ACCESS_RESET, NULL);
110 }
111
112 //
113 // Construct a TokenDatabase given subservice information.
114 // We are currently ignoring the 'name' argument.
115 //
116 TokenDatabase::TokenDatabase(uint32 ssid, Process &proc,
117 const char *name, const AccessCredentials *cred)
118 : Database(proc)
119 {
120 // locate Token object
121 RefPointer<Token> token = Token::find(ssid);
122
123 Session &session = process().session();
124 StLock<Mutex> _(session);
125 if (TokenDbCommon *dbcom = session.findFirst<TokenDbCommon, uint32>(&TokenDbCommon::subservice, ssid)) {
126 parent(*dbcom);
127 secdebug("tokendb", "open tokendb %p(%ld) at known common %p",
128 this, subservice(), dbcom);
129 } else {
130 // DbCommon not present; make a new one
131 parent(*new TokenDbCommon(proc.session(), *token, name));
132 secdebug("tokendb", "open tokendb %p(%ld) with new common %p",
133 this, subservice(), &common());
134 }
135 mOpenCreds = copy(cred, Allocator::standard());
136 proc.addReference(*this);
137 }
138
139 TokenDatabase::~TokenDatabase()
140 {
141 Allocator::standard().free(mOpenCreds);
142 }
143
144
145 //
146 // Basic Database virtual implementations
147 //
148 TokenDbCommon &TokenDatabase::common() const
149 {
150 return parent<TokenDbCommon>();
151 }
152
153 TokenDaemon &TokenDatabase::tokend()
154 {
155 return common().token().tokend();
156 }
157
158 const char *TokenDatabase::dbName() const
159 {
160 return common().dbName().c_str();
161 }
162
163 bool TokenDatabase::transient() const
164 {
165 //@@@ let tokend decide? Are there any secure transient keystores?
166 return false;
167 }
168
169
170 SecurityServerAcl &TokenDatabase::acl()
171 {
172 return token();
173 }
174
175 bool TokenDatabase::isLocked() const
176 {
177 Access access(token());
178 return access().isLocked();
179 }
180
181
182 //
183 // TokenDatabases implement the dbName-setting function.
184 // This sets the print name of the token, which is persistently
185 // stored in the token cache. So this is a de-facto rename of
186 // the token, at least on this system.
187 //
188 void TokenDatabase::dbName(const char *name)
189 {
190 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
191 }
192
193
194 //
195 // Given a key handle and CssmKey returned from tokend, create a Key representing
196 // it. This takes care of raw returns by turning them into keys of the process's
197 // local transient store.
198 //
199 RefPointer<Key> TokenDatabase::makeKey(KeyHandle hKey, const CssmKey *key,
200 const AclEntryPrototype *owner)
201 {
202 switch (key->blobType()) {
203 case CSSM_KEYBLOB_REFERENCE:
204 return new TokenKey(*this, hKey, key->header());
205 case CSSM_KEYBLOB_RAW:
206 return process().makeTemporaryKey(*key, 0, owner);
207 default:
208 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); // bad key return from tokend
209 }
210 //@@@ Server::releaseWhenDone(key);
211 }
212
213
214 //
215 // Adjust key attributes for newly created keys
216 //
217 static CSSM_KEYATTR_FLAGS modattrs(CSSM_KEYATTR_FLAGS attrs)
218 {
219 static const CSSM_KEYATTR_FLAGS CSSM_KEYATTR_RETURN_FLAGS = 0xff000000;
220 switch (attrs & CSSM_KEYATTR_RETURN_FLAGS) {
221 case CSSM_KEYATTR_RETURN_REF:
222 case CSSM_KEYATTR_RETURN_DATA:
223 break; // as requested
224 case CSSM_KEYATTR_RETURN_NONE:
225 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK);
226 case CSSM_KEYATTR_RETURN_DEFAULT:
227 if (attrs & CSSM_KEYATTR_PERMANENT)
228 attrs |= CSSM_KEYATTR_RETURN_REF;
229 else
230 attrs |= CSSM_KEYATTR_RETURN_DATA;
231 break;
232 }
233 return attrs;
234 }
235
236
237 //
238 // TokenDatabases support remote secret validation by sending a secret
239 // (aka passphrase et al) to tokend for processing.
240 //
241 bool TokenDatabase::validateSecret(const AclSubject *subject, const AccessCredentials *cred)
242 {
243 secdebug("tokendb", "%p attempting remote validation", this);
244 try {
245 Access access(token());
246 // @@@ Use cached mode
247 access().authenticate(CSSM_DB_ACCESS_READ, cred);
248 secdebug("tokendb", "%p remote validation successful", this);
249 return true;
250 }
251 catch (...) {
252 secdebug("tokendb", "%p remote validation failed", this);
253 // return false;
254 throw; // try not to mask error
255 }
256 }
257
258
259 //
260 // Key inquiries
261 //
262 void TokenDatabase::queryKeySizeInBits(Key &key, CssmKeySize &result)
263 {
264 Access access(token());
265 TRY
266 GUARD
267 access().queryKeySizeInBits(myKey(key).tokenHandle(), result);
268 DONE
269 }
270
271
272 //
273 // Signatures and MACs
274 //
275 void TokenDatabase::generateSignature(const Context &context, Key &key,
276 CSSM_ALGORITHMS signOnlyAlgorithm, const CssmData &data, CssmData &signature)
277 {
278 Access access(token(), key);
279 TRY
280 key.validate(CSSM_ACL_AUTHORIZATION_SIGN, context);
281 GUARD
282 access().generateSignature(context, myKey(key).tokenHandle(), data, signature, signOnlyAlgorithm);
283 DONE
284 }
285
286
287 void TokenDatabase::verifySignature(const Context &context, Key &key,
288 CSSM_ALGORITHMS verifyOnlyAlgorithm, const CssmData &data, const CssmData &signature)
289 {
290 Access access(token(), key);
291 TRY
292 GUARD
293 access().verifySignature(context, myKey(key).tokenHandle(), data, signature, verifyOnlyAlgorithm);
294 DONE
295 }
296
297 void TokenDatabase::generateMac(const Context &context, Key &key,
298 const CssmData &data, CssmData &mac)
299 {
300 Access access(token());
301 TRY
302 key.validate(CSSM_ACL_AUTHORIZATION_MAC, context);
303 GUARD
304 access().generateMac(context, myKey(key).tokenHandle(), data, mac);
305 DONE
306 }
307
308 void TokenDatabase::verifyMac(const Context &context, Key &key,
309 const CssmData &data, const CssmData &mac)
310 {
311 Access access(token());
312 TRY
313 key.validate(CSSM_ACL_AUTHORIZATION_MAC, context);
314 GUARD
315 access().verifyMac(context, myKey(key).tokenHandle(), data, mac);
316 DONE
317 }
318
319
320 //
321 // Encryption/decryption
322 //
323 void TokenDatabase::encrypt(const Context &context, Key &key,
324 const CssmData &clear, CssmData &cipher)
325 {
326 Access access(token());
327 TRY
328 key.validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context);
329 GUARD
330 access().encrypt(context, myKey(key).tokenHandle(), clear, cipher);
331 DONE
332 }
333
334
335 void TokenDatabase::decrypt(const Context &context, Key &key,
336 const CssmData &cipher, CssmData &clear)
337 {
338 Access access(token());
339 TRY
340 key.validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context);
341 GUARD
342 access().decrypt(context, myKey(key).tokenHandle(), cipher, clear);
343 DONE
344 }
345
346
347 //
348 // Key generation and derivation.
349 // Currently, we consider symmetric key generation to be fast, but
350 // asymmetric key generation to be (potentially) slow.
351 //
352 void TokenDatabase::generateKey(const Context &context,
353 const AccessCredentials *cred, const AclEntryPrototype *owner,
354 CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, RefPointer<Key> &newKey)
355 {
356 Access access(token());
357 TRY
358 GUARD
359 KeyHandle hKey;
360 CssmKey *result;
361 access().generateKey(context, cred, owner, usage, modattrs(attrs), hKey, result);
362 newKey = makeKey(hKey, result, owner);
363 DONE
364 }
365
366 void TokenDatabase::generateKey(const Context &context,
367 const AccessCredentials *cred, const AclEntryPrototype *owner,
368 CSSM_KEYUSE pubUsage, CSSM_KEYATTR_FLAGS pubAttrs,
369 CSSM_KEYUSE privUsage, CSSM_KEYATTR_FLAGS privAttrs,
370 RefPointer<Key> &publicKey, RefPointer<Key> &privateKey)
371 {
372 Access access(token());
373 TRY
374 GUARD
375 KeyHandle hPrivate, hPublic;
376 CssmKey *privKey, *pubKey;
377 access().generateKey(context, cred, owner,
378 pubUsage, modattrs(pubAttrs), privUsage, modattrs(privAttrs),
379 hPublic, pubKey, hPrivate, privKey);
380 publicKey = makeKey(hPublic, pubKey, owner);
381 privateKey = makeKey(hPrivate, privKey, owner);
382 DONE
383 }
384
385
386 //
387 // Key wrapping and unwrapping.
388 // Note that the key argument (the key in the context) is optional because of the special
389 // case of "cleartext" (null algorithm) wrapping for import/export.
390 //
391 void TokenDatabase::wrapKey(const Context &context, const AccessCredentials *cred,
392 Key *wrappingKey, Key &subjectKey,
393 const CssmData &descriptiveData, CssmKey &wrappedKey)
394 {
395 Access access(token());
396 InputKey cWrappingKey(wrappingKey);
397 InputKey cSubjectKey(subjectKey);
398 TRY
399 subjectKey.validate(context.algorithm() == CSSM_ALGID_NONE ?
400 CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED,
401 cred);
402 if (wrappingKey)
403 wrappingKey->validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context);
404 GUARD
405 CssmKey *rWrappedKey;
406 access().wrapKey(context, cred,
407 cWrappingKey, cWrappingKey, cSubjectKey, cSubjectKey,
408 descriptiveData, rWrappedKey);
409 wrappedKey = *rWrappedKey;
410 //@@@ ownership of wrappedKey.keyData() ??
411 DONE
412 }
413
414 void TokenDatabase::unwrapKey(const Context &context,
415 const AccessCredentials *cred, const AclEntryPrototype *owner,
416 Key *wrappingKey, Key *publicKey, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs,
417 const CssmKey wrappedKey, RefPointer<Key> &unwrappedKey, CssmData &descriptiveData)
418 {
419 Access access(token());
420 InputKey cWrappingKey(wrappingKey);
421 InputKey cPublicKey(publicKey);
422 TRY
423 if (wrappingKey)
424 wrappingKey->validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context);
425 // we are not checking access on the public key, if any
426 GUARD
427 KeyHandle hKey;
428 CssmKey *result;
429 access().unwrapKey(context, cred, owner,
430 cWrappingKey, cWrappingKey, cPublicKey, cPublicKey,
431 wrappedKey, usage, modattrs(attrs), descriptiveData, hKey, result);
432 unwrappedKey = makeKey(hKey, result, owner);
433 DONE
434 }
435
436
437 //
438 // Key derivation
439 //
440 void TokenDatabase::deriveKey(const Context &context, Key *sourceKey,
441 const AccessCredentials *cred, const AclEntryPrototype *owner,
442 CssmData *param, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, RefPointer<Key> &derivedKey)
443 {
444 Access access(token());
445 InputKey cSourceKey(sourceKey);
446 TRY
447 if (sourceKey)
448 sourceKey->validate(CSSM_ACL_AUTHORIZATION_DERIVE, cred);
449 GUARD
450 KeyHandle hKey;
451 CssmKey *result;
452 CssmData params = param ? *param : CssmData();
453 access().deriveKey(noDb, context,
454 cSourceKey, cSourceKey,
455 usage, modattrs(attrs), params, cred, owner,
456 hKey, result);
457 if (param) {
458 *param = params;
459 //@@@ leak? what's the rule here?
460 }
461 derivedKey = makeKey(hKey, result, owner);
462 DONE
463 }
464
465
466 //
467 // Miscellaneous CSSM functions
468 //
469 void TokenDatabase::getOutputSize(const Context &context, Key &key,
470 uint32 inputSize, bool encrypt, uint32 &result)
471 {
472 Access access(token());
473 TRY
474 GUARD
475 access().getOutputSize(context, myKey(key).tokenHandle(), inputSize, encrypt, result);
476 DONE
477 }
478
479
480 //
481 // (Re-)Authenticate the database.
482 // We use dbAuthenticate as the catch-all "do something about authentication" call.
483 //
484 void TokenDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode, const AccessCredentials *cred)
485 {
486 Access access(token());
487 TRY
488 GUARD
489 if (mode != CSSM_DB_ACCESS_RESET && cred) {
490 secdebug("tokendb", "%p authenticate calling validate", this);
491 int pin;
492 if (sscanf(cred->EntryTag, "PIN%d", &pin) == 1)
493 {
494 validate(CSSM_ACL_AUTHORIZATION_PREAUTH(pin), cred);
495 notify(kNotificationEventUnlocked);
496 return;
497 }
498 }
499
500 access().authenticate(mode, cred);
501 switch (mode) {
502 case CSSM_DB_ACCESS_RESET:
503 // this mode is known to trigger "lockdown" (i.e. reset)
504 common().resetAcls();
505 notify(kNotificationEventLocked);
506 break;
507 default:
508 {
509 // no idea what that did to the token;
510 // But let's remember the new creds for our own sake.
511 AccessCredentials *newCred = copy(cred, Allocator::standard());
512 Allocator::standard().free(mOpenCreds);
513 mOpenCreds = newCred;
514 break;
515 }
516 }
517 DONE
518 }
519
520 //
521 // Data access interface.
522 //
523 // Note that the attribute vectors are passed between our two IPC interfaces
524 // as relocated but contiguous memory blocks (to avoid an extra copy). This means
525 // you can read them at will, but can't change them in transit unless you're
526 // willing to repack them right here.
527 //
528 void TokenDatabase::findFirst(const CssmQuery &query,
529 CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength,
530 CssmData *data, RefPointer<Key> &key,
531 RefPointer<Database::Search> &rSearch, RefPointer<Database::Record> &rRecord,
532 CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength)
533 {
534 Access access(token());
535 RefPointer<Search> search = new Search(*this);
536 RefPointer<Record> record = new Record(*this);
537 TRY
538 KeyHandle hKey = noKey;
539 validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds());
540 GUARD
541 record->tokenHandle() = access().Tokend::ClientSession::findFirst(query,
542 inAttributes, inAttributesLength, search->tokenHandle(), NULL, hKey,
543 outAttributes, outAttributesLength);
544 if (!record->tokenHandle()) { // no match (but no other error)
545 rRecord = NULL; // return null record
546 return;
547 }
548 if (data) {
549 if (!hKey)
550 record->validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds());
551 CssmDbRecordAttributeData *noAttributes;
552 mach_msg_type_number_t noAttributesLength;
553 access().Tokend::ClientSession::findRecordHandle(record->tokenHandle(),
554 NULL, 0, data, hKey, noAttributes, noAttributesLength);
555 if (hKey) { // tokend returned a key reference & data
556 CssmKey &keyForm = *data->interpretedAs<CssmKey>(CSSMERR_CSP_INVALID_KEY);
557 key = new TokenKey(*this, hKey, keyForm.header());
558 }
559 }
560 rSearch = search->commit();
561 rRecord = record->commit();
562 DONE
563 }
564
565 void TokenDatabase::findNext(Database::Search *rSearch,
566 CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength,
567 CssmData *data, RefPointer<Key> &key, RefPointer<Database::Record> &rRecord,
568 CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength)
569 {
570 Access access(token());
571 RefPointer<Record> record = new Record(*this);
572 Search *search = safe_cast<Search *>(rSearch);
573 TRY
574 KeyHandle hKey = noKey;
575 validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds());
576 GUARD
577 record->tokenHandle() = access().Tokend::ClientSession::findNext(
578 search->tokenHandle(), inAttributes, inAttributesLength,
579 NULL, hKey, outAttributes, outAttributesLength);
580 if (!record->tokenHandle()) { // no more matches
581 releaseSearch(*search); // release search handle (consumed by EOD)
582 rRecord = NULL; // return null record
583 return;
584 }
585 if (data) {
586 if (!hKey)
587 record->validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds());
588 CssmDbRecordAttributeData *noAttributes;
589 mach_msg_type_number_t noAttributesLength;
590 access().Tokend::ClientSession::findRecordHandle(record->tokenHandle(),
591 NULL, 0, data, hKey, noAttributes, noAttributesLength);
592 if (hKey) { // tokend returned a key reference & data
593 CssmKey &keyForm = *data->interpretedAs<CssmKey>(CSSMERR_CSP_INVALID_KEY);
594 key = new TokenKey(*this, hKey, keyForm.header());
595 }
596 }
597 rRecord = record->commit();
598 DONE
599 }
600
601 void TokenDatabase::findRecordHandle(Database::Record *rRecord,
602 CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength,
603 CssmData *data, RefPointer<Key> &key,
604 CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength)
605 {
606 Access access(token());
607 Record *record = safe_cast<Record *>(rRecord);
608 access.add(*record);
609 TRY
610 KeyHandle hKey = noKey;
611 validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds());
612 if (data)
613 record->validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds());
614 GUARD
615 access().Tokend::ClientSession::findRecordHandle(record->tokenHandle(),
616 inAttributes, inAttributesLength, data, hKey, outAttributes, outAttributesLength);
617 rRecord = record;
618 if (hKey != noKey && data) { // tokend returned a key reference & data
619 CssmKey &keyForm = *data->interpretedAs<CssmKey>(CSSMERR_CSP_INVALID_KEY);
620 key = new TokenKey(*this, hKey, keyForm.header());
621 }
622 DONE
623 }
624
625 void TokenDatabase::insertRecord(CSSM_DB_RECORDTYPE recordType,
626 const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t attributesLength,
627 const CssmData &data, RefPointer<Database::Record> &rRecord)
628 {
629 Access access(token());
630 RefPointer<Record> record = new Record(*this);
631 access.add(*record);
632 TRY
633 validate(CSSM_ACL_AUTHORIZATION_DB_INSERT, openCreds());
634 GUARD
635 access().Tokend::ClientSession::insertRecord(recordType,
636 attributes, attributesLength, data, record->tokenHandle());
637 rRecord = record;
638 DONE
639 }
640
641 void TokenDatabase::modifyRecord(CSSM_DB_RECORDTYPE recordType, Record *rRecord,
642 const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t attributesLength,
643 const CssmData *data, CSSM_DB_MODIFY_MODE modifyMode)
644 {
645 Access access(token());
646 Record *record = safe_cast<Record *>(rRecord);
647 access.add(*record);
648 TRY
649 validate(CSSM_ACL_AUTHORIZATION_DB_MODIFY, openCreds());
650 record->validate(CSSM_ACL_AUTHORIZATION_DB_MODIFY, openCreds());
651 GUARD
652 access().Tokend::ClientSession::modifyRecord(recordType,
653 record->tokenHandle(), attributes, attributesLength, data, modifyMode);
654 DONE
655 }
656
657 void TokenDatabase::deleteRecord(Database::Record *rRecord)
658 {
659 Access access(token(), *this);
660 Record *record = safe_cast<Record *>(rRecord);
661 access.add(*record);
662 TRY
663 validate(CSSM_ACL_AUTHORIZATION_DB_DELETE, openCreds());
664 record->validate(CSSM_ACL_AUTHORIZATION_DB_DELETE, openCreds());
665 GUARD
666 access().Tokend::ClientSession::deleteRecord(record->tokenHandle());
667 DONE
668 }
669
670
671 //
672 // Record/Search object handling
673 //
674 TokenDatabase::Search::~Search()
675 {
676 if (mHandle)
677 try {
678 database().token().tokend().Tokend::ClientSession::releaseSearch(mHandle);
679 } catch (...) {
680 secdebug("tokendb", "%p release search handle %ld threw (ignored)",
681 this, mHandle);
682 }
683 }
684
685 TokenDatabase::Record::~Record()
686 {
687 if (mHandle)
688 try {
689 database().token().tokend().Tokend::ClientSession::releaseRecord(mHandle);
690 } catch (...) {
691 secdebug("tokendb", "%p release record handle %ld threw (ignored)",
692 this, mHandle);
693 }
694 }
695
696
697 //
698 // TokenAcl personality of Record
699 //
700 AclKind TokenDatabase::Record::aclKind() const
701 {
702 return objectAcl;
703 }
704
705 Token &TokenDatabase::Record::token()
706 {
707 return safer_cast<TokenDatabase &>(database()).token();
708 }
709
710 GenericHandle TokenDatabase::Record::tokenHandle() const
711 {
712 return Handler::tokenHandle();
713 }
714
715
716 //
717 // Local utility classes
718 //
719 void TokenDatabase::InputKey::setup(Key *key)
720 {
721 if (TokenKey *myKey = dynamic_cast<TokenKey *>(key)) {
722 // one of ours
723 mKeyHandle = myKey->tokenHandle();
724 mKeyPtr = NULL;
725 } else if (LocalKey *hisKey = dynamic_cast<LocalKey *>(key)) {
726 // a local key - turn into raw form
727 CssmClient::WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
728 wrap(hisKey->cssmKey(), mKey);
729 mKeyHandle = noKey;
730 mKeyPtr = &mKey;
731 } else {
732 // no key at all
733 mKeyHandle = noKey;
734 mKeyPtr = NULL;
735 }
736 }
737
738
739 TokenDatabase::InputKey::~InputKey()
740 {
741 if (mKeyPtr) {
742 //@@@ Server::csp().freeKey(mKey) ??
743 Server::csp()->allocator().free(mKey.keyData());
744 }
745 }