6243 lines
132 KiB
C++
6243 lines
132 KiB
C++
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: db.cpp
|
|
//
|
|
// Contents: Cert Server Database interface implementation
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "csprop.h"
|
|
#include "db.h"
|
|
#include "column.h"
|
|
#include "row.h"
|
|
#include "view.h"
|
|
#include "backup.h"
|
|
#include "restore.h"
|
|
#include "dbw.h"
|
|
|
|
#define __dwFILE__ __dwFILE_CERTDB_DB_CPP__
|
|
|
|
|
|
#define SEEKPOS_FIRST 0
|
|
#define SEEKPOS_LAST 1
|
|
#define SEEKPOS_INDEXFIRST 2
|
|
#define SEEKPOS_INDEXLAST 3
|
|
|
|
LONG g_cCertDB = 0;
|
|
LONG g_cCertDBTotal = 0;
|
|
LONG g_cXactCommit = 0;
|
|
LONG g_cXactAbort = 0;
|
|
LONG g_cXactTotal = 0;
|
|
|
|
char *g_pszDBFile = NULL;
|
|
|
|
typedef struct _DBJETPARM {
|
|
DWORD paramid;
|
|
DWORD lParam;
|
|
char *pszParam;
|
|
BOOL fString;
|
|
} DBJETPARM;
|
|
|
|
|
|
DBJETPARM g_aParm[] = {
|
|
|
|
#define JP_LOGPATH 0
|
|
{ JET_paramLogFilePath, 0, NULL, TRUE },
|
|
|
|
#define JP_SYSTEMPATH 1
|
|
{ JET_paramSystemPath, 0, NULL, TRUE },
|
|
|
|
#define JP_TEMPPATH 2
|
|
{ JET_paramTempPath, 0, NULL, TRUE },
|
|
|
|
#define JP_EVENTSOURCE 3
|
|
{ JET_paramEventSource, 0, NULL, TRUE },
|
|
|
|
#define JP_SESSIONMAX 4
|
|
{ JET_paramMaxSessions, 0, NULL, FALSE },
|
|
|
|
#define JP_CACHESIZEMIN 5
|
|
{ JET_paramCacheSizeMin, 64, NULL, FALSE },
|
|
|
|
#define JP_CACHESIZEMAX 6
|
|
{ JET_paramCacheSizeMax, 512, NULL, FALSE },
|
|
|
|
#define JP_VERPAGESMAX 7 // 16k units: 64k per session
|
|
{ JET_paramMaxVerPages, 4 * DBSESSIONCOUNTDEFAULT, NULL, FALSE },
|
|
|
|
{ JET_paramRecovery, 0, "on", TRUE },
|
|
{ JET_paramMaxVerPages, 64, NULL, FALSE },
|
|
{ JET_paramMaxTemporaryTables, 5, NULL, FALSE },
|
|
{ JET_paramLogBuffers, 41, NULL, FALSE },
|
|
{ JET_paramLogFileSize, 1024, NULL, FALSE },
|
|
{ JET_paramAssertAction, JET_AssertBreak, NULL, FALSE },
|
|
{ JET_paramBaseName, 0, szDBBASENAMEPARM, TRUE } // "edb"
|
|
};
|
|
#define CDBPARM (sizeof(g_aParm)/sizeof(g_aParm[0]))
|
|
|
|
|
|
VOID
|
|
DBFreeParms()
|
|
{
|
|
if (NULL != g_aParm[JP_LOGPATH].pszParam)
|
|
{
|
|
LocalFree(g_aParm[JP_LOGPATH].pszParam);
|
|
g_aParm[JP_LOGPATH].pszParam = NULL;
|
|
}
|
|
if (NULL != g_aParm[JP_SYSTEMPATH].pszParam)
|
|
{
|
|
LocalFree(g_aParm[JP_SYSTEMPATH].pszParam);
|
|
g_aParm[JP_SYSTEMPATH].pszParam = NULL;
|
|
}
|
|
if (NULL != g_aParm[JP_TEMPPATH].pszParam)
|
|
{
|
|
LocalFree(g_aParm[JP_TEMPPATH].pszParam);
|
|
g_aParm[JP_TEMPPATH].pszParam = NULL;
|
|
}
|
|
if (NULL != g_aParm[JP_EVENTSOURCE].pszParam)
|
|
{
|
|
LocalFree(g_aParm[JP_EVENTSOURCE].pszParam);
|
|
g_aParm[JP_EVENTSOURCE].pszParam = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DBInitParms(
|
|
IN DWORD cSession,
|
|
IN BOOL fCircularLogging,
|
|
OPTIONAL IN WCHAR const *pwszEventSource,
|
|
OPTIONAL IN WCHAR const *pwszLogDir,
|
|
OPTIONAL IN WCHAR const *pwszSystemDir,
|
|
OPTIONAL IN WCHAR const *pwszTempDir,
|
|
OUT JET_INSTANCE *pInstance)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
DBJETPARM const *pjp;
|
|
WCHAR awc[MAX_PATH];
|
|
DWORD dwPerfTweak = 0;
|
|
|
|
DBFreeParms();
|
|
|
|
if (NULL != pwszLogDir)
|
|
{
|
|
wcscpy(awc, pwszLogDir);
|
|
wcscat(awc, L"\\");
|
|
if (!ConvertWszToSz(&g_aParm[JP_LOGPATH].pszParam, awc, -1))
|
|
{
|
|
_JumpError(hr, error, "ConvertWszToSz(LogDir)");
|
|
}
|
|
}
|
|
|
|
if (NULL != pwszSystemDir)
|
|
{
|
|
wcscpy(awc, pwszSystemDir);
|
|
wcscat(awc, L"\\");
|
|
if (!ConvertWszToSz(&g_aParm[JP_SYSTEMPATH].pszParam, awc, -1))
|
|
{
|
|
_JumpError(hr, error, "ConvertWszToSz(SystemDir)");
|
|
}
|
|
}
|
|
|
|
if (NULL != pwszTempDir)
|
|
{
|
|
wcscpy(awc, pwszTempDir);
|
|
wcscat(awc, L"\\");
|
|
if (!ConvertWszToSz(&g_aParm[JP_TEMPPATH].pszParam, awc, -1))
|
|
{
|
|
_JumpError(hr, error, "ConvertWszToSz(TempDir)");
|
|
}
|
|
}
|
|
|
|
if (NULL != pwszEventSource)
|
|
{
|
|
if (!ConvertWszToSz(
|
|
&g_aParm[JP_EVENTSOURCE].pszParam,
|
|
pwszEventSource,
|
|
-1))
|
|
{
|
|
_JumpError(hr, error, "ConvertWszToSz(EventSource)");
|
|
}
|
|
}
|
|
|
|
g_aParm[JP_SESSIONMAX].lParam = cSession + 1;
|
|
if (8 * cSession > g_aParm[JP_CACHESIZEMIN].lParam)
|
|
{
|
|
g_aParm[JP_CACHESIZEMIN].lParam = 8 * cSession;
|
|
}
|
|
if (8 * 8 * cSession > g_aParm[JP_CACHESIZEMAX].lParam)
|
|
{
|
|
g_aParm[JP_CACHESIZEMAX].lParam = 8 * 8 * cSession;
|
|
}
|
|
if (4 * cSession > g_aParm[JP_VERPAGESMAX].lParam)
|
|
{
|
|
g_aParm[JP_VERPAGESMAX].lParam = 4 * cSession;
|
|
}
|
|
for (pjp = g_aParm; pjp < &g_aParm[CDBPARM]; pjp++)
|
|
{
|
|
if (!pjp->fString || NULL != pjp->pszParam)
|
|
{
|
|
_dbgJetSetSystemParameter(
|
|
pInstance,
|
|
0,
|
|
pjp->paramid,
|
|
pjp->lParam,
|
|
pjp->pszParam);
|
|
}
|
|
}
|
|
|
|
if (fCircularLogging)
|
|
{
|
|
DBGPRINT((DBG_SS_CERTSRV, "Jet: circular logging enabled\n"));
|
|
_dbgJetSetSystemParameter(
|
|
pInstance,
|
|
0,
|
|
JET_paramCircularLog,
|
|
TRUE,
|
|
NULL);
|
|
}
|
|
|
|
|
|
if (S_OK == myGetCertRegDWValue(NULL, NULL, NULL, L"PerfTweak", &dwPerfTweak))
|
|
{
|
|
if (dwPerfTweak & 0x1)
|
|
{
|
|
_dbgJetSetSystemParameter(
|
|
pInstance,
|
|
0,
|
|
JET_paramLogBuffers,
|
|
480, // should be logfilesize (1024k) - 64k, specified in 512b units
|
|
NULL);
|
|
}
|
|
|
|
if (dwPerfTweak & 0x2)
|
|
{
|
|
_dbgJetSetSystemParameter(
|
|
pInstance,
|
|
0,
|
|
JET_paramCommitDefault,
|
|
JET_bitCommitLazyFlush,
|
|
NULL);
|
|
}
|
|
|
|
if (dwPerfTweak & 0x4)
|
|
{
|
|
// real fix is not to set this at all, but setting it to a large number should suffice
|
|
_dbgJetSetSystemParameter(
|
|
pInstance,
|
|
0,
|
|
JET_paramCacheSizeMax,
|
|
512*100, // 100x the size we usually run with
|
|
NULL);
|
|
}
|
|
|
|
if (dwPerfTweak & 0x8)
|
|
{
|
|
_dbgJetSetSystemParameter(
|
|
pInstance,
|
|
0,
|
|
JET_paramCheckpointDepthMax,
|
|
60 * 1024 * 1024, // 60MB -- triple the size we usually run with (20MB)
|
|
NULL);
|
|
}
|
|
|
|
|
|
if (dwPerfTweak & 0x10)
|
|
{
|
|
_dbgJetSetSystemParameter(
|
|
pInstance,
|
|
0,
|
|
JET_paramLogFileSize,
|
|
16384, // 16x the size we usually run with (1MB)
|
|
NULL);
|
|
}
|
|
|
|
if (dwPerfTweak & 0x20)
|
|
{
|
|
_dbgJetSetSystemParameter(
|
|
pInstance,
|
|
0,
|
|
JET_paramLogBuffers,
|
|
256, // usually run with 41
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if DBG_CERTSRV
|
|
|
|
WCHAR const *
|
|
wszCSFFlags(
|
|
IN LONG Flags)
|
|
{
|
|
static WCHAR s_awc[256];
|
|
|
|
wsprintf(s_awc, L"{%x", Flags);
|
|
|
|
if (CSF_INUSE & Flags) dbgcat(s_awc, L"InUse");
|
|
if (CSF_READONLY & Flags) dbgcat(s_awc, L"ReadOnly");
|
|
if (CSF_CREATE & Flags) dbgcat(s_awc, L"Create");
|
|
if (CSF_VIEW & Flags) dbgcat(s_awc, L"View");
|
|
if (CSF_VIEWRESET & Flags) dbgcat(s_awc, L"ViewReset");
|
|
|
|
wcscat(s_awc, L"}");
|
|
CSASSERT(wcslen(s_awc) < ARRAYSIZE(s_awc));
|
|
return(s_awc);
|
|
}
|
|
|
|
|
|
WCHAR const *
|
|
wszCSTFlags(
|
|
IN LONG Flags)
|
|
{
|
|
static WCHAR s_awc[256];
|
|
|
|
wsprintf(s_awc, L"{%x", Flags);
|
|
|
|
if (CST_SEEKINDEXRANGE & Flags) dbgcat(s_awc, L"IndexRange");
|
|
if (CST_SEEKNOTMOVE & Flags) dbgcat(s_awc, L"SeekNotMove");
|
|
if (CST_SEEKUSECURRENT & Flags) dbgcat(s_awc, L"UseCurrent");
|
|
if (0 == (CST_SEEKUSECURRENT & Flags)) dbgcat(s_awc, L"SkipCurrent");
|
|
if (CST_SEEKASCEND & Flags) dbgcat(s_awc, L"Ascend");
|
|
if (0 == (CST_SEEKASCEND & Flags)) dbgcat(s_awc, L"Descend");
|
|
|
|
wcscat(s_awc, L"}");
|
|
CSASSERT(wcslen(s_awc) < ARRAYSIZE(s_awc));
|
|
return(s_awc);
|
|
}
|
|
|
|
|
|
WCHAR const *
|
|
wszTable(
|
|
IN DWORD dwTable)
|
|
{
|
|
WCHAR const *pwsz;
|
|
|
|
switch (dwTable)
|
|
{
|
|
case TABLE_REQUESTS:
|
|
pwsz = wszREQUESTTABLE;
|
|
break;
|
|
|
|
case TABLE_CERTIFICATES:
|
|
pwsz = wszCERTIFICATETABLE;
|
|
break;
|
|
|
|
case TABLE_ATTRIBUTES:
|
|
pwsz = wszREQUESTATTRIBUTETABLE;
|
|
break;
|
|
|
|
case TABLE_EXTENSIONS:
|
|
pwsz = wszCERTIFICATEEXTENSIONTABLE;
|
|
break;
|
|
|
|
case TABLE_CRLS:
|
|
pwsz = wszCRLTABLE;
|
|
break;
|
|
|
|
default:
|
|
pwsz = L"???";
|
|
break;
|
|
}
|
|
return(pwsz);
|
|
}
|
|
|
|
|
|
WCHAR const *
|
|
wszSeekOperator(
|
|
IN LONG SeekOperator)
|
|
{
|
|
WCHAR const *pwsz;
|
|
static WCHAR s_wszBuf[20];
|
|
|
|
switch (CVR_SEEK_MASK & SeekOperator)
|
|
{
|
|
case CVR_SEEK_NONE: pwsz = L"None"; break;
|
|
case CVR_SEEK_EQ: pwsz = L"=="; break;
|
|
case CVR_SEEK_LT: pwsz = L"<"; break;
|
|
case CVR_SEEK_LE: pwsz = L"<="; break;
|
|
case CVR_SEEK_GE: pwsz = L">="; break;
|
|
case CVR_SEEK_GT: pwsz = L">"; break;
|
|
default:
|
|
wsprintf(s_wszBuf, L"???=%x", SeekOperator);
|
|
pwsz = s_wszBuf;
|
|
break;
|
|
}
|
|
if (s_wszBuf != pwsz && (CVR_SEEK_NODELTA & SeekOperator))
|
|
{
|
|
wcscpy(s_wszBuf, pwsz);
|
|
wcscat(s_wszBuf, L",NoDelta");
|
|
pwsz = s_wszBuf;
|
|
}
|
|
|
|
return(pwsz);
|
|
}
|
|
|
|
|
|
WCHAR const *
|
|
wszSortOperator(
|
|
IN LONG SortOrder)
|
|
{
|
|
WCHAR const *pwsz;
|
|
static WCHAR s_wszBuf[20];
|
|
|
|
switch (SortOrder)
|
|
{
|
|
case CVR_SORT_NONE: pwsz = L"None"; break;
|
|
case CVR_SORT_ASCEND: pwsz = L"Ascend"; break;
|
|
case CVR_SORT_DESCEND: pwsz = L"Descend"; break;
|
|
default:
|
|
wsprintf(s_wszBuf, L"???=%x", SortOrder);
|
|
pwsz = s_wszBuf;
|
|
break;
|
|
}
|
|
return(pwsz);
|
|
}
|
|
|
|
|
|
VOID
|
|
dbDumpFileTime(
|
|
IN DWORD dwSubSystemId,
|
|
IN CHAR const *pszPrefix,
|
|
IN FILETIME const *pft)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwsz;
|
|
|
|
hr = myGMTFileTimeToWszLocalTime(pft, TRUE, &pwsz);
|
|
if (S_OK == hr)
|
|
{
|
|
DBGPRINT((dwSubSystemId, "%hs%ws\n", pszPrefix, pwsz));
|
|
LocalFree(pwsz);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
dbDumpValue(
|
|
IN DWORD dwSubSystemId,
|
|
OPTIONAL IN DBTABLE const *pdt,
|
|
IN BYTE const *pbValue,
|
|
IN DWORD cbValue)
|
|
{
|
|
if (NULL != pdt && NULL != pbValue && ISTEXTCOLTYP(pdt->dbcoltyp))
|
|
{
|
|
cbValue += sizeof(WCHAR);
|
|
}
|
|
if (JET_coltypDateTime == pdt->dbcoltyp && sizeof(FILETIME) == cbValue)
|
|
{
|
|
dbDumpFileTime(dwSubSystemId, "", (FILETIME const *) pbValue);
|
|
}
|
|
DBGDUMPHEX((dwSubSystemId, DH_NOADDRESS, pbValue, cbValue));
|
|
}
|
|
|
|
|
|
VOID
|
|
CCertDB::DumpRestriction(
|
|
IN DWORD dwSubSystemId,
|
|
IN LONG i,
|
|
IN CERTVIEWRESTRICTION const *pcvr)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR wszColumn[20];
|
|
DBTABLE const *pdt;
|
|
WCHAR const *pwszTable = L"???";
|
|
WCHAR const *pwszCol;
|
|
|
|
hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "_MapPropIdIndex");
|
|
wsprintf(wszColumn, L"???=%x", pcvr->ColumnIndex);
|
|
pdt = NULL;
|
|
pwszCol = wszColumn;
|
|
}
|
|
else
|
|
{
|
|
pwszCol = pdt->pwszPropName;
|
|
pwszTable = wszTable(pdt->dwTable);
|
|
}
|
|
|
|
|
|
DBGPRINT((
|
|
dwSubSystemId,
|
|
"Restriction[%d]: Col=%ws.%ws\n"
|
|
" Seek='%ws' Sort=%ws cb=%x, pb=%x\n",
|
|
i,
|
|
pwszTable,
|
|
pwszCol,
|
|
wszSeekOperator(pcvr->SeekOperator),
|
|
wszSortOperator(pcvr->SortOrder),
|
|
pcvr->cbValue,
|
|
pcvr->pbValue));
|
|
dbDumpValue(dwSubSystemId, pdt, pcvr->pbValue, pcvr->cbValue);
|
|
}
|
|
|
|
|
|
VOID
|
|
dbDumpColumn(
|
|
IN DWORD dwSubSystemId,
|
|
IN DBTABLE const *pdt,
|
|
IN BYTE const *pbValue,
|
|
IN DWORD cbValue)
|
|
{
|
|
DBGPRINT((dwSubSystemId, "Column: cb=%x pb=%x\n", cbValue, pbValue));
|
|
dbDumpValue(dwSubSystemId, pdt, pbValue, cbValue);
|
|
}
|
|
|
|
|
|
DBAUXDATA const *
|
|
dbGetAuxTable(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid)
|
|
{
|
|
DBAUXDATA const *pdbaux;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
if (tableid == pcs->aTable[CSTI_CERTIFICATE].TableId)
|
|
{
|
|
pdbaux = &g_dbauxCertificates;
|
|
}
|
|
else if (tableid == pcs->aTable[CSTI_ATTRIBUTE].TableId)
|
|
{
|
|
pdbaux = &g_dbauxAttributes;
|
|
}
|
|
else if (tableid == pcs->aTable[CSTI_EXTENSION].TableId)
|
|
{
|
|
pdbaux = &g_dbauxExtensions;
|
|
}
|
|
else
|
|
{
|
|
CSASSERT(tableid == pcs->aTable[CSTI_PRIMARY].TableId);
|
|
|
|
pdbaux = &g_dbauxRequests;
|
|
switch (CSF_TABLEMASK & pcs->SesFlags)
|
|
{
|
|
case TABLE_CERTIFICATES:
|
|
pdbaux = &g_dbauxCertificates;
|
|
break;
|
|
|
|
case TABLE_ATTRIBUTES:
|
|
pdbaux = &g_dbauxAttributes;
|
|
break;
|
|
|
|
case TABLE_EXTENSIONS:
|
|
pdbaux = &g_dbauxExtensions;
|
|
break;
|
|
|
|
case TABLE_CRLS:
|
|
pdbaux = &g_dbauxCRLs;
|
|
break;
|
|
}
|
|
}
|
|
return(pdbaux);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_DumpRowId(
|
|
IN CHAR const *psz,
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid)
|
|
{
|
|
HRESULT hr;
|
|
|
|
#define DBG_SS_DUMPREQUESTID DBG_SS_CERTDBI
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
if (DbgIsSSActive(DBG_SS_DUMPREQUESTID))
|
|
{
|
|
DWORD cb;
|
|
DWORD dwTmp;
|
|
DBAUXDATA const *pdbaux = dbGetAuxTable(pcs, tableid);
|
|
WCHAR awchr[cwcHRESULTSTRING];
|
|
|
|
cb = sizeof(dwTmp);
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdbaux->pdtRowId->dbcolumnid,
|
|
pdbaux->pdtRowId->dbcoltyp,
|
|
&cb,
|
|
(BYTE *) &dwTmp);
|
|
if (S_OK != hr)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_DUMPREQUESTID,
|
|
"%hs: %hs.RowId: pcs=%d: %ws\n",
|
|
psz,
|
|
pdbaux->pszTable,
|
|
pcs->RowId,
|
|
myHResultToString(awchr, hr)));
|
|
_JumpError2(hr, error, "_RetrieveColumn", hr);
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_DUMPREQUESTID,
|
|
"%hs: %hs.RowId: pcs=%d dbcol=%d\n",
|
|
psz,
|
|
pdbaux->pszTable,
|
|
pcs->RowId,
|
|
dwTmp));
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_DumpColumn(
|
|
IN CHAR const *psz,
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid,
|
|
IN DBTABLE const *pdt)
|
|
{
|
|
HRESULT hr;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
CSASSERT(0 != pdt->dbcolumnid);
|
|
if (DbgIsSSActive(DBG_SS_CERTDBI))
|
|
{
|
|
DWORD cb;
|
|
BYTE ab[64 * 1024];
|
|
DBAUXDATA const *pdbaux = dbGetAuxTable(pcs, tableid);
|
|
BOOL fIsText;
|
|
|
|
cb = sizeof(ab);
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdt->dbcolumnid,
|
|
pdt->dbcoltyp,
|
|
&cb,
|
|
ab);
|
|
_JumpIfError(hr, error, "_RetrieveColumn");
|
|
|
|
fIsText = ISTEXTCOLTYP(pdt->dbcoltyp);
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"%hs: _DumpColumn(%hs, %hs): Value:%hs%ws%hs\n",
|
|
psz,
|
|
pdbaux->pszTable,
|
|
pdt->pszFieldName,
|
|
fIsText? " '" : "",
|
|
fIsText? (WCHAR *) ab : L"",
|
|
fIsText? "'" : ""));
|
|
dbDumpValue(DBG_SS_CERTDBI, pdt, ab, cb);
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
#endif // DBG_CERTSRV
|
|
|
|
|
|
|
|
CCertDB::CCertDB()
|
|
{
|
|
HRESULT hr;
|
|
|
|
InterlockedIncrement(&g_cCertDB);
|
|
InterlockedIncrement(&g_cCertDBTotal);
|
|
m_Instance = 0;
|
|
m_fDBOpen = FALSE;
|
|
m_fDBRestart = FALSE;
|
|
m_fPendingShutDown = FALSE;
|
|
m_fFoundOldColumns = FALSE;
|
|
m_fAddedNewColumns = FALSE;
|
|
m_aSession = NULL;
|
|
m_cSession = 0;
|
|
m_cbPage = 0;
|
|
m_cCritSec = 0;
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&m_critsecSession);
|
|
m_cCritSec++;
|
|
InitializeCriticalSection(&m_critsecAutoIncTables);
|
|
m_cCritSec++;
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
CCertDB::~CCertDB()
|
|
{
|
|
ShutDown(0);
|
|
if (0 < m_cCritSec)
|
|
{
|
|
DeleteCriticalSection(&m_critsecSession);
|
|
if (1 < m_cCritSec)
|
|
{
|
|
DeleteCriticalSection(&m_critsecAutoIncTables);
|
|
}
|
|
}
|
|
InterlockedDecrement(&g_cCertDB);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CCertDB::Open(
|
|
/* [in] */ DWORD Flags,
|
|
/* [in] */ DWORD cSession,
|
|
/* [in] */ WCHAR const *pwszEventSource,
|
|
/* [in] */ WCHAR const *pwszDBFile,
|
|
/* [in] */ WCHAR const *pwszLogDir,
|
|
/* [in] */ WCHAR const *pwszSystemDir,
|
|
/* [in] */ WCHAR const *pwszTempDir)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
DBCREATETABLE const *pct;
|
|
JET_GRBIT grbit;
|
|
DWORD CreateFlags;
|
|
CERTSESSION *pcs = NULL;
|
|
|
|
if (NULL == pwszDBFile ||
|
|
NULL == pwszLogDir ||
|
|
NULL == pwszSystemDir ||
|
|
NULL == pwszTempDir)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
|
|
hr = InitGlobalWriterState();
|
|
// _JumpIfError(hr, error, "InitGlobalWriterState");
|
|
|
|
m_fDBOpen = FALSE;
|
|
m_fDBRestart = FALSE;
|
|
m_fDBReadOnly = (CDBOPEN_READONLY & Flags)? TRUE : FALSE;
|
|
|
|
CSASSERT(NULL == m_aSession); // code assumes we do not have session
|
|
m_cSession = 0;
|
|
m_aSession = (CERTSESSION *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cSession * sizeof(m_aSession[0]));
|
|
hr = E_OUTOFMEMORY;
|
|
if (NULL == m_aSession)
|
|
{
|
|
_JumpError(hr, error, "LocalAlloc(m_aSession)");
|
|
}
|
|
for (i = 0; i < cSession; i++)
|
|
{
|
|
m_aSession[i].SesId = -1;
|
|
m_aSession[i].DBId = -1;
|
|
}
|
|
|
|
if (!ConvertWszToSz(&g_pszDBFile, pwszDBFile, -1))
|
|
{
|
|
_JumpError(hr, error, "ConvertWszToSz(DBFile)");
|
|
}
|
|
|
|
hr = DBInitParms(
|
|
cSession,
|
|
(CDBOPEN_CIRCULARLOGGING & Flags)? TRUE : FALSE,
|
|
pwszEventSource,
|
|
pwszLogDir,
|
|
pwszSystemDir,
|
|
pwszTempDir,
|
|
&m_Instance);
|
|
_JumpIfError(hr, error, "DBInitParms");
|
|
|
|
hr = _dbgJetInit(&m_Instance);
|
|
if ((HRESULT) JET_errLogFileSizeMismatchDatabasesConsistent == hr ||
|
|
(HRESULT) JET_errLogFileSizeMismatch == hr)
|
|
{
|
|
_PrintError(hr, "JetInit(old log file size)");
|
|
_dbgJetSetSystemParameter(
|
|
&m_Instance,
|
|
0,
|
|
JET_paramLogFileSize,
|
|
1000,
|
|
NULL);
|
|
hr = _dbgJetInit(&m_Instance);
|
|
}
|
|
_JumpIfError(
|
|
hr,
|
|
error,
|
|
JET_errFileAccessDenied == hr?
|
|
"JetInit(Server already running?)" :
|
|
"JetInit(JetSetSystemParameter problem?)");
|
|
|
|
for (i = 0; i < cSession; i++)
|
|
{
|
|
hr = _dbgJetBeginSession(m_Instance, &m_aSession[i].SesId, NULL, NULL);
|
|
_JumpIfError(hr, error, "_dbgJetBeginSession");
|
|
|
|
m_cSession++;
|
|
|
|
if (0 == i)
|
|
{
|
|
CreateFlags = 0;
|
|
grbit = m_fDBReadOnly?
|
|
JET_bitDbReadOnly : JET_bitDbDeleteCorruptIndexes;
|
|
|
|
hr = _dbgJetAttachDatabase(
|
|
m_aSession[i].SesId,
|
|
g_pszDBFile,
|
|
grbit);
|
|
if ((HRESULT) JET_errFileNotFound == hr &&
|
|
(CDBOPEN_CREATEIFNEEDED & Flags))
|
|
{
|
|
DBGPRINT((DBG_SS_CERTDB, "Creating Database\n"));
|
|
CreateFlags |= CF_DATABASE;
|
|
}
|
|
else
|
|
if ((HRESULT) JET_wrnCorruptIndexDeleted == hr)
|
|
{
|
|
// Rebuild deleted indexes over Unicode columns...
|
|
|
|
DBGPRINT((DBG_SS_CERTDB, "Creating Database Indexes\n"));
|
|
CreateFlags |= CF_MISSINGINDEXES;
|
|
}
|
|
else
|
|
if ((HRESULT) JET_wrnDatabaseAttached != hr)
|
|
{
|
|
_JumpIfError(hr, error, "JetAttachDatabase");
|
|
}
|
|
if (m_fDBReadOnly)
|
|
{
|
|
if (CreateFlags)
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
_JumpError(hr, error, "ReadOnly");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CreateFlags |= CF_MISSINGTABLES | CF_MISSINGCOLUMNS;
|
|
hr = _Create(CreateFlags, g_pszDBFile);
|
|
_JumpIfError(hr, error, "_Create");
|
|
}
|
|
}
|
|
|
|
hr = _dbgJetOpenDatabase(
|
|
m_aSession[i].SesId,
|
|
g_pszDBFile,
|
|
NULL,
|
|
&m_aSession[i].DBId,
|
|
0);
|
|
_JumpIfError(hr, error, "JetOpenDatabase");
|
|
}
|
|
|
|
hr = _AllocateSession(&pcs);
|
|
_JumpIfError(hr, error, "_AllocateSession");
|
|
|
|
for (pct = g_actDataBase; NULL != pct->pszTableName; pct++)
|
|
{
|
|
hr = _BuildColumnIds(pcs, pct->pszTableName, pct->pdt);
|
|
_JumpIfError(hr, error, "_BuildColumnIds");
|
|
}
|
|
if (!m_fDBReadOnly)
|
|
{
|
|
for (pct = g_actDataBase; NULL != pct->pszTableName; pct++)
|
|
{
|
|
hr = _ConvertOldColumnData(
|
|
pcs,
|
|
pct->pszTableName,
|
|
pct->pdbaux,
|
|
pct->pdt);
|
|
_JumpIfError(hr, error, "_ConvertOldColumnData");
|
|
}
|
|
}
|
|
m_fDBOpen = TRUE;
|
|
|
|
error:
|
|
if (NULL != pcs)
|
|
{
|
|
ReleaseSession(pcs);
|
|
}
|
|
hr = myJetHResult(hr);
|
|
if (S_OK == hr && m_fDBRestart)
|
|
{
|
|
hr = S_FALSE; // Restart required for DB changes to take effect.
|
|
_PrintError(hr, "m_fDBRestart");
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CCertDB::ShutDown(
|
|
/* [in] */ DWORD dwFlags)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
|
|
if (CDBSHUTDOWN_PENDING == dwFlags)
|
|
{
|
|
m_fPendingShutDown = TRUE;
|
|
goto error;
|
|
}
|
|
if (NULL != m_aSession)
|
|
{
|
|
DBGPRINT((DBG_SS_CERTDB, "Database shutdown...\n"));
|
|
for (i = 0; i < m_cSession; i++)
|
|
{
|
|
hr = _dbgJetEndSession(
|
|
m_aSession[i].SesId,
|
|
JET_bitForceSessionClosed);
|
|
_PrintIfError(hr, "JetEndSession");
|
|
}
|
|
|
|
hr = _dbgJetTerm2(m_Instance, JET_bitTermComplete);
|
|
DBGPRINT((DBG_SS_CERTDB, "Database shutdown complete\n"));
|
|
|
|
LocalFree(m_aSession);
|
|
m_aSession = NULL;
|
|
}
|
|
if (NULL != g_pszDBFile)
|
|
{
|
|
LocalFree(g_pszDBFile);
|
|
g_pszDBFile = NULL;
|
|
}
|
|
DBFreeParms();
|
|
UnInitGlobalWriterState();
|
|
|
|
error:
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::BeginTransaction(
|
|
IN CERTSESSION *pcs,
|
|
IN BOOL fPrepareUpdate)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fTransacted = FALSE;
|
|
DWORD i;
|
|
|
|
if (NULL == pcs)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
if (0 != pcs->cTransact)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
_JumpError(hr, error, "Nested transaction");
|
|
}
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetBeginTransaction(pcs->SesId);
|
|
_JumpIfError(hr, error, "JetBeginTransaction");
|
|
|
|
fTransacted = TRUE;
|
|
|
|
if (fPrepareUpdate)
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
for (i = 0; i < CSTI_MAX; i++)
|
|
{
|
|
if (IsValidJetTableId(pcs->aTable[i].TableId))
|
|
{
|
|
hr = _dbgJetPrepareUpdate(
|
|
pcs->SesId,
|
|
pcs->aTable[i].TableId,
|
|
JET_prepReplace);
|
|
_JumpIfError(hr, error, "JetPrepareUpdate");
|
|
}
|
|
}
|
|
}
|
|
pcs->cTransact++;
|
|
InterlockedIncrement(&g_cXactTotal);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr && fTransacted)
|
|
{
|
|
HRESULT hr2;
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr2 = _Rollback(pcs);
|
|
_PrintIfError(hr2, "_Rollback");
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::CommitTransaction(
|
|
IN CERTSESSION *pcs,
|
|
IN BOOL fCommit)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
|
|
if (NULL == pcs)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
CSASSERT(0 != pcs->cTransact);
|
|
|
|
if (fCommit)
|
|
{
|
|
if (0 == (CSF_DELETE & pcs->SesFlags))
|
|
{
|
|
for (i = 0; i < CSTI_MAXDIRECT; i++)
|
|
{
|
|
if (IsValidJetTableId(pcs->aTable[i].TableId))
|
|
{
|
|
hr = _UpdateTable(pcs, pcs->aTable[i].TableId);
|
|
_JumpIfError(hr, error, "_UpdateTable");
|
|
}
|
|
}
|
|
}
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetCommitTransaction(pcs->SesId, 0);
|
|
_JumpIfError(hr, error, "JetCommitTransaction");
|
|
}
|
|
else
|
|
{
|
|
hr = _Rollback(pcs);
|
|
_JumpIfError(hr, error, "_Rollback");
|
|
}
|
|
pcs->cTransact--;
|
|
if (fCommit)
|
|
{
|
|
InterlockedIncrement(&g_cXactCommit);
|
|
}
|
|
else
|
|
{
|
|
InterlockedIncrement(&g_cXactAbort);
|
|
}
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_AllocateSession(
|
|
OUT CERTSESSION **ppcs)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
BOOL fEnterCritSec = FALSE;
|
|
|
|
CSASSERT(NULL != ppcs);
|
|
|
|
*ppcs = NULL;
|
|
|
|
if (0 == m_cCritSec)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
|
|
_JumpError(hr, error, "InitializeCriticalSection failure");
|
|
}
|
|
EnterCriticalSection(&m_critsecSession);
|
|
fEnterCritSec = TRUE;
|
|
|
|
for (i = 0; 0 != m_aSession[i].SesFlags; i++)
|
|
{
|
|
if (i + 1 == m_cSession)
|
|
{
|
|
hr = CERTSRV_E_NO_DB_SESSIONS;
|
|
_JumpIfError(hr, error, "no more sessions");
|
|
}
|
|
}
|
|
*ppcs = &m_aSession[i];
|
|
CSASSERT(0 == (*ppcs)->RowId);
|
|
(*ppcs)->SesFlags = CSF_INUSE;
|
|
(*ppcs)->dwThreadId = GetCurrentThreadId();
|
|
ZeroMemory((*ppcs)->aTable, sizeof((*ppcs)->aTable));
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (fEnterCritSec)
|
|
{
|
|
LeaveCriticalSection(&m_critsecSession);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_OpenTableRow(
|
|
IN CERTSESSION *pcs,
|
|
IN DBAUXDATA const *pdbaux,
|
|
OPTIONAL IN CERTVIEWRESTRICTION const *pcvr,
|
|
OUT CERTSESSIONTABLE *pTable,
|
|
OUT DWORD *pdwRowIdMismatch)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwRowId;
|
|
DWORD cb;
|
|
|
|
CSASSERT(NULL == pTable->TableId);
|
|
CSASSERT(0 == pTable->TableFlags);
|
|
*pdwRowIdMismatch = 0;
|
|
|
|
if (CSF_CREATE & pcs->SesFlags)
|
|
{
|
|
CSASSERT(NULL == pcvr);
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetOpenTable(
|
|
pcs->SesId,
|
|
pcs->DBId,
|
|
pdbaux->pszTable,
|
|
NULL,
|
|
0,
|
|
0,
|
|
&pTable->TableId);
|
|
_JumpIfError(hr, error, "JetOpenTable");
|
|
}
|
|
else
|
|
{
|
|
if (NULL == pcvr)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
hr = _OpenTable(pcs, pdbaux, pcvr, pTable);
|
|
if (S_FALSE == hr)
|
|
{
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
}
|
|
_JumpIfError2(hr, error, "_OpenTable", CERTSRV_E_PROPERTY_EMPTY);
|
|
}
|
|
|
|
if (!((CSF_READONLY | CSF_DELETE) & pcs->SesFlags))
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetPrepareUpdate(
|
|
pcs->SesId,
|
|
pTable->TableId,
|
|
(CSF_CREATE & pcs->SesFlags)?
|
|
JET_prepInsert : JET_prepReplace);
|
|
_JumpIfError(hr, error, "JetPrepareUpdate");
|
|
}
|
|
|
|
// Requests table RequestId column is JET_bitColumnAutoincrement.
|
|
// Certificates table RequestId column is manually initialized here.
|
|
//
|
|
// When creating a Certificates table row, the RequestId column must be
|
|
// set from pcs->RowId, which must already have been set by first creating
|
|
// the Requests table row.
|
|
//
|
|
// When opening an existing row in either table, just fetch the column.
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetRetrieveColumn(
|
|
pcs->SesId,
|
|
pTable->TableId,
|
|
pdbaux->pdtRowId->dbcolumnid,
|
|
&dwRowId,
|
|
sizeof(dwRowId),
|
|
&cb,
|
|
JET_bitRetrieveCopy,
|
|
NULL);
|
|
if ((HRESULT) JET_wrnColumnNull == hr)
|
|
{
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
}
|
|
_PrintIfError2(hr, "JetRetrieveColumn", CERTSRV_E_PROPERTY_EMPTY);
|
|
if (S_OK != hr || 0 == dwRowId)
|
|
{
|
|
CSASSERT(CSF_CREATE & pcs->SesFlags);
|
|
if (0 == (CSF_CREATE & pcs->SesFlags))
|
|
{
|
|
if (S_OK == hr)
|
|
{
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
}
|
|
_JumpError(hr, error, "JetRetrieveColumn");
|
|
}
|
|
dwRowId = pcs->RowId;
|
|
hr = _dbgJetSetColumn(
|
|
pcs->SesId,
|
|
pTable->TableId,
|
|
pdbaux->pdtRowId->dbcolumnid,
|
|
&dwRowId,
|
|
sizeof(dwRowId),
|
|
0,
|
|
NULL);
|
|
_JumpIfError(hr, error, "JetSetColumn");
|
|
}
|
|
else if (0 == pcs->RowId)
|
|
{
|
|
pcs->RowId = dwRowId;
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_OpenTableRow:%hs %hs --> RowId=%d(dwRowId(RetrieveColumn)=%d)\n",
|
|
(CSF_CREATE & pcs->SesFlags)? " (Create)" : "",
|
|
pdbaux->pszTable,
|
|
pcs->RowId,
|
|
dwRowId));
|
|
CSASSERT(0 != pcs->RowId);
|
|
if (pcs->RowId > dwRowId)
|
|
{
|
|
*pdwRowIdMismatch = dwRowId;
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
_JumpError(hr, error, "Missing autoincrement RowId");
|
|
}
|
|
CSASSERT(pcs->RowId == dwRowId);
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
if (IsValidJetTableId(pTable->TableId))
|
|
{
|
|
HRESULT hr2;
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr2 = _dbgJetCloseTable(pcs->SesId, pTable->TableId);
|
|
_PrintIfError(hr2, "JetCloseTable");
|
|
}
|
|
ZeroMemory(pTable, sizeof(*pTable));
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::OpenTables(
|
|
IN CERTSESSION *pcs,
|
|
OPTIONAL IN CERTVIEWRESTRICTION const *pcvr)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fCertTableFirst = FALSE;
|
|
BOOL fCertTableLast = FALSE;
|
|
CERTVIEWRESTRICTION cvrRowId;
|
|
CERTVIEWRESTRICTION const *pcvrPrimary;
|
|
CERTVIEWRESTRICTION const *pcvrCertificates;
|
|
BOOL fEnterCritSec = FALSE;
|
|
DBAUXDATA const *pdbauxPrimary;
|
|
|
|
if (NULL == pcs)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
|
|
pcvrPrimary = pcvr;
|
|
pcvrCertificates = NULL;
|
|
pdbauxPrimary = &g_dbauxRequests;
|
|
if (TABLE_REQCERTS == (CSF_TABLEMASK & pcs->SesFlags))
|
|
{
|
|
fCertTableLast = TRUE;
|
|
if (NULL != pcvr)
|
|
{
|
|
cvrRowId.SeekOperator = CVR_SEEK_EQ;
|
|
cvrRowId.SortOrder = CVR_SORT_ASCEND;
|
|
cvrRowId.pbValue = (BYTE *) &pcs->RowId;
|
|
cvrRowId.cbValue = sizeof(pcs->RowId);
|
|
|
|
switch (DTI_TABLEMASK & pcvr->ColumnIndex)
|
|
{
|
|
case DTI_REQUESTTABLE:
|
|
pcvrCertificates = &cvrRowId;
|
|
cvrRowId.ColumnIndex = DTI_CERTIFICATETABLE | DTC_REQUESTID;
|
|
break;
|
|
|
|
case DTI_CERTIFICATETABLE:
|
|
fCertTableLast = FALSE;
|
|
fCertTableFirst = TRUE;
|
|
pcvrCertificates = pcvr;
|
|
pcvrPrimary = &cvrRowId;
|
|
cvrRowId.ColumnIndex = DTI_REQUESTTABLE | DTR_REQUESTID;
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "ColumnIndex Table");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (CSF_TABLEMASK & pcs->SesFlags)
|
|
{
|
|
case TABLE_ATTRIBUTES:
|
|
pdbauxPrimary = &g_dbauxAttributes;
|
|
break;
|
|
|
|
case TABLE_EXTENSIONS:
|
|
pdbauxPrimary = &g_dbauxExtensions;
|
|
break;
|
|
|
|
case TABLE_CRLS:
|
|
pdbauxPrimary = &g_dbauxCRLs;
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "bad table");
|
|
}
|
|
}
|
|
|
|
if (1 >= m_cCritSec)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
|
|
_JumpError(hr, error, "InitializeCriticalSection failure");
|
|
}
|
|
|
|
EnterCriticalSection(&m_critsecAutoIncTables);
|
|
fEnterCritSec = TRUE;
|
|
|
|
__try
|
|
{
|
|
DWORD dwRowIdMismatch;
|
|
|
|
if (fCertTableFirst)
|
|
{
|
|
hr = _OpenTableRow(
|
|
pcs,
|
|
&g_dbauxCertificates,
|
|
pcvrCertificates,
|
|
&pcs->aTable[CSTI_CERTIFICATE],
|
|
&dwRowIdMismatch);
|
|
_LeaveIfError2(hr, "_OpenTableRow", CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
CSASSERT(0 != pcs->RowId);
|
|
CSASSERT(IsValidJetTableId(pcs->aTable[CSTI_CERTIFICATE].TableId));
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"OpenTables: %hs: %ws\n",
|
|
g_dbauxCertificates.pszTable,
|
|
wszCSTFlags(pcs->aTable[CSTI_CERTIFICATE].TableFlags)));
|
|
}
|
|
|
|
hr = _OpenTableRow(
|
|
pcs,
|
|
pdbauxPrimary,
|
|
pcvrPrimary,
|
|
&pcs->aTable[CSTI_PRIMARY],
|
|
&dwRowIdMismatch);
|
|
_LeaveIfError2(hr, "_OpenTableRow", CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
CSASSERT(0 != pcs->RowId);
|
|
CSASSERT(IsValidJetTableId(pcs->aTable[CSTI_PRIMARY].TableId));
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"OpenTables: %hs: %ws\n",
|
|
g_dbauxRequests.pszTable,
|
|
wszCSTFlags(pcs->aTable[CSTI_PRIMARY].TableFlags)));
|
|
|
|
if (fCertTableLast)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
hr = _OpenTableRow(
|
|
pcs,
|
|
&g_dbauxCertificates,
|
|
pcvrCertificates,
|
|
&pcs->aTable[CSTI_CERTIFICATE],
|
|
&dwRowIdMismatch);
|
|
_PrintIfError(hr, "_OpenTableRow");
|
|
if (S_OK == hr || 0 == dwRowIdMismatch)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
_PrintIfError(hr, "_OpenTableRow");
|
|
//_LeaveIfError(hr, "_OpenTableRow");
|
|
if (S_OK == hr)
|
|
{
|
|
CSASSERT(IsValidJetTableId(pcs->aTable[CSTI_CERTIFICATE].TableId));
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"OpenTables: %hs: %ws\n",
|
|
g_dbauxCertificates.pszTable,
|
|
wszCSTFlags(pcs->aTable[CSTI_CERTIFICATE].TableFlags)));
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
__try
|
|
{
|
|
HRESULT hr2;
|
|
DWORD i;
|
|
|
|
for (i = 0; i < CSTI_MAX; i++)
|
|
{
|
|
if (NULL != pcs)
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
if (IsValidJetTableId(pcs->aTable[i].TableId))
|
|
{
|
|
hr2 = _dbgJetCloseTable(
|
|
pcs->SesId,
|
|
pcs->aTable[i].TableId);
|
|
_PrintIfError(hr2, "JetCloseTable");
|
|
}
|
|
}
|
|
ZeroMemory(&pcs->aTable[i], sizeof(pcs->aTable[i]));
|
|
}
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
if (fEnterCritSec)
|
|
{
|
|
LeaveCriticalSection(&m_critsecAutoIncTables);
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::CloseTables(
|
|
IN CERTSESSION *pcs)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hr2;
|
|
DWORD i;
|
|
|
|
if (NULL == pcs)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
for (i = 0; i < CSTI_MAX; i++)
|
|
{
|
|
if (IsValidJetTableId(pcs->aTable[i].TableId))
|
|
{
|
|
hr2 = CloseTable(pcs, pcs->aTable[i].TableId);
|
|
_PrintIfError(hr2, "CloseTable");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
}
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::Delete(
|
|
IN CERTSESSION *pcs)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hr2;
|
|
DWORD i;
|
|
|
|
if (NULL == pcs)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
for (i = 0; i < CSTI_MAXDIRECT; i++)
|
|
{
|
|
if (IsValidJetTableId(pcs->aTable[i].TableId))
|
|
{
|
|
hr2 = _dbgJetDelete(pcs->SesId, pcs->aTable[i].TableId);
|
|
_PrintIfError(hr2, "JetDelete");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
}
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_UpdateTable(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid)
|
|
{
|
|
HRESULT hr;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetUpdate(pcs->SesId, tableid, NULL, 0, NULL);
|
|
_JumpIfError(hr, error, "JetUpdate");
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::CloseTable(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL == pcs)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetCloseTable(pcs->SesId, tableid);
|
|
_JumpIfError(hr, error, "JetCloseTable");
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CCertDB::OpenRow(
|
|
/* [in] */ DWORD dwFlags,
|
|
/* [in] */ DWORD RowId,
|
|
/* [in] */ WCHAR const *pwszSerialNumberOrCertHash, // OPTIONAL
|
|
/* [out] */ ICertDBRow **pprow)
|
|
{
|
|
HRESULT hr;
|
|
ICertDBRow *prow = NULL;
|
|
DWORD SesFlags = 0;
|
|
BOOL fCreate;
|
|
DWORD i;
|
|
CERTSESSION *pcs = NULL;
|
|
CERTVIEWRESTRICTION cvr;
|
|
CERTVIEWRESTRICTION *pcvr;
|
|
|
|
if (NULL == pprow)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
*pprow = NULL;
|
|
|
|
switch (PROPTABLE_MASK & dwFlags)
|
|
{
|
|
case PROPTABLE_REQCERT:
|
|
SesFlags |= TABLE_REQCERTS;
|
|
cvr.ColumnIndex = DTI_REQUESTTABLE | DTC_REQUESTID;
|
|
break;
|
|
|
|
case PROPTABLE_ATTRIBUTE:
|
|
SesFlags |= TABLE_ATTRIBUTES;
|
|
cvr.ColumnIndex = DTI_ATTRIBUTETABLE | DTA_REQUESTID;
|
|
break;
|
|
|
|
case PROPTABLE_EXTENSION:
|
|
SesFlags |= TABLE_EXTENSIONS;
|
|
cvr.ColumnIndex = DTI_EXTENSIONTABLE | DTE_REQUESTID;
|
|
break;
|
|
|
|
case PROPTABLE_CRL:
|
|
SesFlags |= TABLE_CRLS;
|
|
cvr.ColumnIndex = DTI_CRLTABLE | DTL_ROWID;
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "bad table");
|
|
}
|
|
if ((PROPOPEN_CERTHASH & dwFlags) && NULL == pwszSerialNumberOrCertHash)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "bad PROPOPEN_CERTHASH");
|
|
}
|
|
if (PROPTABLE_REQCERT != (PROPTABLE_MASK & dwFlags) &&
|
|
NULL != pwszSerialNumberOrCertHash)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "bad pwszSerialNumberOrCertHash");
|
|
}
|
|
if ((PROPOPEN_READONLY | PROPOPEN_DELETE) ==
|
|
((PROPOPEN_READONLY | PROPOPEN_DELETE) & dwFlags))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "delete + read-only");
|
|
}
|
|
|
|
if (0 == RowId && NULL == pwszSerialNumberOrCertHash)
|
|
{
|
|
if ((PROPOPEN_READONLY | PROPOPEN_DELETE) & dwFlags)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "OpenRow: create vs. delete or read-only");
|
|
}
|
|
SesFlags |= CSF_CREATE;
|
|
pcvr = NULL;
|
|
}
|
|
else
|
|
{
|
|
cvr.SeekOperator = CVR_SEEK_EQ;
|
|
cvr.SortOrder = CVR_SORT_ASCEND;
|
|
if (NULL != pwszSerialNumberOrCertHash)
|
|
{
|
|
cvr.ColumnIndex = (PROPOPEN_CERTHASH & dwFlags)?
|
|
(DTI_CERTIFICATETABLE | DTC_CERTIFICATEHASH) :
|
|
(DTI_CERTIFICATETABLE | DTC_CERTIFICATESERIALNUMBER);
|
|
|
|
cvr.cbValue = wcslen(pwszSerialNumberOrCertHash) * sizeof(WCHAR);
|
|
cvr.pbValue = (BYTE *) pwszSerialNumberOrCertHash;
|
|
}
|
|
else
|
|
{
|
|
cvr.cbValue = sizeof(RowId);
|
|
cvr.pbValue = (BYTE *) &RowId;
|
|
}
|
|
pcvr = &cvr;
|
|
}
|
|
|
|
if (PROPOPEN_READONLY & dwFlags)
|
|
{
|
|
SesFlags |= CSF_READONLY;
|
|
}
|
|
else
|
|
{
|
|
if (PROPOPEN_DELETE & dwFlags)
|
|
{
|
|
SesFlags |= CSF_DELETE;
|
|
}
|
|
if (m_fDBReadOnly)
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
_JumpError(hr, error, "OpenRow: read-only DB");
|
|
}
|
|
}
|
|
|
|
prow = new CCertDBRow;
|
|
if (NULL == prow)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "new CCertDBRow");
|
|
}
|
|
|
|
hr = _AllocateSession(&pcs);
|
|
_JumpIfError(hr, error, "_AllocateSession");
|
|
|
|
pcs->RowId = RowId;
|
|
pcs->SesFlags |= SesFlags;
|
|
pcs->prow = prow;
|
|
|
|
hr = ((CCertDBRow *) prow)->Open(pcs, this, pcvr);
|
|
_JumpIfError2(hr, error, "Open", CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
*pprow = prow;
|
|
prow = NULL;
|
|
pcs = NULL;
|
|
|
|
error:
|
|
if (NULL != prow)
|
|
{
|
|
prow->Release();
|
|
}
|
|
if (NULL != pcs)
|
|
{
|
|
ReleaseSession(pcs);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CCertDB::OpenView(
|
|
/* [in] */ DWORD ccvr,
|
|
/* [in] */ CERTVIEWRESTRICTION const *acvr,
|
|
/* [in] */ DWORD ccolOut,
|
|
/* [in] */ DWORD const *acolOut,
|
|
/* [in] */ DWORD const dwFlags,
|
|
/* [out] */ IEnumCERTDBRESULTROW **ppenum)
|
|
{
|
|
HRESULT hr;
|
|
IEnumCERTDBRESULTROW *penum = NULL;
|
|
BOOL fCreate;
|
|
CERTSESSION *pcs;
|
|
|
|
if ((NULL == acvr && 0 != ccvr) || NULL == acolOut || NULL == ppenum)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
*ppenum = NULL;
|
|
|
|
penum = new CEnumCERTDBRESULTROW(0 != (CDBOPENVIEW_WORKERTHREAD & dwFlags));
|
|
if (NULL == penum)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "new CEnumCERTDBRESULTROW");
|
|
}
|
|
|
|
hr = _AllocateSession(&pcs);
|
|
_JumpIfError(hr, error, "_AllocateSession");
|
|
|
|
pcs->SesFlags |= CSF_READONLY | CSF_VIEW;
|
|
pcs->pview = penum;
|
|
|
|
hr = ((CEnumCERTDBRESULTROW *) penum)->Open(
|
|
pcs,
|
|
this,
|
|
ccvr,
|
|
acvr,
|
|
ccolOut,
|
|
acolOut);
|
|
_JumpIfError(hr, error, "Open");
|
|
|
|
*ppenum = penum;
|
|
penum = NULL;
|
|
|
|
error:
|
|
if (NULL != penum)
|
|
{
|
|
penum->Release();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::OpenBackup(
|
|
/* [in] */ LONG grbitJet,
|
|
/* [out] */ ICertDBBackup **ppBackup)
|
|
{
|
|
HRESULT hr;
|
|
ICertDBBackup *pBackup = NULL;
|
|
CERTSESSION *pcs = NULL;
|
|
|
|
if (NULL == ppBackup)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
*ppBackup = NULL;
|
|
|
|
pBackup = new CCertDBBackup;
|
|
if (NULL == pBackup)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "new CCertDBBackup");
|
|
}
|
|
|
|
hr = _AllocateSession(&pcs);
|
|
_JumpIfError(hr, error, "_AllocateSession");
|
|
|
|
hr = ((CCertDBBackup *) pBackup)->Open(grbitJet, pcs, this);
|
|
_JumpIfError(hr, error, "Open");
|
|
|
|
*ppBackup = pBackup;
|
|
pBackup = NULL;
|
|
pcs = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pBackup)
|
|
{
|
|
pBackup->Release();
|
|
}
|
|
if (NULL != pcs)
|
|
{
|
|
ReleaseSession(pcs);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::ReleaseSession(
|
|
IN CERTSESSION *pcs)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HRESULT hr2;
|
|
|
|
if (NULL == pcs)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
CSASSERT(CSF_INUSE & pcs->SesFlags);
|
|
while (0 != pcs->cTransact)
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr2 = _dbgJetRollback(pcs->SesId, 0);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
_JumpIfError(hr2, loop, "JetRollback");
|
|
|
|
DBGPRINT((
|
|
(CSF_READONLY & pcs->SesFlags)? DBG_SS_CERTDBI : DBG_SS_CERTDB,
|
|
"ReleaseSession: Rollback transaction: %x\n",
|
|
pcs->cTransact));
|
|
loop:
|
|
CSASSERT(0 == pcs->cTransact);
|
|
pcs->cTransact--;
|
|
InterlockedIncrement(&g_cXactAbort);
|
|
}
|
|
//EnterCriticalSection(&m_critsecSession);
|
|
pcs->RowId = 0;
|
|
pcs->prow = NULL;
|
|
pcs->SesFlags = 0; // turn off CSF_INUSE -- must be LAST!
|
|
//LeaveCriticalSection(&m_critsecSession);
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_Rollback(
|
|
IN CERTSESSION *pcs)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD i;
|
|
|
|
if (NULL == pcs)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
CSASSERT(CSF_INUSE & pcs->SesFlags);
|
|
|
|
for (i = 0; i < CSTI_MAX; i++)
|
|
{
|
|
pcs->aTable[i].TableId = 0;
|
|
}
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetRollback(pcs->SesId, 0);
|
|
_JumpIfError(hr, error, "JetRollback");
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::BackupBegin(
|
|
IN LONG grbitJet)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = _dbgJetBeginExternalBackup(grbitJet);
|
|
_JumpIfError(hr, error, "JetBeginExternalBackup");
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_BackupGetFileList(
|
|
IN BOOL fDBFiles,
|
|
IN OUT DWORD *pcwcList,
|
|
OUT WCHAR *pwszzList) // OPTIONAL
|
|
{
|
|
HRESULT hr;
|
|
CHAR buf[12];
|
|
CHAR *pszz = buf;
|
|
DWORD cbbuf = ARRAYSIZE(buf);
|
|
DWORD cbActual;
|
|
WCHAR *pwszz = NULL;
|
|
DWORD cwc;
|
|
WCHAR *pwsz;
|
|
DWORD cwcActual;
|
|
|
|
while (TRUE)
|
|
{
|
|
if (fDBFiles)
|
|
{
|
|
hr = _dbgJetGetAttachInfo(pszz, cbbuf, &cbActual);
|
|
_JumpIfError(hr, error, "JetGetAttachInfo");
|
|
}
|
|
else
|
|
{
|
|
hr = _dbgJetGetLogInfo(pszz, cbbuf, &cbActual);
|
|
_JumpIfError(hr, error, "JetGetLogInfo");
|
|
}
|
|
if (cbbuf >= cbActual)
|
|
{
|
|
break;
|
|
}
|
|
CSASSERT(buf == pszz);
|
|
pszz = (CHAR *) LocalAlloc(LMEM_FIXED, cbActual);
|
|
if (NULL == pszz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
cbbuf = cbActual;
|
|
}
|
|
if (!ConvertSzToWsz(&pwszz, pszz, cbActual))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertSzToWsz");
|
|
}
|
|
|
|
pwsz = pwszz;
|
|
do
|
|
{
|
|
cwc = wcslen(pwsz);
|
|
pwsz += cwc + 1;
|
|
} while (0 != cwc);
|
|
cwc = SAFE_SUBTRACT_POINTERS(pwsz, pwszz); // includes double trailing L'\0's
|
|
if (NULL != pwszzList)
|
|
{
|
|
CopyMemory(pwszzList, pwszz, min(cwc, *pcwcList) * sizeof(WCHAR));
|
|
if (cwc > *pcwcList)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
}
|
|
}
|
|
*pcwcList = cwc;
|
|
_JumpIfError(hr, error, "Buffer Overflow");
|
|
|
|
error:
|
|
if (NULL != pszz && buf != pszz)
|
|
{
|
|
LocalFree(pszz);
|
|
}
|
|
if (NULL != pwszz)
|
|
{
|
|
LocalFree(pwszz);
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::BackupGetDBFileList(
|
|
IN OUT DWORD *pcwcList,
|
|
OUT WCHAR *pwszzList) // OPTIONAL
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = _BackupGetFileList(TRUE, pcwcList, pwszzList);
|
|
_JumpIfError(hr, error, "_BackupGetFileList");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::BackupGetLogFileList(
|
|
IN OUT DWORD *pcwcList,
|
|
OUT WCHAR *pwszzList) // OPTIONAL
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = _BackupGetFileList(FALSE, pcwcList, pwszzList);
|
|
_JumpIfError(hr, error, "_BackupGetFileList");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::BackupOpenFile(
|
|
IN WCHAR const *pwszFile,
|
|
OUT JET_HANDLE *phFileDB,
|
|
OPTIONAL OUT ULARGE_INTEGER *pliSize)
|
|
{
|
|
HRESULT hr;
|
|
CHAR *pszFile = NULL;
|
|
|
|
if (!ConvertWszToSz(&pszFile, pwszFile, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToSz(pwszFile)");
|
|
}
|
|
hr = _dbgJetOpenFile(
|
|
pszFile,
|
|
phFileDB,
|
|
&pliSize->LowPart,
|
|
&pliSize->HighPart);
|
|
_JumpIfErrorStr(hr, error, "JetOpenFile", pwszFile);
|
|
|
|
error:
|
|
if (NULL != pszFile)
|
|
{
|
|
LocalFree(pszFile);
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::BackupReadFile(
|
|
IN JET_HANDLE hFileDB,
|
|
OUT BYTE *pb,
|
|
IN DWORD cb,
|
|
OUT DWORD *pcb)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbAlloc = NULL;
|
|
BYTE *pbRead;
|
|
|
|
if (0 == m_cbPage)
|
|
{
|
|
SYSTEM_INFO si;
|
|
|
|
GetSystemInfo(&si);
|
|
m_cbPage = si.dwPageSize;
|
|
}
|
|
if ((m_cbPage - 1) & cb)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "bad read size");
|
|
|
|
}
|
|
pbRead = pb;
|
|
|
|
// If the caller's buffer is not page aligned, allocate an aligned buffer
|
|
// and copy the data.
|
|
|
|
if ((m_cbPage - 1) & (DWORD_PTR) pb)
|
|
{
|
|
pbAlloc = (BYTE *) VirtualAlloc(NULL, cb, MEM_COMMIT, PAGE_READWRITE);
|
|
if (NULL == pbAlloc)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpIfError(hr, error, "VirtualAlloc");
|
|
}
|
|
pbRead = pbAlloc;
|
|
}
|
|
|
|
hr = _dbgJetReadFile(hFileDB, pbRead, cb, pcb);
|
|
_JumpIfError(hr, error, "JetReadFile");
|
|
|
|
if (NULL != pbAlloc)
|
|
{
|
|
CopyMemory(pb, pbAlloc, *pcb);
|
|
}
|
|
|
|
error:
|
|
if (NULL != pbAlloc)
|
|
{
|
|
VirtualFree(pbAlloc, 0, MEM_RELEASE);
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::BackupCloseFile(
|
|
IN JET_HANDLE hFileDB)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = _dbgJetCloseFile(hFileDB);
|
|
_JumpIfError(hr, error, "JetCloseFile");
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::BackupTruncateLog()
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = _dbgJetTruncateLog();
|
|
_JumpIfError(hr, error, "JetTruncateLog");
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::BackupEnd()
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = _dbgJetEndExternalBackup();
|
|
_JumpIfError(hr, error, "JetEndExternalBackup");
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
DBTABLE const *
|
|
CCertDB::_MapTable(
|
|
IN WCHAR const *pwszPropName,
|
|
IN DBTABLE const *pdt)
|
|
{
|
|
while (NULL != pdt->pwszPropName)
|
|
{
|
|
if (0 == (DBTF_MISSING & pdt->dwFlags) &&
|
|
(0 == lstrcmpi(pwszPropName, pdt->pwszPropName) ||
|
|
(NULL != pdt->pwszPropNameObjId &&
|
|
0 == lstrcmpi(pwszPropName, pdt->pwszPropNameObjId))))
|
|
{
|
|
return(pdt);
|
|
}
|
|
pdt++;
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_MapPropIdIndex(
|
|
IN DWORD ColumnIndex,
|
|
OUT DBTABLE const **ppdt,
|
|
OPTIONAL OUT DWORD *pType)
|
|
{
|
|
HRESULT hr;
|
|
DBTABLE const *pdt = NULL;
|
|
DWORD iCol = DTI_COLUMNMASK & ColumnIndex;
|
|
|
|
switch (DTI_TABLEMASK & ColumnIndex)
|
|
{
|
|
case DTI_REQUESTTABLE:
|
|
if (DTR_MAX > iCol)
|
|
{
|
|
pdt = g_adtRequests;
|
|
}
|
|
break;
|
|
|
|
case DTI_CERTIFICATETABLE:
|
|
if (DTC_MAX > iCol)
|
|
{
|
|
pdt = g_adtCertificates;
|
|
}
|
|
break;
|
|
|
|
case DTI_ATTRIBUTETABLE:
|
|
if (DTA_MAX > iCol)
|
|
{
|
|
pdt = g_adtRequestAttributes;
|
|
}
|
|
break;
|
|
|
|
case DTI_EXTENSIONTABLE:
|
|
if (DTE_MAX > iCol)
|
|
{
|
|
pdt = g_adtCertExtensions;
|
|
}
|
|
break;
|
|
|
|
case DTI_CRLTABLE:
|
|
if (DTL_MAX > iCol)
|
|
{
|
|
pdt = g_adtCRLs;
|
|
}
|
|
break;
|
|
}
|
|
if (NULL == pdt)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"_MapPropIdIndex(%x) -> %x\n",
|
|
ColumnIndex,
|
|
hr));
|
|
_JumpError(hr, error, "column index");
|
|
}
|
|
pdt += iCol;
|
|
if (NULL != pType)
|
|
{
|
|
switch (pdt->dbcoltyp)
|
|
{
|
|
case JET_coltypDateTime:
|
|
*pType = PROPTYPE_DATE;
|
|
break;
|
|
|
|
case JET_coltypLong:
|
|
*pType = PROPTYPE_LONG;
|
|
break;
|
|
|
|
case JET_coltypText:
|
|
case JET_coltypLongText:
|
|
*pType = PROPTYPE_STRING;
|
|
break;
|
|
|
|
case JET_coltypLongBinary:
|
|
default:
|
|
*pType = PROPTYPE_BINARY;
|
|
break;
|
|
}
|
|
if (NULL != pdt->pszIndexName &&
|
|
0 == (DBTF_INDEXREQUESTID & pdt->dwFlags))
|
|
{
|
|
*pType |= PROPFLAGS_INDEXED;
|
|
}
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_MapPropIdIndex(%x) -> %ws.%ws\n",
|
|
ColumnIndex,
|
|
wszTable(pdt->dwTable),
|
|
pdt->pwszPropName));
|
|
hr = S_OK;
|
|
|
|
error:
|
|
*ppdt = pdt;
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::MapPropId(
|
|
IN WCHAR const *pwszPropName,
|
|
IN DWORD dwFlags,
|
|
OUT DBTABLE *pdtOut)
|
|
{
|
|
DBTABLE const *pdt = NULL;
|
|
WCHAR wszPrefix[2 * (sizeof(wszPROPSUBJECTDOT) / sizeof(WCHAR))];
|
|
DWORD dwTable;
|
|
HRESULT hr = S_OK;
|
|
DBTABLE const *pdbTable;
|
|
WCHAR const *pwszStart;
|
|
BOOL fSubject = FALSE;
|
|
BOOL fRequest = FALSE;
|
|
|
|
if (NULL == pwszPropName || NULL == pdtOut)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
|
|
dwTable = PROPTABLE_MASK & dwFlags;
|
|
CSASSERT(
|
|
PROPTABLE_REQUEST == dwTable ||
|
|
PROPTABLE_CERTIFICATE == dwTable ||
|
|
PROPTABLE_CRL == dwTable);
|
|
|
|
// Check to see if the request is for L"Subject.".
|
|
|
|
pwszStart = pwszPropName;
|
|
|
|
if (PROPTABLE_CRL != dwTable)
|
|
{
|
|
while (!fSubject)
|
|
{
|
|
WCHAR const *pwsz;
|
|
|
|
pwsz = wcschr(pwszStart, L'.');
|
|
|
|
if (NULL == pwsz ||
|
|
pwsz - pwszStart + 2 > sizeof(wszPrefix)/sizeof(WCHAR))
|
|
{
|
|
pwsz = pwszStart;
|
|
break;
|
|
}
|
|
pwsz++; // skip past L'.'
|
|
|
|
CopyMemory(
|
|
wszPrefix,
|
|
pwszStart,
|
|
(SAFE_SUBTRACT_POINTERS(pwsz, pwszStart) * sizeof(WCHAR)));
|
|
wszPrefix[pwsz - pwszStart] = L'\0';
|
|
|
|
if (!fSubject)
|
|
{
|
|
pwszStart = pwsz;
|
|
if (0 == lstrcmpi(wszPrefix, wszPROPSUBJECTDOT))
|
|
{
|
|
fSubject = TRUE;
|
|
continue;
|
|
}
|
|
else
|
|
if (!fRequest &&
|
|
PROPTABLE_REQUEST == dwTable &&
|
|
0 == lstrcmpi(wszPrefix, wszPROPREQUESTDOT))
|
|
{
|
|
fRequest = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
hr = E_INVALIDARG;
|
|
_JumpErrorStr(hr, error, "Invalid prefix", pwszPropName);
|
|
}
|
|
}
|
|
|
|
pdbTable = NULL;
|
|
|
|
// Search the requested table for a matching property name or property
|
|
// objectid string.
|
|
|
|
switch (dwTable)
|
|
{
|
|
case PROPTABLE_REQUEST:
|
|
pdbTable = g_adtRequests;
|
|
break;
|
|
|
|
case PROPTABLE_CERTIFICATE:
|
|
pdbTable = g_adtCertificates;
|
|
break;
|
|
|
|
case PROPTABLE_CRL:
|
|
pdbTable = g_adtCRLs;
|
|
break;
|
|
}
|
|
CSASSERT(NULL != pdbTable);
|
|
|
|
pdt = _MapTable(pwszStart, pdbTable);
|
|
if (NULL == pdt || (fSubject && 0 == (DBTF_SUBJECT & pdt->dwFlags)))
|
|
{
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
_JumpErrorStr(
|
|
hr,
|
|
error,
|
|
PROPTABLE_REQUEST == dwTable?
|
|
"unknown Request property" :
|
|
PROPTABLE_CERTIFICATE == dwTable?
|
|
"unknown Certificate property" :
|
|
"unknown CRL property",
|
|
pwszPropName);
|
|
}
|
|
*pdtOut = *pdt; // structure copy
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::TestShutDownState()
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (m_fPendingShutDown)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS);
|
|
_JumpError(hr, error, "m_fPendingShutDown");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::SetProperty(
|
|
IN CERTSESSION *pcs,
|
|
IN DBTABLE const *pdt,
|
|
IN DWORD cbProp,
|
|
IN BYTE const *pbProp) // OPTIONAL
|
|
{
|
|
HRESULT hr;
|
|
JET_TABLEID tableid;
|
|
|
|
if (NULL == pcs ||
|
|
NULL == pdt ||
|
|
(NULL == pbProp && !ISTEXTCOLTYP(pdt->dbcoltyp)))
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"SetProperty for %hs into table %d\n",
|
|
pdt->pszFieldName,
|
|
pdt->dwTable));
|
|
|
|
if (ISTEXTCOLTYP(pdt->dbcoltyp))
|
|
{
|
|
DBGPRINT((DBG_SS_CERTDBI, "SetProperty setting string %ws\n", pbProp));
|
|
}
|
|
if (JET_coltypDateTime == pdt->dbcoltyp)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"SetProperty setting date: %x:%x\n",
|
|
((DWORD *) pbProp)[0],
|
|
((DWORD *) pbProp)[1]));
|
|
}
|
|
|
|
switch (pdt->dwTable)
|
|
{
|
|
case TABLE_CRLS:
|
|
case TABLE_REQUESTS:
|
|
tableid = pcs->aTable[CSTI_PRIMARY].TableId;
|
|
break;
|
|
|
|
case TABLE_CERTIFICATES:
|
|
tableid = pcs->aTable[CSTI_CERTIFICATE].TableId;
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "unknown table type");
|
|
}
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
hr = _SetColumn(
|
|
pcs->SesId,
|
|
tableid,
|
|
pdt->dbcolumnid,
|
|
cbProp,
|
|
pbProp);
|
|
_JumpIfErrorStr(hr, error, "_SetColumn", pdt->pwszPropName);
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::GetProperty(
|
|
IN CERTSESSION *pcs,
|
|
IN DBTABLE const *pdt,
|
|
IN OUT DWORD *pcbProp,
|
|
OUT BYTE *pbProp) // OPTIONAL
|
|
{
|
|
HRESULT hr;
|
|
JET_COLUMNDEF columndef;
|
|
JET_TABLEID tableid;
|
|
|
|
if (NULL == pcs || NULL == pdt || NULL == pcbProp)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"GetProperty for %hs from table %d\n",
|
|
pdt->pszFieldName,
|
|
pdt->dwTable));
|
|
|
|
if ((CSF_TABLEMASK & pcs->SesFlags) != pdt->dwTable)
|
|
{
|
|
if (TABLE_REQCERTS != (CSF_TABLEMASK & pcs->SesFlags) ||
|
|
(TABLE_REQUESTS != pdt->dwTable &&
|
|
TABLE_CERTIFICATES != pdt->dwTable))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "mismatched table");
|
|
}
|
|
}
|
|
if (TABLE_CERTIFICATES == pdt->dwTable)
|
|
{
|
|
tableid = pcs->aTable[CSTI_CERTIFICATE].TableId;
|
|
}
|
|
else
|
|
{
|
|
tableid = pcs->aTable[CSTI_PRIMARY].TableId;
|
|
}
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdt->dbcolumnid,
|
|
pdt->dbcoltyp,
|
|
pcbProp,
|
|
pbProp);
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"_RetrieveColumn",
|
|
pdt->pwszPropName,
|
|
CERTSRV_E_PROPERTY_EMPTY,
|
|
HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW));
|
|
|
|
if (ISTEXTCOLTYP(pdt->dbcoltyp))
|
|
{
|
|
DBGPRINT((DBG_SS_CERTDBI, "GetProperty returning string %ws\n", pbProp));
|
|
}
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::CopyRequestNames(
|
|
IN CERTSESSION *pcs)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DBTABLE dt;
|
|
DWORD cbProp;
|
|
BYTE *pbProp = NULL;
|
|
DWORD i;
|
|
|
|
BYTE rgbFastBuf[64];
|
|
|
|
if (NULL == pcs)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
for (i = 0; NULL != g_dntr[i].pszFieldName; i++)
|
|
{
|
|
hr = MapPropId(g_dntr[i].pwszPropName, PROPTABLE_REQUEST, &dt);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_OK;
|
|
continue; // Optional column doesn't exist
|
|
}
|
|
_JumpIfError(hr, error, "MapPropId");
|
|
|
|
// re-point at fastbuf
|
|
pbProp = rgbFastBuf;
|
|
cbProp = sizeof(rgbFastBuf);
|
|
|
|
hr = GetProperty(pcs, &dt, &cbProp, pbProp);
|
|
if (S_OK != hr)
|
|
{
|
|
if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
|
|
{
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_OK;
|
|
continue;
|
|
}
|
|
_JumpIfError(hr, error, "GetProperty");
|
|
}
|
|
CSASSERT (ARRAYSIZE(rgbFastBuf) < cbProp);
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"FastBuf miss: CopyRequestNames(cbProp=%u)\n",
|
|
cbProp));
|
|
|
|
pbProp = (BYTE *) LocalAlloc(LMEM_FIXED, cbProp);
|
|
if (NULL == pbProp)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
hr = GetProperty(pcs, &dt, &cbProp, pbProp);
|
|
_JumpIfError(hr, error, "GetProperty");
|
|
} // have data in hand
|
|
|
|
hr = MapPropId(g_dntr[i].pwszPropName, PROPTABLE_CERTIFICATE, &dt);
|
|
_JumpIfError(hr, error, "MapPropId");
|
|
|
|
hr = SetProperty(pcs, &dt, cbProp, pbProp);
|
|
_JumpIfError(hr, error, "SetProperty");
|
|
|
|
if (NULL != pbProp && rgbFastBuf != pbProp)
|
|
{
|
|
LocalFree(pbProp);
|
|
}
|
|
pbProp = NULL;
|
|
}
|
|
|
|
error:
|
|
if (NULL != pbProp && rgbFastBuf != pbProp)
|
|
{
|
|
LocalFree(pbProp);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CCertDB::EnumCertDBColumn(
|
|
/* [in] */ DWORD dwTable,
|
|
/* [out] */ IEnumCERTDBCOLUMN **ppenum)
|
|
{
|
|
HRESULT hr;
|
|
IEnumCERTDBCOLUMN *penum = NULL;
|
|
|
|
if (NULL == ppenum)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
*ppenum = NULL;
|
|
|
|
penum = new CEnumCERTDBCOLUMN;
|
|
if (NULL == penum)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "new CEnumCERTDBCOLUMN");
|
|
}
|
|
|
|
hr = ((CEnumCERTDBCOLUMN *) penum)->Open(dwTable, this);
|
|
_JumpIfError(hr, error, "Open");
|
|
|
|
*ppenum = penum;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr && NULL != penum)
|
|
{
|
|
penum->Release();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CCertDB::GetDefaultColumnSet(
|
|
/* [in] */ DWORD iColumnSetDefault,
|
|
/* [in] */ DWORD cColumnIds,
|
|
/* [out] */ DWORD *pcColumnIds,
|
|
/* [out, ref] */ DWORD *pColumnIds) // OPTIONAL
|
|
{
|
|
HRESULT hr;
|
|
DWORD *pcol;
|
|
DWORD ccol;
|
|
|
|
if (NULL == pcColumnIds)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
switch (iColumnSetDefault)
|
|
{
|
|
case CV_COLUMN_LOG_FAILED_DEFAULT:
|
|
case CV_COLUMN_QUEUE_DEFAULT:
|
|
pcol = g_aColumnViewQueue;
|
|
ccol = g_cColumnViewQueue;
|
|
break;
|
|
|
|
case CV_COLUMN_LOG_REVOKED_DEFAULT:
|
|
pcol = g_aColumnViewRevoked;
|
|
ccol = g_cColumnViewRevoked;
|
|
break;
|
|
|
|
case CV_COLUMN_LOG_DEFAULT:
|
|
pcol = g_aColumnViewLog;
|
|
ccol = g_cColumnViewLog;
|
|
break;
|
|
|
|
case CV_COLUMN_EXTENSION_DEFAULT:
|
|
pcol = g_aColumnViewExtension;
|
|
ccol = g_cColumnViewExtension;
|
|
break;
|
|
|
|
case CV_COLUMN_ATTRIBUTE_DEFAULT:
|
|
pcol = g_aColumnViewAttribute;
|
|
ccol = g_cColumnViewAttribute;
|
|
break;
|
|
|
|
case CV_COLUMN_CRL_DEFAULT:
|
|
pcol = g_aColumnViewCRL;
|
|
ccol = g_cColumnViewCRL;
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "iColumnSetDefault");
|
|
}
|
|
|
|
*pcColumnIds = ccol;
|
|
hr = S_OK;
|
|
|
|
if (NULL != pColumnIds)
|
|
{
|
|
if (ccol > cColumnIds)
|
|
{
|
|
ccol = cColumnIds;
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
}
|
|
CopyMemory(pColumnIds, pcol, ccol * sizeof(*pColumnIds));
|
|
}
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::GetColumnType(
|
|
IN LONG ColumnIndex,
|
|
OUT DWORD *pType)
|
|
{
|
|
HRESULT hr;
|
|
DBTABLE const *pdt;
|
|
|
|
if (NULL == pType)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
hr = _MapPropIdIndex(ColumnIndex, &pdt, pType);
|
|
_JumpIfError(hr, error, "_MapPropIdIndex");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::EnumCertDBColumnNext(
|
|
IN DWORD dwTable, // CVRC_TABLE_*
|
|
IN ULONG ielt,
|
|
IN ULONG celt,
|
|
OUT CERTDBCOLUMN *rgelt,
|
|
OUT ULONG *pielt,
|
|
OUT ULONG *pceltFetched)
|
|
{
|
|
HRESULT hr;
|
|
ULONG ieltEnd;
|
|
ULONG ieltMax;
|
|
ULONG TableIndex;
|
|
CERTDBCOLUMN *pelt;
|
|
WCHAR const *pwszPrefix;
|
|
WCHAR const *pwszDisplayName;
|
|
|
|
if (NULL == rgelt || NULL == pielt || NULL == pceltFetched)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
switch (dwTable)
|
|
{
|
|
case CVRC_TABLE_REQCERT:
|
|
TableIndex = DTI_REQUESTTABLE;
|
|
ieltMax = DTR_MAX + DTC_MAX;
|
|
break;
|
|
|
|
case CVRC_TABLE_EXTENSIONS:
|
|
TableIndex = DTI_EXTENSIONTABLE;
|
|
ieltMax = DTE_MAX;
|
|
break;
|
|
|
|
case CVRC_TABLE_ATTRIBUTES:
|
|
TableIndex = DTI_ATTRIBUTETABLE;
|
|
ieltMax = DTA_MAX;
|
|
break;
|
|
|
|
case CVRC_TABLE_CRL:
|
|
TableIndex = DTI_CRLTABLE;
|
|
ieltMax = DTL_MAX;
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Bad table");
|
|
}
|
|
|
|
if (ieltMax + ielt < celt)
|
|
{
|
|
celt = ieltMax - ielt;
|
|
}
|
|
ieltEnd = ielt + celt;
|
|
|
|
ZeroMemory(rgelt, celt * sizeof(rgelt[0]));
|
|
|
|
hr = S_OK;
|
|
for (pelt = rgelt; pelt < &rgelt[celt]; ielt++, pelt++)
|
|
{
|
|
DBTABLE const *pdt;
|
|
ULONG ieltBase = 0;
|
|
|
|
if (ieltMax <= ielt)
|
|
{
|
|
if (pelt == rgelt)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
break;
|
|
}
|
|
pwszPrefix = NULL;
|
|
|
|
if (CVRC_TABLE_REQCERT == dwTable)
|
|
{
|
|
if (DTR_MAX > ielt)
|
|
{
|
|
pwszPrefix = wszPROPREQUESTDOT;
|
|
TableIndex = DTI_REQUESTTABLE;
|
|
}
|
|
else
|
|
{
|
|
ieltBase = DTR_MAX;
|
|
TableIndex = DTI_CERTIFICATETABLE;
|
|
}
|
|
}
|
|
|
|
pelt->Index = TableIndex | (ielt - ieltBase);
|
|
|
|
hr = _MapPropIdIndex(pelt->Index, &pdt, &pelt->Type);
|
|
_JumpIfError(hr, error, "_MapPropIdIndex");
|
|
|
|
pelt->cbMax = pdt->dwcbMax;
|
|
hr = _DupString(pwszPrefix, pdt->pwszPropName, &pelt->pwszName);
|
|
_JumpIfError(hr, error, "_DupString");
|
|
|
|
hr = myGetColumnDisplayName(pelt->pwszName, &pwszDisplayName);
|
|
_PrintIfError(hr, "myGetColumnDisplayName");
|
|
if (S_OK != hr)
|
|
{
|
|
pwszDisplayName = pelt->pwszName;
|
|
}
|
|
|
|
hr = _DupString(NULL, pwszDisplayName, &pelt->pwszDisplayName);
|
|
_JumpIfError(hr, error, "_DupString");
|
|
}
|
|
|
|
*pceltFetched = SAFE_SUBTRACT_POINTERS(pelt, rgelt);
|
|
*pielt = ielt;
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
if (NULL != rgelt)
|
|
{
|
|
for (pelt = rgelt; pelt < &rgelt[celt]; pelt++)
|
|
{
|
|
if (NULL != pelt->pwszName)
|
|
{
|
|
CoTaskMemFree(pelt->pwszName);
|
|
pelt->pwszName = NULL;
|
|
}
|
|
if (NULL != pelt->pwszDisplayName)
|
|
{
|
|
CoTaskMemFree(pelt->pwszDisplayName);
|
|
pelt->pwszDisplayName = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::EnumCertDBResultRowNext(
|
|
IN CERTSESSION *pcs,
|
|
IN DWORD ccvr,
|
|
IN CERTVIEWRESTRICTION const *pcvr,
|
|
IN DWORD ccolOut,
|
|
IN DWORD const *acolOut,
|
|
IN LONG cskip,
|
|
IN ULONG celt,
|
|
OUT CERTDBRESULTROW *rgelt,
|
|
OUT ULONG *pceltFetched,
|
|
OUT LONG *pcskipped)
|
|
{
|
|
HRESULT hr;
|
|
DWORD iRow;
|
|
CERTDBRESULTROW *pResultRow;
|
|
LONG cskipped;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"EnumCertDBResultRowNext called: cskip: %d\n", cskip));
|
|
|
|
if (NULL == pcvr ||
|
|
NULL == acolOut ||
|
|
NULL == rgelt ||
|
|
NULL == pceltFetched ||
|
|
NULL == pcskipped)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
*pcskipped = 0;
|
|
hr = S_OK;
|
|
for (iRow = 0; iRow < celt; iRow++)
|
|
{
|
|
hr = TestShutDownState();
|
|
_JumpIfError(hr, error, "TestShutDownState");
|
|
|
|
hr = _GetResultRow(
|
|
pcs,
|
|
ccvr,
|
|
pcvr,
|
|
cskip,
|
|
ccolOut,
|
|
acolOut,
|
|
&rgelt[iRow],
|
|
&cskipped);
|
|
if (S_FALSE == hr)
|
|
{
|
|
*pcskipped += cskipped;
|
|
break;
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"EnumCertDBResultRowNext: rowid %u\n", rgelt[iRow].rowid));
|
|
|
|
_JumpIfError(hr, error, "_GetResultRow");
|
|
|
|
*pcskipped += cskipped;
|
|
cskip = 0;
|
|
}
|
|
*pceltFetched = iRow;
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"EnumCertDBResultRowNext: %u rows, hr=%x\n",
|
|
*pceltFetched,
|
|
hr));
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
ReleaseResultRow(celt, rgelt);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_CompareColumnValue(
|
|
IN CERTSESSION *pcs,
|
|
IN CERTVIEWRESTRICTION const *pcvr)
|
|
{
|
|
HRESULT hr;
|
|
JET_TABLEID tableid;
|
|
DBTABLE const *pdt;
|
|
WCHAR *pwszValue = NULL;
|
|
BOOL fMatch;
|
|
int r;
|
|
|
|
BYTE rgbFastBuf[256];
|
|
BYTE *pbProp = rgbFastBuf;
|
|
DWORD cb = sizeof(rgbFastBuf);
|
|
|
|
// if SEEK_NONE, short circuit tests
|
|
if (CVR_SEEK_NONE == (CVR_SEEK_MASK & pcvr->SeekOperator))
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
|
|
_JumpIfError(hr, error, "_MapPropIdIndex");
|
|
|
|
if (TABLE_CERTIFICATES == pdt->dwTable)
|
|
{
|
|
tableid = pcs->aTable[CSTI_CERTIFICATE].TableId;
|
|
}
|
|
else
|
|
{
|
|
tableid = pcs->aTable[CSTI_PRIMARY].TableId;
|
|
}
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdt->dbcolumnid,
|
|
pdt->dbcoltyp,
|
|
&cb,
|
|
rgbFastBuf);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
|
|
{
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
_PrintError2(hr, "_RetrieveColumn", hr);
|
|
hr = S_FALSE;
|
|
}
|
|
_JumpError2(hr, error, "_RetrieveColumn", S_FALSE);
|
|
}
|
|
|
|
// buffer not big enough, dyn-alloc
|
|
CSASSERT(ARRAYSIZE(rgbFastBuf) < cb);
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"FastBuf miss: _CompareColumnValue(cbProp=%u)\n",
|
|
cb));
|
|
|
|
pbProp = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pbProp)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdt->dbcolumnid,
|
|
pdt->dbcoltyp,
|
|
&cb,
|
|
pbProp);
|
|
_JumpIfError(hr, error, "_RetrieveColumn");
|
|
|
|
} // we have data in-hand
|
|
|
|
#if DBG_CERTSRV
|
|
DumpRestriction(DBG_SS_CERTDBI, -1, pcvr);
|
|
dbDumpColumn(DBG_SS_CERTDBI, pdt, pbProp, cb);
|
|
#endif
|
|
|
|
fMatch = FALSE;
|
|
switch (pdt->dbcoltyp)
|
|
{
|
|
case JET_coltypLong:
|
|
if (cb == pcvr->cbValue && sizeof(LONG) == cb)
|
|
{
|
|
LONG lRestriction;
|
|
LONG lColumn;
|
|
|
|
lRestriction = *(LONG *) pcvr->pbValue;
|
|
lColumn = *(LONG *) pbProp;
|
|
switch (CVR_SEEK_MASK & pcvr->SeekOperator)
|
|
{
|
|
case CVR_SEEK_EQ:
|
|
fMatch = lColumn == lRestriction;
|
|
break;
|
|
|
|
case CVR_SEEK_LT:
|
|
fMatch = lColumn < lRestriction;
|
|
break;
|
|
|
|
case CVR_SEEK_LE:
|
|
fMatch = lColumn <= lRestriction;
|
|
break;
|
|
|
|
case CVR_SEEK_GE:
|
|
fMatch = lColumn >= lRestriction;
|
|
break;
|
|
|
|
case CVR_SEEK_GT:
|
|
fMatch = lColumn > lRestriction;
|
|
break;
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_CompareColumnValue(lColumn=%x %ws lRestriction=%x) -> fMatch=%x\n",
|
|
lColumn,
|
|
wszSeekOperator(pcvr->SeekOperator),
|
|
lRestriction,
|
|
fMatch));
|
|
}
|
|
break;
|
|
|
|
case JET_coltypDateTime:
|
|
if (cb == pcvr->cbValue && sizeof(FILETIME) == cb)
|
|
{
|
|
r = CompareFileTime(
|
|
(FILETIME *) pcvr->pbValue,
|
|
(FILETIME *) pbProp);
|
|
switch (CVR_SEEK_MASK & pcvr->SeekOperator)
|
|
{
|
|
case CVR_SEEK_EQ:
|
|
fMatch = 0 == r;
|
|
break;
|
|
|
|
case CVR_SEEK_LT:
|
|
fMatch = 0 < r;
|
|
break;
|
|
|
|
case CVR_SEEK_LE:
|
|
fMatch = 0 <= r;
|
|
break;
|
|
|
|
case CVR_SEEK_GE:
|
|
fMatch = 0 >= r;
|
|
break;
|
|
|
|
case CVR_SEEK_GT:
|
|
fMatch = 0 > r;
|
|
break;
|
|
}
|
|
#if DBG_CERTSRV
|
|
dbDumpFileTime(
|
|
DBG_SS_CERTDBI,
|
|
"Column: ",
|
|
(FILETIME const *) pbProp);
|
|
dbDumpFileTime(
|
|
DBG_SS_CERTDBI,
|
|
"Restriction: ",
|
|
(FILETIME const *) pcvr->pbValue);
|
|
#endif
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_CompareColumnValue(ftColumn=%08x:%08x %ws ftRestriction=%08x:%08x) -> r=%d, fMatch=%x\n",
|
|
((LARGE_INTEGER *) pbProp)->HighPart,
|
|
((LARGE_INTEGER *) pbProp)->LowPart,
|
|
wszSeekOperator(pcvr->SeekOperator),
|
|
((LARGE_INTEGER *) pcvr->pbValue)->HighPart,
|
|
((LARGE_INTEGER *) pcvr->pbValue)->LowPart,
|
|
r,
|
|
fMatch));
|
|
}
|
|
break;
|
|
|
|
case JET_coltypText:
|
|
case JET_coltypLongText:
|
|
CSASSERT(
|
|
(1 + wcslen((WCHAR const *) pcvr->pbValue)) * sizeof(WCHAR) ==
|
|
pcvr->cbValue);
|
|
CSASSERT(wcslen((WCHAR const *) pbProp) * sizeof(WCHAR) == cb);
|
|
r = lstrcmpi((WCHAR const *) pcvr->pbValue, (WCHAR const *) pbProp); //pwszValue
|
|
switch (CVR_SEEK_MASK & pcvr->SeekOperator)
|
|
{
|
|
case CVR_SEEK_EQ:
|
|
fMatch = 0 == r;
|
|
break;
|
|
|
|
case CVR_SEEK_LT:
|
|
fMatch = 0 < r;
|
|
break;
|
|
|
|
case CVR_SEEK_LE:
|
|
fMatch = 0 <= r;
|
|
break;
|
|
|
|
case CVR_SEEK_GE:
|
|
fMatch = 0 >= r;
|
|
break;
|
|
|
|
case CVR_SEEK_GT:
|
|
fMatch = 0 > r;
|
|
break;
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_CompareColumnValue(pwszColumn=%ws %ws pwszRestriction=%ws) -> r=%d, fMatch=%x\n",
|
|
pbProp, //pwszValue,
|
|
wszSeekOperator(pcvr->SeekOperator),
|
|
pcvr->pbValue,
|
|
r,
|
|
fMatch));
|
|
break;
|
|
|
|
case JET_coltypLongBinary:
|
|
if (CVR_SEEK_EQ != (CVR_SEEK_MASK & pcvr->SeekOperator))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Bad dbcoltyp");
|
|
}
|
|
fMatch = cb == pcvr->cbValue &&
|
|
0 == memcmp(pcvr->pbValue, pbProp, cb);
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Bad dbcoltyp");
|
|
}
|
|
|
|
if (!fMatch)
|
|
{
|
|
hr = S_FALSE;
|
|
_JumpError2(hr, error, "No match", S_FALSE);
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszValue)
|
|
{
|
|
LocalFree(pwszValue);
|
|
}
|
|
if (NULL != pbProp && rgbFastBuf != pbProp)
|
|
{
|
|
LocalFree(pbProp);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_MakeSeekKey(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid,
|
|
IN DBTABLE const *pdt,
|
|
IN BYTE const *pbValue,
|
|
IN DWORD cbValue)
|
|
{
|
|
HRESULT hr;
|
|
JET_GRBIT grbitKey = JET_bitNewKey;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
if (DBTF_INDEXREQUESTID & pdt->dwFlags)
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetMakeKey(
|
|
pcs->SesId,
|
|
tableid,
|
|
&pcs->RowId,
|
|
sizeof(pcs->RowId),
|
|
grbitKey);
|
|
_JumpIfError(hr, error, "JetMakeKey(RowId)");
|
|
|
|
DBGPRINT((DBG_SS_CERTDBI, "_MakeSeekKey key(RowId):\n"));
|
|
DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, (BYTE *) &pcs->RowId, sizeof(pcs->RowId)));
|
|
grbitKey = 0;
|
|
}
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetMakeKey(pcs->SesId, tableid, pbValue, cbValue, grbitKey);
|
|
_JumpIfErrorStr(hr, error, "JetMakeKey", pdt->pwszPropName);
|
|
|
|
DBGPRINT((DBG_SS_CERTDBI, "_MakeSeekKey key:\n"));
|
|
DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, pbValue, cbValue));
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_SeekTable(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid,
|
|
IN CERTVIEWRESTRICTION const *pcvr,
|
|
IN DBTABLE const *pdt,
|
|
IN DWORD dwPosition,
|
|
OUT DWORD *pTableFlags
|
|
DBGPARM(IN DBAUXDATA const *pdbaux))
|
|
{
|
|
HRESULT hr;
|
|
DBSEEKDATA SeekData;
|
|
BYTE *pbValue;
|
|
DWORD cbValue;
|
|
BYTE abRangeKey[JET_cbKeyMost];
|
|
DWORD cbRangeKey;
|
|
|
|
*pTableFlags = 0;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
hr = _JetSeekFromRestriction(pcvr, dwPosition, &SeekData);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
_JumpIfError2(hr, error, "_JetSeekFromRestriction", S_FALSE);
|
|
|
|
cbValue = pcvr->cbValue;
|
|
pbValue = pcvr->pbValue;
|
|
|
|
if (ISTEXTCOLTYP(pdt->dbcoltyp) &&
|
|
NULL != pbValue &&
|
|
cbValue == -1)
|
|
{
|
|
cbValue = wcslen((WCHAR const *) pbValue) * sizeof(WCHAR);
|
|
}
|
|
|
|
// If we need to set an index limit, seek to the limit location, and save
|
|
// a copy of the key until after the initial record is located.
|
|
|
|
if (CST_SEEKINDEXRANGE & SeekData.SeekFlags)
|
|
{
|
|
hr = _MakeSeekKey(pcs, tableid, pdt, pbValue, cbValue);
|
|
_JumpIfError(hr, error, "_MakeSeekKey");
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetSeek(pcs->SesId, tableid, SeekData.grbitSeekRange);
|
|
if ((HRESULT) JET_errRecordNotFound == hr)
|
|
{
|
|
// No record exists past the data we're interested in.
|
|
// Just use the end of the index as the limit.
|
|
|
|
_PrintError2(hr, "JetSeek(Range Limit): no key, index end is limit", hr);
|
|
SeekData.SeekFlags &= ~CST_SEEKINDEXRANGE;
|
|
hr = S_OK;
|
|
}
|
|
else if ((HRESULT) JET_wrnSeekNotEqual == hr)
|
|
{
|
|
_PrintError2(hr, "JetSeek(Range): ignoring key not equal", hr);
|
|
hr = S_OK; // Ignore inexact match when seeking >= or <=
|
|
}
|
|
//_JumpIfError2(hr, error, "JetSeek(IndexRange)", S_FALSE);
|
|
_JumpIfError(hr, error, "JetSeek(IndexRange)");
|
|
}
|
|
|
|
// If we found a valid key at the limit location, save it now.
|
|
|
|
if (CST_SEEKINDEXRANGE & SeekData.SeekFlags)
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetRetrieveKey(
|
|
pcs->SesId,
|
|
tableid,
|
|
abRangeKey,
|
|
ARRAYSIZE(abRangeKey),
|
|
&cbRangeKey,
|
|
0);
|
|
_JumpIfError(hr, error, "JetRetrieveKey");
|
|
|
|
DBGPRINT((DBG_SS_CERTDBI, "RetrieveKey(Range):\n"));
|
|
DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, abRangeKey, cbRangeKey));
|
|
}
|
|
|
|
// Locate the initial record: seek to a key or move to one end of the index
|
|
|
|
if (CST_SEEKNOTMOVE & SeekData.SeekFlags)
|
|
{
|
|
hr = _MakeSeekKey(pcs, tableid, pdt, pbValue, cbValue);
|
|
_JumpIfError(hr, error, "_MakeSeekKey");
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetSeek(pcs->SesId, tableid, SeekData.grbitInitial);
|
|
if ((HRESULT) JET_errRecordNotFound == hr)
|
|
{
|
|
// Routine GetAttribute/Extension call:
|
|
|
|
_PrintError2(hr, "JetSeek: Property EMPTY", hr);
|
|
hr = S_FALSE;
|
|
}
|
|
else if ((HRESULT) JET_wrnSeekNotEqual == hr)
|
|
{
|
|
hr = S_OK; // Ignore inexact match when seeking >= or <=
|
|
}
|
|
_JumpIfError2(hr, error, "JetSeek(Initial)", S_FALSE);
|
|
}
|
|
else
|
|
{
|
|
// grbitInitial is a move count here, not a grbit
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetMove(pcs->SesId, tableid, SeekData.grbitInitial, 0);
|
|
if ((HRESULT) JET_errNoCurrentRecord == hr)
|
|
{
|
|
// Routine Enumerate call:
|
|
|
|
// _JumpIfError(hr, error, "JetMove: no more elements");
|
|
hr = S_FALSE;
|
|
}
|
|
_JumpIfError2(hr, error, "JetMove(End)", S_FALSE);
|
|
|
|
// If moving the cursor to the last element, we want to position
|
|
// ourselves to step over the end again (skip the last element).
|
|
//
|
|
// If moving to the first element, we want to position ourselves on the
|
|
// first element and use it before stepping
|
|
|
|
if (SEEKPOS_FIRST == dwPosition || SEEKPOS_INDEXFIRST == dwPosition)
|
|
{
|
|
SeekData.SeekFlags |= CST_SEEKUSECURRENT;
|
|
}
|
|
}
|
|
|
|
// We're done seeking around; set the index limit from the saved key.
|
|
|
|
if (CST_SEEKINDEXRANGE & SeekData.SeekFlags)
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetMakeKey(
|
|
pcs->SesId,
|
|
tableid,
|
|
abRangeKey,
|
|
cbRangeKey,
|
|
JET_bitNormalizedKey);
|
|
_JumpIfError(hr, error, "JetMakeKey");
|
|
|
|
DBGPRINT((DBG_SS_CERTDBI, "RangeKey:\n"));
|
|
DBGDUMPHEX((DBG_SS_CERTDBI, DH_NOADDRESS, abRangeKey, cbRangeKey));
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetSetIndexRange(
|
|
pcs->SesId,
|
|
tableid,
|
|
SeekData.grbitRange);
|
|
if ((HRESULT) JET_errNoCurrentRecord == hr)
|
|
{
|
|
// No records to enumerate:
|
|
_PrintError2(hr, "JetSetIndexRange: no records to enumerate", hr);
|
|
hr = S_FALSE;
|
|
}
|
|
_JumpIfError2(hr, error, "JetSetIndexRange", S_FALSE);
|
|
}
|
|
|
|
DBGCODE(_DumpRowId("post-_SeekTable", pcs, tableid));
|
|
DBGCODE(_DumpColumn("post-_SeekTable", pcs, tableid, pdt));
|
|
|
|
*pTableFlags = SeekData.SeekFlags;
|
|
|
|
error:
|
|
if (S_FALSE == hr)
|
|
{
|
|
DWORD dwPosition2 = dwPosition;
|
|
|
|
switch (dwPosition)
|
|
{
|
|
case SEEKPOS_FIRST:
|
|
dwPosition2 = SEEKPOS_INDEXFIRST;
|
|
break;
|
|
|
|
case SEEKPOS_LAST:
|
|
dwPosition2 = SEEKPOS_INDEXLAST;
|
|
break;
|
|
}
|
|
if (dwPosition2 != dwPosition)
|
|
{
|
|
hr = _SeekTable(
|
|
pcs,
|
|
tableid,
|
|
pcvr,
|
|
pdt,
|
|
dwPosition2,
|
|
pTableFlags
|
|
DBGPARM(pdbaux));
|
|
_PrintIfError2(hr, "_SeekTable: recurse on index first/last", S_FALSE);
|
|
}
|
|
}
|
|
#if DBG_CERTSRV
|
|
if (S_OK != hr)
|
|
{
|
|
DumpRestriction(DBG_SS_CERTDBI, 0, pcvr);
|
|
}
|
|
#endif
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_MoveTable(
|
|
IN CERTSESSION *pcs,
|
|
IN DWORD ccvr,
|
|
IN CERTVIEWRESTRICTION const *pcvr,
|
|
IN LONG cskip,
|
|
OUT LONG *pcskipped)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cb;
|
|
DBAUXDATA const *pdbaux;
|
|
DBTABLE const *pdt;
|
|
DWORD icvr;
|
|
DWORD SeekFlags;
|
|
LONG lSeek;
|
|
LONG skipIncrement;
|
|
LONG cskipRemain;
|
|
BOOL fHitEnd = FALSE;
|
|
LONG cskippeddummy;
|
|
CERTSESSIONTABLE *pTable;
|
|
CERTSESSIONTABLE *pTable2;
|
|
|
|
*pcskipped = 0;
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_MoveTable called(ccvr=%d, cskip=%d, flags=%ws)\n",
|
|
ccvr,
|
|
cskip,
|
|
wszCSFFlags(pcs->SesFlags)));
|
|
|
|
hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
|
|
_JumpIfError(hr, error, "_MapPropIdIndex");
|
|
|
|
pTable = &pcs->aTable[CSTI_PRIMARY];
|
|
pTable2 = NULL;
|
|
|
|
switch (DTI_TABLEMASK & pcvr->ColumnIndex)
|
|
{
|
|
case DTI_REQUESTTABLE:
|
|
pdbaux = &g_dbauxRequests;
|
|
pTable2 = &pcs->aTable[CSTI_CERTIFICATE];
|
|
break;
|
|
|
|
case DTI_CERTIFICATETABLE:
|
|
pdbaux = &g_dbauxCertificates;
|
|
pTable = &pcs->aTable[CSTI_CERTIFICATE];
|
|
pTable2 = &pcs->aTable[CSTI_PRIMARY];
|
|
break;
|
|
|
|
case DTI_EXTENSIONTABLE:
|
|
pdbaux = &g_dbauxExtensions;
|
|
break;
|
|
|
|
case DTI_ATTRIBUTETABLE:
|
|
pdbaux = &g_dbauxAttributes;
|
|
break;
|
|
|
|
case DTI_CRLTABLE:
|
|
pdbaux = &g_dbauxCRLs;
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "ColumnIndex Table");
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_MoveTable(Table=%hs, TableFlags=%ws)\n",
|
|
pdbaux->pszTable,
|
|
wszCSTFlags(pTable->TableFlags)));
|
|
|
|
if (NULL != pTable2 && IsValidJetTableId(pTable2->TableId))
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_MoveTable(Table2=%hs, TableFlags2=%ws)\n",
|
|
&g_dbauxCertificates == pdbaux?
|
|
g_dbauxRequests.pszTable :
|
|
g_dbauxCertificates.pszTable,
|
|
wszCSTFlags(pTable2->TableFlags)));
|
|
}
|
|
|
|
switch (pcvr->SortOrder)
|
|
{
|
|
case CVR_SORT_DESCEND:
|
|
lSeek = JET_MovePrevious;
|
|
break;
|
|
|
|
case CVR_SORT_NONE:
|
|
default:
|
|
CSASSERT(!"bad pcvr->SortOrder"); // shouldn't get this far
|
|
// FALL THROUGH
|
|
|
|
case CVR_SORT_ASCEND:
|
|
lSeek = JET_MoveNext;
|
|
break;
|
|
}
|
|
|
|
// Add one to the skip count for the implicit Next operation. Next
|
|
// always moves forward one, even when a negative skip count moves
|
|
// backward. The net result may be a forward or backward skip.
|
|
|
|
cskipRemain = cskip + 1;
|
|
skipIncrement = 1;
|
|
if (0 > cskipRemain)
|
|
{
|
|
CSASSERT(JET_MoveNext == -1 * JET_MovePrevious);
|
|
lSeek *= -1; // Seek in opposite direction
|
|
cskipRemain *= -1; // make the skip count positive
|
|
skipIncrement = -1;
|
|
}
|
|
CSASSERT(0 <= cskipRemain);
|
|
|
|
while (0 != cskipRemain)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_MoveTable loop: ccvr=%d, cskipRemain=%d, lSeek=%d, flags=%ws\n",
|
|
ccvr,
|
|
cskipRemain,
|
|
lSeek,
|
|
wszCSFFlags(pcs->SesFlags)));
|
|
|
|
DBGCODE(_DumpRowId("_MoveTable(loop top)", pcs, pTable->TableId));
|
|
|
|
if (CSF_VIEW & pcs->SesFlags)
|
|
{
|
|
hr = TestShutDownState();
|
|
_JumpIfError(hr, error, "TestShutDownState");
|
|
}
|
|
|
|
if (CSF_VIEWRESET & pcs->SesFlags)
|
|
{
|
|
hr = _SeekTable(
|
|
pcs,
|
|
pTable->TableId,
|
|
pcvr,
|
|
pdt,
|
|
SEEKPOS_FIRST,
|
|
&pTable->TableFlags
|
|
DBGPARM(pdbaux));
|
|
_JumpIfError(hr, error, "_SeekTable");
|
|
|
|
pcs->SesFlags &= ~CSF_VIEWRESET;
|
|
}
|
|
if (0 == (CST_SEEKUSECURRENT & pTable->TableFlags))
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetMove(pcs->SesId, pTable->TableId, lSeek, 0);
|
|
if ((HRESULT) JET_errNoCurrentRecord == hr)
|
|
{
|
|
_PrintIfError2(hr, "JetMove: no more elements", hr);
|
|
|
|
if (fHitEnd)
|
|
{
|
|
// we hit the end trying to backstep! We're done
|
|
hr = S_FALSE;
|
|
_JumpError(hr, error, "JetMove: db backstep hit beginning");
|
|
}
|
|
fHitEnd = TRUE;
|
|
|
|
// NOTE: Tough case
|
|
//
|
|
// We just hit the end of the database index, which could be a
|
|
// virtual end or the real end. To recover, we call _SeekTable
|
|
// to position ourselves at the last legal element computed by
|
|
// the 1st restriction, then allow this routine to rewind until
|
|
// we position ourselves on the very last legal element as
|
|
// computed by 2nd through Nth restrictions.
|
|
|
|
// Routine Seek call to position at end of enumeration
|
|
|
|
hr = _SeekTable(
|
|
pcs,
|
|
pTable->TableId,
|
|
pcvr,
|
|
pdt,
|
|
SEEKPOS_LAST, // cursor at end
|
|
&pTable->TableFlags
|
|
DBGPARM(pdbaux));
|
|
_JumpIfError(hr, error, "_SeekTable moving to last elt");
|
|
|
|
// now fall through, allow other restrictions to test for 1st
|
|
// valid element
|
|
|
|
lSeek *= -1; // Seek in opposite direction
|
|
cskipRemain = 1; // one valid element
|
|
pcskipped = &cskippeddummy; // stop counting skipped rows
|
|
}
|
|
_JumpIfError2(hr, error, "JetMove", S_FALSE);
|
|
|
|
DBGCODE(_DumpRowId("_MoveTable(post-move)", pcs, pTable->TableId));
|
|
|
|
hr = _CompareColumnValue(pcs, pcvr);
|
|
_JumpIfError2(hr, error, "_CompareColumnValue", S_FALSE);
|
|
}
|
|
pTable->TableFlags &= ~CST_SEEKUSECURRENT;
|
|
|
|
// Fetch RowId from the first table, form a key for the second
|
|
// table and seek to the corresponding record in the second table.
|
|
|
|
cb = sizeof(pcs->RowId);
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
pTable->TableId,
|
|
pdbaux->pdtRowId->dbcolumnid,
|
|
pdbaux->pdtRowId->dbcoltyp,
|
|
&cb,
|
|
(BYTE *) &pcs->RowId);
|
|
_JumpIfError(hr, error, "_RetrieveColumn");
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_MoveTable(Primary) %hs --> RowId=%d\n",
|
|
pdbaux->pszTable,
|
|
pcs->RowId));
|
|
|
|
if (NULL != pTable2 && IsValidJetTableId(pTable2->TableId))
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetMakeKey(
|
|
pcs->SesId,
|
|
pTable2->TableId,
|
|
&pcs->RowId,
|
|
sizeof(pcs->RowId),
|
|
JET_bitNewKey);
|
|
_JumpIfError(hr, error, "JetMakeKey");
|
|
|
|
hr = _dbgJetSeek(pcs->SesId, pTable2->TableId, JET_bitSeekEQ);
|
|
if ((HRESULT) JET_errRecordNotFound == hr)
|
|
{
|
|
// Database is inconsistent
|
|
hr = S_FALSE;
|
|
}
|
|
_JumpIfError2(hr, error, "JetSeek", S_FALSE);
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_MoveTable(Secondary) %hs --> RowId=%d\n",
|
|
&g_dbauxCertificates == pdbaux?
|
|
g_dbauxRequests.pszTable :
|
|
g_dbauxCertificates.pszTable,
|
|
pcs->RowId));
|
|
}
|
|
|
|
// Now verify that any addtional restrictions are satisfied
|
|
|
|
for (icvr = 1; icvr < ccvr; icvr++)
|
|
{
|
|
#if 0
|
|
printf(
|
|
"RowId=%u, cvr[%u]: seek=%x, *pb=%x\n",
|
|
pcs->RowId,
|
|
icvr,
|
|
pcvr[icvr].SeekOperator,
|
|
*(DWORD *) pcvr[icvr].pbValue);
|
|
#endif
|
|
hr = _CompareColumnValue(pcs, &pcvr[icvr]);
|
|
if (S_FALSE == hr)
|
|
{
|
|
break; // skip row silently
|
|
}
|
|
_JumpIfError(hr, error, "_CompareColumnValue");
|
|
}
|
|
if (icvr >= ccvr)
|
|
{
|
|
*pcskipped += skipIncrement;
|
|
cskipRemain--; // found a matching row
|
|
}
|
|
} // while (cskipRemain)
|
|
|
|
error:
|
|
// if we nailed the end and rewound, return failure
|
|
if (fHitEnd && S_OK == hr)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_GetResultRow(
|
|
IN CERTSESSION *pcs,
|
|
IN DWORD ccvr,
|
|
IN CERTVIEWRESTRICTION const *pcvr,
|
|
IN LONG cskip,
|
|
IN DWORD ccolOut,
|
|
IN DWORD const *acolOut,
|
|
OUT CERTDBRESULTROW *pelt,
|
|
OUT LONG *pcskipped)
|
|
{
|
|
HRESULT hr;
|
|
DWORD iCol;
|
|
BYTE *pbProp = NULL;
|
|
BYTE *pbT;
|
|
DWORD cbAlloc = 0;
|
|
DWORD cbProp;
|
|
WCHAR awc[CCH_DBMAXTEXT_LONG];
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_GetResultRow(ccvr=%d, ccolOut=%d, cskip=%d, flags=%ws)\n",
|
|
ccvr,
|
|
ccolOut,
|
|
cskip,
|
|
wszCSFFlags(pcs->SesFlags)));
|
|
|
|
// This may move past the end of the database index entries.
|
|
// In that case, we're positioned at the end of the index.
|
|
|
|
hr = _MoveTable(pcs, ccvr, pcvr, cskip, pcskipped);
|
|
_JumpIfError2(hr, error, "_MoveTable", S_FALSE);
|
|
|
|
DBGPRINT((DBG_SS_CERTDBI, "_GetResultRow: RowId=%d\n", pcs->RowId));
|
|
|
|
pelt->acol = (CERTDBRESULTCOLUMN *) CoTaskMemAlloc(
|
|
ccolOut * sizeof(pelt->acol[0]));
|
|
if (NULL == pelt->acol)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "alloc acol");
|
|
}
|
|
|
|
ZeroMemory(pelt->acol, ccolOut * sizeof(pelt->acol[0]));
|
|
pelt->rowid = pcs->RowId;
|
|
pelt->ccol = ccolOut;
|
|
|
|
for (iCol = 0; iCol < ccolOut; iCol++)
|
|
{
|
|
DBTABLE const *pdt;
|
|
CERTDBRESULTCOLUMN *pCol;
|
|
|
|
pCol = &pelt->acol[iCol];
|
|
pCol->Index = acolOut[iCol];
|
|
|
|
hr = _MapPropIdIndex(pCol->Index, &pdt, &pCol->Type);
|
|
_JumpIfError(hr, error, "_MapPropIdIndex");
|
|
|
|
while (TRUE)
|
|
{
|
|
cbProp = cbAlloc;
|
|
hr = GetProperty(pcs, pdt, &cbProp, pbProp);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
break; // leave 0 size, NULL pointer
|
|
}
|
|
if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
|
|
{
|
|
_JumpIfError(hr, error, "GetProperty");
|
|
}
|
|
|
|
if (cbAlloc >= cbProp)
|
|
{
|
|
CSASSERT(S_OK == hr);
|
|
CSASSERT(0 != cbProp && NULL != pbProp);
|
|
break; // property value is in cbProp, pbProp
|
|
}
|
|
|
|
// Property value is too large for the buffer -- grow it
|
|
if (NULL == pbProp)
|
|
{
|
|
pbT = (BYTE *) LocalAlloc(LMEM_FIXED, cbProp);
|
|
}
|
|
else
|
|
{
|
|
pbT = (BYTE *) LocalReAlloc(pbProp, cbProp, LMEM_MOVEABLE);
|
|
}
|
|
if (NULL == pbT)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc/LocalReAlloc property");
|
|
}
|
|
pbProp = pbT;
|
|
cbAlloc = cbProp;
|
|
}
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
BYTE const *pb = pbProp;
|
|
DWORD cwc;
|
|
|
|
if (PROPTYPE_STRING == (PROPTYPE_MASK & pCol->Type))
|
|
{
|
|
CSASSERT( *((WCHAR*) &(pbProp[cbProp])) == L'\0');
|
|
cbProp += sizeof(WCHAR); // include NULL term
|
|
}
|
|
pCol->cbValue = cbProp;
|
|
pCol->pbValue = (BYTE *) CoTaskMemAlloc(cbProp);
|
|
if (NULL == pCol->pbValue)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "CoTaskMemAlloc");
|
|
}
|
|
CopyMemory(pCol->pbValue, pb, pCol->cbValue);
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_GetResultRow: fetch %ws.%ws: type=%x cb=%x\n",
|
|
wszTable(pdt->dwTable),
|
|
pdt->pwszPropName,
|
|
pCol->Type,
|
|
pCol->cbValue));
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pbProp)
|
|
{
|
|
LocalFree(pbProp);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::ReleaseResultRow(
|
|
IN ULONG celt,
|
|
IN OUT CERTDBRESULTROW *rgelt)
|
|
{
|
|
HRESULT hr;
|
|
DWORD iRow;
|
|
DWORD iCol;
|
|
CERTDBRESULTROW *pResultRow;
|
|
|
|
if (NULL == rgelt)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
for (iRow = 0; iRow < celt; iRow++)
|
|
{
|
|
pResultRow = &rgelt[iRow];
|
|
if (NULL != pResultRow->acol)
|
|
{
|
|
for (iCol = 0; iCol < pResultRow->ccol; iCol++)
|
|
{
|
|
if (NULL != pResultRow->acol[iCol].pbValue)
|
|
{
|
|
CoTaskMemFree(pResultRow->acol[iCol].pbValue);
|
|
pResultRow->acol[iCol].pbValue = NULL;
|
|
}
|
|
}
|
|
CoTaskMemFree(pResultRow->acol);
|
|
pResultRow->acol = NULL;
|
|
}
|
|
pResultRow->ccol = 0;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::EnumerateSetup(
|
|
IN CERTSESSION *pcs,
|
|
IN OUT DWORD *pFlags,
|
|
OUT JET_TABLEID *ptableid)
|
|
{
|
|
HRESULT hr;
|
|
JET_TABLEID tableid = 0;
|
|
DBAUXDATA const *pdbaux;
|
|
|
|
if (NULL == pcs || NULL == ptableid)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
|
|
switch (*pFlags)
|
|
{
|
|
case CIE_TABLE_ATTRIBUTES:
|
|
pdbaux = &g_dbauxAttributes;
|
|
break;
|
|
|
|
case CIE_TABLE_EXTENSIONS:
|
|
pdbaux = &g_dbauxExtensions;
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "*pFlags");
|
|
}
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetOpenTable(
|
|
pcs->SesId,
|
|
pcs->DBId,
|
|
pdbaux->pszTable,
|
|
NULL,
|
|
0,
|
|
0,
|
|
&tableid);
|
|
_JumpIfError(hr, error, "JetOpenTable");
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetSetCurrentIndex2(
|
|
pcs->SesId,
|
|
tableid,
|
|
pdbaux->pszRowIdIndex,
|
|
JET_bitMoveFirst);
|
|
_JumpIfError(hr, error, "JetSetCurrentIndex2");
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetMakeKey(
|
|
pcs->SesId,
|
|
tableid,
|
|
&pcs->RowId,
|
|
sizeof(pcs->RowId),
|
|
JET_bitNewKey);
|
|
_JumpIfError(hr, error, "JetMakeKey");
|
|
|
|
*pFlags |= CIE_RESET;
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
*ptableid = tableid;
|
|
tableid = 0;
|
|
|
|
error:
|
|
if (IsValidJetTableId(tableid))
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
_dbgJetCloseTable(pcs->SesId, tableid);
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_EnumerateMove(
|
|
IN CERTSESSION *pcs,
|
|
IN OUT DWORD *pFlags,
|
|
IN DBAUXDATA const *pdbaux,
|
|
IN JET_TABLEID tableid,
|
|
IN LONG cskip)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cb;
|
|
DWORD RowId;
|
|
LONG lSeek;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_EnumerateMove(cskip=%d, flags=%x%hs)\n",
|
|
cskip,
|
|
*pFlags,
|
|
(CIE_RESET & *pFlags)? " Reset" : ""));
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
if (CIE_RESET & *pFlags)
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetSeek(pcs->SesId, tableid, JET_bitSeekEQ);
|
|
if ((HRESULT) JET_errRecordNotFound == hr)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
_JumpIfError2(hr, error, "JetSeek", S_FALSE);
|
|
|
|
*pFlags &= ~CIE_RESET;
|
|
}
|
|
else
|
|
{
|
|
// Add one to the skip count for the implicit Next operation. Next
|
|
// always moves forward one, even when a negative skip count moves
|
|
// backward. The net result may be a forward or backward skip.
|
|
|
|
cskip++;
|
|
}
|
|
|
|
if (0 != cskip)
|
|
{
|
|
lSeek = JET_MoveNext * cskip;
|
|
CSASSERT(JET_MoveNext == -1 * JET_MovePrevious);
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetMove(pcs->SesId, tableid, lSeek, 0);
|
|
if ((HRESULT) JET_errNoCurrentRecord == hr)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
_JumpIfError2(hr, error, "JetMove", S_FALSE);
|
|
|
|
// Make sure this entry is for the same request:
|
|
|
|
cb = sizeof(RowId);
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdbaux->pdtRowId->dbcolumnid,
|
|
pdbaux->pdtRowId->dbcoltyp,
|
|
&cb,
|
|
(BYTE *) &RowId);
|
|
_JumpIfError(hr, error, "_RetrieveColumn");
|
|
|
|
if (RowId != pcs->RowId)
|
|
{
|
|
hr = S_FALSE;
|
|
goto error;
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::EnumerateNext(
|
|
IN CERTSESSION *pcs,
|
|
IN OUT DWORD *pFlags,
|
|
IN JET_TABLEID tableid,
|
|
IN LONG cskip,
|
|
IN ULONG celt,
|
|
OUT CERTDBNAME *rgelt,
|
|
OUT ULONG *pceltFetched)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cb;
|
|
DWORD cwc;
|
|
DWORD RowId;
|
|
CERTDBNAME *pelt;
|
|
WCHAR wszTmp[MAX_PATH];
|
|
DBAUXDATA const *pdbaux;
|
|
|
|
if (NULL == pcs || NULL == rgelt || NULL == pceltFetched)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
ZeroMemory(rgelt, celt * sizeof(rgelt[0]));
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
switch (CIE_TABLE_MASK & *pFlags)
|
|
{
|
|
case CIE_TABLE_ATTRIBUTES:
|
|
pdbaux = &g_dbauxAttributes;
|
|
break;
|
|
|
|
case CIE_TABLE_EXTENSIONS:
|
|
pdbaux = &g_dbauxExtensions;
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "*pFlags");
|
|
}
|
|
|
|
hr = S_OK;
|
|
for (pelt = rgelt; pelt < &rgelt[celt]; pelt++)
|
|
{
|
|
hr = _EnumerateMove(pcs, pFlags, pdbaux, tableid, cskip);
|
|
if (S_FALSE == hr)
|
|
{
|
|
break;
|
|
}
|
|
_JumpIfError(hr, error, "_EnumerateMove");
|
|
|
|
cskip = 0;
|
|
|
|
cb = sizeof(wszTmp);
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdbaux->pdtName->dbcolumnid,
|
|
pdbaux->pdtName->dbcoltyp,
|
|
&cb,
|
|
(BYTE *) wszTmp);
|
|
_JumpIfError(hr, error, "_RetrieveColumn");
|
|
|
|
CSASSERT(0 == (cb % sizeof(WCHAR))); // integer # of wchars
|
|
CSASSERT(L'\0' == wszTmp[cb/sizeof(WCHAR)]); // zero term
|
|
|
|
hr = _DupString(NULL, wszTmp, &pelt->pwszName);
|
|
_JumpIfError(hr, error, "_DupString");
|
|
}
|
|
|
|
*pceltFetched = SAFE_SUBTRACT_POINTERS(pelt, rgelt);
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
if (NULL != rgelt)
|
|
{
|
|
for (pelt = rgelt; pelt < &rgelt[celt]; pelt++)
|
|
{
|
|
if (NULL != pelt->pwszName)
|
|
{
|
|
CoTaskMemFree(pelt->pwszName);
|
|
pelt->pwszName = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::EnumerateClose(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL == pcs)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetCloseTable(pcs->SesId, tableid);
|
|
_JumpIfError(hr, error, "JetCloseTable");
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_BuildColumnIds(
|
|
IN CERTSESSION *pcs,
|
|
IN CHAR const *pszTableName,
|
|
IN DBTABLE *pdt)
|
|
{
|
|
HRESULT hr;
|
|
JET_TABLEID tableid;
|
|
JET_COLUMNDEF columndef;
|
|
BOOL fOpen = FALSE;
|
|
|
|
hr = _dbgJetOpenTable(
|
|
pcs->SesId,
|
|
pcs->DBId,
|
|
pszTableName,
|
|
NULL,
|
|
0,
|
|
0,
|
|
&tableid);
|
|
_JumpIfError(hr, error, "JetOpenTable");
|
|
fOpen = TRUE;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
for ( ; NULL != pdt->pwszPropName; pdt++)
|
|
{
|
|
hr = _dbgJetGetColumnInfo(
|
|
pcs->SesId,
|
|
pcs->DBId,
|
|
pszTableName,
|
|
pdt->pszFieldName,
|
|
&columndef,
|
|
sizeof(columndef),
|
|
JET_ColInfo);
|
|
if ((HRESULT) JET_errColumnNotFound == hr &&
|
|
(DBTF_SOFTFAIL & pdt->dwFlags))
|
|
{
|
|
pdt->dwFlags |= DBTF_MISSING;
|
|
pdt->dbcolumnid = -1;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"_BuildColumnIds: %hs.%hs Ignoring missing column\n",
|
|
pszTableName,
|
|
pdt->pszFieldName));
|
|
hr = S_OK;
|
|
continue;
|
|
}
|
|
_JumpIfError(hr, error, "JetGetColumnInfo");
|
|
|
|
pdt->dbcolumnid = columndef.columnid;
|
|
|
|
CSASSERT(
|
|
pdt->dbcoltyp == columndef.coltyp ||
|
|
(ISTEXTCOLTYP(pdt->dbcoltyp) && ISTEXTCOLTYP(columndef.coltyp)));
|
|
|
|
if (JET_coltypText == pdt->dbcoltyp)
|
|
{
|
|
CSASSERT(pdt->dwcbMax == pdt->dbcolumnMax);
|
|
CSASSERT(0 != pdt->dbcolumnMax);
|
|
CSASSERT(CB_DBMAXTEXT_MAXINTERNAL >= pdt->dbcolumnMax);
|
|
}
|
|
else if (JET_coltypLongText == pdt->dbcoltyp)
|
|
{
|
|
CSASSERT(pdt->dwcbMax == pdt->dbcolumnMax);
|
|
CSASSERT(CB_DBMAXTEXT_MAXINTERNAL < pdt->dbcolumnMax);
|
|
}
|
|
else if (JET_coltypLongBinary == pdt->dbcoltyp)
|
|
{
|
|
CSASSERT(pdt->dwcbMax == pdt->dbcolumnMax);
|
|
CSASSERT(0 != pdt->dbcolumnMax);
|
|
}
|
|
else if (JET_coltypDateTime == pdt->dbcoltyp)
|
|
{
|
|
CSASSERT(sizeof(DATE) == pdt->dwcbMax);
|
|
CSASSERT(0 == pdt->dbcolumnMax);
|
|
}
|
|
else if (JET_coltypLong == pdt->dbcoltyp)
|
|
{
|
|
CSASSERT(sizeof(LONG) == pdt->dwcbMax);
|
|
CSASSERT(0 == pdt->dbcolumnMax);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"_BuildColumnIds: %hs.%hs Unknown column type %u\n",
|
|
pszTableName,
|
|
pdt->pszFieldName,
|
|
pdt->dbcoltyp));
|
|
CSASSERT(!"Unknown column type");
|
|
}
|
|
if (pdt->dwcbMax != columndef.cbMax)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"_BuildColumnIds: %hs.%hs length %u, expected %u\n",
|
|
pszTableName,
|
|
pdt->pszFieldName,
|
|
columndef.cbMax,
|
|
pdt->dwcbMax));
|
|
|
|
// max size can only be increased...
|
|
|
|
if (pdt->dwcbMax > columndef.cbMax)
|
|
{
|
|
JET_DDLMAXCOLUMNSIZE jdmcs;
|
|
|
|
jdmcs.szTable = const_cast<char *>(pszTableName);
|
|
jdmcs.szColumn = const_cast<char *>(pdt->pszFieldName);
|
|
jdmcs.cbMax = pdt->dwcbMax;
|
|
|
|
hr = _dbgJetConvertDDL(
|
|
pcs->SesId,
|
|
pcs->DBId,
|
|
opDDLConvIncreaseMaxColumnSize,
|
|
&jdmcs,
|
|
sizeof(jdmcs));
|
|
_PrintIfError(hr, "JetConvertDDL");
|
|
if (S_OK == hr)
|
|
{
|
|
m_fDBRestart = TRUE;
|
|
}
|
|
}
|
|
}
|
|
pdt->dbcolumnidOld = -1;
|
|
if (chTEXTPREFIX == *pdt->pszFieldName ||
|
|
(DBTF_COLUMNRENAMED & pdt->dwFlags))
|
|
{
|
|
char const *pszFieldName = &pdt->pszFieldName[1];
|
|
|
|
if (DBTF_COLUMNRENAMED & pdt->dwFlags)
|
|
{
|
|
pszFieldName += strlen(pszFieldName) + 1;
|
|
}
|
|
CSASSERT(
|
|
chTEXTPREFIX != *pszTableName ||
|
|
ISTEXTCOLTYP(columndef.coltyp));
|
|
|
|
hr = _dbgJetGetColumnInfo(
|
|
pcs->SesId,
|
|
pcs->DBId,
|
|
pszTableName,
|
|
pszFieldName,
|
|
&columndef,
|
|
sizeof(columndef),
|
|
JET_ColInfo);
|
|
if (S_OK == hr)
|
|
{
|
|
CSASSERT(
|
|
chTEXTPREFIX != *pszTableName ||
|
|
ISTEXTCOLTYP(columndef.coltyp));
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"Found Old Column: %hs.%hs: %x\n",
|
|
pszTableName,
|
|
pszFieldName,
|
|
columndef.columnid));
|
|
|
|
pdt->dwFlags |= DBTF_OLDCOLUMNID;
|
|
pdt->dbcolumnidOld = columndef.columnid;
|
|
m_fFoundOldColumns = TRUE;
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (fOpen)
|
|
{
|
|
HRESULT hr2;
|
|
|
|
hr2 = _dbgJetCloseTable(pcs->SesId, tableid);
|
|
_PrintIfError(hr2, "JetCloseTable");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_AddKeyLengthColumn(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid,
|
|
IN DWORD RowId,
|
|
IN DBTABLE const *pdtPublicKey,
|
|
IN DBTABLE const *pdtPublicKeyAlgorithm,
|
|
IN DBTABLE const *pdtPublicKeyParameters,
|
|
IN DBTABLE const *pdtPublicKeyLength,
|
|
IN DBAUXDATA const *pdbaux,
|
|
IN OUT BYTE **ppbBuf,
|
|
IN OUT DWORD *pcbBuf)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cb;
|
|
DWORD KeyLength;
|
|
CERT_PUBLIC_KEY_INFO PublicKeyInfo;
|
|
|
|
ZeroMemory(&PublicKeyInfo, sizeof(PublicKeyInfo));
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"Converting %hs[%d].%hs\n",
|
|
pdbaux->pszTable,
|
|
RowId,
|
|
pdtPublicKeyLength->pszFieldName));
|
|
|
|
cb = sizeof(KeyLength);
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdtPublicKeyLength->dbcolumnid,
|
|
pdtPublicKeyLength->dbcoltyp,
|
|
&cb,
|
|
(BYTE *) &KeyLength);
|
|
if (S_OK == hr)
|
|
{
|
|
goto error; // already set -- skip this column
|
|
}
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
_JumpError(hr, error, "_RetrieveColumn");
|
|
}
|
|
|
|
// Fetch the public key algorithm ObjId & copy as ansi to alloc'd memory.
|
|
|
|
hr = _RetrieveColumnBuffer(
|
|
pcs,
|
|
tableid,
|
|
pdtPublicKeyAlgorithm->dbcolumnid,
|
|
pdtPublicKeyAlgorithm->dbcoltyp,
|
|
&cb,
|
|
ppbBuf,
|
|
pcbBuf);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_OK;
|
|
goto error; // No old data -- skip this column
|
|
}
|
|
_JumpIfErrorStr(
|
|
hr,
|
|
error,
|
|
"_RetrieveColumnBuffer",
|
|
pdtPublicKeyAlgorithm->pwszPropName);
|
|
|
|
if (!ConvertWszToSz(
|
|
&PublicKeyInfo.Algorithm.pszObjId,
|
|
(WCHAR const *) *ppbBuf,
|
|
-1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToSz(LogDir)");
|
|
}
|
|
|
|
// Fetch the public key algorithm paramaters, and copy to alloc'd memory.
|
|
|
|
hr = _RetrieveColumnBuffer(
|
|
pcs,
|
|
tableid,
|
|
pdtPublicKeyParameters->dbcolumnid,
|
|
pdtPublicKeyParameters->dbcoltyp,
|
|
&PublicKeyInfo.Algorithm.Parameters.cbData,
|
|
ppbBuf,
|
|
pcbBuf);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_OK;
|
|
goto error; // No old data -- skip this column
|
|
}
|
|
_JumpIfErrorStr(
|
|
hr,
|
|
error,
|
|
"_RetrieveColumnBuffer",
|
|
pdtPublicKeyParameters->pwszPropName);
|
|
|
|
PublicKeyInfo.Algorithm.Parameters.pbData = (BYTE *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
PublicKeyInfo.Algorithm.Parameters.cbData);
|
|
if (NULL == PublicKeyInfo.Algorithm.Parameters.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToSz(LogDir)");
|
|
}
|
|
CopyMemory(
|
|
PublicKeyInfo.Algorithm.Parameters.pbData,
|
|
*ppbBuf,
|
|
PublicKeyInfo.Algorithm.Parameters.cbData);
|
|
|
|
// Fetch the public key, and leave in dynamic buffer.
|
|
|
|
hr = _RetrieveColumnBuffer(
|
|
pcs,
|
|
tableid,
|
|
pdtPublicKey->dbcolumnid,
|
|
pdtPublicKey->dbcoltyp,
|
|
&PublicKeyInfo.PublicKey.cbData,
|
|
ppbBuf,
|
|
pcbBuf);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_OK;
|
|
goto error; // No old data -- skip this column
|
|
}
|
|
_JumpIfErrorStr(
|
|
hr,
|
|
error,
|
|
"_RetrieveColumnBuffer",
|
|
pdtPublicKey->pwszPropName);
|
|
|
|
PublicKeyInfo.PublicKey.pbData = *ppbBuf;
|
|
KeyLength = CertGetPublicKeyLength(X509_ASN_ENCODING, &PublicKeyInfo);
|
|
|
|
// Store the key length in the new column
|
|
|
|
hr = _SetColumn(
|
|
pcs->SesId,
|
|
tableid,
|
|
pdtPublicKeyLength->dbcolumnid,
|
|
sizeof(KeyLength),
|
|
(BYTE const *) &KeyLength);
|
|
_JumpIfErrorStr(hr, error, "_SetColumn", pdtPublicKeyLength->pwszPropName);
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"Converted %hs[%d].%hs: %u\n",
|
|
pdbaux->pszTable,
|
|
RowId,
|
|
pdtPublicKeyLength->pszFieldName,
|
|
KeyLength));
|
|
|
|
error:
|
|
if (NULL != PublicKeyInfo.Algorithm.pszObjId)
|
|
{
|
|
LocalFree(PublicKeyInfo.Algorithm.pszObjId);
|
|
}
|
|
if (NULL != PublicKeyInfo.Algorithm.Parameters.pbData)
|
|
{
|
|
LocalFree(PublicKeyInfo.Algorithm.Parameters.pbData);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_AddCallerName(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid,
|
|
IN DWORD RowId,
|
|
IN DBTABLE const *pdtCallerName,
|
|
IN DBTABLE const *pdtRequesterName,
|
|
IN DBAUXDATA const *pdbaux,
|
|
IN OUT BYTE **ppbBuf,
|
|
IN OUT DWORD *pcbBuf)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cb;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"Converting %hs[%d].%hs\n",
|
|
pdbaux->pszTable,
|
|
RowId,
|
|
pdtCallerName->pszFieldName));
|
|
|
|
cb = 0;
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdtCallerName->dbcolumnid,
|
|
pdtCallerName->dbcoltyp,
|
|
&cb,
|
|
NULL);
|
|
if (S_OK == hr)
|
|
{
|
|
goto error; // already set -- skip this column
|
|
}
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
_JumpError(hr, error, "_RetrieveColumn");
|
|
}
|
|
|
|
// Fetch the ReqesterName
|
|
|
|
hr = _RetrieveColumnBuffer(
|
|
pcs,
|
|
tableid,
|
|
pdtRequesterName->dbcolumnid,
|
|
pdtRequesterName->dbcoltyp,
|
|
&cb,
|
|
ppbBuf,
|
|
pcbBuf);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_OK;
|
|
goto error; // No old data -- skip this column
|
|
}
|
|
_JumpIfErrorStr(
|
|
hr,
|
|
error,
|
|
"_RetrieveColumnBuffer",
|
|
pdtRequesterName->pwszPropName);
|
|
|
|
// Store the RequesterName as the CallerName in the new column
|
|
|
|
hr = _SetColumn(
|
|
pcs->SesId,
|
|
tableid,
|
|
pdtCallerName->dbcolumnid,
|
|
cb,
|
|
*ppbBuf);
|
|
_JumpIfErrorStr(hr, error, "_SetColumn", pdtCallerName->pwszPropName);
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"Converted %hs[%d].%hs: %ws\n",
|
|
pdbaux->pszTable,
|
|
RowId,
|
|
pdtCallerName->pszFieldName,
|
|
*ppbBuf));
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_ConvertColumnData(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid,
|
|
IN DWORD RowId,
|
|
IN DBTABLE const *pdt,
|
|
IN DBAUXDATA const *pdbaux,
|
|
IN OUT BYTE **ppbBuf,
|
|
IN OUT DWORD *pcbBuf)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszNew = NULL;
|
|
BYTE const *pbNew;
|
|
DWORD cb;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"Converting %hs[%d].%hs:\n",
|
|
pdbaux->pszTable,
|
|
RowId,
|
|
pdt->pszFieldName));
|
|
|
|
// Fetch old column. Grows the buffer if necessary.
|
|
|
|
hr = _RetrieveColumnBuffer(
|
|
pcs,
|
|
tableid,
|
|
pdt->dbcolumnidOld,
|
|
pdt->dbcoltyp,
|
|
&cb,
|
|
ppbBuf,
|
|
pcbBuf);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = S_OK;
|
|
goto error; // No old data -- skip this column
|
|
}
|
|
_JumpIfErrorStr(hr, error, "_RetrieveColumnBuffer", pdt->pwszPropName);
|
|
|
|
if (DBTF_COLUMNRENAMED & pdt->dwFlags)
|
|
{
|
|
pbNew = *ppbBuf;
|
|
}
|
|
else
|
|
{
|
|
if (!ConvertSzToWsz(&pwszNew, (char *) *ppbBuf, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertSzToWsz");
|
|
}
|
|
pbNew = (BYTE const *) pwszNew;
|
|
cb = wcslen(pwszNew) * sizeof(WCHAR);
|
|
}
|
|
|
|
// Store the converted string in the Unicode column
|
|
|
|
hr = _SetColumn(pcs->SesId, tableid, pdt->dbcolumnid, cb, pbNew);
|
|
_JumpIfErrorStr(hr, error, "_SetColumn", pdt->pwszPropName);
|
|
|
|
if (JET_coltypLong != pdt->dbcoltyp)
|
|
{
|
|
// Clear out the old column
|
|
|
|
hr = _SetColumn(pcs->SesId, tableid, pdt->dbcolumnidOld, 0, NULL);
|
|
_JumpIfErrorStr(hr, error, "_SetColumn(Clear old)", pdt->pwszPropName);
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"Converted %hs[%d].%hs: %ws\n",
|
|
pdbaux->pszTable,
|
|
RowId,
|
|
pdt->pszFieldName,
|
|
ISTEXTCOLTYP(pdt->dbcoltyp)? (WCHAR const *) pbNew : L""));
|
|
if (!ISTEXTCOLTYP(pdt->dbcoltyp))
|
|
{
|
|
DBGDUMPHEX((DBG_SS_CERTDB, DH_NOADDRESS, pbNew, cb));
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszNew)
|
|
{
|
|
LocalFree(pwszNew);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
DBTABLE *
|
|
dbFindColumn(
|
|
IN DBTABLE *adt,
|
|
IN char const *pszFieldName)
|
|
{
|
|
DBTABLE *pdt;
|
|
DBTABLE *pdtRet = NULL;
|
|
|
|
for (pdt = adt; NULL != pdt->pwszPropName; pdt++)
|
|
{
|
|
if (0 == _stricmp(pszFieldName, pdt->pszFieldName))
|
|
{
|
|
pdtRet = pdt;
|
|
break;
|
|
}
|
|
}
|
|
return(pdtRet);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_ConvertOldColumnData(
|
|
IN CERTSESSION *pcs,
|
|
IN CHAR const *pszTableName,
|
|
IN DBAUXDATA const *pdbaux,
|
|
IN DBTABLE *adt)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
JET_TABLEID tableid;
|
|
JET_COLUMNDEF columndef;
|
|
BOOL fOpen = FALSE;
|
|
BOOL fTransacted = FALSE;
|
|
DBTABLE *pdt;
|
|
DWORD RowId;
|
|
DWORD cb;
|
|
BYTE *pbBuf = NULL;
|
|
DWORD cbBuf = 0;
|
|
BOOL fZeroIssuerNameId = FALSE;
|
|
DWORD IssuerNameId;
|
|
DBTABLE *pdtPublicKeyLength = NULL;
|
|
DBTABLE *pdtPublicKey;
|
|
DBTABLE *pdtPublicKeyAlgorithm;
|
|
DBTABLE *pdtPublicKeyParameters;
|
|
DBTABLE *pdtCallerName = NULL;
|
|
DBTABLE *pdtRequesterName;
|
|
|
|
hr = _dbgJetOpenTable(
|
|
pcs->SesId,
|
|
pcs->DBId,
|
|
pszTableName,
|
|
NULL,
|
|
0,
|
|
0,
|
|
&tableid);
|
|
_JumpIfError(hr, error, "JetOpenTable");
|
|
|
|
fOpen = TRUE;
|
|
|
|
// Step through the RowId index for this table.
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
hr = _dbgJetSetCurrentIndex2(
|
|
pcs->SesId,
|
|
tableid,
|
|
pdbaux->pszRowIdIndex,
|
|
JET_bitMoveFirst);
|
|
_JumpIfError(hr, error, "JetSetCurrentIndex2");
|
|
|
|
if (NULL != pdbaux->pdtIssuerNameId)
|
|
{
|
|
cb = sizeof(IssuerNameId);
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdbaux->pdtIssuerNameId->dbcolumnid,
|
|
pdbaux->pdtIssuerNameId->dbcoltyp,
|
|
&cb,
|
|
(BYTE *) &IssuerNameId);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
fZeroIssuerNameId = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// swallow error if empty database
|
|
|
|
_PrintIfErrorStr2(
|
|
hr,
|
|
"_RetrieveColumn",
|
|
pdbaux->pdtIssuerNameId->pwszPropName,
|
|
myJetHResult(JET_errNoCurrentRecord));
|
|
}
|
|
}
|
|
|
|
pdtPublicKeyLength = dbFindColumn(adt, szPUBLICKEYLENGTH);
|
|
if (NULL != pdtPublicKeyLength)
|
|
{
|
|
pdtPublicKey = dbFindColumn(adt, szPUBLICKEY);
|
|
pdtPublicKeyAlgorithm = dbFindColumn(adt, szPUBLICKEYALGORITHM);
|
|
pdtPublicKeyParameters = dbFindColumn(adt, szPUBLICKEYPARAMS);
|
|
if (NULL == pdtPublicKey ||
|
|
NULL == pdtPublicKeyAlgorithm ||
|
|
NULL == pdtPublicKeyParameters)
|
|
{
|
|
pdtPublicKeyLength = NULL;
|
|
}
|
|
else
|
|
{
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdtPublicKeyLength->dbcolumnid,
|
|
pdtPublicKeyLength->dbcoltyp,
|
|
&cb,
|
|
NULL);
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
pdtPublicKeyLength = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
pdtCallerName = dbFindColumn(adt, szCALLERNAME);
|
|
if (NULL != pdtCallerName)
|
|
{
|
|
pdtRequesterName = dbFindColumn(adt, szREQUESTERNAME);
|
|
if (NULL == pdtRequesterName)
|
|
{
|
|
pdtCallerName = NULL;
|
|
}
|
|
else
|
|
{
|
|
// Update all rows only if the first row's CallerName is empty
|
|
// and the first row's RequesterName is NOT empty.
|
|
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdtCallerName->dbcolumnid,
|
|
pdtCallerName->dbcoltyp,
|
|
&cb,
|
|
NULL);
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
pdtCallerName = NULL;
|
|
}
|
|
else
|
|
{
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdtRequesterName->dbcolumnid,
|
|
pdtRequesterName->dbcoltyp,
|
|
&cb,
|
|
NULL);
|
|
if (S_OK != hr)
|
|
{
|
|
pdtCallerName = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL != pdtPublicKeyLength ||
|
|
NULL != pdtCallerName ||
|
|
m_fFoundOldColumns ||
|
|
fZeroIssuerNameId)
|
|
{
|
|
DBGPRINT((DBG_SS_CERTDB, "Updating %hs table.\n", pdbaux->pszTable));
|
|
|
|
while (TRUE)
|
|
{
|
|
// Fetch RowId from the table.
|
|
|
|
cb = sizeof(pcs->RowId);
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdbaux->pdtRowId->dbcolumnid,
|
|
pdbaux->pdtRowId->dbcoltyp,
|
|
&cb,
|
|
(BYTE *) &RowId);
|
|
if (S_OK != hr)
|
|
{
|
|
if (myJetHResult(JET_errNoCurrentRecord) == hr)
|
|
{
|
|
hr = S_OK; // Table is empty
|
|
break;
|
|
}
|
|
_JumpError(hr, error, "_RetrieveColumn");
|
|
}
|
|
|
|
hr = _dbgJetBeginTransaction(pcs->SesId);
|
|
_JumpIfError(hr, error, "JetBeginTransaction");
|
|
|
|
fTransacted = TRUE;
|
|
|
|
// Transact each row.
|
|
//
|
|
// If fZeroIssuerNameId, set EMPTY IssuerNameId columns to zero.
|
|
//
|
|
// if the first row's public key length column was empty
|
|
// Read the public key column, compute the size and store it
|
|
//
|
|
// if the first row's CallerName was empty
|
|
// Copy RequesterName to CallerName
|
|
//
|
|
// if m_fFoundOldColumns
|
|
// For each text column, do the following:
|
|
// Retrieve old string from the old column,
|
|
// Convert to Unicode (if old column was Ansi),
|
|
// Write the Unicode string to the new column,
|
|
// Set the old column to NULL.
|
|
|
|
hr = _dbgJetPrepareUpdate(
|
|
pcs->SesId,
|
|
tableid,
|
|
JET_prepReplace);
|
|
_JumpIfError(hr, error, "JetPrepareUpdate");
|
|
|
|
if (fZeroIssuerNameId)
|
|
{
|
|
cb = sizeof(IssuerNameId);
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
pdbaux->pdtIssuerNameId->dbcolumnid,
|
|
pdbaux->pdtIssuerNameId->dbcoltyp,
|
|
&cb,
|
|
(BYTE *) &IssuerNameId);
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
_JumpIfError(hr, error, "_RetrieveColumn");
|
|
}
|
|
else
|
|
{
|
|
// Only set EMPTY columns!
|
|
|
|
IssuerNameId = 0;
|
|
|
|
hr = _SetColumn(
|
|
pcs->SesId,
|
|
tableid,
|
|
pdbaux->pdtIssuerNameId->dbcolumnid,
|
|
sizeof(IssuerNameId),
|
|
(BYTE const *) &IssuerNameId);
|
|
_JumpIfError(hr, error, "_SetColumn");
|
|
}
|
|
}
|
|
|
|
// Convert old columns first.
|
|
|
|
if (m_fFoundOldColumns)
|
|
{
|
|
for (pdt = adt; NULL != pdt->pwszPropName; pdt++)
|
|
{
|
|
if (DBTF_OLDCOLUMNID & pdt->dwFlags)
|
|
{
|
|
hr = _ConvertColumnData(
|
|
pcs,
|
|
tableid,
|
|
RowId,
|
|
pdt,
|
|
pdbaux,
|
|
&pbBuf,
|
|
&cbBuf);
|
|
_JumpIfErrorStr(
|
|
hr,
|
|
error,
|
|
"_ConvertColumnData",
|
|
pdt->pwszPropName);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now compute new columns.
|
|
|
|
if (NULL != pdtPublicKeyLength)
|
|
{
|
|
hr = _AddKeyLengthColumn(
|
|
pcs,
|
|
tableid,
|
|
RowId,
|
|
pdtPublicKey,
|
|
pdtPublicKeyAlgorithm,
|
|
pdtPublicKeyParameters,
|
|
pdtPublicKeyLength,
|
|
pdbaux,
|
|
&pbBuf,
|
|
&cbBuf);
|
|
_JumpIfError(hr, error, "_AddKeyLengthColumn");
|
|
}
|
|
if (NULL != pdtCallerName)
|
|
{
|
|
hr = _AddCallerName(
|
|
pcs,
|
|
tableid,
|
|
RowId,
|
|
pdtCallerName,
|
|
pdtRequesterName,
|
|
pdbaux,
|
|
&pbBuf,
|
|
&cbBuf);
|
|
_JumpIfError(hr, error, "_AddCallerName");
|
|
}
|
|
|
|
// Done with this row.
|
|
|
|
hr = _dbgJetUpdate(pcs->SesId, tableid, NULL, 0, NULL);
|
|
_JumpIfError(hr, error, "JetUpdate");
|
|
|
|
hr = _dbgJetCommitTransaction(pcs->SesId, 0);
|
|
_JumpIfError(hr, error, "JetCommitTransaction");
|
|
|
|
fTransacted = FALSE;
|
|
|
|
hr = _dbgJetMove(pcs->SesId, tableid, JET_MoveNext, 0);
|
|
if ((HRESULT) JET_errNoCurrentRecord == hr)
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_fFoundOldColumns)
|
|
{
|
|
hr = _dbgJetBeginTransaction(pcs->SesId);
|
|
_JumpIfError(hr, error, "JetBeginTransaction");
|
|
|
|
fTransacted = TRUE;
|
|
|
|
for (pdt = adt; NULL != pdt->pwszPropName; pdt++)
|
|
{
|
|
char const *pszFieldName;
|
|
|
|
if (0 == (DBTF_OLDCOLUMNID & pdt->dwFlags))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pszFieldName = &pdt->pszFieldName[1];
|
|
if (DBTF_COLUMNRENAMED & pdt->dwFlags)
|
|
{
|
|
pszFieldName += strlen(pszFieldName) + 1;
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"Deleting column %hs.%hs\n",
|
|
pdbaux->pszTable,
|
|
pszFieldName));
|
|
|
|
hr = _dbgJetDeleteColumn(pcs->SesId, tableid, pszFieldName);
|
|
_PrintIfError(hr, "JetDeleteColumn");
|
|
if (JET_errColumnInUse == hr)
|
|
{
|
|
hr = S_OK; // we'll delete the column next time we restart
|
|
}
|
|
_JumpIfError(hr, error, "JetDeleteColumn");
|
|
}
|
|
|
|
hr = _dbgJetCommitTransaction(pcs->SesId, 0);
|
|
_JumpIfError(hr, error, "JetCommitTransaction");
|
|
|
|
fTransacted = FALSE;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pbBuf)
|
|
{
|
|
LocalFree(pbBuf);
|
|
}
|
|
if (fTransacted)
|
|
{
|
|
hr2 = _Rollback(pcs);
|
|
_PrintIfError(hr2, "_Rollback");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
if (fOpen)
|
|
{
|
|
hr2 = _dbgJetCloseTable(pcs->SesId, tableid);
|
|
_PrintIfError(hr2, "JetCloseTable");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_SetColumn(
|
|
IN JET_SESID SesId,
|
|
IN JET_TABLEID tableid,
|
|
IN JET_COLUMNID columnid,
|
|
IN DWORD cbProp,
|
|
OPTIONAL IN BYTE const *pbProp)
|
|
{
|
|
HRESULT hr;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
hr = _dbgJetSetColumn(SesId, tableid, columnid, pbProp, cbProp, 0, NULL);
|
|
if ((HRESULT) JET_wrnColumnMaxTruncated == hr)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
}
|
|
_JumpIfError(hr, error, "JetSetColumn");
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::SetAttribute(
|
|
IN CERTSESSION *pcs,
|
|
IN WCHAR const *pwszAttributeName,
|
|
IN DWORD cbValue,
|
|
IN BYTE const *pbValue) // OPTIONAL
|
|
{
|
|
return(_SetIndirect(
|
|
pcs,
|
|
&pcs->aTable[CSTI_ATTRIBUTE],
|
|
pwszAttributeName,
|
|
NULL,
|
|
cbValue,
|
|
pbValue));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::GetAttribute(
|
|
IN CERTSESSION *pcs,
|
|
IN WCHAR const *pwszAttributeName,
|
|
IN OUT DWORD *pcbValue,
|
|
OUT BYTE *pbValue) // OPTIONAL
|
|
{
|
|
return(_GetIndirect(
|
|
pcs,
|
|
&pcs->aTable[CSTI_ATTRIBUTE],
|
|
pwszAttributeName,
|
|
NULL,
|
|
pcbValue,
|
|
pbValue));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::SetExtension(
|
|
IN CERTSESSION *pcs,
|
|
IN WCHAR const *pwszExtensionName,
|
|
IN DWORD dwExtFlags,
|
|
IN DWORD cbValue,
|
|
IN BYTE const *pbValue) // OPTIONAL
|
|
{
|
|
return(_SetIndirect(
|
|
pcs,
|
|
&pcs->aTable[CSTI_EXTENSION],
|
|
pwszExtensionName,
|
|
&dwExtFlags,
|
|
cbValue,
|
|
pbValue));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::GetExtension(
|
|
IN CERTSESSION *pcs,
|
|
IN WCHAR const *pwszExtensionName,
|
|
OUT DWORD *pdwExtFlags,
|
|
IN OUT DWORD *pcbValue,
|
|
OUT BYTE *pbValue) // OPTIONAL
|
|
{
|
|
return(_GetIndirect(
|
|
pcs,
|
|
&pcs->aTable[CSTI_EXTENSION],
|
|
pwszExtensionName,
|
|
pdwExtFlags,
|
|
pcbValue,
|
|
pbValue));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_JetSeekFromRestriction(
|
|
IN CERTVIEWRESTRICTION const *pcvr,
|
|
IN DWORD dwPosition,
|
|
OUT DBSEEKDATA *pSeekData)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fAscend;
|
|
DBSEEKDATA SeekFirst; // seek to first element matching restriction
|
|
DBSEEKDATA SeekLast; // seek to last element matching restriction
|
|
DBSEEKDATA SeekIndexFirst; // seek to first index element
|
|
DBSEEKDATA SeekIndexLast; // seek to last index element
|
|
DBSEEKDATA *pSeek;
|
|
BOOL fValid;
|
|
|
|
// SeekLast.SeekFlags: where to seek to retrieve end-of-range key
|
|
// SeekLast.grbitSeekRange: where to set the cursor initially: move or seek
|
|
// SeekLast.grbitRange: other flags to be ingested while setting range:
|
|
// (bitRange UpperLimit, Inclusive)
|
|
|
|
#if DBG_CERTSRV
|
|
DumpRestriction(DBG_SS_CERTDBI, 0, pcvr);
|
|
#endif
|
|
|
|
fAscend = (CVR_SORT_DESCEND != pcvr->SortOrder);
|
|
CSASSERT(
|
|
CVR_SORT_NONE == pcvr->SortOrder ||
|
|
CVR_SORT_ASCEND == pcvr->SortOrder ||
|
|
CVR_SORT_DESCEND == pcvr->SortOrder);
|
|
|
|
ZeroMemory(&SeekFirst, sizeof(SeekFirst));
|
|
ZeroMemory(&SeekLast, sizeof(SeekLast));
|
|
ZeroMemory(&SeekIndexFirst, sizeof(SeekIndexFirst));
|
|
ZeroMemory(&SeekIndexLast, sizeof(SeekIndexLast));
|
|
|
|
switch (CVR_SEEK_MASK & pcvr->SeekOperator)
|
|
{
|
|
case CVR_SEEK_EQ:
|
|
if (fAscend)
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKUSECURRENT |
|
|
CST_SEEKNOTMOVE |
|
|
CST_SEEKINDEXRANGE;
|
|
|
|
SeekFirst.grbitSeekRange = JET_bitSeekEQ;
|
|
SeekFirst.grbitInitial = JET_bitSeekEQ;
|
|
|
|
SeekFirst.grbitRange = JET_bitRangeUpperLimit |
|
|
JET_bitRangeInclusive;
|
|
|
|
SeekLast.SeekFlags = CST_SEEKINDEXRANGE;
|
|
SeekLast.grbitSeekRange = JET_bitSeekGT;
|
|
SeekLast.grbitInitial = JET_MovePrevious;
|
|
SeekLast.grbitRange = JET_bitRangeUpperLimit;
|
|
}
|
|
else
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKNOTMOVE | CST_SEEKINDEXRANGE;
|
|
SeekFirst.grbitSeekRange = JET_bitSeekEQ;
|
|
SeekFirst.grbitInitial = JET_bitSeekGT;
|
|
SeekFirst.grbitRange = JET_bitRangeInclusive;
|
|
|
|
SeekLast.SeekFlags = CST_SEEKINDEXRANGE;
|
|
SeekLast.grbitSeekRange = JET_bitSeekEQ;
|
|
SeekLast.grbitInitial = JET_MovePrevious;
|
|
SeekLast.grbitRange = JET_bitRangeInclusive;
|
|
}
|
|
break;
|
|
|
|
case CVR_SEEK_LT:
|
|
if (fAscend)
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
|
|
SeekFirst.grbitSeekRange = JET_bitSeekGE;
|
|
SeekFirst.grbitInitial = JET_MoveFirst;
|
|
SeekFirst.grbitRange = JET_bitRangeUpperLimit;
|
|
|
|
SeekLast.SeekFlags = CST_SEEKINDEXRANGE;
|
|
SeekLast.grbitSeekRange = JET_bitSeekGE;
|
|
SeekLast.grbitInitial = JET_MovePrevious;
|
|
SeekLast.grbitRange = JET_bitRangeUpperLimit;
|
|
}
|
|
else
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKNOTMOVE;
|
|
SeekFirst.grbitInitial = JET_bitSeekGE;
|
|
|
|
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
|
|
SeekLast.grbitInitial = JET_MoveFirst;
|
|
|
|
SeekIndexFirst.SeekFlags = CST_SEEKUSECURRENT;
|
|
SeekIndexFirst.grbitInitial = JET_MoveLast;
|
|
}
|
|
break;
|
|
|
|
case CVR_SEEK_LE:
|
|
if (fAscend)
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
|
|
SeekFirst.grbitSeekRange = JET_bitSeekGT;
|
|
SeekFirst.grbitInitial = JET_MoveFirst;
|
|
SeekFirst.grbitRange = JET_bitRangeUpperLimit;
|
|
|
|
SeekLast.SeekFlags = CST_SEEKINDEXRANGE; // !CST_SEEKUSECURRENT
|
|
SeekLast.grbitSeekRange = JET_bitSeekGT;
|
|
SeekLast.grbitInitial = JET_MovePrevious;
|
|
SeekLast.grbitRange = JET_bitRangeUpperLimit;
|
|
}
|
|
else
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKNOTMOVE;
|
|
SeekFirst.grbitInitial = JET_bitSeekGT;
|
|
|
|
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
|
|
SeekLast.grbitInitial = JET_MoveFirst;
|
|
|
|
SeekIndexFirst.SeekFlags = CST_SEEKUSECURRENT;
|
|
SeekIndexFirst.grbitInitial = JET_MoveLast;
|
|
}
|
|
break;
|
|
|
|
case CVR_SEEK_GE:
|
|
if (fAscend)
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKNOTMOVE;
|
|
SeekFirst.grbitInitial = JET_bitSeekGE;
|
|
|
|
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
|
|
SeekLast.grbitInitial = JET_MoveLast;
|
|
}
|
|
else
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
|
|
SeekFirst.grbitSeekRange = JET_bitSeekLT;
|
|
SeekFirst.grbitInitial = JET_MoveLast;
|
|
// Implied: SeekFirst.grbitRange = JET_bitRangeLowerLimit;
|
|
|
|
SeekLast.SeekFlags = CST_SEEKNOTMOVE;
|
|
SeekLast.grbitInitial = JET_bitSeekLT;
|
|
|
|
SeekIndexLast.SeekFlags = CST_SEEKUSECURRENT;
|
|
SeekIndexLast.grbitInitial = JET_MoveFirst;
|
|
}
|
|
break;
|
|
|
|
case CVR_SEEK_GT:
|
|
if (fAscend)
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKNOTMOVE;
|
|
SeekFirst.grbitInitial = JET_bitSeekGT;
|
|
|
|
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
|
|
SeekLast.grbitInitial = JET_MoveLast;
|
|
}
|
|
else
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKUSECURRENT | CST_SEEKINDEXRANGE;
|
|
SeekFirst.grbitSeekRange = JET_bitSeekLE;
|
|
SeekFirst.grbitInitial = JET_MoveLast;
|
|
// Implied: SeekFirst.grbitRange = JET_bitRangeLowerLimit;
|
|
|
|
SeekLast.SeekFlags = CST_SEEKNOTMOVE;
|
|
SeekLast.grbitInitial = JET_bitSeekLE;
|
|
|
|
SeekIndexLast.SeekFlags = CST_SEEKUSECURRENT;
|
|
SeekIndexLast.grbitInitial = JET_MoveFirst;
|
|
}
|
|
break;
|
|
|
|
case CVR_SEEK_NONE:
|
|
if (fAscend)
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKUSECURRENT;
|
|
SeekFirst.grbitInitial = JET_MoveFirst;
|
|
|
|
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
|
|
SeekLast.grbitInitial = JET_MoveLast;
|
|
}
|
|
else
|
|
{
|
|
SeekFirst.SeekFlags = CST_SEEKUSECURRENT;
|
|
SeekFirst.grbitInitial = JET_MoveLast;
|
|
|
|
//SeekLast.SeekFlags = 0; // not CST_SEEKUSECURRENT
|
|
SeekLast.grbitInitial = JET_MoveFirst;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CSASSERT(!"bad pcvr->SeekOperator"); // shouldn't get this far
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Seek value");
|
|
}
|
|
|
|
fValid = TRUE;
|
|
switch (dwPosition)
|
|
{
|
|
case SEEKPOS_FIRST:
|
|
pSeek = &SeekFirst;
|
|
break;
|
|
|
|
case SEEKPOS_LAST:
|
|
pSeek = &SeekLast;
|
|
break;
|
|
|
|
case SEEKPOS_INDEXFIRST:
|
|
pSeek = &SeekIndexFirst;
|
|
fValid = 0 != pSeek->SeekFlags;
|
|
break;
|
|
|
|
case SEEKPOS_INDEXLAST:
|
|
pSeek = &SeekIndexLast;
|
|
fValid = 0 != pSeek->SeekFlags;
|
|
break;
|
|
|
|
default:
|
|
CSASSERT(!"bad dwPosition"); // shouldn't get this far
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "dwPosition value");
|
|
}
|
|
if (!fValid)
|
|
{
|
|
// For this SeekOperator, if seeking to the first or last matching
|
|
// restriction failed, there's no point in seeking to the index end.
|
|
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
_JumpError2(hr, error, "pSeek->SeekFlags", hr);
|
|
}
|
|
*pSeekData = *pSeek; // structure copy
|
|
if (fAscend)
|
|
{
|
|
pSeekData->SeekFlags |= CST_SEEKASCEND;
|
|
}
|
|
|
|
hr = S_OK;
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_JetSeekFromRestriction: SeekFlags=%ws, grbitStart=%ws\n",
|
|
wszCSTFlags(pSeekData->SeekFlags),
|
|
(CST_SEEKNOTMOVE & pSeekData->SeekFlags)?
|
|
wszSeekgrbit(pSeekData->grbitInitial) :
|
|
wszMovecrow(pSeekData->grbitInitial)));
|
|
|
|
if (CST_SEEKINDEXRANGE & pSeekData->SeekFlags)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_JetSeekFromRestriction: grbitSeekRange=%ws, grbitRange=%ws\n",
|
|
wszSeekgrbit(pSeekData->grbitSeekRange),
|
|
wszSetIndexRangegrbit(pSeekData->grbitRange)));
|
|
}
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_OpenTable(
|
|
IN CERTSESSION *pcs,
|
|
IN DBAUXDATA const *pdbaux,
|
|
IN CERTVIEWRESTRICTION const *pcvr,
|
|
IN OUT CERTSESSIONTABLE *pTable)
|
|
{
|
|
HRESULT hr;
|
|
DBTABLE const *pdt;
|
|
BOOL fOpened = FALSE;
|
|
|
|
hr = _MapPropIdIndex(pcvr->ColumnIndex, &pdt, NULL);
|
|
_JumpIfError(hr, error, "_MapPropIdIndex");
|
|
|
|
if (NULL == pdt->pszIndexName)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Column not indexed");
|
|
}
|
|
|
|
if (!IsValidJetTableId(pTable->TableId))
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetOpenTable(
|
|
pcs->SesId,
|
|
pcs->DBId,
|
|
pdbaux->pszTable,
|
|
NULL,
|
|
0,
|
|
0,
|
|
&pTable->TableId);
|
|
_JumpIfError(hr, error, "JetOpenTable");
|
|
|
|
fOpened = TRUE;
|
|
|
|
// Find RowId and/or Named column.
|
|
// It's more efficient to pass NULL for primary index name.
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetSetCurrentIndex2(
|
|
pcs->SesId,
|
|
pTable->TableId,
|
|
(DBTF_INDEXPRIMARY & pdt->dwFlags)?
|
|
NULL : pdt->pszIndexName,
|
|
JET_bitMoveFirst);
|
|
_JumpIfError(hr, error, "JetSetCurrentIndex2");
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_OpenTable Table=%hs, Index=%hs\n",
|
|
pdbaux->pszTable,
|
|
pdt->pszIndexName));
|
|
|
|
}
|
|
hr = _SeekTable(
|
|
pcs,
|
|
pTable->TableId,
|
|
pcvr,
|
|
pdt,
|
|
SEEKPOS_FIRST,
|
|
&pTable->TableFlags
|
|
DBGPARM(pdbaux));
|
|
_JumpIfError2(hr, error, "_SeekTable", S_FALSE);
|
|
|
|
error:
|
|
if (S_OK != hr && S_FALSE != hr && fOpened)
|
|
{
|
|
if (IsValidJetTableId(pTable->TableId))
|
|
{
|
|
HRESULT hr2;
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr2 = _dbgJetCloseTable(pcs->SesId, pTable->TableId);
|
|
_PrintIfError(hr2, "JetCloseTable");
|
|
}
|
|
ZeroMemory(pTable, sizeof(*pTable));
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_SetIndirect(
|
|
IN CERTSESSION *pcs,
|
|
IN OUT CERTSESSIONTABLE *pTable,
|
|
IN WCHAR const *pwszNameValue,
|
|
OPTIONAL IN DWORD const *pdwExtFlags,
|
|
IN DWORD cbValue,
|
|
OPTIONAL IN BYTE const *pbValue)
|
|
{
|
|
HRESULT hr;
|
|
DBAUXDATA const *pdbaux;
|
|
BOOL fExisting = FALSE;
|
|
BOOL fDelete;
|
|
CERTVIEWRESTRICTION cvr;
|
|
|
|
if (NULL == pcs || NULL == pwszNameValue)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
|
|
fDelete = NULL == pbValue;
|
|
if (NULL == pdwExtFlags)
|
|
{
|
|
pdbaux = &g_dbauxAttributes;
|
|
cvr.ColumnIndex = DTI_ATTRIBUTETABLE | DTA_ATTRIBUTENAME;
|
|
}
|
|
else
|
|
{
|
|
if (0 != *pdwExtFlags)
|
|
{
|
|
fDelete = FALSE;
|
|
}
|
|
pdbaux = &g_dbauxExtensions;
|
|
cvr.ColumnIndex = DTI_EXTENSIONTABLE | DTE_EXTENSIONNAME;
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"IN: _SetIndirect(%hs.%ws) cb = %x%ws\n",
|
|
pdbaux->pszTable,
|
|
pwszNameValue,
|
|
cbValue,
|
|
fDelete? L" DELETE" : L""));
|
|
|
|
cvr.SeekOperator = CVR_SEEK_EQ;
|
|
cvr.SortOrder = CVR_SORT_NONE;
|
|
cvr.cbValue = wcslen(pwszNameValue) * sizeof(WCHAR);
|
|
cvr.pbValue = (BYTE *) pwszNameValue;
|
|
|
|
hr = _OpenTable(pcs, pdbaux, &cvr, pTable);
|
|
if (S_FALSE != hr)
|
|
{
|
|
_JumpIfError(hr, error, "_OpenTable");
|
|
|
|
fExisting = TRUE;
|
|
}
|
|
_PrintIfError2(hr, "_OpenTable", S_FALSE);
|
|
|
|
if (fDelete)
|
|
{
|
|
if (fExisting)
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetDelete(pcs->SesId, pTable->TableId);
|
|
_JumpIfError(hr, error, "JetDelete");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetPrepareUpdate(
|
|
pcs->SesId,
|
|
pTable->TableId,
|
|
!fExisting? JET_prepInsert : JET_prepReplace);
|
|
_JumpIfError(hr, error, "JetPrepareUpdate");
|
|
|
|
if (!fExisting)
|
|
{
|
|
// No existing row -- insert a new one:
|
|
|
|
// Set RowId
|
|
|
|
hr = _SetColumn(
|
|
pcs->SesId,
|
|
pTable->TableId,
|
|
pdbaux->pdtRowId->dbcolumnid,
|
|
sizeof(pcs->RowId),
|
|
(BYTE const *) &pcs->RowId);
|
|
_JumpIfError(hr, error, "_SetColumn");
|
|
|
|
|
|
// Set row's name column
|
|
|
|
hr = _SetColumn(
|
|
pcs->SesId,
|
|
pTable->TableId,
|
|
pdbaux->pdtName->dbcolumnid,
|
|
wcslen(pwszNameValue)*sizeof(WCHAR), //cch,
|
|
(BYTE const *) pwszNameValue /*szTmp*/);
|
|
_JumpIfError(hr, error, "_SetColumn");
|
|
|
|
}
|
|
|
|
if (NULL != pdwExtFlags)
|
|
{
|
|
// Set or update flags
|
|
|
|
hr = _SetColumn(
|
|
pcs->SesId,
|
|
pTable->TableId,
|
|
pdbaux->pdtFlags->dbcolumnid,
|
|
sizeof(*pdwExtFlags),
|
|
(BYTE const *) pdwExtFlags);
|
|
_JumpIfError(hr, error, "_SetColumn");
|
|
}
|
|
|
|
|
|
// Set or update value
|
|
|
|
hr = _SetColumn(
|
|
pcs->SesId,
|
|
pTable->TableId,
|
|
pdbaux->pdtValue->dbcolumnid,
|
|
cbValue,
|
|
pbValue);
|
|
_JumpIfError(hr, error, "_SetColumn");
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
hr = _dbgJetUpdate(pcs->SesId, pTable->TableId, NULL, 0, NULL);
|
|
_JumpIfError(hr, error, "JetUpdate");
|
|
}
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_GetIndirect(
|
|
IN CERTSESSION *pcs,
|
|
IN OUT CERTSESSIONTABLE *pTable,
|
|
IN WCHAR const *pwszNameValue,
|
|
OPTIONAL OUT DWORD *pdwExtFlags,
|
|
IN OUT DWORD *pcbValue,
|
|
OPTIONAL OUT BYTE *pbValue)
|
|
{
|
|
HRESULT hr;
|
|
DBAUXDATA const *pdbaux;
|
|
CERTSESSIONTABLE Table;
|
|
CERTVIEWRESTRICTION cvr;
|
|
|
|
if (NULL == pcs || NULL == pwszNameValue || NULL == pcbValue)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
if (NULL == pdwExtFlags)
|
|
{
|
|
pdbaux = &g_dbauxAttributes;
|
|
cvr.ColumnIndex = DTI_ATTRIBUTETABLE | DTA_ATTRIBUTENAME;
|
|
}
|
|
else
|
|
{
|
|
pdbaux = &g_dbauxExtensions;
|
|
cvr.ColumnIndex = DTI_EXTENSIONTABLE | DTE_EXTENSIONNAME;
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"IN: _GetIndirect(%hs.%ws) cb = %x\n",
|
|
pdbaux->pszTable,
|
|
pwszNameValue,
|
|
*pcbValue));
|
|
|
|
cvr.SeekOperator = CVR_SEEK_EQ;
|
|
cvr.SortOrder = CVR_SORT_NONE;
|
|
cvr.cbValue = wcslen(pwszNameValue) * sizeof(WCHAR);
|
|
cvr.pbValue = (BYTE *) pwszNameValue;
|
|
|
|
hr = _OpenTable(pcs, pdbaux, &cvr, pTable);
|
|
if (S_FALSE == hr)
|
|
{
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
}
|
|
_JumpIfError2(hr, error, "_OpenTable", CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
if (NULL != pdwExtFlags)
|
|
{
|
|
DWORD cb;
|
|
|
|
// Get flags column
|
|
|
|
cb = sizeof(*pdwExtFlags);
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
pTable->TableId,
|
|
pdbaux->pdtFlags->dbcolumnid,
|
|
pdbaux->pdtFlags->dbcoltyp,
|
|
&cb,
|
|
(BYTE *) pdwExtFlags);
|
|
_JumpIfError(hr, error, "_RetrieveColumn");
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_GetIndirect(%hs): Flags = %x\n",
|
|
pdbaux->pszTable,
|
|
*pdwExtFlags));
|
|
}
|
|
|
|
|
|
// Get value column
|
|
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
pTable->TableId,
|
|
pdbaux->pdtValue->dbcolumnid,
|
|
pdbaux->pdtValue->dbcoltyp,
|
|
pcbValue,
|
|
pbValue);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr && NULL != pdwExtFlags)
|
|
{
|
|
// return zero length property value and S_OK, so the caller can see
|
|
// the extension flags.
|
|
|
|
*pcbValue = 0;
|
|
hr = S_OK;
|
|
}
|
|
_JumpIfError(hr, error, "_RetrieveColumn");
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"OUT: _GetIndirect(%hs.%ws) cb = %x\n",
|
|
pdbaux->pszTable,
|
|
pwszNameValue,
|
|
*pcbValue));
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
#define CB_FETCHDELTA 256
|
|
|
|
// Fetch a column. Loop if we have to grow the buffer.
|
|
|
|
HRESULT
|
|
CCertDB::_RetrieveColumnBuffer(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid,
|
|
IN JET_COLUMNID columnid,
|
|
IN JET_COLTYP coltyp,
|
|
OUT DWORD *pcbProp,
|
|
IN OUT BYTE **ppbBuf,
|
|
IN OUT DWORD *pcbBuf)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbBuf = *ppbBuf;
|
|
DWORD cbBuf = *pcbBuf;
|
|
DWORD cb;
|
|
|
|
cb = cbBuf;
|
|
while (TRUE)
|
|
{
|
|
if (NULL == pbBuf)
|
|
{
|
|
// If cbBuf == 0, allocate CB_FETCHDELTA bytes.
|
|
// Otherwise, allocate column size *plus* CB_FETCHDELTA bytes.
|
|
// Ensures we make no more than two calls to _RetrieveColumn.
|
|
|
|
cb += CB_FETCHDELTA;
|
|
pbBuf = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pbBuf)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"Grow buffer: %x --> %x\n", cbBuf, cb));
|
|
cbBuf = cb;
|
|
}
|
|
cb = cbBuf;
|
|
hr = _RetrieveColumn(
|
|
pcs,
|
|
tableid,
|
|
columnid,
|
|
coltyp,
|
|
&cb,
|
|
pbBuf);
|
|
if (S_OK == hr)
|
|
{
|
|
*pcbProp = cb;
|
|
break; // data fit in the buffer
|
|
}
|
|
if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
|
|
{
|
|
_JumpError2(hr, error, "_RetrieveColumn", CERTSRV_E_PROPERTY_EMPTY);
|
|
}
|
|
|
|
// Data won't fit. Grow the buffer.
|
|
|
|
CSASSERT(NULL != pbBuf);
|
|
LocalFree(pbBuf);
|
|
pbBuf = NULL;
|
|
}
|
|
CSASSERT(S_OK == hr);
|
|
|
|
error:
|
|
*ppbBuf = pbBuf;
|
|
*pcbBuf = cbBuf;
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_RetrieveColumn(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid,
|
|
IN JET_COLUMNID columnid,
|
|
IN JET_COLTYP coltyp,
|
|
IN OUT DWORD *pcbProp,
|
|
OPTIONAL OUT BYTE *pbProp)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cbActual;
|
|
DWORD cbTotal;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
hr = _dbgJetRetrieveColumn(
|
|
pcs->SesId,
|
|
tableid,
|
|
columnid,
|
|
NULL,
|
|
0,
|
|
&cbActual,
|
|
JET_bitRetrieveCopy,
|
|
NULL);
|
|
if ((HRESULT) JET_wrnColumnNull == hr)
|
|
{
|
|
// Routine GetProperty call:
|
|
// _JumpIfError(hr, error, "JetRetrieveColumn: Property EMPTY");
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
goto error;
|
|
}
|
|
if ((HRESULT) JET_wrnBufferTruncated != hr)
|
|
{
|
|
_JumpIfError2(hr, error, "JetRetrieveColumn", JET_errNoCurrentRecord);
|
|
}
|
|
|
|
if (cbActual == 0)
|
|
{
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
_JumpError(hr, error, "JetRetrieveColumn: cbActual=0: Property EMPTY");
|
|
}
|
|
|
|
cbTotal = cbActual;
|
|
|
|
if (ISTEXTCOLTYP(coltyp))
|
|
{
|
|
DBGPRINT((DBG_SS_CERTDBI, "Size of text %d\n", cbActual));
|
|
cbTotal += sizeof(WCHAR);
|
|
}
|
|
if (NULL == pbProp || cbTotal > *pcbProp)
|
|
{
|
|
*pcbProp = cbTotal;
|
|
hr = S_OK;
|
|
if (NULL != pbProp)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
//_PrintError(hr, "output buffer too small");
|
|
}
|
|
goto error;
|
|
}
|
|
|
|
hr = _dbgJetRetrieveColumn(
|
|
pcs->SesId,
|
|
tableid,
|
|
columnid,
|
|
pbProp,
|
|
cbActual,
|
|
&cbActual,
|
|
JET_bitRetrieveCopy,
|
|
NULL);
|
|
_JumpIfError(hr, error, "JetRetrieveColumn");
|
|
|
|
*pcbProp = cbActual;
|
|
|
|
if (ISTEXTCOLTYP(coltyp))
|
|
{
|
|
*(WCHAR *) &pbProp[cbActual] = L'\0';
|
|
}
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_CreateIndex(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid,
|
|
IN CHAR const *pszIndexName,
|
|
IN CHAR const *pchKey,
|
|
IN DWORD cbKey,
|
|
IN DWORD flags)
|
|
{
|
|
HRESULT hr;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
hr = _dbgJetCreateIndex(
|
|
pcs->SesId,
|
|
tableid,
|
|
pszIndexName,
|
|
flags,
|
|
pchKey,
|
|
cbKey,
|
|
0); // lDensity %, for splits (use default of 80%)
|
|
_JumpIfError3(
|
|
hr,
|
|
error,
|
|
"JetCreateIndex",
|
|
(HRESULT) JET_errIndexDuplicate,
|
|
(HRESULT) JET_errIndexHasPrimary);
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"CreateIndex: %x:%hs idx=%hs len=%x flags=%x\n",
|
|
tableid,
|
|
pszIndexName,
|
|
pchKey,
|
|
cbKey,
|
|
flags));
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_AddColumn(
|
|
IN CERTSESSION *pcs,
|
|
IN JET_TABLEID tableid,
|
|
IN DBTABLE const *pdt)
|
|
{
|
|
HRESULT hr;
|
|
JET_COLUMNDEF columndef;
|
|
JET_COLUMNID columnid;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
ZeroMemory(&columndef, sizeof(columndef));
|
|
columndef.cbStruct = sizeof(columndef);
|
|
columndef.cp = 1200; // unicode (1200) instead of Ascii (1252)
|
|
columndef.langid = 0x409;
|
|
columndef.wCountry = 1;
|
|
columndef.coltyp = pdt->dbcoltyp;
|
|
columndef.cbMax = pdt->dbcolumnMax;
|
|
columndef.grbit = pdt->dbgrbit;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"AddColumn: %x:%hs coltyp=%x cbMax=%x grbit=%x\n",
|
|
tableid,
|
|
pdt->pszFieldName,
|
|
pdt->dbcoltyp,
|
|
pdt->dbcolumnMax,
|
|
pdt->dbgrbit));
|
|
|
|
hr = _dbgJetAddColumn(
|
|
pcs->SesId,
|
|
tableid,
|
|
pdt->pszFieldName,
|
|
&columndef,
|
|
NULL,
|
|
0,
|
|
&columnid);
|
|
CSASSERT(JET_wrnColumnMaxTruncated != hr);
|
|
_JumpIfErrorStr3(
|
|
hr,
|
|
error,
|
|
"JetAddColumn",
|
|
pdt->pwszPropName,
|
|
(HRESULT) JET_errColumnDuplicate,
|
|
(HRESULT) JET_errColumnRedundant);
|
|
|
|
error:
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_CreateTable(
|
|
IN DWORD CreateFlags, // CF_*
|
|
IN CERTSESSION *pcs,
|
|
IN DBCREATETABLE const *pct)
|
|
{
|
|
HRESULT hr;
|
|
JET_TABLEID tableid;
|
|
BOOL fTableOpen;
|
|
DWORD dwLength;
|
|
CHAR achCol[MAX_PATH];
|
|
DBTABLE const *pdt;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_CreateTable(%x, %hs)\n",
|
|
CreateFlags,
|
|
pct->pszTableName));
|
|
|
|
fTableOpen = FALSE;
|
|
if (CF_MISSINGTABLES & CreateFlags)
|
|
{
|
|
hr = _dbgJetCreateTable(
|
|
pcs->SesId,
|
|
pcs->DBId,
|
|
pct->pszTableName,
|
|
4,
|
|
0,
|
|
&tableid);
|
|
if ((HRESULT) JET_errTableDuplicate != hr)
|
|
{
|
|
_JumpIfError(hr, error, "JetCreateTable");
|
|
|
|
if (!(CF_DATABASE & CreateFlags))
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"Created Missing Table: %hs:%x\n",
|
|
pct->pszTableName,
|
|
tableid));
|
|
}
|
|
hr = _dbgJetCloseTable(pcs->SesId, tableid);
|
|
_JumpIfError(hr, error, "JetCloseTable");
|
|
}
|
|
}
|
|
|
|
hr = _dbgJetOpenTable(
|
|
pcs->SesId,
|
|
pcs->DBId,
|
|
pct->pszTableName,
|
|
NULL, // pvParameters
|
|
0, // cbParameters
|
|
JET_bitTableDenyRead, // grbit
|
|
&tableid);
|
|
_JumpIfError(hr, error, "JetOpenTable");
|
|
fTableOpen = TRUE;
|
|
|
|
CSASSERT(IsValidJetTableId(tableid));
|
|
DBGPRINT((DBG_SS_CERTDBI, "OpenTable: %hs: %x\n", pct->pszTableName, tableid));
|
|
|
|
if (NULL != pct->pdt)
|
|
{
|
|
HRESULT hrDuplicate;
|
|
HRESULT hrRedundant;
|
|
HRESULT hrHasPrimary;
|
|
|
|
if ((CF_DATABASE | CF_MISSINGTABLES | CF_MISSINGCOLUMNS) & CreateFlags)
|
|
{
|
|
hrDuplicate = myJetHResult(JET_errColumnDuplicate);
|
|
hrRedundant = myJetHResult(JET_errColumnRedundant);
|
|
|
|
for (pdt = pct->pdt; NULL != pdt->pwszPropName; pdt++)
|
|
{
|
|
hr = _AddColumn(pcs, tableid, pdt);
|
|
if (hrDuplicate == hr || hrRedundant == hr)
|
|
{
|
|
_PrintError2(hr, "_AddColumn", hr);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
if (S_OK == hr && !(CF_DATABASE & CreateFlags))
|
|
{
|
|
m_fAddedNewColumns = TRUE;
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"Added Missing Column: %hs.%hs\n",
|
|
pct->pszTableName,
|
|
pdt->pszFieldName));
|
|
}
|
|
_JumpIfErrorStr(hr, error, "_AddColumn", pdt->pwszPropName);
|
|
}
|
|
}
|
|
if ((CF_DATABASE | CF_MISSINGTABLES | CF_MISSINGCOLUMNS | CF_MISSINGINDEXES) & CreateFlags)
|
|
{
|
|
hrDuplicate = myJetHResult(JET_errIndexDuplicate);
|
|
hrHasPrimary = myJetHResult(JET_errIndexHasPrimary);
|
|
|
|
for (pdt = pct->pdt; NULL != pdt->pwszPropName; pdt++)
|
|
{
|
|
if (NULL != pdt->pszIndexName)
|
|
{
|
|
DWORD dwCreateIndexFlags = 0;
|
|
char *psz = achCol;
|
|
|
|
if (DBTF_INDEXPRIMARY & pdt->dwFlags)
|
|
{
|
|
dwCreateIndexFlags |= JET_bitIndexPrimary;
|
|
}
|
|
if (DBTF_INDEXUNIQUE & pdt->dwFlags)
|
|
{
|
|
dwCreateIndexFlags |= JET_bitIndexUnique;
|
|
}
|
|
if (DBTF_INDEXIGNORENULL & pdt->dwFlags)
|
|
{
|
|
dwCreateIndexFlags |= JET_bitIndexIgnoreNull;
|
|
}
|
|
|
|
if (DBTF_INDEXREQUESTID & pdt->dwFlags)
|
|
{
|
|
psz += sprintf(psz, "+%hs", szREQUESTID) + 1;
|
|
}
|
|
psz += sprintf(psz, "+%hs", pdt->pszFieldName) + 1;
|
|
*psz++ = '\0'; // double terminate
|
|
|
|
|
|
if (ISTEXTCOLTYP(pdt->dbcoltyp))
|
|
{
|
|
// if text field, include 2-byte langid
|
|
*(WORD UNALIGNED *) psz = (WORD) 0x409;
|
|
psz += sizeof(WORD);
|
|
*psz++ = '\0'; // double terminate
|
|
*psz++ = '\0'; // double terminate
|
|
}
|
|
|
|
hr = _CreateIndex(
|
|
pcs,
|
|
tableid,
|
|
pdt->pszIndexName,
|
|
achCol,
|
|
SAFE_SUBTRACT_POINTERS(psz, achCol),
|
|
dwCreateIndexFlags);
|
|
if (hrDuplicate == hr ||
|
|
(hrHasPrimary == hr &&
|
|
(DBTF_INDEXPRIMARY & pdt->dwFlags)))
|
|
{
|
|
_PrintError2(hr, "_CreateIndex", hr);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
if (S_OK == hr && !(CF_DATABASE & CreateFlags))
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"Added Missing Index: %hs.%hs\n",
|
|
pct->pszTableName,
|
|
pdt->pszIndexName));
|
|
if (chTEXTPREFIX == *pdt->pszIndexName ||
|
|
(DBTF_INDEXRENAMED & pdt->dwFlags))
|
|
{
|
|
char const *pszIndexName = &pdt->pszIndexName[1];
|
|
|
|
CSASSERTTHREAD(pcs);
|
|
if (DBTF_INDEXRENAMED & pdt->dwFlags)
|
|
{
|
|
pszIndexName += strlen(pszIndexName) + 1;
|
|
}
|
|
hr = _dbgJetDeleteIndex(
|
|
pcs->SesId,
|
|
tableid,
|
|
pszIndexName);
|
|
_PrintIfError2(hr, "JetDeleteIndex", hr);
|
|
if (S_OK == hr)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTDB,
|
|
"Deleted index %hs.%hs\n",
|
|
pct->pszTableName,
|
|
pszIndexName));
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
_JumpIfError(hr, error, "_CreateIndex");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (fTableOpen)
|
|
{
|
|
HRESULT hr2;
|
|
|
|
hr2 = _dbgJetCloseTable(pcs->SesId, tableid);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
_JumpIfError(hr, error, "JetCloseTable");
|
|
}
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_Create(
|
|
IN DWORD CreateFlags, // CF_*
|
|
IN CHAR const *pszDataBaseName)
|
|
{
|
|
HRESULT hr;
|
|
DBCREATETABLE const *pct;
|
|
CERTSESSION *pcs = NULL;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTDBI,
|
|
"_Create(%x, %hs)\n",
|
|
CreateFlags,
|
|
pszDataBaseName));
|
|
|
|
hr = _AllocateSession(&pcs);
|
|
_JumpIfError(hr, error, "_AllocateSession");
|
|
|
|
if (CF_DATABASE & CreateFlags)
|
|
{
|
|
hr = _dbgJetCreateDatabase(
|
|
pcs->SesId,
|
|
pszDataBaseName,
|
|
NULL,
|
|
&pcs->DBId,
|
|
0);
|
|
_JumpIfError(hr, error, "JetCreateDatabase");
|
|
|
|
hr = _dbgJetCloseDatabase(pcs->SesId, pcs->DBId, 0);
|
|
_JumpIfError(hr, error, "JetCloseDatabase");
|
|
}
|
|
|
|
hr = _dbgJetOpenDatabase(
|
|
pcs->SesId,
|
|
pszDataBaseName,
|
|
NULL,
|
|
&pcs->DBId,
|
|
JET_bitDbExclusive);
|
|
_JumpIfError(hr, error, "JetOpenDatabase");
|
|
|
|
hr = _dbgJetBeginTransaction(pcs->SesId);
|
|
_JumpIfError(hr, error, "JetBeginTransaction");
|
|
|
|
for (pct = g_actDataBase; NULL != pct->pszTableName; pct++)
|
|
{
|
|
hr = _CreateTable(CreateFlags, pcs, pct);
|
|
_JumpIfError(hr, error, "_CreateTable");
|
|
}
|
|
|
|
hr = _dbgJetCommitTransaction(pcs->SesId, 0);
|
|
_JumpIfError(hr, error, "JetCommitTransaction");
|
|
|
|
hr = _dbgJetCloseDatabase(pcs->SesId, pcs->DBId, 0);
|
|
_JumpIfError(hr, error, "JetCloseDatabase");
|
|
|
|
error:
|
|
if (NULL != pcs)
|
|
{
|
|
ReleaseSession(pcs);
|
|
}
|
|
return(myJetHResult(hr));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCertDB::_DupString(
|
|
OPTIONAL IN WCHAR const *pwszPrefix,
|
|
IN WCHAR const *pwszIn,
|
|
OUT WCHAR **ppwszOut)
|
|
{
|
|
DWORD cbPrefix;
|
|
DWORD cb;
|
|
HRESULT hr;
|
|
|
|
cbPrefix = 0;
|
|
if (NULL != pwszPrefix)
|
|
{
|
|
cbPrefix = wcslen(pwszPrefix) * sizeof(WCHAR);
|
|
}
|
|
cb = (wcslen(pwszIn) + 1) * sizeof(WCHAR);
|
|
*ppwszOut = (WCHAR *) CoTaskMemAlloc(cbPrefix + cb);
|
|
if (NULL == *ppwszOut)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "CoTaskMemAlloc");
|
|
}
|
|
if (NULL != pwszPrefix)
|
|
{
|
|
CopyMemory(*ppwszOut, pwszPrefix, cbPrefix);
|
|
}
|
|
CopyMemory((BYTE *) *ppwszOut + cbPrefix, pwszIn, cb);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|