2  * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved. 
   8  * This file contains Original Code and/or Modifications of Original Code 
   9  * as defined in and that are subject to the Apple Public Source License 
  10  * Version 2.0 (the 'License'). You may not use this file except in 
  11  * compliance with the License. Please obtain a copy of the License at 
  12  * http://www.opensource.apple.com/apsl/ and read it before using this 
  15  * The Original Code and all software distributed under the License are 
  16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  20  * Please see the License for the specific language governing rights and 
  21  * limitations under the License. 
  23  * @APPLE_LICENSE_HEADER_END@ 
  28 // kcdatabase - software database container implementation. 
  30 // General implementation notes: 
  31 // This leverages LocalDatabase/LocalKey for cryptography, and adds the 
  32 //  storage coder/decoder logic that implements "keychain" databases in their 
  33 //  intricately choreographed dance between securityd and the AppleCSPDL. 
  34 // As always, Database objects are lifetime-bound to their Process referent; 
  35 //  they can also be destroyed explicitly with a client release call. 
  36 // DbCommons are reference-held by their Databases, with one extra special 
  37 //  reference (from the Session) introduced when the database unlocks, and 
  38 //  removed when it locks again. That way, an unused DbCommon dies when it 
  39 //  is locked or when the Session dies, whichever happens earlier. 
  40 // There is (as yet) no global-scope Database object for Keychain databases. 
  42 #include "kcdatabase.h" 
  43 #include "agentquery.h" 
  47 #include "notifications.h" 
  48 #include <security_agent_client/agentclient.h> 
  49 #include <security_cdsa_utilities/acl_any.h>    // for default owner ACLs 
  50 #include <security_cdsa_client/wrapkey.h> 
  51 #include <security_cdsa_client/genkey.h> 
  52 #include <security_cdsa_client/signclient.h> 
  53 #include <security_cdsa_client/cryptoclient.h> 
  54 #include <security_cdsa_client/macclient.h> 
  55 #include <securityd_client/dictionary.h> 
  56 #include <security_utilities/endian.h> 
  60 // Create a Database object from initial parameters (create operation) 
  62 KeychainDatabase::KeychainDatabase(const DLDbIdentifier 
&id
, const DBParameters 
¶ms
, Process 
&proc
, 
  63             const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
) 
  64     : LocalDatabase(proc
), mValidData(false), version(0), mBlob(NULL
) 
  66     // save a copy of the credentials for later access control 
  67     mCred 
= DataWalkers::copy(cred
, Allocator::standard()); 
  69     // create a new random signature to complete the DLDbIdentifier 
  70     DbBlob::Signature newSig
; 
  71     Server::active().random(newSig
.bytes
); 
  72     DbIdentifier 
ident(id
, newSig
); 
  74     // create common block and initialize 
  75         RefPointer
<KeychainDbCommon
> newCommon 
= new KeychainDbCommon(proc
.session(), ident
); 
  76         StLock
<Mutex
> _(*newCommon
); 
  78         // new common is now visible (in ident-map) but we hold its lock 
  80         // establish the new master secret 
  81         establishNewSecrets(cred
, SecurityAgent::newDatabase
); 
  83         // set initial database parameters 
  84         common().mParams 
= params
; 
  86         // the common is "unlocked" now 
  87         common().makeNewSecrets(); 
  89         // establish initial ACL 
  91                 cssmSetInitial(*owner
); 
  93                 cssmSetInitial(new AnyAclSubject()); 
  96     // for now, create the blob immediately 
  99         proc
.addReference(*this); 
 100         secdebug("SSdb", "database %s(%p) created, common at %p", 
 101                 common().dbName(), this, &common()); 
 106 // Create a Database object from a database blob (decoding) 
 108 KeychainDatabase::KeychainDatabase(const DLDbIdentifier 
&id
, const DbBlob 
*blob
, Process 
&proc
, 
 109     const AccessCredentials 
*cred
) 
 110         : LocalDatabase(proc
), mValidData(false), version(0) 
 112     // perform basic validation on the incoming blob 
 114     blob
