#include <security_cdsa_client/dlclient.h>
#include <security_cdsa_client/aclclient.h>
#include <Security/cssmapple.h>
#include <Security/cssmapplePriv.h>
using namespace CssmClient;
const uint32 kBlobType = 0x1;
DbMaker::~DbMaker()
{ }
DbCursorMaker::~DbCursorMaker()
{ }
DbUniqueRecordMaker::~DbUniqueRecordMaker()
{ }
DLImpl::DLImpl(const Guid &guid) : AttachmentImpl(guid, CSSM_SERVICE_DL)
{
}
DLImpl::DLImpl(const Module &module) : AttachmentImpl(module, CSSM_SERVICE_DL)
{
}
DLImpl::~DLImpl()
{
}
void
DLImpl::getDbNames(char **)
{
CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
}
void
DLImpl::freeNameList(char **)
{
CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
}
DbImpl *
DLImpl::newDb(const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
{
return new DbImpl(DL(this), inDbName, inDbLocation);
}
DbImpl::DbImpl(const DL &dl, const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
: ObjectImpl(dl), mDbName(inDbName, inDbLocation),
mUseNameFromHandle(!inDbName), mNameFromHandle(NULL),
mAccessRequest(CSSM_DB_ACCESS_READ), mAccessCredentials(NULL),
mDefaultCredentials(NULL), mOpenParameters(NULL), mDbInfo(NULL),
mResourceControlContext(NULL)
{
}
DbImpl::~DbImpl()
{
try
{
if (mNameFromHandle)
allocator().free(mNameFromHandle);
deactivate();
}
catch(...) {}
}
void
DbImpl::open()
{
{
StLock<Mutex> _(mActivateMutex);
if (!mActive)
{
assert(mDbInfo == nil);
mHandle.DLHandle = dl()->handle();
check(CSSM_DL_DbOpen(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
mAccessRequest, mAccessCredentials,
mOpenParameters, &mHandle.DBHandle));
mActive = true;
}
}
if (!mAccessCredentials && mDefaultCredentials)
if (const AccessCredentials *creds = mDefaultCredentials->makeCredentials())
CSSM_DL_Authenticate(handle(), mAccessRequest, creds); }
void
DbImpl::createWithBlob(CssmData &blob)
{
if (mActive)
CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
if (mDbInfo == nil) {
static const CSSM_DBINFO nullDbInfo = { };
mDbInfo = &nullDbInfo;
}
mHandle.DLHandle = dl()->handle();
CSSM_APPLE_CSPDL_DB_CREATE_WITH_BLOB_PARAMETERS params;
params.dbName = mDbName.canonicalName ();
params.dbLocation = dbLocation ();
params.dbInfo = mDbInfo;
params.accessRequest = mAccessRequest;
params.credAndAclEntry = NULL;
params.openParameters = mOpenParameters;
params.blob = &blob;
check(CSSM_DL_PassThrough (mHandle, CSSM_APPLECSPDL_DB_CREATE_WITH_BLOB, ¶ms, (void**) &mHandle.DBHandle));
}
void
DbImpl::create()
{
StLock<Mutex> _(mActivateMutex);
if (mActive)
CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
if (mDbInfo == nil) {
static const CSSM_DBINFO nullDbInfo = { };
mDbInfo = &nullDbInfo;
}
mHandle.DLHandle = dl()->handle();
if (!mResourceControlContext && mAccessCredentials) {
AclFactory::AnyResourceContext ctx(mAccessCredentials);
check(CSSM_DL_DbCreate(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
mDbInfo, mAccessRequest, &ctx,
mOpenParameters, &mHandle.DBHandle));
} else {
check(CSSM_DL_DbCreate(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
mDbInfo, mAccessRequest, mResourceControlContext,
mOpenParameters, &mHandle.DBHandle));
}
mActive = true;
}
void
DbImpl::close()
{
StLock<Mutex> _(mActivateMutex);
if (mActive)
{
check(CSSM_DL_DbClose (mHandle));
mActive = false;
}
}
void
DbImpl::activate()
{
if (!mActive)
{
if (mDbInfo)
create();
else
open();
}
}
void
DbImpl::deactivate()
{
StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive = false;
close();
}
}
void
DbImpl::deleteDb()
{
deactivate();
check(CSSM_DL_DbDelete(dl()->handle(), mDbName.canonicalName(), dbLocation(),
mAccessCredentials));
}
void
DbImpl::rename(const char *newName)
{
deactivate();
if (::rename(mDbName.canonicalName(), newName))
UnixError::throwMe(errno);
mDbName = DbName(newName, dbLocation());
}
void
DbImpl::authenticate(CSSM_DB_ACCESS_TYPE inAccessRequest,
const CSSM_ACCESS_CREDENTIALS *inAccessCredentials)
{
if (!mActive)
{
if (!mDbInfo)
{
accessRequest(inAccessRequest);
accessCredentials(inAccessCredentials);
activate();
return;
}
}
check(CSSM_DL_Authenticate(handle(), inAccessRequest, inAccessCredentials));
}
void
DbImpl::name(char *&outDbName)
{
check(CSSM_DL_GetDbNameFromHandle(handle(), &outDbName));
}
const char *
DbImpl::name()
{
if (mUseNameFromHandle)
{
if (mNameFromHandle
|| !CSSM_DL_GetDbNameFromHandle(handle(), &mNameFromHandle))
{
return mNameFromHandle;
}
mUseNameFromHandle = false;
}
return mDbName.canonicalName();
}
void
DbImpl::createRelation(CSSM_DB_RECORDTYPE inRelationID,
const char *inRelationName,
uint32 inNumberOfAttributes,
const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *pAttributeInfo,
uint32 inNumberOfIndexes,
const CSSM_DB_SCHEMA_INDEX_INFO *pIndexInfo)
{
check(CSSM_DL_CreateRelation(handle(), inRelationID, inRelationName,
inNumberOfAttributes, pAttributeInfo,
inNumberOfIndexes, pIndexInfo));
}
void
DbImpl::destroyRelation(CSSM_DB_RECORDTYPE inRelationID)
{
check(CSSM_DL_DestroyRelation(handle(), inRelationID));
}
DbUniqueRecord
DbImpl::insert(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
const CSSM_DATA *data)
{
DbUniqueRecord uniqueId(Db(this));
check(CSSM_DL_DataInsert(handle(), recordType,
attributes,
data, uniqueId));
uniqueId->activate();
return uniqueId;
}
DbUniqueRecord
DbImpl::insertWithoutEncryption(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
CSSM_DATA *data)
{
DbUniqueRecord uniqueId(Db(this));
CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION_PARAMETERS params;
params.recordType = recordType;
params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
params.data = *data;
CSSM_DB_UNIQUE_RECORD_PTR *uniquePtr = uniqueId;
passThrough (CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION, ¶ms, (void**) uniquePtr);
uniqueId->activate();
return uniqueId;
}
void DbImpl::passThrough(uint32 passThroughId, const void *in, void **out)
{
check(CSSM_DL_PassThrough(handle(), passThroughId, in, out));
}
void
DbImpl::lock()
{
check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_LOCK, NULL, NULL));
}
void
DbImpl::unlock()
{
check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, NULL, NULL));
}
void
DbImpl::unlock(const CSSM_DATA &password)
{
check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, &password, NULL));
}
void
DbImpl::getSettings(uint32 &outIdleTimeout, bool &outLockOnSleep)
{
CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR settings;
check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_GET_SETTINGS,
NULL, reinterpret_cast<void **>(&settings)));
outIdleTimeout = settings->idleTimeout;
outLockOnSleep = settings->lockOnSleep;
allocator().free(settings);
}
void
DbImpl::setSettings(uint32 inIdleTimeout, bool inLockOnSleep)
{
CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS settings;
settings.idleTimeout = inIdleTimeout;
settings.lockOnSleep = inLockOnSleep;
check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_SET_SETTINGS, &settings, NULL));
}
bool
DbImpl::isLocked()
{
CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params;
check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_IS_LOCKED,
NULL, reinterpret_cast<void **>(¶ms)));
bool isLocked = params->isLocked;
allocator().free(params);
return isLocked;
}
void
DbImpl::changePassphrase(const CSSM_ACCESS_CREDENTIALS *cred)
{
CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS params;
params.accessCredentials = const_cast<CSSM_ACCESS_CREDENTIALS *>(cred);
check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_CHANGE_PASSWORD, ¶ms, NULL));
}
void DbImpl::recode(const CSSM_DATA &data, const CSSM_DATA &extraData)
{
CSSM_APPLECSPDL_RECODE_PARAMETERS params;
params.dbBlob = data;
params.extraData = extraData;
check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_CSP_RECODE, ¶ms, NULL));
}
void DbImpl::copyBlob (CssmData &data)
{
check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_COPY_BLOB, NULL, (void**) (CSSM_DATA*) &data));
}
void DbImpl::setBatchMode(Boolean mode, Boolean rollback)
{
CSSM_RETURN result;
CSSM_DL_DB_HANDLE dldbHandleOfUnderlyingDL;
result = CSSM_DL_PassThrough(handle(),
CSSM_APPLECSPDL_DB_GET_HANDLE,
NULL,
(void **)&dldbHandleOfUnderlyingDL);
if ( result == noErr )
{
CSSM_BOOL modeToUse = !mode;
if (rollback)
{
result = (OSStatus)CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
CSSM_APPLEFILEDL_ROLLBACK, NULL, NULL);
}
result = CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
(void *)(modeToUse),
NULL);
if (!rollback && modeToUse)
result = CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
CSSM_APPLEFILEDL_COMMIT,
NULL,
NULL);
}
}
DbCursorImpl *
DbImpl::newDbCursor(const CSSM_QUERY &query, Allocator &allocator)
{
return new DbDbCursorImpl(Db(this), query, allocator);
}
DbCursorImpl *
DbImpl::newDbCursor(uint32 capacity, Allocator &allocator)
{
return new DbDbCursorImpl(Db(this), capacity, allocator);
}
void DbImpl::getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag) const
{
aclInfos.allocator(allocator());
check(CSSM_DL_GetDbAcl(const_cast<DbImpl*>(this)->handle(),
reinterpret_cast<const CSSM_STRING *>(selectionTag), aclInfos, aclInfos));
}
void DbImpl::changeAcl(const CSSM_ACL_EDIT &aclEdit,
const CSSM_ACCESS_CREDENTIALS *accessCred)
{
check(CSSM_DL_ChangeDbAcl(handle(), AccessCredentials::needed(accessCred), &aclEdit));
}
void DbImpl::getOwner(AutoAclOwnerPrototype &owner) const
{
owner.allocator(allocator());
check(CSSM_DL_GetDbOwner(const_cast<DbImpl*>(this)->handle(), owner));
}
void DbImpl::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
const CSSM_ACCESS_CREDENTIALS *accessCred)
{
check(CSSM_DL_ChangeDbOwner(handle(),
AccessCredentials::needed(accessCred), &newOwner));
}
void DbImpl::defaultCredentials(DefaultCredentialsMaker *maker)
{
mDefaultCredentials = maker;
}
DbImpl::DefaultCredentialsMaker::~DefaultCredentialsMaker()
{ }
CSSM_HANDLE Db::dlGetFirst(const CSSM_QUERY &query, CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes,
CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
{
CSSM_HANDLE result;
switch (CSSM_RETURN rc = CSSM_DL_DataGetFirst(handle(), &query, &result, &attributes, data, &id)) {
case CSSM_OK:
return result;
case CSSMERR_DL_ENDOFDATA:
return CSSM_INVALID_HANDLE;
default:
CssmError::throwMe(rc);
return CSSM_INVALID_HANDLE; }
}
bool Db::dlGetNext(CSSM_HANDLE query, CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes,
CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
{
CSSM_RETURN rc = CSSM_DL_DataGetNext(handle(), query, &attributes, data, &id);
switch (rc) {
case CSSM_OK:
return true;
case CSSMERR_DL_ENDOFDATA:
return false;
default:
CssmError::throwMe(rc);
return false; }
}
void Db::dlAbortQuery(CSSM_HANDLE query)
{
CssmError::check(CSSM_DL_DataAbortQuery(handle(), query));
}
void Db::dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD *id)
{
CssmError::check(CSSM_DL_FreeUniqueRecord(handle(), id));
}
void Db::dlDeleteRecord(CSSM_DB_UNIQUE_RECORD *id)
{
CssmError::check(CSSM_DL_DataDelete(handle(), id));
}
Allocator &Db::allocator()
{
return Object::allocator();
}
DbUniqueRecordImpl *
DbImpl::newDbUniqueRecord()
{
return new DbUniqueRecordImpl(Db(this));
}
DLDbIdentifier
DbImpl::dlDbIdentifier()
{
return DLDbIdentifier(dl()->subserviceUid(), mDbName.canonicalName(), dbLocation());
}
DbDbCursorImpl::DbDbCursorImpl(const Db &db, const CSSM_QUERY &query, Allocator &allocator)
: DbCursorImpl(db, query, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
{
}
DbDbCursorImpl::DbDbCursorImpl(const Db &db, uint32 capacity, Allocator &allocator)
: DbCursorImpl(db, capacity, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
{
}
DbDbCursorImpl::~DbDbCursorImpl()
{
try
{
deactivate();
}
catch(...) {}
}
bool
DbDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId)
{
if (attributes)
attributes->deleteValues();
if (data)
data->clear();
CSSM_RETURN result;
Db db(database());
DbUniqueRecord unique(db);
if (!mActive)
{
CSSM_BOOL boolResult;
CSSM_DL_PassThrough(db->handle(), CSSM_APPLECSPDL_DB_RELATION_EXISTS, &RecordType, (void**) &boolResult);
if (!boolResult)
{
if (data != NULL)
{
data->invalidate();
}
return false;
}
result = CSSM_DL_DataGetFirst(db->handle(),
this,
&mResultsHandle,
attributes,
data,
unique);
StLock<Mutex> _(mActivateMutex);
if (result == CSSM_OK)
mActive = true;
else if (data != NULL)
data->invalidate ();
}
else
{
result = CSSM_DL_DataGetNext(db->handle(),
mResultsHandle,
attributes,
data,
unique);
if (result != CSSM_OK && data != NULL)
{
data->invalidate ();
}
}
if (result != CSSM_OK && attributes != NULL)
{
attributes->invalidate();
}
if (result == CSSMERR_DL_ENDOFDATA)
{
StLock<Mutex> _(mActivateMutex);
mActive = false;
return false;
}
check(result);
unique->activate();
uniqueId = unique;
return true;
}
void
DbDbCursorImpl::activate()
{
}
void
DbDbCursorImpl::deactivate()
{
StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive = false;
check(CSSM_DL_DataAbortQuery(database()->handle(), mResultsHandle));
}
}
DbCursorImpl::DbCursorImpl(const Object &parent, const CSSM_QUERY &query, Allocator &allocator) :
ObjectImpl(parent), CssmAutoQuery(query, allocator)
{
}
DbCursorImpl::DbCursorImpl(const Object &parent, uint32 capacity, Allocator &allocator) :
ObjectImpl(parent), CssmAutoQuery(capacity, allocator)
{
}
Allocator &
DbCursorImpl::allocator() const
{
return ObjectImpl::allocator();
}
void
DbCursorImpl::allocator(Allocator &alloc)
{
ObjectImpl::allocator(alloc);
}
DbUniqueRecordImpl::DbUniqueRecordImpl(const Db &db) : ObjectImpl(db), mDestroyID (false)
{
}
DbUniqueRecordImpl::~DbUniqueRecordImpl()
{
try
{
if (mDestroyID)
{
allocator ().free (mUniqueId);
}
deactivate();
}
catch(...) {}
}
void
DbUniqueRecordImpl::deleteRecord()
{
check(CSSM_DL_DataDelete(database()->handle(), mUniqueId));
}
void
DbUniqueRecordImpl::modify(CSSM_DB_RECORDTYPE recordType,
const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
const CSSM_DATA *data,
CSSM_DB_MODIFY_MODE modifyMode)
{
check(CSSM_DL_DataModify(database()->handle(), recordType, mUniqueId,
attributes,
data, modifyMode));
}
void
DbUniqueRecordImpl::modifyWithoutEncryption(CSSM_DB_RECORDTYPE recordType,
const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
const CSSM_DATA *data,
CSSM_DB_MODIFY_MODE modifyMode)
{
CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS params;
params.recordType = recordType;
params.uniqueID = mUniqueId;
params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
params.data = (CSSM_DATA*) data;
params.modifyMode = modifyMode;
check(CSSM_DL_PassThrough(database()->handle(),
CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION,
¶ms,
NULL));
}
void
DbUniqueRecordImpl::get(DbAttributes *attributes,
::CssmDataContainer *data)
{
if (attributes)
attributes->deleteValues();
if (data)
data->clear();
CSSM_RETURN result;
result = CSSM_DL_DataGetFromUniqueRecordId(database()->handle(), mUniqueId,
attributes,
data);
if (result != CSSM_OK)
{
if (attributes)
attributes->invalidate();
if (data != NULL) {
data->invalidate ();
}
}
check(result);
}
void
DbUniqueRecordImpl::getWithoutEncryption(DbAttributes *attributes,
::CssmDataContainer *data)
{
if (attributes)
attributes->deleteValues();
if (data)
data->clear();
CSSM_RETURN result;
CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS params;
params.uniqueID = mUniqueId;
params.attributes = attributes;
::CssmDataContainer recordData;
result = CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION, ¶ms,
(void**) data);
check (result);
}
void
DbUniqueRecordImpl::activate()
{
StLock<Mutex> _(mActivateMutex);
mActive = true;
}
void
DbUniqueRecordImpl::deactivate()
{
StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive = false;
check(CSSM_DL_FreeUniqueRecord(database()->handle(), mUniqueId));
}
}
void
DbUniqueRecordImpl::getRecordIdentifier(CSSM_DATA &data)
{
check(CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_RECORD_IDENTIFIER,
mUniqueId, (void**) &data));
}
void DbUniqueRecordImpl::setUniqueRecordPtr(CSSM_DB_UNIQUE_RECORD_PTR uniquePtr)
{
mUniqueId = (CSSM_DB_UNIQUE_RECORD_PTR) allocator ().malloc (sizeof (CSSM_DB_UNIQUE_RECORD));
*mUniqueId = *uniquePtr;
mDestroyID = true;
}
DbAttributes::DbAttributes()
: CssmAutoDbRecordAttributeData(0, Allocator::standard(), Allocator::standard())
{
}
DbAttributes::DbAttributes(const Db &db, uint32 capacity, Allocator &allocator)
: CssmAutoDbRecordAttributeData(capacity, db->allocator(), allocator)
{
}