X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..ce3c8656732c924baf7e88df75eab50891bdc471:/OSX/libsecurity_apple_cspdl/lib/SSDatabase.cpp?ds=sidebyside diff --git a/OSX/libsecurity_apple_cspdl/lib/SSDatabase.cpp b/OSX/libsecurity_apple_cspdl/lib/SSDatabase.cpp index 672dae88..755d232a 100644 --- a/OSX/libsecurity_apple_cspdl/lib/SSDatabase.cpp +++ b/OSX/libsecurity_apple_cspdl/lib/SSDatabase.cpp @@ -22,6 +22,8 @@ #include "SSDatabase.h" #include +#include +#include using namespace CssmClient; using namespace SecurityServer; @@ -33,6 +35,7 @@ SSDatabaseImpl::SSDatabaseImpl(ClientSession &inClientSession, const CssmClient: const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation) : Db::Impl(dl, inDbName, inDbLocation), mClientSession(inClientSession), mSSDbHandle(noDb) { + mTransaction = NULL; } SSDatabaseImpl::~SSDatabaseImpl() @@ -257,6 +260,7 @@ SSDatabaseImpl::create(const DLDbIdentifier &dlDbIdentifier) mSSDbHandle = mClientSession.createDb(dlDbIdentifier, cred, owner, dbParameters); CssmDataContainer dbb(allocator()); mClientSession.encodeDb(mSSDbHandle, dbb, allocator()); + secdebugfunc("integrity", "opening %s", name()); Db::Impl::insert(DBBlobRelationID, NULL, &dbb); if (autoCommit) { @@ -287,6 +291,7 @@ SSDatabaseImpl::createWithBlob(const DLDbIdentifier &dlDbIdentifier, const CSSM_ { bool autoCommit; commonCreate(dlDbIdentifier, autoCommit); + secdebugfunc("integrity", "opening %s", name()); Db::Impl::insert(DBBlobRelationID, NULL, &blob); if (autoCommit) { @@ -311,81 +316,185 @@ SSDatabaseImpl::open(const DLDbIdentifier &dlDbIdentifier) CssmDataContainer dbb(allocator()); getDbBlobId(&dbb); + secdebugfunc("integrity", "opening %s", name()); + + // Pull our version out of the database blob mSSDbHandle = mClientSession.decodeDb(dlDbIdentifier, AccessCredentials::overlay(accessCredentials()), dbb); } void -SSDatabaseImpl::recode(const CssmData &data, const CssmData &extraData) +SSDatabaseImpl::recode(const CssmData &dbHandleArray, const CssmData &agentData) { - // Start a transaction (Implies activate()). - passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, 0); + // Start a transaction (Implies activate()). + passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, 0); + + try + { + CssmDataContainer dbb(allocator()); + // Make sure mSSDbHandle is valid. + CssmClient::DbUniqueRecord dbBlobId = getDbBlobId(&dbb); + if (mForked()) { + // re-establish the dbHandle with the SecurityServer + mSSDbHandle = mClientSession.decodeDb(mIdentifier, + AccessCredentials::overlay(accessCredentials()), dbb); + } + dbb.clear(); + + DbHandle successfulHdl = mClientSession.authenticateDbsForSync(dbHandleArray, agentData); + + // Create a newDbHandle using the master secrets from the dbBlob we are + // recoding to. + SecurityServer::DbHandle clonedDbHandle = + mClientSession.recodeDbForSync(successfulHdl, mSSDbHandle); + + // @@@ If the dbb changed since we fetched it we should abort or + // retry the operation here. + + recodeHelper(clonedDbHandle, dbBlobId); + + // Commit the transaction to the db + passThrough(CSSM_APPLEFILEDL_COMMIT, NULL); + passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, + reinterpret_cast(1)); + } + catch (...) + { + // Something went wrong rollback the transaction + passThrough(CSSM_APPLEFILEDL_ROLLBACK, NULL); + passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, + reinterpret_cast(1)); + throw; + } +} - try - { - CssmDataContainer dbb(allocator()); - // Make sure mSSDbHandle is valid. - CssmClient::DbUniqueRecord dbBlobId = getDbBlobId(&dbb); - if (mForked()) { - // re-establish the dbHandle with the SecurityServer - mSSDbHandle = mClientSession.decodeDb(mIdentifier, - AccessCredentials::overlay(accessCredentials()), dbb); - } - dbb.clear(); +uint32 +SSDatabaseImpl::recodeDbToVersion(uint32 newBlobVersion) { + // Start a transaction (Implies activate()). + DLTransaction transaction(handle()); + + try + { + if(isLocked()) { + secdebugfunc("integrity", "is currently locked"); + } else { + secdebugfunc("integrity", "is already unlocked"); + } + + CssmDataContainer dbb(allocator()); + // Make sure mSSDbHandle is valid. + CssmClient::DbUniqueRecord dbBlobId = getDbBlobId(&dbb); + + // always establish the dbHandle with the SecurityServer + mSSDbHandle = mClientSession.decodeDb(mIdentifier, AccessCredentials::overlay(accessCredentials()), dbb); + dbb.clear(); + + // Create a newDbHandle using the master secrets from the dbBlob we are recoding to. + secdebugfunc("integrity", "recoding db with handle %d", mSSDbHandle); + SecurityServer::DbHandle clonedDbHandle = mClientSession.recodeDbToVersion(newBlobVersion, mSSDbHandle); + secdebugfunc("integrity", "received db with handle %d", clonedDbHandle); + + // @@@ If the dbb changed since we fetched it we should abort or + // retry the operation here. + + uint32 newBlobVersion = recodeHelper(clonedDbHandle, dbBlobId); + secdebugfunc("integrity", "committing transaction %d", clonedDbHandle); + + // Commit the transaction to the db + transaction.success(); + return newBlobVersion; + } + catch (...) + { + throw; + } +} - DbHandle successfulHdl = mClientSession.authenticateDbsForSync(data, extraData); +void SSDatabaseImpl::takeFileLock() { + if(mTransaction) { + // you're already in the middle of a file lock. + return; + } + mTransaction = new DLTransaction(handle()); + passThrough(CSSM_APPLEFILEDL_TAKE_FILE_LOCK, NULL, NULL); +} - // Create a newDbHandle using the master secrets from the dbBlob we are - // recoding to. - SecurityServer::DbHandle clonedDbHandle = - mClientSession.recodeDbForSync(successfulHdl, mSSDbHandle); +void SSDatabaseImpl::releaseFileLock(bool success) { + if(mTransaction) { + try { + if(success) { + mTransaction->success(); + } + // The destructor will commit the database and re-enable autocommit (if needed) + delete mTransaction; + mTransaction = NULL; + } catch(...) { + mTransaction = NULL; + throw; + } + } +} - // @@@ If the dbb changed since we fetched it we should abort or - // retry the operation here. +void SSDatabaseImpl::makeBackup() { + passThrough(CSSM_APPLEFILEDL_MAKE_BACKUP, NULL, NULL); +} - // Recode all keys - DbCursor cursor(SSDatabase(this)); - cursor->recordType(CSSM_DL_DB_RECORD_ALL_KEYS); - CssmDataContainer keyBlob(allocator()); - CssmClient::DbUniqueRecord keyBlobId; - DbAttributes attributes; - while (cursor->next(&attributes, &keyBlob, keyBlobId)) - { - // Decode the old key - CssmKey::Header header; - KeyHandle keyHandle = - mClientSession.decodeKey(mSSDbHandle, keyBlob, header); - // Recode the key - CssmDataContainer newKeyBlob(mClientSession.returnAllocator); - mClientSession.recodeKey(mSSDbHandle, keyHandle, clonedDbHandle, - newKeyBlob); - mClientSession.releaseKey(keyHandle); - // Write the recoded key blob to the database - keyBlobId->modify(attributes.recordType(), NULL, &newKeyBlob, - CSSM_DB_MODIFY_ATTRIBUTE_NONE); - } - // Commit the new blob to securityd, reencode the db blob, release the - // cloned db handle and commit the new blob to the db. - mClientSession.commitDbForSync(mSSDbHandle, clonedDbHandle, - dbb, allocator()); - dbBlobId->modify(DBBlobRelationID, NULL, &dbb, - CSSM_DB_MODIFY_ATTRIBUTE_NONE); - - // Commit the transaction to the db - passThrough(CSSM_APPLEFILEDL_COMMIT, NULL); - passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, - reinterpret_cast(1)); - } - catch (...) - { - // Something went wrong rollback the transaction - passThrough(CSSM_APPLEFILEDL_ROLLBACK, NULL); - passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, - reinterpret_cast(1)); - throw; - } +uint32 SSDatabaseImpl::recodeHelper(SecurityServer::DbHandle clonedDbHandle, CssmClient::DbUniqueRecord& dbBlobId) { + // Recode all keys + DbCursor cursor(SSDatabase(this)); + cursor->recordType(CSSM_DL_DB_RECORD_ALL_KEYS); + CssmDataContainer keyBlob(allocator()); + CssmClient::DbUniqueRecord keyBlobId; + DbAttributes attributes; + while (cursor->next(&attributes, &keyBlob, keyBlobId)) + { + KeyHandle keyHandle = 0; + try { + // Decode the old key + CssmKey::Header header; + keyHandle = mClientSession.decodeKey(mSSDbHandle, keyBlob, header); + // Recode the key + CssmDataContainer newKeyBlob(mClientSession.returnAllocator); + mClientSession.recodeKey(mSSDbHandle, keyHandle, clonedDbHandle, newKeyBlob); + mClientSession.releaseKey(keyHandle); + keyHandle = 0; + // Write the recoded key blob to the database + keyBlobId->modify(attributes.recordType(), NULL, &newKeyBlob, + CSSM_DB_MODIFY_ATTRIBUTE_NONE); + } catch (CssmError cssme) { + const char* errStr = cssmErrorString(cssme.error); + secdebugfunc("integrity", "corrupt item while recoding: %d %s", (int) cssme.error, errStr); + secdebugfunc("integrity", "deleting corrupt item"); + + + keyBlobId->deleteRecord(); + + if(keyHandle != 0) { + // tell securityd not to worry about this key again + try { + secdebugfunc("integrity", "releasing corrupt key"); + mClientSession.releaseKey(keyHandle); + } catch(CssmError cssme) { + // swallow the error + const char* errStr = cssmErrorString(cssme.error); + secdebugfunc("integrity", "couldn't release corrupt key: %d %s", (int) cssme.error, errStr); + } + } + } + } + + // Commit the new blob to securityd, reencode the db blob, release the + // cloned db handle and commit the new blob to the db. + CssmDataContainer dbb(allocator()); + secdebugfunc("integrity", "committing %d", clonedDbHandle); + mClientSession.commitDbForSync(mSSDbHandle, clonedDbHandle, + dbb, allocator()); + dbBlobId->modify(DBBlobRelationID, NULL, &dbb, + CSSM_DB_MODIFY_ATTRIBUTE_NONE); + return getDbVersionFromBlob(dbb); } + void SSDatabaseImpl::getRecordIdentifier(CSSM_DB_UNIQUE_RECORD_PTR uniqueRecord, CSSM_DATA &recordID) { // the unique ID is composed of three uint32s (plus one filler word). Pull @@ -418,6 +527,22 @@ void SSDatabaseImpl::copyBlob(CSSM_DATA &data) dbb.Length = 0; } +uint32 +SSDatabaseImpl::dbBlobVersion() { + CssmDataContainer dbb(allocator()); + getDbBlobId(&dbb); + return getDbVersionFromBlob(dbb); +} + +uint32 +SSDatabaseImpl::getDbVersionFromBlob(const CssmData& dbb) { + DbBlob* x = Allocator::standard().malloc(dbb.length()); + memcpy(x, dbb, dbb.length()); + uint32 version = x->version(); + Allocator::standard().free(x); + return version; +} + DbUniqueRecordImpl * SSDatabaseImpl::newDbUniqueRecord() {