->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB
); 
 115     switch (blob
->version()) { 
 116 #if defined(COMPAT_OSX_10_0) 
 117     case blob
->version_MacOS_10_0
: 
 120     case blob
->version_MacOS_10_1
: 
 123         CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB
); 
 126     // save a copy of the credentials for later access control 
 127     mCred 
= DataWalkers::copy(cred
, Allocator::standard()); 
 128     mBlob 
= blob
->copy(); 
 130     // check to see if we already know about this database 
 131     DbIdentifier 
ident(id
, blob
->randomSignature
); 
 132         Session 
&session 
= process().session(); 
 133         StLock
<Mutex
> _(session
); 
 134         if (KeychainDbCommon 
*dbcom 
= 
 135                         session
.findFirst
<KeychainDbCommon
, const DbIdentifier 
&>(&KeychainDbCommon::identifier
, ident
)) { 
 137                 //@@@ arbitrate sequence number here, perhaps update common().mParams 
 139                         "open database %s(%p) version %lx at known common %p", 
 140                         common().dbName(), this, blob
->version(), &common()); 
 142                 // DbCommon not present; make a new one 
 143                 parent(*new KeychainDbCommon(proc
.session(), ident
)); 
 144                 common().mParams 
= blob
->params
; 
 145                 secdebug("SSdb", "open database %s(%p) version %lx with new common %p", 
 146                         common().dbName(), this, blob
->version(), &common()); 
 148         proc
.addReference(*this); 
 153 // Destroy a Database 
 155 KeychainDatabase::~KeychainDatabase() 
 157     secdebug("SSdb", "deleting database %s(%p) common %p", 
 158         common().dbName(), this, &common()); 
 159     Allocator::standard().free(mCred
); 
 160         Allocator::standard().free(mBlob
); 
 165 // Basic Database virtual implementations 
 167 KeychainDbCommon 
&KeychainDatabase::common() const 
 169         return parent
<KeychainDbCommon
>(); 
 172 const char *KeychainDatabase::dbName() const 
 174         return common().dbName(); 
 178 static inline KeychainKey 
&myKey(Key 
*key
) 
 180         return *safe_cast
<KeychainKey 
*>(key
); 
 185 // (Re-)Authenticate the database. This changes the stored credentials. 
 187 void KeychainDatabase::authenticate(const AccessCredentials 
*cred
) 
 189         StLock
<Mutex
> _(common()); 
 190         AccessCredentials 
*newCred 
= DataWalkers::copy(cred
, Allocator::standard()); 
 191     Allocator::standard().free(mCred
); 
 197 // Make a new KeychainKey 
 199 RefPointer
<Key
> KeychainDatabase::makeKey(const CssmKey 
&newKey
, 
 200         uint32 moreAttributes
, const AclEntryPrototype 
*owner
) 
 202         return new KeychainKey(*this, newKey
, moreAttributes
, owner
); 
 207 // Return the database blob, recalculating it as needed. 
 209 DbBlob 
*KeychainDatabase::blob() 
 211         StLock
<Mutex
> _(common()); 
 213         makeUnlocked();                 // unlock to get master secret 
 214                 encode();                               // (re)encode blob if needed 
 216     activity();                                 // reset timeout 
 217         assert(validBlob());            // better have a valid blob now... 
 223 // Encode the current database as a blob. 
 224 // Note that this returns memory we own and keep. 
 225 // Caller must hold common lock. 
 227 void KeychainDatabase::encode() 
 229         DbBlob 
*blob 
= common().encode(*this); 
 230         Allocator::standard().free(mBlob
); 
 232         version 
= common().version
; 
 233         secdebug("SSdb", "encoded database %p common %p(%s) version %ld params=(%ld,%d)", 
 234                 this, &common(), dbName(), version
, 
 235                 common().mParams
.idleTimeout
, common().mParams
.lockOnSleep
); 
 240 // Change the passphrase on a database 
 242 void KeychainDatabase::changePassphrase(const AccessCredentials 
*cred
) 
 244         // get and hold the common lock (don't let other threads break in here) 
 245         StLock
