#include "KCCursor.h"
#include "Item.h"
#include <security_cdsa_utilities/Schema.h>
#include <security_cdsa_utilities/KeySchema.h>
#include "cssmdatetime.h"
#include "Globals.h"
#include "StorageManager.h"
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <Security/SecKeychainItemPriv.h>
using namespace KeychainCore;
using namespace CssmClient;
using namespace CSSMDateTimeUtils;
using namespace KeySchema;
static const CSSM_DB_ATTRIBUTE_INFO* gKeyAttributeLookupTable[] =
{
&KeyClass, &PrintName, &Alias, &Permanent, &Private, &Modifiable, &Label, &ApplicationTag, &KeyCreator,
&KeyType, &KeySizeInBits, &EffectiveKeySize, &StartDate, &EndDate, &Sensitive, &AlwaysSensitive, &Extractable,
&NeverExtractable, &Encrypt, &Decrypt, &Derive, &Sign, &Verify, &SignRecover, &VerifyRecover, &Wrap, &Unwrap
};
KCCursorImpl::KCCursorImpl(const StorageManager::KeychainList &searchList, SecItemClass itemClass, const SecKeychainAttributeList *attrList, CSSM_DB_CONJUNCTIVE dbConjunctive, CSSM_DB_OPERATOR dbOperator) :
mSearchList(searchList),
mCurrent(mSearchList.begin()),
mAllFailed(true)
{
recordType(Schema::recordTypeFor(itemClass));
if (!attrList) return;
conjunctive(dbConjunctive);
const SecKeychainAttribute *end=&attrList->attr[attrList->count];
for (const SecKeychainAttribute *attr=attrList->attr; attr != end; ++attr)
{
const CSSM_DB_ATTRIBUTE_INFO *temp;
if (attr->tag <' ') {
temp = gKeyAttributeLookupTable[attr->tag];
}
else
{
temp = &Schema::attributeInfo(attr->tag);
}
const CssmDbAttributeInfo &info = *temp;
void *buf = attr->data;
UInt32 length = attr->length;
uint8 timeString[16];
if (info.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
{
if (length == sizeof(UInt32))
{
MacSecondsToTimeString(*reinterpret_cast<const UInt32 *>(buf),
16, &timeString);
buf = &timeString;
length = 16;
}
else if (length == sizeof(SInt64))
{
MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64 *>(buf),
16, &timeString);
buf = &timeString;
length = 16;
}
}
add(dbOperator ,info, CssmData(buf,length));
}
}
KCCursorImpl::KCCursorImpl(const StorageManager::KeychainList &searchList, const SecKeychainAttributeList *attrList) :
mSearchList(searchList),
mCurrent(mSearchList.begin()),
mAllFailed(true)
{
if (!attrList) return;
conjunctive(CSSM_DB_AND);
bool foundClassAttribute=false;
const SecKeychainAttribute *end=&attrList->attr[attrList->count];
for (const SecKeychainAttribute *attr=attrList->attr; attr != end; ++attr)
{
if (attr->tag!=kSecClassItemAttr) {
const CssmDbAttributeInfo &info = Schema::attributeInfo(attr->tag);
void *buf = attr->data;
UInt32 length = attr->length;
uint8 timeString[16];
if (info.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
{
if (length == sizeof(UInt32))
{
MacSecondsToTimeString(*reinterpret_cast<const UInt32 *>(buf),
16, &timeString);
buf = &timeString;
length = 16;
}
else if (length == sizeof(SInt64))
{
MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64 *>(buf),
16, &timeString);
buf = &timeString;
length = 16;
}
}
add(CSSM_DB_EQUAL,info, CssmData(buf,length));
continue;
}
if (foundClassAttribute || attr->length != sizeof(SecItemClass))
MacOSError::throwMe(paramErr);
recordType(Schema::recordTypeFor(*reinterpret_cast<SecItemClass *>(attr->data)));
foundClassAttribute=true;
}
}
KCCursorImpl::~KCCursorImpl() throw()
{
}
bool
KCCursorImpl::next(Item &item)
{
DbAttributes dbAttributes;
DbUniqueRecord uniqueId;
OSStatus status = 0;
for (;;)
{
if (!mDbCursor)
{
if (mCurrent == mSearchList.end())
{
if (mAllFailed && status)
CssmError::throwMe(status);
return false;
}
mDbCursor = DbCursor((*mCurrent)->database(), *this);
}
bool gotRecord;
try
{
gotRecord = mDbCursor->next(&dbAttributes, NULL, uniqueId);
mAllFailed = false;
}
catch(const CommonError &err)
{
status = err.osStatus();
gotRecord = false;
}
if (!gotRecord)
{
++mCurrent;
mDbCursor = DbCursor();
continue;
}
if (mDbCursor->recordType() == CSSM_DL_DB_RECORD_ANY &&
(dbAttributes.recordType() == 0x80008000
|| dbAttributes.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY))
continue;
break;
}
item = (*mCurrent)->item(dbAttributes.recordType(), uniqueId);
return true;
}