2 * Copyright (c) 2000-2001 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.
20 // database - database session management
22 #include "xdatabase.h"
23 #include "agentquery.h"
27 #include "cfnotifier.h" // legacy
28 #include "notifications.h"
29 #include "SecurityAgentClient.h"
30 #include <Security/acl_any.h> // for default owner ACLs
31 #include <Security/wrapkey.h>
32 #include <Security/endian.h>
36 // Create a Database object from initial parameters (create operation)
38 Database::Database(const DLDbIdentifier
&id
, const DBParameters
¶ms
, Process
&proc
,
39 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
)
40 : SecurityServerAcl(dbAcl
, CssmAllocator::standard()), process(proc
),
41 mValidData(false), version(0), mBlob(NULL
)
43 // save a copy of the credentials for later access control
44 mCred
= DataWalkers::copy(cred
, CssmAllocator::standard());
46 // create a new random signature to complete the DLDbIdentifier
48 Server::active().random(newSig
.bytes
);
49 DbIdentifier
ident(id
, newSig
);
51 // create common block and initialize
52 CommonMap
&commons
= proc
.session
.databases();
53 common
= new Common(ident
, commons
);
54 StLock
<Mutex
> _(*common
);
55 { StLock
<Mutex
> _(commons
);
56 assert(commons
.find(ident
) == commons
.end()); // better be new!
57 commons
[ident
] = common
;
60 // new common is now visible but we hold its lock
62 // establish the new master secret
63 establishNewSecrets(cred
, SecurityAgent::newDatabase
);
65 // set initial database parameters
66 common
->mParams
= params
;
69 common
->makeNewSecrets();
71 // establish initial ACL
73 cssmSetInitial(*owner
);
75 cssmSetInitial(new AnyAclSubject());
78 // for now, create the blob immediately
81 // register with process
82 process
.addDatabase(this);
84 secdebug("SSdb", "database %s(%p) created, common at %p",
85 common
->dbName(), this, common
);
86 IFDUMPING("SSdb", debugDump("creation complete"));
91 // Create a Database object from a database blob (decoding)
93 Database::Database(const DLDbIdentifier
&id
, const DbBlob
*blob
, Process
&proc
,
94 const AccessCredentials
*cred
)
95 : SecurityServerAcl(dbAcl
, CssmAllocator::standard()), process(proc
),
96 mValidData(false), version(0)
98 // perform basic validation on the incoming blob
100 blob
->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB
);
101 switch (blob
->version()) {
102 #if defined(COMPAT_OSX_10_0)
103 case blob
->version_MacOS_10_0
:
106 case blob
->version_MacOS_10_1
:
109 CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB
);
112 // save a copy of the credentials for later access control
113 mCred
= DataWalkers::copy(cred
, CssmAllocator::standard());
115 // check to see if we already know about this database
116 DbIdentifier
ident(id
, blob
->randomSignature
);
117 CommonMap
&commons
= proc
.session
.databases();
118 StLock
<Mutex
> mapLock(commons
);
119 CommonMap::iterator it
= commons
.find(ident
);
120 if (it
!= commons
.end()) {
122 common
= it
->second
; // reuse common component
123 //@@@ arbitrate sequence number here, perhaps update common->mParams
124 StLock
<Mutex
> _(*common
); // lock common against other users
127 "open database %s(%p) version %lx at known common %p(%d)",
128 common
->dbName(), this, blob
->version(), common
, int(common
->useCount
));
131 commons
[ident
] = common
= new Common(ident
, commons
);
132 common
->mParams
= blob
->params
;
134 secdebug("SSdb", "open database %s(%p) version %lx with new common %p",
135 common
->dbName(), this, blob
->version(), common
);
138 // register with process
139 process
.addDatabase(this);
141 mBlob
= blob
->copy();
142 IFDUMPING("SSdb", debugDump("end of decode"));
147 // Destroy a Database
149 Database::~Database()
151 secdebug("SSdb", "deleting database %s(%p) common %p (%d refs)",
152 common
->dbName(), this, common
, int(common
->useCount
));
153 IFDUMPING("SSdb", debugDump("deleting database instance"));
154 process
.removeDatabase(this);
155 CssmAllocator::standard().free(mCred
);
156 CssmAllocator::standard().free(mBlob
);
158 // take the commonLock to avoid races against re-use of the common
159 CommonMap
&commons
= process
.session
.databases();
160 StLock
<Mutex
> __(commons
);
161 if (--common
->useCount
== 0 && common
->isLocked()) {
162 // last use of this database, and it's locked - discard
163 IFDUMPING("SSdb", debugDump("discarding common"));
165 } else if (common
->useCount
== 0)
166 IFDUMPING("SSdb", debugDump("retained because it's unlocked"));
171 // (Re-)Authenticate the database. This changes the stored credentials.
173 void Database::authenticate(const AccessCredentials
*cred
)
175 StLock
<Mutex
> _(*common
);
176 AccessCredentials
*newCred
= DataWalkers::copy(cred
, CssmAllocator::standard());
177 CssmAllocator::standard().free(mCred
);
183 // Return the database blob, recalculating it as needed.
185 DbBlob
*Database::blob()
187 StLock
<Mutex
> _(*common
);
189 makeUnlocked(); // unlock to get master secret
190 encode(); // (re)encode blob if needed
192 activity(); // reset timeout
193 assert(validBlob()); // better have a valid blob now...
199 // Encode the current database as a blob.
200 // Note that this returns memory we own and keep.
201 // Caller must hold common lock.
203 void Database::encode()
205 DbBlob
*blob
= common
->encode(*this);
206 CssmAllocator::standard().free(mBlob
);
208 version
= common
->version
;
209 secdebug("SSdb", "encoded database %p common %p(%s) version %ld params=(%ld,%d)",
210 this, common
, dbName(), version
,
211 common
->mParams
.idleTimeout
, common
->mParams
.lockOnSleep
);
216 // Change the passphrase on a database
218 void Database::changePassphrase(const AccessCredentials
*cred
)
220 // get and hold the common lock (don't let other threads break in here)
221 StLock
<Mutex
> _(*common
);
223 // establish OLD secret - i.e. unlock the database
224 //@@@ do we want to leave the final lock state alone?
227 // establish NEW secret
228 establishNewSecrets(cred
, SecurityAgent::changePassphrase
);
229 common
->version
++; // blob state changed
230 secdebug("SSdb", "Database %s(%p) master secret changed", common
->dbName(), this);
231 encode(); // force rebuild of local blob
233 // send out a notification
234 KeychainNotifier::passphraseChanged(identifier());
236 // I guess this counts as an activity
242 // Extract the database master key as a proper Key object.
244 Key
*Database::extractMasterKey(Database
*db
,
245 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
246 uint32 usage
, uint32 attrs
)
248 // get and hold common lock
249 StLock
<Mutex
> _(*common
);
251 // unlock to establish master secret
254 // extract the raw cryptographic key
255 CssmClient::WrapKey
wrap(Server::csp(), CSSM_ALGID_NONE
);
257 wrap(common
->masterKey(), key
);
259 // make the key object and return it
260 return new Key(db
, key
, attrs
& Key::managedAttributes
, owner
);
265 // Construct a binary blob of moderate size that is suitable for constructing
266 // an index identifying this database.
267 // We construct this from the database's marker blob, which is created with
268 // the database is made, and stays stable thereafter.
269 // Note: Ownership of the index blob passes to the caller.
270 // @@@ This means that physical copies share this index.
272 void Database::getDbIndex(CssmData
&indexData
)
275 encode(); // force blob creation
277 CssmData signature
= CssmData::wrap(mBlob
->randomSignature
);
278 indexData
= CssmAutoData(CssmAllocator::standard(), signature
).release();
283 // Unlock this database (if needed) by obtaining the master secret in some
284 // suitable way and then proceeding to unlock with it.
285 // Does absolutely nothing if the database is already unlocked.
286 // The makeUnlocked forms are identical except the assume the caller already
287 // holds the common lock.
289 void Database::unlock()
291 StLock
<Mutex
> _(*common
);
295 void Database::makeUnlocked()
297 return makeUnlocked(mCred
);
300 void Database::makeUnlocked(const AccessCredentials
*cred
)
302 IFDUMPING("SSdb", debugDump("default procedures unlock"));
304 assert(mBlob
|| (mValidData
&& common
->hasMaster()));
305 establishOldSecrets(cred
);
306 activity(); // set timeout timer
307 } else if (!mValidData
) { // need to decode to get our ACLs, passphrase available
309 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
317 // The following unlock given an explicit passphrase, rather than using
318 // (special cred sample based) default procedures.
320 void Database::unlock(const CssmData
&passphrase
)
322 StLock
<Mutex
> _(*common
);
323 makeUnlocked(passphrase
);
326 void Database::makeUnlocked(const CssmData
&passphrase
)
329 if (decode(passphrase
))
332 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
333 } else if (!mValidData
) { // need to decode to get our ACLs, passphrase available
335 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
343 // Nonthrowing passphrase-based unlock. This returns false if unlock failed.
344 // Note that this requires an explicitly given passphrase.
345 // Caller must hold common lock.
347 bool Database::decode(const CssmData
&passphrase
)
350 common
->setup(mBlob
, passphrase
);
356 // Given the established master secret, decode the working keys and other
357 // functional secrets for this database. Return false (do NOT throw) if
358 // the decode fails. Call this in low(er) level code once you established
361 bool Database::decode()
364 assert(common
->hasMaster());
365 void *privateAclBlob
;
366 if (common
->unlock(mBlob
, &privateAclBlob
)) {
368 importBlob(mBlob
->publicAclBlob(), privateAclBlob
);
371 CssmAllocator::standard().free(privateAclBlob
);
374 secdebug("SSdb", "%p decode failed", this);
380 // Given an AccessCredentials for this database, wring out the existing primary
381 // database secret by whatever means necessary.
382 // On entry, caller must hold the database common lock. It will be held throughout.
383 // On exit, the crypto core has its master secret. If things go wrong,
384 // we will throw a suitable exception. Note that encountering any malformed
385 // credential sample will throw, but this is not guaranteed -- don't assume
386 // that NOT throwing means creds is entirely well-formed.
389 // Walk through the creds. Fish out those credentials (in order) that
390 // are for unlock processing (they have no ACL subject correspondents),
391 // and (try to) obey each in turn, until one produces a valid secret
392 // or you run out. If no special samples are found at all, interpret that as
393 // "use the system global default," which happens to be hard-coded right here.
395 void Database::establishOldSecrets(const AccessCredentials
*creds
)
397 list
<CssmSample
> samples
;
398 if (creds
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) {
399 for (list
<CssmSample
>::iterator it
= samples
.begin(); it
!= samples
.end(); it
++) {
400 TypedList
&sample
= *it
;
401 sample
.checkProper();
402 switch (sample
.type()) {
403 // interactively prompt the user - no additional data
404 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
:
406 secdebug("SSdb", "%p attempting interactive unlock", this);
407 QueryUnlock
query(*this);
408 if (query() == SecurityAgent::noReason
)
412 // try to use an explicitly given passphrase - Data:passphrase
413 case CSSM_SAMPLE_TYPE_PASSWORD
:
414 if (sample
.length() != 2)
415 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
416 secdebug("SSdb", "%p attempting passphrase unlock", this);
417 if (decode(sample
[1]))
420 // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
421 case CSSM_WORDID_SYMMETRIC_KEY
:
423 secdebug("SSdb", "%p attempting explicit key unlock", this);
424 common
->setup(mBlob
, keyFromCreds(sample
));
428 // explicitly defeat the default action but don't try anything in particular
429 case CSSM_WORDID_CANCELED
:
430 secdebug("SSdb", "%p defeat default action", this);
433 // Unknown sub-sample for unlocking.
434 // If we wanted to be fascist, we could now do
435 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
436 // But instead we try to be tolerant and continue on.
437 // This DOES however count as an explicit attempt at specifying unlock,
438 // so we will no longer try the default case below...
439 secdebug("SSdb", "%p unknown sub-sample unlock (%ld) ignored", this, sample
.type());
446 SystemKeychainKey
systemKeychain(kSystemUnlockFile
);
447 if (systemKeychain
.matches(mBlob
->randomSignature
)) {
448 secdebug("SSdb", "%p attempting system unlock", this);
449 common
->setup(mBlob
, CssmClient::Key(Server::csp(), systemKeychain
.key(), true));
454 QueryUnlock
query(*this);
455 if (query() == SecurityAgent::noReason
)
459 // out of options - no secret obtained
460 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
465 // Same thing, but obtain a new secret somehow and set it into the common.
467 void Database::establishNewSecrets(const AccessCredentials
*creds
, SecurityAgent::Reason reason
)
469 list
<CssmSample
> samples
;
470 if (creds
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, samples
)) {
471 for (list
<CssmSample
>::iterator it
= samples
.begin(); it
!= samples
.end(); it
++) {
472 TypedList
&sample
= *it
;
473 sample
.checkProper();
474 switch (sample
.type()) {
475 // interactively prompt the user
476 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
:
478 secdebug("SSdb", "%p specified interactive passphrase", this);
479 QueryNewPassphrase
query(*this, reason
);
480 CssmAutoData
passphrase(CssmAllocator::standard(CssmAllocator::sensitive
));
481 if (query(passphrase
) == SecurityAgent::noReason
) {
482 common
->setup(NULL
, passphrase
);
487 // try to use an explicitly given passphrase
488 case CSSM_SAMPLE_TYPE_PASSWORD
:
489 secdebug("SSdb", "%p specified explicit passphrase", this);
490 if (sample
.length() != 2)
491 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
492 common
->setup(NULL
, sample
[1]);
494 // try to open with a given master key
495 case CSSM_WORDID_SYMMETRIC_KEY
:
496 secdebug("SSdb", "%p specified explicit master key", this);
497 common
->setup(NULL
, keyFromCreds(sample
));
499 // explicitly defeat the default action but don't try anything in particular
500 case CSSM_WORDID_CANCELED
:
501 secdebug("SSdb", "%p defeat default action", this);
504 // Unknown sub-sample for acquiring new secret.
505 // If we wanted to be fascist, we could now do
506 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
507 // But instead we try to be tolerant and continue on.
508 // This DOES however count as an explicit attempt at specifying unlock,
509 // so we will no longer try the default case below...
510 secdebug("SSdb", "%p unknown sub-sample acquisition (%ld) ignored",
511 this, sample
.type());
516 // default action -- interactive (only)
517 QueryNewPassphrase
query(*this, reason
);
518 CssmAutoData
passphrase(CssmAllocator::standard(CssmAllocator::sensitive
));
519 if (query(passphrase
) == SecurityAgent::noReason
) {
520 common
->setup(NULL
, passphrase
);
525 // out of options - no secret obtained
526 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
531 // Given a (truncated) Database credentials TypedList specifying a master key,
532 // locate the key and return a reference to it.
534 CssmClient::Key
Database::keyFromCreds(const TypedList
&sample
)
536 // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY)
537 assert(sample
.type() == CSSM_WORDID_SYMMETRIC_KEY
);
538 if (sample
.length() != 3
539 || sample
[1].type() != CSSM_LIST_ELEMENT_DATUM
540 || sample
[2].type() != CSSM_LIST_ELEMENT_DATUM
)
541 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
542 CSSM_CSP_HANDLE
&handle
= *sample
[1].data().interpretedAs
<CSSM_CSP_HANDLE
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
543 CssmKey
&key
= *sample
[2].data().interpretedAs
<CssmKey
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
545 if (key
.header().cspGuid() == gGuidAppleCSPDL
) {
546 // handleOrKey is a SecurityServer KeyHandle; ignore key argument
547 return Server::key(handle
);
549 // not a KeyHandle reference; use key as a raw key
550 if (key
.header().blobType() != CSSM_KEYBLOB_RAW
)
551 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
552 if (key
.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY
)
553 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
554 return CssmClient::Key(Server::csp(), key
, true);
560 // Verify a putative database passphrase.
561 // If the database is already unlocked, just check the passphrase.
562 // Otherwise, unlock with that passphrase and report success.
563 // Caller must hold the common lock.
565 bool Database::validatePassphrase(const CssmData
&passphrase
) const
567 if (common
->hasMaster()) {
568 // verify against known secret
569 return common
->validatePassphrase(passphrase
);
571 // no master secret - perform "blind" unlock to avoid actual unlock
573 DatabaseCryptoCore test
;
574 test
.setup(mBlob
, passphrase
);
575 test
.decodeCore(mBlob
, NULL
);
585 // Lock this database
587 void Database::lock()
594 // Lock all databases we know of.
595 // This is an interim stop-gap measure, until we can work out how database
596 // state should interact with true multi-session operation.
598 void Database::lockAllDatabases(CommonMap
&commons
, bool forSleep
)
600 StLock
<Mutex
> _(commons
); // hold all changes to Common map
601 for (CommonMap::iterator it
= commons
.begin(); it
!= commons
.end(); it
++)
602 it
->second
->lock(true, forSleep
); // lock, already holding commonLock
607 // Given a Key for this database, encode it into a blob and return it.
609 KeyBlob
*Database::encodeKey(const CssmKey
&key
, const CssmData
&pubAcl
, const CssmData
&privAcl
)
613 // tell the cryptocore to form the key blob
614 return common
->encodeKeyCore(key
, pubAcl
, privAcl
);
619 // Given a "blobbed" key for this database, decode it into its real
620 // key object and (re)populate its ACL.
622 void Database::decodeKey(KeyBlob
*blob
, CssmKey
&key
, void * &pubAcl
, void * &privAcl
)
624 unlock(); // we need our keys
626 common
->decodeKeyCore(blob
, key
, pubAcl
, privAcl
);
627 // memory protocol: pubAcl points into blob; privAcl was allocated
634 // Modify database parameters
636 void Database::setParameters(const DBParameters
¶ms
)
638 StLock
<Mutex
> _(*common
);
640 common
->mParams
= params
;
641 common
->version
++; // invalidate old blobs
643 secdebug("SSdb", "%p common %p(%s) set params=(%ld,%d)",
644 this, common
, dbName(), params
.idleTimeout
, params
.lockOnSleep
);
649 // Retrieve database parameters
651 void Database::getParameters(DBParameters
¶ms
)
653 StLock
<Mutex
> _(*common
);
655 params
= common
->mParams
;
656 //activity(); // getting parameters does not reset the idle timer
661 // Intercept ACL change requests and reset blob validity
663 void Database::instantiateAcl()
665 StLock
<Mutex
> _(*common
);
669 void Database::changedAcl()
671 StLock
<Mutex
> _(*common
);
675 const Database
*Database::relatedDatabase() const
682 #if defined(DEBUGDUMP)
684 void Database::debugDump(const char *msg
)
687 const Signature
&sig
= common
->identifier();
688 uint32 sig4
; memcpy(&sig4
, sig
.bytes
, sizeof(sig4
));
689 Debug::dump("** %s(%8.8lx) common=%p(%ld) %s\n",
690 common
->dbName(), sig4
, common
, common
->useCount
, msg
);
692 Debug::dump(" locked");
694 Time::Absolute when
= common
->when();
695 time_t whenTime
= time_t(when
);
696 Debug::dump(" UNLOCKED(%24.24s/%.2g)", ctime(&whenTime
),
697 (when
- Time::now()).seconds());
699 Debug::dump(" %s blobversion=%ld/%ld %svalidData",
700 (common
->isValid() ? "validkeys" : "!validkeys"),
701 version
, common
->version
,
702 (mValidData
? "" : "!"));
703 Debug::dump(" Params=(%ld %d)\n",
704 common
->mParams
.idleTimeout
, common
->mParams
.lockOnSleep
);
711 // Database::Common basic features
713 Database::Common::Common(const DbIdentifier
&id
, CommonMap
&commonPool
)
714 : pool(commonPool
), mIdentifier(id
), sequence(0), useCount(0), version(1),
715 mIsLocked(true), mValidParams(false)
718 Database::Common::~Common()
720 // explicitly unschedule ourselves
721 Server::active().clearTimer(this);
722 pool
.erase(identifier());
726 void Database::Common::makeNewSecrets()
728 // we already have a master key (right?)
731 // tell crypto core to generate the use keys
732 DatabaseCryptoCore::generateNewSecrets();
734 // we're now officially "unlocked"; set the timer
740 void Database::discard(Common
*common
)
742 // LOCKING: pool lock held, *common NOT held
743 secdebug("SSdb", "discarding dbcommon %p (no users, locked)", common
);
749 // All unlocking activity ultimately funnels through this method.
750 // This unlocks a Common using the secrets setup in its crypto core
751 // component, and performs all the housekeeping needed to represent
754 bool Database::Common::unlock(DbBlob
*blob
, void **privateAclBlob
)
757 // Tell the cryptocore to (try to) decode itself. This will fail
758 // in an astonishing variety of ways if the passphrase is wrong.
760 decodeCore(blob
, privateAclBlob
);
761 secdebug("SSdb", "%p unlock successful", this);
763 secdebug("SSdb", "%p unlock failed", this);
767 // get the database parameters only if we haven't got them yet
769 mParams
= blob
->params
;
770 n2hi(mParams
.idleTimeout
);
771 mValidParams
= true; // sticky
774 // now successfully unlocked
780 // broadcast unlock notification
781 KeychainNotifier::unlock(identifier());
786 void Database::Common::lock(bool holdingCommonLock
, bool forSleep
)
788 StLock
<Mutex
> locker(*this);
790 if (forSleep
&& !mParams
.lockOnSleep
)
791 return; // it doesn't want to
794 DatabaseCryptoCore::invalidate();
795 KeychainNotifier::lock(identifier());
796 Server::active().clearTimer(this);
798 // if no database refers to us now, we're history
799 StLock
<Mutex
> _(pool
, false);
800 if (!holdingCommonLock
)
803 locker
.unlock(); // release object lock
809 DbBlob
*Database::Common::encode(Database
&db
)
811 assert(!isLocked()); // must have been unlocked by caller
813 // export database ACL to blob form
814 CssmData pubAcl
, privAcl
;
815 db
.exportBlob(pubAcl
, privAcl
);
817 // tell the cryptocore to form the blob
819 form
.randomSignature
= identifier();
820 form
.sequence
= sequence
;
821 form
.params
= mParams
;
822 h2ni(form
.params
.idleTimeout
);
825 DbBlob
*blob
= encodeCore(form
, pubAcl
, privAcl
);
828 db
.allocator
.free(pubAcl
);
829 db
.allocator
.free(privAcl
);
835 // Perform deferred lock processing for a database.
837 void Database::Common::action()
839 secdebug("SSdb", "common %s(%p) locked by timer (%d refs)",
840 dbName(), this, int(useCount
));
844 void Database::Common::activity()
847 Server::active().setTimer(this, Time::Interval(int(mParams
.idleTimeout
)));
852 // Implementation of a "system keychain unlock key store"
854 SystemKeychainKey::SystemKeychainKey(const char *path
)
857 // explicitly set up a key header for a raw 3DES key
858 CssmKey::Header
&hdr
= mKey
.header();
859 hdr
.blobType(CSSM_KEYBLOB_RAW
);
860 hdr
.blobFormat(CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
);
861 hdr
.keyClass(CSSM_KEYCLASS_SESSION_KEY
);
862 hdr
.algorithm(CSSM_ALGID_3DES_3KEY_EDE
);
864 hdr
.KeyUsage
= CSSM_KEYUSE_ANY
;
865 mKey
= CssmData::wrap(mBlob
.masterKey
);
868 SystemKeychainKey::~SystemKeychainKey()
872 bool SystemKeychainKey::matches(const DbBlob::Signature
&signature
)
874 return update() && signature
== mBlob
.signature
;
877 bool SystemKeychainKey::update()
879 // if we checked recently, just assume it's okay
880 if (mUpdateThreshold
> Time::now())
885 if (::stat(mPath
.c_str(), &st
)) {
886 // something wrong with the file; can't use it
887 mUpdateThreshold
= Time::now() + Time::Interval(checkDelay
);
888 return mValid
= false;
890 if (mValid
&& Time::Absolute(st
.st_mtimespec
) == mCachedDate
)
892 mUpdateThreshold
= Time::now() + Time::Interval(checkDelay
);
895 secdebug("syskc", "reading system unlock record from %s", mPath
.c_str());
896 AutoFileDesc
fd(mPath
, O_RDONLY
);
897 if (fd
.read(mBlob
) != sizeof(mBlob
))
899 if (mBlob
.isValid()) {
900 mCachedDate
= st
.st_mtimespec
;
901 return mValid
= true;
903 return mValid
= false;
905 secdebug("syskc", "system unlock record not available");