<Mutex
> _(common()); 
 247         // establish OLD secret - i.e. unlock the database 
 248         //@@@ do we want to leave the final lock state alone? 
 251     // establish NEW secret 
 252         establishNewSecrets(cred
, SecurityAgent::changePassphrase
); 
 253         common().version
++;     // blob state changed 
 254         secdebug("SSdb", "Database %s(%p) master secret changed", common().dbName(), this); 
 255         encode();                       // force rebuild of local blob 
 257         // send out a notification 
 258         notify(kNotificationEventPassphraseChanged
); 
 260     // I guess this counts as an activity 
 266 // Extract the database master key as a proper Key object. 
 268 RefPointer
<Key
> KeychainDatabase::extractMasterKey(Database 
&db
, 
 269         const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
, 
 270         uint32 usage
, uint32 attrs
) 
 272         // get and hold common lock 
 273         StLock
<Mutex
> _(common()); 
 275         // unlock to establish master secret 
 278         // extract the raw cryptographic key 
 279         CssmClient::WrapKey 
wrap(Server::csp(), CSSM_ALGID_NONE
); 
 281         wrap(common().masterKey(), key
); 
 283         // make the key object and return it 
 284         return new KeychainKey(db
, key
, attrs 
& Key::managedAttributes
, owner
); 
 289 // Construct a binary blob of moderate size that is suitable for constructing 
 290 // an index identifying this database. 
 291 // We construct this from the database's marker blob, which is created with 
 292 // the database is made, and stays stable thereafter. 
 293 // Note: Ownership of the index blob passes to the caller. 
 294 // @@@ This means that physical copies share this index. 
 296 void KeychainDatabase::getDbIndex(CssmData 
&indexData
) 
 299                 encode();       // force blob creation 
 301         CssmData signature 
= CssmData::wrap(mBlob
->randomSignature
); 
 302         indexData 
= CssmAutoData(Allocator::standard(), signature
).release(); 
 307 // Unlock this database (if needed) by obtaining the master secret in some 
 308 // suitable way and then proceeding to unlock with it. 
 309 // Does absolutely nothing if the database is already unlocked. 
 310 // The makeUnlocked forms are identical except the assume the caller already 
 311 // holds the common lock. 
 313 void KeychainDatabase::unlockDb() 
 315         StLock
