#include "SSDatabase.h"
#include <security_cdsa_utilities/KeySchema.h>
+#include <security_utilities/CSPDLTransaction.h>
+#include <Security/SecBasePriv.h>
using namespace CssmClient;
using namespace SecurityServer;
const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
: Db::Impl(dl, inDbName, inDbLocation), mClientSession(inClientSession), mSSDbHandle(noDb)
{
+ mTransaction = NULL;
}
SSDatabaseImpl::~SSDatabaseImpl()
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)
{
{
bool autoCommit;
commonCreate(dlDbIdentifier, autoCommit);
+ secdebugfunc("integrity", "opening %s", name());
Db::Impl::insert(DBBlobRelationID, NULL, &blob);
if (autoCommit)
{
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<const void *>(1));
+ }
+ catch (...)
+ {
+ // Something went wrong rollback the transaction
+ passThrough(CSSM_APPLEFILEDL_ROLLBACK, NULL);
+ passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
+ reinterpret_cast<const void *>(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<const void *>(1));
- }
- catch (...)
- {
- // Something went wrong rollback the transaction
- passThrough(CSSM_APPLEFILEDL_ROLLBACK, NULL);
- passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
- reinterpret_cast<const void *>(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
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<DbBlob>(dbb.length());
+ memcpy(x, dbb, dbb.length());
+ uint32 version = x->version();
+ Allocator::standard().free(x);
+ return version;
+}
+
DbUniqueRecordImpl *
SSDatabaseImpl::newDbUniqueRecord()
{