#include "SSDLSession.h"
#include "CSPDLPlugin.h"
#include "SSKey.h"
#include <security_cdsa_utilities/cssmbridge.h>
#include <Security/cssmapplePriv.h>
using namespace CssmClient;
using namespace SecurityServer;
using namespace std;
SSDLSession::SSDLSession(CSSM_MODULE_HANDLE handle,
CSPDLPlugin &plug,
const CSSM_VERSION &version,
uint32 subserviceId,
CSSM_SERVICE_TYPE subserviceType,
CSSM_ATTACH_FLAGS attachFlags,
const CSSM_UPCALLS &upcalls,
DatabaseManager &databaseManager,
SSCSPDLSession &ssCSPDLSession)
: DLPluginSession(handle, plug, version, subserviceId, subserviceType,
attachFlags, upcalls, databaseManager),
mSSCSPDLSession(ssCSPDLSession),
mDL(Module(gGuidAppleFileDL, Cssm::standard())),
mClientSession(Allocator::standard(), static_cast<PluginSession &>(*this))
{
mClientSession.registerForAclEdits(SSCSPDLSession::didChangeKeyAclCallback, &mSSCSPDLSession);
mDL->allocator(allocator());
mDL->version(version);
mDL->subserviceId(subserviceId);
mDL->flags(attachFlags);
}
SSDLSession::~SSDLSession()
try
{
StLock<Mutex> _1(mSSUniqueRecordLock);
mSSUniqueRecordMap.clear();
StLock<Mutex> _2(mDbHandleLock);
DbHandleMap::iterator end = mDbHandleMap.end();
for (DbHandleMap::iterator it = mDbHandleMap.begin(); it != end; ++it)
it->second->close();
mDbHandleMap.clear();
mDL->detach();
}
catch (...)
{
}
void
SSDLSession::GetDbNames(CSSM_NAME_LIST_PTR &outNameList)
{
CSSM_DL_GetDbNames(mDL->handle(), &outNameList);
}
void
SSDLSession::FreeNameList(CSSM_NAME_LIST &inNameList)
{
CSSM_DL_FreeNameList(mDL->handle(), &inNameList);
}
void
SSDLSession::DbDelete(const char *inDbName,
const CSSM_NET_ADDRESS *inDbLocation,
const AccessCredentials *inAccessCred)
{
SSDatabase db(mClientSession, mDL, inDbName, inDbLocation);
db->accessCredentials(inAccessCred);
db->deleteDb();
}
void
SSDLSession::DbCreate(const char *inDbName,
const CSSM_NET_ADDRESS *inDbLocation,
const CSSM_DBINFO &inDBInfo,
CSSM_DB_ACCESS_TYPE inAccessRequest,
const CSSM_RESOURCE_CONTROL_CONTEXT *inCredAndAclEntry,
const void *inOpenParameters,
CSSM_DB_HANDLE &outDbHandle)
{
SSDatabase db(mClientSession, mDL, inDbName, inDbLocation);
db->dbInfo(&inDBInfo);
db->accessRequest(inAccessRequest);
db->resourceControlContext(inCredAndAclEntry);
db->openParameters(inOpenParameters);
db->create(DLDbIdentifier(CssmSubserviceUid(plugin.myGuid(), &version(), subserviceId(),
CSSM_SERVICE_DL | CSSM_SERVICE_CSP),
inDbName, inDbLocation));
db->dbInfo(NULL);
outDbHandle = makeDbHandle(db);
}
void
SSDLSession::CreateWithBlob(const char *DbName,
const CSSM_NET_ADDRESS *DbLocation,
const CSSM_DBINFO &DBInfo,
CSSM_DB_ACCESS_TYPE AccessRequest,
const void *OpenParameters,
const CSSM_DATA &blob,
CSSM_DB_HANDLE &DbHandle)
{
SSDatabase db(mClientSession, mDL, DbName, DbLocation);
db->dbInfo(&DBInfo);
db->accessRequest(AccessRequest);
db->resourceControlContext(NULL);
db->openParameters(OpenParameters);
db->createWithBlob(DLDbIdentifier(CssmSubserviceUid(plugin.myGuid(), &version(), subserviceId(),
CSSM_SERVICE_DL | CSSM_SERVICE_CSP),
DbName, DbLocation),
blob);
db->dbInfo(NULL);
DbHandle = makeDbHandle(db);
}
void
SSDLSession::DbOpen(const char *inDbName,
const CSSM_NET_ADDRESS *inDbLocation,
CSSM_DB_ACCESS_TYPE inAccessRequest,
const AccessCredentials *inAccessCred,
const void *inOpenParameters,
CSSM_DB_HANDLE &outDbHandle)
{
SSDatabase db(mClientSession, mDL, inDbName, inDbLocation);
db->accessRequest(inAccessRequest);
db->accessCredentials(inAccessCred);
db->openParameters(inOpenParameters);
db->open(DLDbIdentifier(CssmSubserviceUid(plugin.myGuid(), &version(), subserviceId(),
CSSM_SERVICE_DL | CSSM_SERVICE_CSP),
inDbName, inDbLocation));
outDbHandle = makeDbHandle(db);
}
void
SSDLSession::DbClose(CSSM_DB_HANDLE inDbHandle)
{
killDbHandle(inDbHandle)->close();
}
void
SSDLSession::CreateRelation(CSSM_DB_HANDLE inDbHandle,
CSSM_DB_RECORDTYPE inRelationID,
const char *inRelationName,
uint32 inNumberOfAttributes,
const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo,
uint32 inNumberOfIndexes,
const CSSM_DB_SCHEMA_INDEX_INFO &inIndexInfo)
{
SSDatabase db = findDbHandle(inDbHandle);
db->createRelation(inRelationID, inRelationName,
inNumberOfAttributes, inAttributeInfo,
inNumberOfIndexes, &inIndexInfo);
}
void
SSDLSession::DestroyRelation(CSSM_DB_HANDLE inDbHandle,
CSSM_DB_RECORDTYPE inRelationID)
{
SSDatabase db = findDbHandle(inDbHandle);
db->destroyRelation(inRelationID);
}
void
SSDLSession::Authenticate(CSSM_DB_HANDLE inDbHandle,
CSSM_DB_ACCESS_TYPE inAccessRequest,
const AccessCredentials &inAccessCred)
{
SSDatabase db = findDbHandle(inDbHandle);
db->authenticate(inAccessRequest, &inAccessCred);
}
void
SSDLSession::GetDbAcl(CSSM_DB_HANDLE inDbHandle,
const CSSM_STRING *inSelectionTag,
uint32 &outNumberOfAclInfos,
CSSM_ACL_ENTRY_INFO_PTR &outAclInfos)
{
SSDatabase db = findDbHandle(inDbHandle);
mClientSession.getDbAcl(db->dbHandle(),
inSelectionTag ? *inSelectionTag : NULL,
outNumberOfAclInfos, AclEntryInfo::overlayVar(outAclInfos), allocator());
}
void
SSDLSession::ChangeDbAcl(CSSM_DB_HANDLE inDbHandle,
const AccessCredentials &inAccessCred,
const CSSM_ACL_EDIT &inAclEdit)
{
SSDatabase db = findDbHandle(inDbHandle);
mClientSession.changeDbAcl(db->dbHandle(), inAccessCred, AclEdit::overlay(inAclEdit));
}
void
SSDLSession::GetDbOwner(CSSM_DB_HANDLE inDbHandle,
CSSM_ACL_OWNER_PROTOTYPE &outOwner)
{
SSDatabase db = findDbHandle(inDbHandle);
mClientSession.getDbOwner(db->dbHandle(),
AclOwnerPrototype::overlay(outOwner), allocator());
}
void
SSDLSession::ChangeDbOwner(CSSM_DB_HANDLE inDbHandle,
const AccessCredentials &inAccessCred,
const CSSM_ACL_OWNER_PROTOTYPE &inNewOwner)
{
SSDatabase db = findDbHandle(inDbHandle);
mClientSession.changeDbOwner(db->dbHandle(), inAccessCred,
AclOwnerPrototype::overlay(inNewOwner));
}
void
SSDLSession::GetDbNameFromHandle(CSSM_DB_HANDLE inDbHandle,
char **outDbName)
{
SSDatabase db = findDbHandle(inDbHandle);
db->name(*outDbName);
}
void
SSDLSession::DataInsert(CSSM_DB_HANDLE inDbHandle,
CSSM_DB_RECORDTYPE inRecordType,
const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
const CssmData *inData,
CSSM_DB_UNIQUE_RECORD_PTR &outUniqueId)
{
SSDatabase db = findDbHandle(inDbHandle);
SSUniqueRecord uniqueId = db->insert(inRecordType, inAttributes, inData, true); outUniqueId = makeSSUniqueRecord(uniqueId);
}
void
SSDLSession::DataDelete(CSSM_DB_HANDLE inDbHandle,
const CSSM_DB_UNIQUE_RECORD &inUniqueRecordIdentifier)
{
SSDatabase db = findDbHandle(inDbHandle);
SSUniqueRecord uniqueId = findSSUniqueRecord(inUniqueRecordIdentifier);
uniqueId->deleteRecord();
}
void
SSDLSession::DataModify(CSSM_DB_HANDLE inDbHandle,
CSSM_DB_RECORDTYPE inRecordType,
CSSM_DB_UNIQUE_RECORD &inoutUniqueRecordIdentifier,
const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributesToBeModified,
const CssmData *inDataToBeModified,
CSSM_DB_MODIFY_MODE inModifyMode)
{
SSDatabase db = findDbHandle(inDbHandle);
SSUniqueRecord uniqueId = findSSUniqueRecord(inoutUniqueRecordIdentifier);
uniqueId->modify(inRecordType, inAttributesToBeModified, inDataToBeModified, inModifyMode);
}
CSSM_HANDLE
SSDLSession::DataGetFirst(CSSM_DB_HANDLE inDbHandle,
const CssmQuery *inQuery,
CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
CssmData *inoutData,
CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord)
{
SSDatabase db = findDbHandle(inDbHandle);
CSSM_HANDLE resultsHandle = CSSM_INVALID_HANDLE;
SSUniqueRecord uniqueId(db);
CSSM_DB_RECORD_ATTRIBUTE_DATA attributes;
CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pAttributes;
if (inoutAttributes)
pAttributes = inoutAttributes;
else
{
pAttributes = &attributes;
memset(pAttributes, 0, sizeof(attributes));
}
CSSM_RETURN result = CSSM_DL_DataGetFirst(db->handle(), inQuery, &resultsHandle,
pAttributes, inoutData, uniqueId);
if (result)
{
if (result == CSSMERR_DL_ENDOFDATA)
return CSSM_INVALID_HANDLE;
CssmError::throwMe(result);
}
uniqueId->activate();
if (inoutData)
{
if (pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PUBLIC_KEY
|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PRIVATE_KEY
|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
{
CssmKey *outKey = DatabaseSession::alloc<CssmKey>();
new SSKey(*this, *outKey, db, uniqueId, pAttributes->DataRecordType, *inoutData);
allocator().free(inoutData->Data);
inoutData->Length = sizeof(*outKey);
inoutData->Data = reinterpret_cast<uint8 *>(outKey);
}
}
outUniqueRecord = makeSSUniqueRecord(uniqueId);
return resultsHandle;
}
bool
SSDLSession::DataGetNext(CSSM_DB_HANDLE inDbHandle,
CSSM_HANDLE inResultsHandle,
CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
CssmData *inoutData,
CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord)
{
SSDatabase db = findDbHandle(inDbHandle);
SSUniqueRecord uniqueId(db);
CSSM_DB_RECORD_ATTRIBUTE_DATA attributes;
CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pAttributes;
if (inoutAttributes)
pAttributes = inoutAttributes;
else
{
pAttributes = &attributes;
memset(pAttributes, 0, sizeof(attributes));
}
CSSM_RETURN result = CSSM_DL_DataGetNext(db->handle(), inResultsHandle,
inoutAttributes, inoutData, uniqueId);
if (result)
{
if (result == CSSMERR_DL_ENDOFDATA)
return false;
CssmError::throwMe(result);
}
uniqueId->activate();
if (inoutData)
{
if (pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PUBLIC_KEY
|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PRIVATE_KEY
|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
{
CssmKey *outKey = DatabaseSession::alloc<CssmKey>();
new SSKey(*this, *outKey, db, uniqueId, pAttributes->DataRecordType, *inoutData);
allocator().free(inoutData->Data);
inoutData->Length = sizeof(*outKey);
inoutData->Data = reinterpret_cast<uint8 *>(outKey);
}
}
outUniqueRecord = makeSSUniqueRecord(uniqueId);
return true;
}
void
SSDLSession::DataAbortQuery(CSSM_DB_HANDLE inDbHandle,
CSSM_HANDLE inResultsHandle)
{
SSDatabase db = findDbHandle(inDbHandle);
CSSM_RETURN result = CSSM_DL_DataAbortQuery(db->handle(), inResultsHandle);
if (result)
CssmError::throwMe(result);
}
void
SSDLSession::DataGetFromUniqueRecordId(CSSM_DB_HANDLE inDbHandle,
const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
CssmData *inoutData)
{
SSDatabase db = findDbHandle(inDbHandle);
const SSUniqueRecord uniqueId = findSSUniqueRecord(inUniqueRecord);
CSSM_DB_RECORD_ATTRIBUTE_DATA attributes;
CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pAttributes;
if (inoutAttributes)
pAttributes = inoutAttributes;
else
{
pAttributes = &attributes;
memset(pAttributes, 0, sizeof(attributes));
}
CSSM_RETURN result = CSSM_DL_DataGetFromUniqueRecordId(db->handle(),
uniqueId, pAttributes, inoutData);
if (result)
CssmError::throwMe(result);
if (inoutData)
{
if (pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PUBLIC_KEY
|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PRIVATE_KEY
|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
{
CssmKey *outKey = DatabaseSession::alloc<CssmKey>();
new SSKey(*this, *outKey, db, uniqueId, pAttributes->DataRecordType, *inoutData);
allocator().free(inoutData->Data);
inoutData->Length = sizeof(*outKey);
inoutData->Data = reinterpret_cast<uint8 *>(outKey);
}
}
}
void
SSDLSession::FreeUniqueRecord(CSSM_DB_HANDLE inDbHandle,
CSSM_DB_UNIQUE_RECORD &inUniqueRecordIdentifier)
{
killSSUniqueRecord(inUniqueRecordIdentifier);
}
static const uint32 kGenericAttributeNames[] =
{
'cdat', 'mdat', 'desc', 'icmt', 'crtr', 'type', 'scrp', 7, 8, 'invi', 'nega', 'cusi', 'prot', 'acct', 'svce',
'gena'
};
const uint32 kNumGenericAttributes = sizeof (kGenericAttributeNames) / sizeof (uint32);
static const uint32 kApplesharePasswordNames[] =
{
'cdat', 'mdat', 'desc', 'icmt', 'crtr', 'type', 'scrp', 7, 8, 'invi', 'nega', 'cusi', 'prot', 'acct', 'vlme',
'srvr', 'ptcl', 'addr', 'ssig'
};
const uint32 kNumApplesharePasswordAttributes = sizeof (kApplesharePasswordNames) / sizeof (uint32);
static const uint32 kInternetPasswordNames[] =
{
'cdat', 'mdat', 'desc', 'icmt', 'crtr', 'type', 'scrp', 7, 8, 'invi', 'nega', 'cusi', 'prot', 'acct', 'sdmn',
'srvr', 'ptcl', 'atyp', 'port', 'path'
};
const uint32 kNumInternetPasswordAttributes = sizeof (kInternetPasswordNames) / sizeof (uint32);
const uint32 kKeyAttributeNames[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26
};
const uint32 kNumKeyAttributes = sizeof (kKeyAttributeNames) / sizeof (uint32);
const uint32 kCertificateAttributeNames[] =
{
'ctyp', 'cenc', 'labl', 'alis', 'subj', 'issu', 'snbr', 'skid', 'hpky'
};
const uint32 kNumCertificateAttributes = sizeof (kCertificateAttributeNames) / sizeof (uint32);
const unsigned kSymmetricKeyLabel = 6; const unsigned kLabelSize = 20;
const unsigned kNumSymmetricAttributes = 27;
static void appendUInt32ToData (const uint32 value, CssmDataContainer &data)
{
data.append (CssmPolyData (uint32 (htonl (value))));
}
static inline uint32 GetUInt32AtFinger (uint8 *&finger)
{
uint32 a = ((finger[0] << 24) | (finger[1] << 16) | (finger[2] << 8) | finger[3]);
finger += sizeof (uint32);
return a;
}
void
SSDLSession::unwrapAttributesAndData (uint32 &numAttributes,
CSSM_DB_ATTRIBUTE_DATA_PTR &attributes,
CSSM_DATA &data,
CSSM_DATA &input)
{
uint8* finger = input.Data;
numAttributes = GetUInt32AtFinger (finger);
uint8* maximum = input.Data + input.Length;
attributes = (CSSM_DB_ATTRIBUTE_DATA*) allocator ().malloc (numAttributes * sizeof (CSSM_DB_ATTRIBUTE_DATA));
unsigned i;
for (i = 0; i < numAttributes; ++i)
{
attributes[i].Info.AttributeNameFormat = GetUInt32AtFinger (finger);
attributes[i].Info.Label.AttributeID = GetUInt32AtFinger (finger);
attributes[i].Info.AttributeFormat = GetUInt32AtFinger (finger);
attributes[i].NumberOfValues = GetUInt32AtFinger (finger);
attributes[i].Value = (CSSM_DATA*) allocator ().malloc (sizeof (CSSM_DATA) * attributes[i].NumberOfValues);
unsigned j;
for (j = 0; j < attributes[i].NumberOfValues; ++j)
{
attributes[i].Value[j].Length = GetUInt32AtFinger (finger);
if (attributes[i].Value[j].Length != 0)
{
if (finger > maximum || finger + attributes[i].Value[j].Length > maximum)
{
CssmError::throwMe (CSSM_ERRCODE_INVALID_POINTER);
}
attributes[i].Value[j].Data = (uint8*) allocator ().malloc (attributes[i].Value[j].Length);
switch (attributes[i].Info.AttributeFormat)
{
default:
{
memmove (attributes[i].Value[j].Data, finger, attributes[i].Value[j].Length);
finger += attributes[i].Value[j].Length;
break;
}
case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
{
*(uint32*) attributes[i].Value[j].Data = GetUInt32AtFinger (finger);
break;
}
case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32:
{
uint32* d = (uint32*) attributes[i].Value[j].Data;
unsigned long numValues = attributes[i].Value[j].Length / sizeof (UInt32);
while (numValues--)
{
*d++ = GetUInt32AtFinger (finger);
}
break;
}
}
}
else
{
attributes[i].Value[j].Data = NULL;
}
}
}
data.Length = GetUInt32AtFinger (finger);
if (data.Length != 0)
{
if (finger + data.Length > maximum)
{
CssmError::throwMe (CSSM_ERRCODE_INVALID_POINTER);
}
data.Data = (uint8*) allocator ().malloc (data.Length);
memmove (data.Data, finger, data.Length);
finger += data.Length;
}
else
{
data.Data = NULL;
}
}
void
SSDLSession::getWrappedAttributesAndData (SSDatabase &db,
CSSM_DB_RECORDTYPE recordType,
CSSM_DB_UNIQUE_RECORD_PTR recordPtr,
CssmDataContainer &output,
CSSM_DATA *dataBlob)
{
const uint32* attributeNameArray;
uint32 numAttributeNames;
switch (recordType)
{
case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
{
attributeNameArray = kGenericAttributeNames;
numAttributeNames = kNumGenericAttributes;
break;
}
case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
{
attributeNameArray = kInternetPasswordNames;
numAttributeNames = kNumInternetPasswordAttributes;
break;
}
case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
{
attributeNameArray = kApplesharePasswordNames;
numAttributeNames = kNumApplesharePasswordAttributes;
break;
}
case CSSM_DL_DB_RECORD_X509_CERTIFICATE:
{
attributeNameArray = kCertificateAttributeNames;
numAttributeNames = kNumCertificateAttributes;
break;
}
case CSSM_DL_DB_RECORD_PUBLIC_KEY:
case CSSM_DL_DB_RECORD_PRIVATE_KEY:
case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
{
attributeNameArray = kKeyAttributeNames;
numAttributeNames = kNumKeyAttributes;
break;
}
default:
{
CssmError::throwMe (CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
}
}
size_t arraySize = numAttributeNames * sizeof (CSSM_DB_ATTRIBUTE_DATA);
CSSM_DB_ATTRIBUTE_DATA_PTR attributes =
(CSSM_DB_ATTRIBUTE_DATA_PTR) allocator ().malloc (arraySize);
memset (attributes, 0, arraySize);
unsigned i;
for (i = 0; i < numAttributeNames; ++i)
{
attributes[i].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
attributes[i].Info.Label.AttributeID = attributeNameArray[i];
}
CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
attrData.DataRecordType = recordType;
attrData.SemanticInformation = 0;
attrData.NumberOfAttributes = numAttributeNames;
attrData.AttributeData = attributes;
CssmDataContainer data;
CSSM_RETURN result = CSSM_DL_DataGetFromUniqueRecordId (db->handle (),
recordPtr,
&attrData,
&data);
if (result != 0)
{
CssmError::throwMe (result);
}
appendUInt32ToData (numAttributeNames, output);
for (i = 0; i < numAttributeNames; ++i)
{
appendUInt32ToData (attributes[i].Info.AttributeNameFormat, output);
appendUInt32ToData (attributes[i].Info.Label.AttributeID, output);
appendUInt32ToData (attributes[i].Info.AttributeFormat, output);
appendUInt32ToData (attributes[i].NumberOfValues, output);
unsigned j;
for (j = 0; j < attributes[i].NumberOfValues; ++j)
{
appendUInt32ToData ((uint32)attributes[i].Value[j].Length, output);
if (attributes[i].Value[j].Length != 0)
{
switch (attributes[i].Info.AttributeFormat)
{
default:
{
output.append (CssmPolyData (attributes[i].Value[j]));
break;
}
case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
{
uint32 n = htonl (*(uint32*) attributes[i].Value[j].Data);
CSSM_DATA d;
d.Length = sizeof (uint32);
d.Data = (uint8*) &n;
output.append (CssmPolyData (d));
break;
}
}
}
}
}
appendUInt32ToData ((uint32)data.Length, output);
if (data.Length != 0)
{
output.append (CssmPolyData (data));
}
for (i = 0; i < numAttributeNames; ++i)
{
unsigned j;
for (j = 0; j < attributes[i].NumberOfValues; ++j)
{
allocator ().free (attributes[i].Value[j].Data);
}
allocator ().free (attributes[i].Value);
}
allocator ().free (attributes);
if (dataBlob)
{
dataBlob->Data = data.Data;
dataBlob->Length = data.Length;
data.Data = NULL;
data.Length = 0;
}
}
void
SSDLSession::getUniqueIdForSymmetricKey (SSDatabase &db, CSSM_DATA &label,
CSSM_DB_UNIQUE_RECORD_PTR &uniqueRecord)
{
CSSM_SELECTION_PREDICATE predicate;
predicate.DbOperator = CSSM_DB_EQUAL;
predicate.Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
predicate.Attribute.Info.Label.AttributeID = kSymmetricKeyLabel;
predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
predicate.Attribute.NumberOfValues = 1;
predicate.Attribute.Value = &label;
CSSM_QUERY query;
query.RecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
query.Conjunctive = CSSM_DB_NONE;
query.NumSelectionPredicates = 1;
query.SelectionPredicate = &predicate;
CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttributeData;
recordAttributeData.DataRecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
recordAttributeData.SemanticInformation = 0;
recordAttributeData.NumberOfAttributes = 0;
recordAttributeData.AttributeData = NULL;
CSSM_HANDLE handle;
CSSM_RETURN result = CSSM_DL_DataGetFirst (db->handle (), &query, &handle, &recordAttributeData, NULL,
&uniqueRecord);
if (result)
{
CssmError::throwMe (result);
}
CSSM_DL_DataAbortQuery (db->handle (), handle);
}
void
SSDLSession::getCorrespondingSymmetricKey (SSDatabase &db, CSSM_DATA &labelData, CssmDataContainer &data)
{
CSSM_DB_UNIQUE_RECORD_PTR uniqueRecord;
getUniqueIdForSymmetricKey (db, labelData, uniqueRecord);
getWrappedAttributesAndData (db, CSSM_DL_DB_RECORD_SYMMETRIC_KEY, uniqueRecord, data, NULL);
CSSM_DL_FreeUniqueRecord (db->handle (), uniqueRecord);
}
void SSDLSession::doGetWithoutEncryption (SSDatabase &db, const void *inInputParams, void **outOutputParams)
{
CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS* params =
(CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS*) inInputParams;
SSUniqueRecord uniqueID = findSSUniqueRecord(*(params->uniqueID));
CSSM_DATA *outputData = (CSSM_DATA*) outOutputParams;
CssmDataContainer output;
CssmDataContainer data;
CSSM_RETURN result = CSSM_DL_DataGetFromUniqueRecordId(db->handle(),
uniqueID,
params->attributes,
NULL);
if (result)
{
CssmError::throwMe(result);
}
CssmDataContainer blobData;
getWrappedAttributesAndData (db, params->attributes->DataRecordType, uniqueID, data, &blobData);
appendUInt32ToData ((uint32)data.Length, output);
output.append (CssmPolyData (data));
CssmDataContainer key;
switch (params->attributes->DataRecordType)
{
case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
{
CSSM_DATA label = {kLabelSize, blobData.Data};
getCorrespondingSymmetricKey (db, label, key);
}
break;
default:
{
break;
}
}
appendUInt32ToData ((uint32)key.Length, output);
if (key.Length != 0)
{
output.append (CssmPolyData (key));
}
outputData->Data = output.Data;
output.Data = NULL;
outputData->Length = output.Length;
output.Length = 0;
}
void
SSDLSession::cleanupAttributes (uint32 numAttributes, CSSM_DB_ATTRIBUTE_DATA_PTR attributes)
{
unsigned i;
for (i = 0; i < numAttributes; ++i)
{
unsigned j;
for (j = 0; j < attributes[i].NumberOfValues; ++j)
{
free (attributes[i].Value[j].Data);
}
free (attributes[i].Value);
}
free (attributes);
}
void
SSDLSession::doModifyWithoutEncryption (SSDatabase &db, const void* inInputParams, void** outOutputParams)
{
CSSM_RETURN result;
CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS* params =
(CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS*) inInputParams;
uint8* finger = params->data->Data;
CSSM_DATA data;
data.Length = GetUInt32AtFinger (finger);
data.Data = finger;
if (data.Length + sizeof (UInt32) > params->data->Length)
{
CssmError::throwMe (CSSM_ERRCODE_INVALID_POINTER);
}
finger += data.Length;
uint32 numAttributes;
CSSM_DB_ATTRIBUTE_DATA_PTR attributes;
CssmDataContainer dataBlob;
unwrapAttributesAndData (numAttributes, attributes, dataBlob, data);
CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
attrData.DataRecordType = params->attributes->DataRecordType;
attrData.SemanticInformation = 0;
attrData.NumberOfAttributes = numAttributes;
attrData.AttributeData = attributes;
SSUniqueRecord uniqueID = findSSUniqueRecord(*(params->uniqueID));
CSSM_DB_UNIQUE_RECORD *uniqueIDPtr = uniqueID;
switch (attrData.DataRecordType)
{
case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
{
CssmDataContainer oldData;
result = CSSM_DL_DataGetFromUniqueRecordId (db->handle(),
uniqueIDPtr,
NULL,
&oldData);
if (result)
{
CssmError::throwMe (result);
}
CSSM_DB_MODIFY_MODE modifyMode = params->modifyMode;
CssmDataContainer keyBlob;
data.Length = GetUInt32AtFinger (finger);
data.Data = finger;
CSSM_DB_RECORD_ATTRIBUTE_DATA* attrDataPtr = NULL;
CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
CSSM_DATA labelData = {kLabelSize, oldData.Data};
CSSM_DB_UNIQUE_RECORD_PTR recordID;
getUniqueIdForSymmetricKey (db, labelData, recordID);
CSSM_DB_ATTRIBUTE_DATA_PTR keyAttributes;
uint32 numKeyAttributes;
unwrapAttributesAndData (numKeyAttributes, keyAttributes, keyBlob, data);
attrData.DataRecordType = params->recordType;
attrData.SemanticInformation = 0;
attrData.NumberOfAttributes = numKeyAttributes;
attrData.AttributeData = keyAttributes;
attrDataPtr = &attrData;
result = CSSM_DL_DataModify (db->handle(),
CSSM_DL_DB_RECORD_SYMMETRIC_KEY,
recordID,
attrDataPtr,
&keyBlob,
modifyMode);
CSSM_DL_FreeUniqueRecord (db->handle (), recordID);
cleanupAttributes (numKeyAttributes, keyAttributes);
break;
}
default:
{
break;
}
}
result = CSSM_DL_DataModify(db->handle(),
params->recordType,
uniqueIDPtr,
&attrData,
&dataBlob,
params->modifyMode);
cleanupAttributes (numAttributes, attributes);
if (result)
{
CssmError::throwMe(result);
}
}
void
SSDLSession::doInsertWithoutEncryption (SSDatabase &db, const void* inInputParams, void** outOutputParams)
{
CSSM_RETURN result;
CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION_PARAMETERS* params =
(CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION_PARAMETERS*) inInputParams;
uint8* finger = params->data.Data;
CSSM_DATA data;
data.Length = GetUInt32AtFinger (finger);
data.Data = finger;
finger += data.Length;
uint32 numAttributes;
CSSM_DB_ATTRIBUTE_DATA_PTR attributes;
CSSM_DATA dataBlob;
unwrapAttributesAndData (numAttributes, attributes, dataBlob, data);
CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
attrData.DataRecordType = params->recordType;
attrData.SemanticInformation = 0;
attrData.NumberOfAttributes = numAttributes;
attrData.AttributeData = attributes;
SSUniqueRecord uniqueID (db);
result = CSSM_DL_DataInsert (db->handle(), params->recordType,
&attrData,
&dataBlob,
uniqueID);
allocator ().free (dataBlob.Data);
cleanupAttributes (numAttributes, attributes);
CSSM_DB_UNIQUE_RECORD_PTR newRecord = makeSSUniqueRecord(uniqueID);
*(CSSM_DB_UNIQUE_RECORD_PTR*) outOutputParams = newRecord;
if (result)
{
CssmError::throwMe(result);
}
data.Length = GetUInt32AtFinger (finger);
if (data.Length != 0)
{
data.Data = finger;
unwrapAttributesAndData (numAttributes, attributes, dataBlob, data);
CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
attrData.DataRecordType = params->recordType;
attrData.SemanticInformation = 0;
attrData.NumberOfAttributes = numAttributes;
attrData.AttributeData = attributes;
CSSM_DB_UNIQUE_RECORD_PTR uniqueRecord;
result = CSSM_DL_DataInsert (db->handle(), CSSM_DL_DB_RECORD_SYMMETRIC_KEY, &attrData, &dataBlob,
&uniqueRecord);
if (result)
{
CssmError::throwMe (result);
}
CSSM_DL_FreeUniqueRecord (db->handle (), uniqueRecord);
allocator ().free (dataBlob.Data);
cleanupAttributes (numAttributes, attributes);
}
}
void
SSDLSession::doConvertRecordIdentifier (SSDatabase &db, const void *inInputParams, void **outOutputParams)
{
SSUniqueRecord uniqueId (db);
CSSM_DB_UNIQUE_RECORD_PTR clone = (CSSM_DB_UNIQUE_RECORD_PTR) allocator ().malloc (sizeof (CSSM_DB_UNIQUE_RECORD));
*clone = *(CSSM_DB_UNIQUE_RECORD_PTR) inInputParams;
uniqueId->setUniqueRecordPtr (clone);
uint32* idArray = (uint32*) clone->RecordIdentifier.Data;
idArray[0] = ntohl (idArray[0]);
idArray[1] = ntohl (idArray[1]);
idArray[2] = ntohl (idArray[2]);
CSSM_DB_UNIQUE_RECORD_PTR newRecord = makeSSUniqueRecord(uniqueId);
*(CSSM_DB_UNIQUE_RECORD_PTR*) outOutputParams = newRecord;
}
void
SSDLSession::PassThrough(CSSM_DB_HANDLE inDbHandle,
uint32 inPassThroughId,
const void *inInputParams,
void **outOutputParams)
{
if (inPassThroughId == CSSM_APPLECSPDL_DB_CREATE_WITH_BLOB)
{
CSSM_APPLE_CSPDL_DB_CREATE_WITH_BLOB_PARAMETERS* params = (CSSM_APPLE_CSPDL_DB_CREATE_WITH_BLOB_PARAMETERS*) inInputParams;
CreateWithBlob(params->dbName, params->dbLocation, *params->dbInfo, params->accessRequest, params->openParameters, *params->blob,
* (CSSM_DB_HANDLE*) outOutputParams);
return;
}
SSDatabase db = findDbHandle(inDbHandle);
switch (inPassThroughId)
{
case CSSM_APPLECSPDL_DB_LOCK:
db->lock();
break;
case CSSM_APPLECSPDL_DB_UNLOCK:
if (inInputParams)
db->unlock(*reinterpret_cast<const CSSM_DATA *>(inInputParams));
else
db->unlock();
break;
case CSSM_APPLECSPDL_DB_STASH:
db->stash();
break;
case CSSM_APPLECSPDL_DB_STASH_CHECK:
db->stashCheck();
break;
case CSSM_APPLECSPDL_DB_GET_SETTINGS:
{
if (!outOutputParams)
CssmError::throwMe(CSSM_ERRCODE_INVALID_OUTPUT_POINTER);
CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR params =
DatabaseSession::alloc<CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS>();
try
{
uint32 idleTimeout;
bool lockOnSleep;
db->getSettings(idleTimeout, lockOnSleep);
params->idleTimeout = idleTimeout;
params->lockOnSleep = lockOnSleep;
}
catch(...)
{
allocator().free(params);
throw;
}
*reinterpret_cast<CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR *>(outOutputParams) = params;
break;
}
case CSSM_APPLECSPDL_DB_SET_SETTINGS:
{
if (!inInputParams)
CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
const CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS *params =
reinterpret_cast<const CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS *>(inInputParams);
db->setSettings(params->idleTimeout, params->lockOnSleep);
break;
}
case CSSM_APPLECSPDL_DB_IS_LOCKED:
{
if (!outOutputParams)
CssmError::throwMe(CSSM_ERRCODE_INVALID_OUTPUT_POINTER);
CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params =
DatabaseSession::alloc<CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS>();
try
{
params->isLocked = db->isLocked();
}
catch(...)
{
allocator().free(params);
throw;
}
*reinterpret_cast<CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR *>(outOutputParams) = params;
break;
}
case CSSM_APPLECSPDL_DB_CHANGE_PASSWORD:
{
if (!inInputParams)
CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
const CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS *params =
reinterpret_cast<const CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS *>(inInputParams);
db->changePassphrase(params->accessCredentials);
break;
}
case CSSM_APPLECSPDL_DB_GET_HANDLE:
{
using SecurityServer::DbHandle;
Required(outOutputParams, CSSM_ERRCODE_INVALID_OUTPUT_POINTER);
*reinterpret_cast<CSSM_DL_DB_HANDLE *>(outOutputParams) = db->handle();
break;
}
case CSSM_APPLECSPDL_CSP_RECODE:
{
if (!inInputParams)
CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
const CSSM_APPLECSPDL_RECODE_PARAMETERS *params =
reinterpret_cast<const CSSM_APPLECSPDL_RECODE_PARAMETERS *>(inInputParams);
db->recode(CssmData::overlay(params->dbBlob),
CssmData::overlay(params->extraData));
break;
}
case CSSM_APPLECSPDL_DB_GET_RECORD_IDENTIFIER:
{
SSUniqueRecord uniqueID = findSSUniqueRecord(*(CSSM_DB_UNIQUE_RECORD_PTR) inInputParams);
db->getRecordIdentifier(uniqueID, *reinterpret_cast<CSSM_DATA *>(outOutputParams));
break;
}
case CSSM_APPLECSPDL_DB_COPY_BLOB:
{
db->copyBlob(*reinterpret_cast<CSSM_DATA *>(outOutputParams));
break;
}
case CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION:
{
doInsertWithoutEncryption (db, inInputParams, outOutputParams);
break;
}
case CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION:
{
doModifyWithoutEncryption (db, inInputParams, outOutputParams);
break;
}
case CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION:
{
doGetWithoutEncryption (db, inInputParams, outOutputParams);
break;
}
case CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER:
{
doConvertRecordIdentifier (db, inInputParams, outOutputParams);
break;
}
default:
{
CSSM_RETURN result = CSSM_DL_PassThrough(db->handle(), inPassThroughId, inInputParams, outOutputParams);
if (result)
CssmError::throwMe(result);
break;
}
}
}
CSSM_DB_HANDLE
SSDLSession::makeDbHandle(SSDatabase &inDb)
{
StLock<Mutex> _(mDbHandleLock);
CSSM_DB_HANDLE aDbHandle = inDb->handle().DBHandle;
bool inserted;
inserted = mDbHandleMap.insert(DbHandleMap::value_type(aDbHandle, inDb)).second;
assert(inserted);
return aDbHandle;
}
SSDatabase
SSDLSession::killDbHandle(CSSM_DB_HANDLE inDbHandle)
{
StLock<Mutex> _(mDbHandleLock);
DbHandleMap::iterator it = mDbHandleMap.find(inDbHandle);
if (it == mDbHandleMap.end())
{
CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE);
}
SSDatabase db = it->second;
mDbHandleMap.erase(it);
return db;
}
SSDatabase
SSDLSession::findDbHandle(CSSM_DB_HANDLE inDbHandle)
{
StLock<Mutex> _(mDbHandleLock);
DbHandleMap::iterator it = mDbHandleMap.find(inDbHandle);
if (it == mDbHandleMap.end())
{
DbHandleMap::iterator it = mDbHandleMap.begin();
while (it != mDbHandleMap.end())
{
it++;
}
CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE);
}
return it->second;
}
CSSM_DB_UNIQUE_RECORD_PTR
SSDLSession::makeSSUniqueRecord(SSUniqueRecord &uniqueId)
{
StLock<Mutex> _(mSSUniqueRecordLock);
CSSM_HANDLE ref = CSSM_HANDLE(static_cast<CSSM_DB_UNIQUE_RECORD *>(uniqueId));
bool inserted;
inserted = mSSUniqueRecordMap.insert(SSUniqueRecordMap::value_type(ref, uniqueId)).second;
assert(inserted);
return createUniqueRecord(ref);
}
SSUniqueRecord
SSDLSession::killSSUniqueRecord(CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
{
CSSM_HANDLE ref = parseUniqueRecord(inUniqueRecord);
StLock<Mutex> _(mSSUniqueRecordLock);
SSUniqueRecordMap::iterator it = mSSUniqueRecordMap.find(ref);
if (it == mSSUniqueRecordMap.end())
CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
SSUniqueRecord uniqueRecord = it->second;
mSSUniqueRecordMap.erase(it);
freeUniqueRecord(inUniqueRecord);
return uniqueRecord;
}
SSUniqueRecord
SSDLSession::findSSUniqueRecord(const CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
{
CSSM_HANDLE ref = parseUniqueRecord(inUniqueRecord);
StLock<Mutex> _(mSSUniqueRecordLock);
SSUniqueRecordMap::iterator it = mSSUniqueRecordMap.find(ref);
if (it == mSSUniqueRecordMap.end())
CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
return it->second;
}
CSSM_DB_UNIQUE_RECORD_PTR
SSDLSession::createUniqueRecord(CSSM_HANDLE ref)
{
CSSM_DB_UNIQUE_RECORD *aUniqueRecord = DatabaseSession::alloc<CSSM_DB_UNIQUE_RECORD>();
memset(aUniqueRecord, 0, sizeof(CSSM_DB_UNIQUE_RECORD));
aUniqueRecord->RecordIdentifier.Length = sizeof(CSSM_HANDLE);
try
{
aUniqueRecord->RecordIdentifier.Data = DatabaseSession::alloc<uint8>(sizeof(CSSM_HANDLE));
*reinterpret_cast<CSSM_HANDLE *>(aUniqueRecord->RecordIdentifier.Data) = ref;
}
catch(...)
{
free(aUniqueRecord);
throw;
}
return aUniqueRecord;
}
CSSM_HANDLE
SSDLSession::parseUniqueRecord(const CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
{
if (inUniqueRecord.RecordIdentifier.Length != sizeof(CSSM_HANDLE))
CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
return *reinterpret_cast<CSSM_HANDLE *>(inUniqueRecord.RecordIdentifier.Data);
}
void
SSDLSession::freeUniqueRecord(CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
{
if (inUniqueRecord.RecordIdentifier.Length != 0
&& inUniqueRecord.RecordIdentifier.Data != NULL)
{
inUniqueRecord.RecordIdentifier.Length = 0;
allocator().free(inUniqueRecord.RecordIdentifier.Data);
}
allocator().free(&inUniqueRecord);
}