<Mutex
> _(common()); 
 319 void KeychainDatabase::makeUnlocked() 
 321         return makeUnlocked(mCred
); 
 324 void KeychainDatabase::makeUnlocked(const AccessCredentials 
*cred
) 
 327                 secdebug("SSdb", "%p(%p) unlocking for makeUnlocked()", this, &common()); 
 328         assert(mBlob 
|| (mValidData 
&& common().hasMaster())); 
 329                 establishOldSecrets(cred
); 
 330                 common().setUnlocked(); // mark unlocked 
 331                 activity();                             // set timeout timer 
 332         } else if (!mValidData
) {       // need to decode to get our ACLs, master secret available 
 333                 secdebug("SSdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common()); 
 335                         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 343 // The following unlock given an explicit passphrase, rather than using 
 344 // (special cred sample based) default procedures. 
 346 void KeychainDatabase::unlockDb(const CssmData 
&passphrase
) 
 348         StLock
<Mutex
> _(common()); 
 349         makeUnlocked(passphrase
); 
 352 void KeychainDatabase::makeUnlocked(const CssmData 
&passphrase
) 
 355                 if (decode(passphrase
)) 
 358                         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 359         } else if (!mValidData
) {       // need to decode to get our ACLs, passphrase available 
 361                         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 369 // Nonthrowing passphrase-based unlock. This returns false if unlock failed. 
 370 // Note that this requires an explicitly given passphrase. 
 371 // Caller must hold common lock. 
 373 bool KeychainDatabase::decode(const CssmData 
&passphrase
) 
 376         common().setup(mBlob
, passphrase
); 
 382 // Given the established master secret, decode the working keys and other 
 383 // functional secrets for this database. Return false (do NOT throw) if 
 384 // the decode fails. Call this in low(er) level code once you established 
 387 bool KeychainDatabase::decode() 
 390         assert(common().hasMaster()); 
 391         void *privateAclBlob
; 
 392         if (common().unlockDb(mBlob
, &privateAclBlob
)) { 
 394                         importBlob(mBlob
->publicAclBlob(), privateAclBlob
); 
 397                 Allocator::standard().free(privateAclBlob
); 
 400         secdebug("SSdb", "%p decode failed", this); 
 406 // Given an AccessCredentials for this database, wring out the existing primary 
 407 // database secret by whatever means necessary. 
 408 // On entry, caller must hold the database common lock. It will be held throughout. 
 409 // On exit, the crypto core has its master secret. If things go wrong, 
 410 // we will throw a suitable exception. Note that encountering any malformed 
 411 // credential sample will throw, but this is not guaranteed -- don't assume 
 412 // that NOT throwing means creds is entirely well-formed (it may just be good 
 413 // enough to work THIS time). 
 416 // Walk through the creds. Fish out those credentials (in order) that 
 417 // are for unlock processing (they have no ACL subject correspondents), 
 418 // and (try to) obey each in turn, until one produces a valid secret 
 419 // or you run out. If no special samples are found at all, interpret that as 
 420 // "use the system global default," which happens to be hard-coded right here. 
 422 void KeychainDatabase::establishOldSecrets(const AccessCredentials 
*creds
) 
 424         list
<CssmSample
> samples
; 
 425         if (creds 
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) { 
 426                 for (list
<CssmSample
>::iterator it 
= samples
.begin(); it 
!= samples
.end(); it
++) { 
 427                         TypedList 
&sample 
= *it
; 
 428                         sample
.checkProper(); 
 429                         switch (sample
.type()) { 
 430                         // interactively prompt the user - no additional data 
 431                         case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: 
 433                                 secdebug("SSdb", "%p attempting interactive unlock", this); 
 434                                 QueryUnlock 
query(*this); 
 435                                 query
.inferHints(Server::process()); 
 436                                 if (query() == SecurityAgent::noReason
) 
 440                         // try to use an explicitly given passphrase - Data:passphrase 
 441                         case CSSM_SAMPLE_TYPE_PASSWORD
: 
 442                                 if (sample
.length() != 2) 
 443                                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
 444                                 secdebug("SSdb", "%p attempting passphrase unlock", this); 
 445                                 if (decode(sample
[1])) 
 448                         // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey 
 449                         case CSSM_WORDID_SYMMETRIC_KEY
: 
 451                                 secdebug("SSdb", "%p attempting explicit key unlock", this); 
 452                                 common().setup(mBlob
, keyFromCreds(sample
)); 
 456                         // explicitly defeat the default action but don't try anything in particular 
 457                         case CSSM_WORDID_CANCELED
: 
 458                                 secdebug("SSdb", "%p defeat default action", this); 
 461                                 // Unknown sub-sample for unlocking. 
 462                                 // If we wanted to be fascist, we could now do 
 463                                 //  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED); 
 464                                 // But instead we try to be tolerant and continue on. 
 465                                 // This DOES however count as an explicit attempt at specifying unlock, 
 466                                 // so we will no longer try the default case below... 
 467                                 secdebug("SSdb", "%p unknown sub-sample unlock (%ld) ignored", this, sample
.type()); 
 475                 // attempt system-keychain unlock 
 476                 SystemKeychainKey 
systemKeychain(kSystemUnlockFile
); 
 477                 if (systemKeychain
.matches(mBlob
->randomSignature
)) { 
 478                         secdebug("SSdb", "%p attempting system unlock", this); 
 479                         common().setup(mBlob
, CssmClient::Key(Server::csp(), systemKeychain
.key(), true)); 
 484                 // attempt interactive unlock 
 485                 QueryUnlock 
query(*this); 
 486                 query
.inferHints(Server::process()); 
 487                 if (query() == SecurityAgent::noReason
) 
 491         // out of options - no secret obtained 
 492         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 497 // Same thing, but obtain a new secret somehow and set it into the common. 
 499 void KeychainDatabase::establishNewSecrets(const AccessCredentials 
*creds
, SecurityAgent::Reason reason
) 
 501         list
<CssmSample
> samples
; 
 502         if (creds 
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, samples
)) { 
 503                 for (list
<CssmSample
>::iterator it 
= samples
.begin(); it 
!= samples
.end(); it
++) { 
 504                         TypedList 
&sample 
= *it
; 
 505                         sample
.checkProper(); 
 506                         switch (sample
.type()) { 
 507                         // interactively prompt the user 
 508                         case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: 
 510                                 secdebug("SSdb", "%p specified interactive passphrase", this); 
 511                                 QueryNewPassphrase 
query(*this, reason
); 
 512                                 query
.inferHints(Server::process()); 
 513                                 CssmAutoData 
passphrase(Allocator::standard(Allocator::sensitive
)); 
 514                                 if (query(passphrase
) == SecurityAgent::noReason
) { 
 515                                         common().setup(NULL
, passphrase
); 
 520                         // try to use an explicitly given passphrase 
 521                         case CSSM_SAMPLE_TYPE_PASSWORD
: 
 522                                 secdebug("SSdb", "%p specified explicit passphrase", this); 
 523                                 if (sample
.length() != 2) 
 524                                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
 525                                 common().setup(NULL
, sample
[1]); 
 527                         // try to open with a given master key 
 528                         case CSSM_WORDID_SYMMETRIC_KEY
: 
 529                                 secdebug("SSdb", "%p specified explicit master key", this); 
 530                                 common().setup(NULL
, keyFromCreds(sample
)); 
 532                         // explicitly defeat the default action but don't try anything in particular 
 533                         case CSSM_WORDID_CANCELED
: 
 534                                 secdebug("SSdb", "%p defeat default action", this); 
 537                                 // Unknown sub-sample for acquiring new secret. 
 538                                 // If we wanted to be fascist, we could now do 
 539                                 //  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED); 
 540                                 // But instead we try to be tolerant and continue on. 
 541                                 // This DOES however count as an explicit attempt at specifying unlock, 
 542                                 // so we will no longer try the default case below... 
 543                                 secdebug("SSdb", "%p unknown sub-sample acquisition (%ld) ignored", 
 544                                         this, sample
.type()); 
 549                 // default action -- interactive (only) 
 550                 QueryNewPassphrase 
query(*this, reason
); 
 551         query
.inferHints(Server::process()); 
 552                 CssmAutoData 
passphrase(Allocator::standard(Allocator::sensitive
)); 
 553                 if (query(passphrase
) == SecurityAgent::noReason
) { 
 554                         common().setup(NULL
, passphrase
); 
 559         // out of options - no secret obtained 
 560         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 565 // Given a (truncated) Database credentials TypedList specifying a master key, 
 566 // locate the key and return a reference to it. 
 568 CssmClient::Key 
KeychainDatabase::keyFromCreds(const TypedList 
&sample
) 
 570         // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY) 
 571         assert(sample
.type() == CSSM_WORDID_SYMMETRIC_KEY
); 
 572         if (sample
.length() != 3 
 573                 || sample
[1].type() != CSSM_LIST_ELEMENT_DATUM
 
 574                 || sample
[2].type() != CSSM_LIST_ELEMENT_DATUM
) 
 575                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
 576         CSSM_CSP_HANDLE 
&handle 
= *sample
[1].data().interpretedAs
<CSSM_CSP_HANDLE
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
 577         CssmKey 
&key 
= *sample
[2].data().interpretedAs
<CssmKey
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
 579         if (key
.header().cspGuid() == gGuidAppleCSPDL
) { 
 580                 // handleOrKey is a SecurityServer KeyHandle; ignore key argument 
 581                 return myKey(Server::key(handle
)); 
 583                 // not a KeyHandle reference; use key as a raw key 
 584                 if (key
.header().blobType() != CSSM_KEYBLOB_RAW
) 
 585                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
); 
 586                 if (key
.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY
) 
 587                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
); 
 588                 return CssmClient::Key(Server::csp(), key
, true); 
 594 // Verify a putative database passphrase. 
 595 // If the database is already unlocked, just check the passphrase. 
 596 // Otherwise, unlock with that passphrase and report success. 
 597 // Caller must hold the common lock. 
 599 bool KeychainDatabase::validatePassphrase(const CssmData 
&passphrase
) const 
 601         if (common().hasMaster()) { 
 602                 // verify against known secret 
 603                 return common().validatePassphrase(passphrase
); 
 605                 // no master secret - perform "blind" unlock to avoid actual unlock 
 607                         DatabaseCryptoCore test
; 
 608                         test
.setup(mBlob
, passphrase
); 
 609                         test
.decodeCore(mBlob
, NULL
); 
 619 // Lock this database 
 621 void KeychainDatabase::lockDb() 
 628 // Given a Key for this database, encode it into a blob and return it. 
 630 KeyBlob 
*KeychainDatabase::encodeKey(const CssmKey 
&key
, const CssmData 
&pubAcl
, const CssmData 
&privAcl
) 
 634     // tell the cryptocore to form the key blob 
 635     return common().encodeKeyCore(key
, pubAcl
, privAcl
); 
 640 // Given a "blobbed" key for this database, decode it into its real 
 641 // key object and (re)populate its ACL. 
 643 void KeychainDatabase::decodeKey(KeyBlob 
*blob
, CssmKey 
&key
, void * &pubAcl
, void * &privAcl
) 
 645     unlockDb();                                                 // we need our keys 
 647     common().decodeKeyCore(blob
, key
, pubAcl
, privAcl
); 
 648     // memory protocol: pubAcl points into blob; privAcl was allocated 
 655 // Modify database parameters 
 657 void KeychainDatabase::setParameters(const DBParameters 
¶ms
) 
 659         StLock
<Mutex
> _(common()); 
 661         common().mParams 
= params
; 
 662     common().version
++;         // invalidate old blobs 
 664         secdebug("SSdb", "%p common %p(%s) set params=(%ld,%d)", 
 665                 this, &common(), dbName(), params
.idleTimeout
, params
.lockOnSleep
); 
 670 // Retrieve database parameters 
 672 void KeychainDatabase::getParameters(DBParameters 
¶ms
) 
 674         StLock
<Mutex
> _(common()); 
 676         params 
= common().mParams
; 
 677     //activity();               // getting parameters does not reset the idle timer 
 682 // Intercept ACL change requests and reset blob validity 
 684 void KeychainDatabase::instantiateAcl() 
 686         StLock
<Mutex
> _(common()); 
 690 void KeychainDatabase::changedAcl() 
 692         StLock
<Mutex
> _(common()); 
 696 const Database 
*KeychainDatabase::relatedDatabase() const 
 703 #if defined(DEBUGDUMP) 
 705 void KeychainDbCommon::dumpNode() 
 707         PerSession::dumpNode(); 
 708         uint32 sig
; memcpy(&sig
, &mIdentifier
.signature(), sizeof(sig
)); 
 709         Debug::dump(" %s[%8.8lx]", mIdentifier
.dbName(), sig
); 
 711                 Debug::dump(" locked"); 
 713                 time_t whenTime 
= time_t(when()); 
 714                 Debug::dump(" unlocked(%24.24s/%.2g)", ctime(&whenTime
), 
 715                         (when() - Time::now()).seconds()); 
 717         Debug::dump(" params=(%ld,%d)", mParams
.idleTimeout
, mParams
.lockOnSleep
); 
 720 void KeychainDatabase::dumpNode() 
 722         PerProcess::dumpNode(); 
 723         Debug::dump(" %s vers=%ld", 
 724                 mValidData 
? " data" : " nodata", version
); 
 726                 uint32 sig
; memcpy(&sig
, &mBlob
->randomSignature
, sizeof(sig
)); 
 727                 Debug::dump(" blob=%p[%8.8lx]", mBlob
, sig
); 
 729                 Debug::dump(" noblob"); 
 737 // DbCommon basic features 
 739 KeychainDbCommon::KeychainDbCommon(Session 
&ssn
, const DbIdentifier 
&id
) 
 740         : DbCommon(ssn
), mIdentifier(id
), sequence(0), version(1), 
 741       mIsLocked(true), mValidParams(false) 
 744 KeychainDbCommon::~KeychainDbCommon() 
 746         secdebug("SSdb", "DbCommon %p destroyed", this); 
 748         // explicitly unschedule ourselves 
 749         Server::active().clearTimer(this); 
 753 void KeychainDbCommon::makeNewSecrets() 
 755         // we already have a master key (right?) 
 758         // tell crypto core to generate the use keys 
 759         DatabaseCryptoCore::generateNewSecrets(); 
 761         // we're now officially "unlocked"; set the timer 
 763         activity();                     // set lock timer 
 768 // All unlocking activity ultimately funnels through this method. 
 769 // This unlocks a DbCommon using the secrets setup in its crypto core 
 770 // component, and performs all the housekeeping needed to represent 
 772 // Returns true if unlock was successful, false if it failed due to 
 773 // invalid/insufficient secrets. Throws on other errors. 
 775 bool KeychainDbCommon::unlockDb(DbBlob 
*blob
, void **privateAclBlob
) 
 778                 // Tell the cryptocore to (try to) decode itself. This will fail 
 779                 // in an astonishing variety of ways if the passphrase is wrong. 
 781                 decodeCore(blob
, privateAclBlob
); 
 782                 secdebug("SSdb", "%p unlock successful", this); 
 784                 secdebug("SSdb", "%p unlock failed", this); 
 788         // get the database parameters only if we haven't got them yet 
 790                 mParams 
= blob
->params
; 
 791                 n2hi(mParams
.idleTimeout
); 
 792                 mValidParams 
= true;    // sticky 
 795         setUnlocked();          // mark unlocked 
 796         activity();                     // set lock timer 
 798         // broadcast unlock notification 
 799         notify(kNotificationEventUnlocked
); 
 803 void KeychainDbCommon::setUnlocked() 
 805         session().addReference(*this); // active/held 
 806         mIsLocked 
= false;  // mark unlocked 
 810 void KeychainDbCommon::lockDb(bool forSleep
) 
 812     StLock
<Mutex
> locker(*this); 
 814         if (forSleep 
&& !mParams
.lockOnSleep
) 
 815             return;     // it doesn't want to 
 817                 DatabaseCryptoCore::invalidate(); 
 818         notify(kNotificationEventLocked
); 
 819                 Server::active().clearTimer(this); 
 821                 mIsLocked 
= true;               // mark locked 
 822                 locker
.unlock();                // release DbCommon lock now 
 823                 session().removeReference(*this); // remove active/hold 
 828 DbBlob 
*KeychainDbCommon::encode(KeychainDatabase 
&db
) 
 830     assert(!isLocked());        // must have been unlocked by caller 
 832     // export database ACL to blob form 
 833     CssmData pubAcl
, privAcl
; 
 834     db
.exportBlob(pubAcl
, privAcl
); 
 836     // tell the cryptocore to form the blob 
 838     form
.randomSignature 
= identifier(); 
 839     form
.sequence 
= sequence
; 
 840     form
.params 
= mParams
; 
 841         h2ni(form
.params
.idleTimeout
); 
 844     DbBlob 
*blob 
= encodeCore(form
, pubAcl
, privAcl
); 
 847     db
.allocator
.free(pubAcl
); 
 848     db
.allocator
.free(privAcl
); 
 854 // Send a keychain-related notification event about this keychain 
 856 void KeychainDbCommon::notify(NotificationEvent event
) 
 858         // form the data (encoded DLDbIdentifier) 
 859     NameValueDictionary nvd
; 
 860     NameValueDictionary::MakeNameValueDictionaryFromDLDbIdentifier(identifier(), nvd
); 
 864         // inject notification into Security event system 
 865     Listener::notify(kNotificationDomainDatabase
, event
, data
); 
 873 // Perform deferred lock processing for a database. 
 875 void KeychainDbCommon::action() 
 877         secdebug("SSdb", "common %s(%p) locked by timer", dbName(), this); 
 881 void KeychainDbCommon::activity() 
 884                 secdebug("SSdb", "setting DbCommon %p timer to %d", 
 885                         this, int(mParams
.idleTimeout
)); 
 886                 Server::active().setTimer(this, Time::Interval(int(mParams
.idleTimeout
))); 
 890 void KeychainDbCommon::sleepProcessing()