2025-04-27 07:49:33 -04:00

1498 lines
33 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: dbcnvt.cpp
//
// Contents: Cert Server Database conversion
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <esent.h> // JET errors
#include <certdb.h>
#include <conio.h>
#include "certdb2.h"
#include "csprop2.h"
#include "db2.h"
#include "dbcore.h"
#include "odbc.h"
#undef DBG_CERTSRV_DEBUG_PRINT
BOOL
cuDBIsShutDownInProgress();
BOOL
cuDBAbortShutDown(
IN DWORD dwCtrlType);
HRESULT
cuDBOpen(
IN WCHAR const *pwszAuthority,
IN BOOL fReadOnly,
OUT ICertDB **ppdb);
HRESULT
cuDBPrintProperty(
OPTIONAL IN ICertDBRow *prow,
IN DWORD Type,
IN WCHAR const *pwszColName,
IN WCHAR const *pwszDisplayName,
OPTIONAL IN BYTE const *pbValue,
IN DWORD cbValue,
OUT DWORD *pcbValue);
extern CRITICAL_SECTION g_DBEnumCriticalSection;
extern BOOL g_fDBEnumCSInit;
extern LIST_ENTRY g_DBEnumHandleList;
DWORD g_crowConvert;
DWORD g_crowSkipDuplicate;
DWORD g_crowSkipWrongCA;
HRESULT
PrintProperty(
IN DWORD RequestId,
IN WCHAR const *pwszTable,
IN WCHAR const *pwszPropName,
IN DWORD dwPropType,
IN BYTE const *pbProp,
IN DWORD cbProp)
{
HRESULT hr = S_OK;
if (g_fVerbose)
{
WCHAR wszName[MAX_PATH];
BOOL fVerbose = g_fVerbose--;
DWORD cb;
wsprintf(wszName, L"%ws.%ws", pwszTable, pwszPropName);
hr = cuDBPrintProperty(
NULL,
dwPropType,
pwszPropName,
wszName,
pbProp,
cbProp,
&cb);
g_fVerbose = fVerbose;
_JumpIfError(hr, error, "cuDBPrintProperty");
}
error:
return(hr);
}
HRESULT
TranslateToPropType(
SWORD wCType,
DWORD *pdwPropType)
{
HRESULT hr = S_OK;
// translate from SQL proptype to our type
// Later, match these with the import table
switch (wCType)
{
case SQL_C_ULONG:
*pdwPropType = PROPTYPE_LONG;
break;
case SQL_C_BINARY:
*pdwPropType = PROPTYPE_BINARY;
break;
case SQL_C_CHAR:
*pdwPropType = PROPTYPE_STRING;
break;
case SQL_C_TIMESTAMP:
*pdwPropType = PROPTYPE_DATE;
break;
default:
hr = E_UNEXPECTED;
_JumpError(hr, error, "Illegal property type");
}
error:
return(hr);
}
HRESULT
GrowBuffer(
IN DWORD cbProp,
IN OUT DWORD *pcbbuf,
IN OUT BYTE **ppbbuf)
{
HRESULT hr;
if (*pcbbuf < cbProp)
{
BYTE *pbNewAlloc = NULL;
// alloc time!
if (NULL != *ppbbuf)
{
pbNewAlloc = (BYTE *) LocalReAlloc(*ppbbuf, cbProp, LMEM_MOVEABLE);
}
else
{
pbNewAlloc = (BYTE *) LocalAlloc(LMEM_FIXED, cbProp);
}
if (NULL == pbNewAlloc)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Local[Re]Alloc");
}
*ppbbuf = pbNewAlloc;
*pcbbuf = cbProp;
}
hr = S_OK;
error:
return(hr);
}
HRESULT
GetDBPropertyAndReAlloc(
IN ICertDBRow *prow,
IN WCHAR const *pwszPropName,
IN DWORD PropType,
OUT DWORD *pcbProp,
IN OUT DWORD *pcbbuf,
OUT BYTE **ppbbuf)
{
HRESULT hr;
EnterCriticalSection(&g_DBCriticalSection);
if (cuDBIsShutDownInProgress())
{
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
_JumpError(hr, error, "cuDBIsShutDownInProgress");
}
// if we have a pre-allocated buffer, use it
*pcbProp = *pcbbuf; // try our current buffer
hr = prow->GetProperty(pwszPropName, PropType, pcbProp, *ppbbuf);
if (S_OK != hr)
{
if (HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW) != hr)
{
*pcbProp = 0;
_JumpError2(
hr,
error,
"prow->GetProperty",
CERTSRV_E_PROPERTY_EMPTY);
}
// else HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW, go through realloc
}
else if (NULL != *ppbbuf)
{
// done if we passed non-null and got back S_OK
goto error;
}
hr = GrowBuffer(*pcbProp, pcbbuf, ppbbuf);
_JumpIfError(hr, error, "GrowBuffer");
hr = prow->GetProperty(pwszPropName, PropType, pcbProp, *ppbbuf);
if (S_OK != hr)
{
*pcbProp = 0;
_JumpError(hr, error, "prow->GetProperty");
}
error:
LeaveCriticalSection(&g_DBCriticalSection);
return(hr);
}
HRESULT
RedDBGetPropertyWAndReAlloc(
IN DWORD ReqId,
IN WCHAR const *pwszPropName,
IN DWORD dwFlags,
OUT DWORD *pcbProp,
IN OUT DWORD *pcbbuf,
OUT BYTE **ppbbuf)
{
HRESULT hr;
// if we have a pre-allocated buffer, use it
*pcbProp = *pcbbuf; // try our current buffer
hr = RedDBGetPropertyW(ReqId, pwszPropName, dwFlags, pcbProp, *ppbbuf);
if (S_OK != hr)
{
if (ERROR_MORE_DATA != hr)
{
*pcbProp = 0;
_JumpIfError3(
hr,
error,
"RedDBGetPropertyW",
ERROR_NO_MORE_ITEMS,
CERTSRV_E_PROPERTY_EMPTY);
}
// else ERROR_MORE_DATA: buffer not big enough, go through realloc
}
else if (NULL != *ppbbuf)
{
// done if we passed non-null and got back S_OK
goto error;
}
hr = GrowBuffer(*pcbProp, pcbbuf, ppbbuf);
_JumpIfError(hr, error, "GrowBuffer");
hr = RedDBGetPropertyW(ReqId, pwszPropName, dwFlags, pcbProp, *ppbbuf);
if (S_OK != hr)
{
*pcbProp = 0;
_JumpError(hr, error, "RedDBGetPropertyW");
}
error:
return(hr);
}
#define ANCIENT_CR_DISP_INCOMPLETE 0x00000000 // request did not complete
#define ANCIENT_CR_DISP_ERROR 0x00000001 // request failed
#define ANCIENT_CR_DISP_DENIED 0x00000002 // request denied
#define ANCIENT_CR_DISP_ISSUED 0x00000003 // cert issued
#define ANCIENT_CR_DISP_ISSUED_OUT_OF_BAND 0x00000004 // cert issued separately
#define ANCIENT_CR_DISP_UNDER_SUBMISSION 0x00000005 // taken under submission
#define ANCIENT_CR_DISP_REVOKED 0x00000006 // revoked
HRESULT
FixupRequestDispositionProperty(
IN OUT DWORD *pdwDisposition,
IN DWORD cbDisposition)
{
HRESULT hr = S_OK;
DWORD dwOldDisposition = *pdwDisposition;
DWORD dwNewDisposition;
CSASSERT(sizeof(DWORD) == cbDisposition);
if (sizeof(DWORD) != cbDisposition)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "cbDisposition");
}
switch (dwOldDisposition)
{
case ANCIENT_CR_DISP_ERROR:
case ANCIENT_CR_DISP_INCOMPLETE:
dwNewDisposition = DB_DISP_ERROR;
break;
case ANCIENT_CR_DISP_DENIED:
dwNewDisposition = DB_DISP_DENIED;
break;
case ANCIENT_CR_DISP_ISSUED:
case ANCIENT_CR_DISP_ISSUED_OUT_OF_BAND:
dwNewDisposition = DB_DISP_ISSUED;
break;
case ANCIENT_CR_DISP_UNDER_SUBMISSION:
dwNewDisposition = DB_DISP_PENDING;
break;
case ANCIENT_CR_DISP_REVOKED:
dwNewDisposition = DB_DISP_REVOKED;
break;
default:
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "dwOldDisposition");
break;
}
// make assignment since all went well
*pdwDisposition = dwNewDisposition;
error:
return(hr);
}
typedef struct _DBTABLE_ENTRY
{
LPCWSTR pwszTable;
DBTABLE_RED const *rgTable;
DWORD dwTableType;
} DBTABLE_ENTRY;
DBTABLE_ENTRY dbTables[] =
{
{ L"Request", db_adtRequests, PROPTABLE_REQUEST },
{ L"Certificate", db_adtCertificates, PROPTABLE_CERTIFICATE },
};
HRESULT
SetDBProperty(
IN DWORD RequestId,
IN ICertDBRow *prow,
IN WCHAR const *pwszPropName,
IN DWORD PropType,
IN DWORD cbProp,
IN BYTE const *pbProp)
{
HRESULT hr;
EnterCriticalSection(&g_DBCriticalSection);
if (cuDBIsShutDownInProgress())
{
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
_JumpError(hr, error, "cuDBIsShutDownInProgress");
}
hr = prow->SetProperty(pwszPropName, PropType, cbProp, pbProp);
_JumpIfError(hr, error, "prow->SetProperty");
error:
LeaveCriticalSection(&g_DBCriticalSection);
return(hr);
}
#define RR_READONLY 0
#define RR_COMMIT 1
#define RR_ABORT 2
HRESULT
ReleaseDBRow(
IN OUT ICertDBRow *prow,
IN DWORD State)
{
HRESULT hr = S_OK;
if (NULL != prow)
{
EnterCriticalSection(&g_DBCriticalSection);
if (!cuDBIsShutDownInProgress())
{
if (RR_READONLY != State)
{
hr = prow->CommitTransaction(RR_COMMIT == State);
_PrintIfError(hr, "CommitTransaction");
}
prow->Release();
}
LeaveCriticalSection(&g_DBCriticalSection);
}
return(hr);
}
// convert one certificate or request table column
HRESULT
ConvertDBColumnName(
IN DWORD RequestId,
IN ICertDB *pdb,
IN ICertDBRow *prow,
IN DBTABLE_ENTRY const *pdbte,
IN DBTABLE_RED const *pdbcol,
IN OUT DWORD *pcbbuf,
IN OUT BYTE **ppbbuf)
{
HRESULT hr;
DWORD dwPropType;
BYTE const *pbProp;
DWORD cbProp;
hr = TranslateToPropType(pdbcol->wCType, &dwPropType);
_JumpIfError(hr, error, "TranslateToPropType");
// _NOT_ IssuerNameID
WCHAR wszFullPropName[MAX_PATH];
wcscpy(wszFullPropName, g_wszPropSubjectDot);
wcscat(wszFullPropName, pdbcol->pwszPropName);
// table: "Requests" or "Certificates" ?
hr = RedDBGetPropertyWAndReAlloc(
RequestId,
wszFullPropName,
dwPropType | pdbte->dwTableType,
&cbProp,
pcbbuf,
ppbbuf);
if (hr != S_OK)
{
if (CERTSRV_E_PROPERTY_EMPTY == hr || ERROR_NO_MORE_ITEMS == hr)
{
goto error;
}
_JumpIfError(hr, error, "RedDBGetPropertyWAndReAlloc");
}
pbProp = *ppbbuf;
hr = PrintProperty(
RequestId,
L"\tNames",
wszFullPropName,
dwPropType,
pbProp,
cbProp);
_JumpIfError(hr, error, "PrintProperty");
// Separate names table has been removed in new db. Now, names live within
// each table (Certificates, Requests)
hr = SetDBProperty(
RequestId,
prow,
pdbcol->pwszPropName,
dwPropType | pdbte->dwTableType,
cbProp,
pbProp);
_JumpIfError(hr, error, "SetDBProperty");
error:
return(hr);
}
// convert one certificate or request table column
HRESULT
ConvertDBColumn(
IN DWORD RequestId,
IN ICertDB *pdb,
IN ICertDBRow *prow,
IN DBTABLE_ENTRY const *pdbte,
IN DBTABLE_RED const *pdbcol,
IN OUT BOOL *pfRevoked,
IN OUT BOOL *pfReasonUnspecified,
IN OUT DWORD *pcbbuf,
IN OUT BYTE **ppbbuf)
{
HRESULT hr;
DWORD i;
DWORD dwPropType;
BYTE const *pbProp;
DWORD cbProp;
WCHAR wszFullTableCol[MAX_PATH];
BOOL fSetProperty = TRUE;
hr = TranslateToPropType(pdbcol->wCType, &dwPropType);
_JumpIfError(hr, error, "TranslateToPropType");
hr = RedDBGetPropertyWAndReAlloc(
RequestId,
pdbcol->pwszPropName,
dwPropType | pdbte->dwTableType,
&cbProp,
pcbbuf,
ppbbuf);
if (hr != S_OK)
{
if (CERTSRV_E_PROPERTY_EMPTY == hr || ERROR_NO_MORE_ITEMS == hr)
{
goto error;
}
_JumpError(hr, error, "RedDBGetPropertyWAndReAlloc");
}
pbProp = *ppbbuf;
// special case: do lookup into names table
CSASSERT(0 == lstrcmpi(g_wszPropRequestSubjectNameID, g_wszPropCertificateSubjectNameID));
if (0 == lstrcmpi(g_wszPropRequestSubjectNameID, pdbcol->pwszPropName))
{
DWORD NameId = *(DWORD *) pbProp;
DBTABLE_RED const *pdbcolT;
if (g_fVerbose)
{
wprintf(wszNewLine);
wprintf(myLoadResourceString(IDS_RED_BEGIN_NAMES), RequestId, NameId);
wprintf(wszNewLine);
}
for (pdbcolT = db_adtNames; NULL != pdbcolT->pwszPropName; pdbcolT++)
{
hr = ConvertDBColumnName(
RequestId,
pdb,
prow,
pdbte,
pdbcolT,
pcbbuf,
ppbbuf);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
continue; // skip empty name columns
}
if (ERROR_NO_MORE_ITEMS == hr)
{
break; // done
}
_JumpIfError(hr, error, "ConvertDBColumnName");
}
if (g_fVerbose)
{
wprintf(myLoadResourceString(IDS_RED_END_NAMES), RequestId, NameId);
wprintf(wszNewLine);
wprintf(wszNewLine);
}
}
else
{
hr = PrintProperty(
RequestId,
pdbte->pwszTable,
pdbcol->pwszPropName,
dwPropType,
pbProp,
cbProp);
_JumpIfError(hr, error, "PrintProperty");
if (0 == lstrcmpi(
pdbcol->pwszPropName,
g_wszPropRequestDisposition))
{
hr = FixupRequestDispositionProperty(
(DWORD *) pbProp,
cbProp);
_JumpIfError(hr, error, "FixupRequestDispositionProperty");
}
else if (0 == lstrcmpi(
pdbcol->pwszPropName,
g_wszPropRequestRevokedWhen))
{
if (NULL != pbProp && 0 != cbProp)
{
*pfRevoked = TRUE;
}
}
else if (0 == lstrcmpi(
pdbcol->pwszPropName,
g_wszPropRequestRevokedReason))
{
if (NULL != pbProp && sizeof(DWORD) == cbProp)
{
if (CRL_REASON_UNSPECIFIED == *(DWORD *) pbProp)
{
*pfReasonUnspecified = TRUE;
fSetProperty = FALSE;
}
}
}
// don't try and save AutoIncremented (first) field: RequestID
if (fSetProperty &&
(pdbcol != pdbte->rgTable ||
0 != lstrcmpi(pdbcol->pwszPropName, g_wszPropRequestRequestID)))
{
hr = SetDBProperty(
RequestId,
prow,
pdbcol->pwszPropName,
dwPropType | pdbte->dwTableType,
cbProp,
pbProp);
_JumpIfError(hr, error, "SetDBProperty");
}
}
hr = S_OK;
error:
return(hr);
}
// walk through columns in certificate or request table and convert them
HRESULT
ConvertDBTable(
IN DWORD RequestId,
IN ICertDB *pdb,
IN ICertDBRow *prow,
IN DBTABLE_ENTRY const *pdbte,
IN OUT DWORD *pcbbuf,
IN OUT BYTE **ppbbuf)
{
HRESULT hr;
DBTABLE_RED const *pdbcol;
BOOL fRevoked = FALSE;
BOOL fReasonUnspecified = FALSE;
for (pdbcol = pdbte->rgTable; NULL != pdbcol->pwszPropName; pdbcol++)
{
hr = ConvertDBColumn(
RequestId,
pdb,
prow,
pdbte,
pdbcol,
&fRevoked,
&fReasonUnspecified,
pcbbuf,
ppbbuf);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
continue; // skip empty name columns
}
_JumpIfError2(hr, error, "ConvertDBColumn", ERROR_NO_MORE_ITEMS);
}
// CertSrv1.0 had a funny way of revoking: it set the RevokedWhen
// field, but didn't update the Request Disposition field.
// Thus, after we walk through all columns, if we detected a RevokedWhen
// field, we go back and slam the g_wszPropRequestDisposition field with
// DB_DISP_REVOKED.
if (fRevoked)
{
DWORD dwRevoked = DB_DISP_REVOKED;
hr = SetDBProperty(
RequestId,
prow,
g_wszPropRequestDisposition,
PROPTYPE_LONG | pdbte->dwTableType,
sizeof(dwRevoked),
(PBYTE)&dwRevoked);
_JumpIfError(hr, error, "SetDBProperty DB_DISP_REVOKED");
if (fReasonUnspecified)
{
DWORD dwReason = CRL_REASON_UNSPECIFIED;
hr = SetDBProperty(
RequestId,
prow,
g_wszPropRequestRevokedReason,
PROPTYPE_LONG | pdbte->dwTableType,
sizeof(dwReason),
(BYTE *) &dwReason);
_JumpIfError(hr, error, "SetDBProperty CRL_REASON_UNSPECIFIED");
}
}
hr = S_OK;
error:
return(hr);
}
// convert extensions for this request
HRESULT
ConvertDBExtensions(
IN DWORD RequestId,
IN ICertDB *pdb,
IN ICertDBRow *prow,
IN OUT DWORD *pcbbuf,
IN OUT BYTE **ppbbuf)
{
HRESULT hr;
HANDLE hEnum = NULL;
WCHAR wszPropName[MAX_PATH + 1];
DWORD cwcPropName;
DWORD dwPropType;
DWORD dwExtFlags;
BYTE const *pbProp;
DWORD cbProp;
hr = RedDBEnumerateSetup(RequestId, FALSE, &hEnum);
_JumpIfError(hr, error, "RedDBEnumerateSetup");
while (TRUE)
{
cwcPropName = ARRAYSIZE(wszPropName) - 1;
hr = RedDBEnumerate(hEnum, &cwcPropName, wszPropName);
if (S_OK != hr)
{
break;
}
wszPropName[cwcPropName] = L'\0'; // terminate name
hr = TranslateToPropType(db_dtExtensionFlags.wCType, &dwPropType);
_JumpIfError(hr, error, "TranslateToPropType");
hr = RedDBGetPropertyWAndReAlloc(
RequestId,
wszPropName,
dwPropType |
PROPTABLE_EXTENSION |
PROPTABLE_EXTENSIONFLAGS,
&cbProp,
pcbbuf,
ppbbuf);
if (hr == CERTSRV_E_PROPERTY_EMPTY)
{
// ext flags entry does not exist: not fatal
cbProp = 0;
hr = S_OK;
}
_JumpIfError(hr, error, "RedDBGetPropertyWAndReAlloc");
pbProp = *ppbbuf;
CSASSERT(0 == cbProp || sizeof(DWORD) == cbProp);
dwExtFlags = 0; // default to 0
if (cbProp == sizeof(DWORD))
{
dwExtFlags = *(DWORD *) pbProp;
}
// extension flags
hr = PrintProperty(
RequestId,
L"Extension <Flags>",
wszPropName,
dwPropType,
(BYTE *) &dwExtFlags,
cbProp);
_JumpIfError(hr, error, "PrintProperty");
hr = TranslateToPropType(db_dtExtensionValue.wCType, &dwPropType);
_JumpIfError(hr, error, "TranslateToPropType");
hr = RedDBGetPropertyWAndReAlloc(
RequestId,
wszPropName,
dwPropType |
PROPTABLE_EXTENSION |
PROPTABLE_EXTENSIONVALUE,
&cbProp,
pcbbuf,
ppbbuf);
if (hr == CERTSRV_E_PROPERTY_EMPTY)
{
// ext value entry does not exist: not fatal
cbProp = 0;
hr = S_OK;
}
_JumpIfError(hr, error, "RedDBGetPropertyWAndReAlloc");
pbProp = *ppbbuf;
// extension value
hr = PrintProperty(
RequestId,
L"Extension <Value>",
wszPropName,
dwPropType,
pbProp,
cbProp);
_JumpIfError(hr, error, "PrintProperty");
hr = prow->SetExtension(wszPropName, dwExtFlags, cbProp, pbProp);
_JumpIfError(hr, error, "SetExtension");
}
hr = S_OK;
error:
if (NULL != hEnum)
{
hr = RedDBEnumerateClose(hEnum);
_JumpIfError(hr, error, "RedDBEnumerateClose");
}
return(hr);
}
// convert request attributes for this request
HRESULT
ConvertDBAttributes(
IN DWORD RequestId,
IN ICertDB *pdb,
IN ICertDBRow *prow,
IN OUT DWORD *pcbbuf,
IN OUT BYTE **ppbbuf)
{
HRESULT hr;
HANDLE hEnum = NULL;
WCHAR wszPropName[MAX_PATH + 1];
DWORD cwcPropName;
DWORD dwPropType;
BYTE const *pbProp;
DWORD cbProp;
hr = RedDBEnumerateSetup(RequestId, TRUE, &hEnum);
_JumpIfError(hr, error, "RedDBEnumerateSetup");
while (TRUE)
{
cwcPropName = ARRAYSIZE(wszPropName) - 1;
hr = RedDBEnumerate(hEnum, &cwcPropName, wszPropName);
if (S_OK != hr)
{
break;
}
wszPropName[cwcPropName] = L'\0'; // terminate name
hr = TranslateToPropType(db_attrib.wCType, &dwPropType);
_JumpIfError(hr, error, "TranslateToPropType");
hr = RedDBGetPropertyWAndReAlloc(
RequestId,
wszPropName,
dwPropType | PROPTABLE_ATTRIBUTE,
&cbProp,
pcbbuf,
ppbbuf);
if (hr == CERTSRV_E_PROPERTY_EMPTY)
{
// attr entry does not exist: not fatal
cbProp = 0;
hr = S_OK;
}
_JumpIfError(hr, error, "RedDBGetPropertyWAndReAlloc");
pbProp = *ppbbuf;
// get attribute
hr = PrintProperty(
RequestId,
L"Attribute",
wszPropName,
dwPropType,
pbProp,
cbProp);
_JumpIfError(hr, error, "PrintProperty");
hr = SetDBProperty(
RequestId,
prow,
wszPropName,
dwPropType | PROPTABLE_ATTRIBUTE,
cbProp,
pbProp);
_JumpIfError(hr, error, "SetDBProperty");
}
hr = S_OK;
error:
if (NULL != hEnum)
{
hr = RedDBEnumerateClose(hEnum);
_JumpIfError(hr, error, "RedDBEnumerateClose");
}
return(hr);
}
HRESULT
VerifyRedDBCertificate(
DWORD RequestId,
IN CERT_INFO const *pCACertInfo,
IN OUT DWORD *pcbbuf,
IN OUT BYTE **ppbbuf)
{
HRESULT hr;
DWORD cbCert;
DWORD dw;
hr = RedDBGetPropertyWAndReAlloc(
RequestId,
g_wszPropRawCertificate,
PROPTYPE_BINARY | PROPTABLE_CERTIFICATE,
&cbCert,
pcbbuf,
ppbbuf);
_JumpIfError(hr, error, "RedDBGetPropertyWAndReAlloc");
if (!CryptVerifyCertificateSignature(
NULL,
X509_ASN_ENCODING,
*ppbbuf,
cbCert,
const_cast<CERT_PUBLIC_KEY_INFO *>(
&pCACertInfo->SubjectPublicKeyInfo)))
{
hr = myHLastError();
_JumpError(hr, error, "CryptVerifyCertificateSignature");
}
error:
if (1 < g_fForce)
{
hr = S_OK;
}
return(hr);
}
// walk through columns in certificate request tables and convert them.
// walk through related extensions and attributes and convert them.
HRESULT
ConvertDB(
IN ICertDB *pdb,
IN CERT_INFO const *pCACertInfo,
IN OUT DWORD *pcbbuf,
IN OUT BYTE **ppbbuf)
{
HRESULT hr;
DWORD RequestId;
DWORD RequestIdNew;
ICertDBRow *prow = NULL;
DWORD i;
DWORD cbProp;
WCHAR wszSerial[15];
WCHAR *pwszSerial = NULL;
DWORD dwStart;
DWORD dwEnd;
WCHAR wszRowId[MAX_PATH];
for (RequestId = 1; ; RequestId++)
{
// If the RequestId doesn't exist in the old database, we're done!
hr = RedDBGetPropertyWAndReAlloc(
RequestId,
g_wszPropRequestRequestID,
PROPTYPE_LONG | PROPTABLE_REQUEST,
&cbProp,
pcbbuf,
ppbbuf);
if (ERROR_NO_MORE_ITEMS == hr)
{
break;
}
_JumpIfError(hr, error, "RedDBGetPropertyWAndReAlloc");
CSASSERT(sizeof(DWORD) == cbProp);
CSASSERT(*(DWORD const *) *ppbbuf == RequestId);
if (g_fVerbose)
{
wprintf(wszNewLine);
}
wsprintf(wszRowId, myLoadResourceString(IDS_RED_ROWID), RequestId);
_cprintf("\r%ws\r", wszRowId);
if (g_fVerbose)
{
wprintf(L"----------------------------------------------------------------\n");
}
if (NULL != pwszSerial && wszSerial != pwszSerial)
{
LocalFree(pwszSerial);
pwszSerial = NULL;
}
// Fetch old SerialNumber. Generate one for failed requests.
hr = RedDBGetPropertyWAndReAlloc(
RequestId,
g_wszPropCertificateSerialNumber,
PROPTYPE_STRING | PROPTABLE_CERTIFICATE,
&cbProp,
pcbbuf,
ppbbuf);
if (S_OK != hr)
{
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
_JumpError(hr, error, "RedDBGetPropertyWAndReAlloc");
}
wsprintf(wszSerial, L"ConvertMDB%04x", RequestId);
CSASSERT(wcslen(wszSerial) < ARRAYSIZE(wszSerial));
pwszSerial = wszSerial;
}
else
{
hr = myDupString((WCHAR const *) *ppbbuf, &pwszSerial);
_JumpIfError(hr, error, "myDupString");
}
// If old SerialNumber already exists in new database, skip this row
hr = pdb->OpenRow(TRUE, 0, pwszSerial, &prow);
if (S_OK == hr)
{
ReleaseDBRow(prow, RR_READONLY);
prow = NULL;
wprintf(myLoadResourceString(IDS_RED_SKIP_DUP), RequestId, pwszSerial);
wprintf(wszNewLine);
g_crowSkipDuplicate++;
continue;
}
hr = VerifyRedDBCertificate(RequestId, pCACertInfo, pcbbuf, ppbbuf);
if (S_OK != hr && CERTSRV_E_PROPERTY_EMPTY != hr)
{
wprintf(myLoadResourceString(IDS_RED_SKIP_BADCA), RequestId, pwszSerial);
g_crowSkipWrongCA++;
continue;
}
// RequestId 0, pwszSerialNumber NULL --> create new row
hr = pdb->OpenRow(FALSE, 0, NULL, &prow);
_JumpIfError(hr, error, "OpenRow");
prow->GetRowId(&RequestIdNew);
if (g_fVerbose)
{
wprintf(
myLoadResourceString(IDS_RED_ROW_MAP),
RequestId,
RequestIdNew);
wprintf(wszNewLine);
}
// Set SerialNumber in new database only if we generated one.
if (wszSerial == pwszSerial)
{
hr = SetDBProperty(
RequestId,
prow,
g_wszPropCertificateSerialNumber,
PROPTYPE_STRING |
PROPCALLER_ADMIN |
PROPTABLE_CERTIFICATE,
wcslen(pwszSerial) * sizeof(WCHAR),
(BYTE *) pwszSerial);
_JumpIfError(hr, error, "SetDBProperty");
}
// convert columns in certificate & request tables
for (i = 0; i < ARRAYSIZE(dbTables); i++)
{
hr = ConvertDBTable(
RequestId,
pdb,
prow,
&dbTables[i],
pcbbuf,
ppbbuf);
_JumpIfError(hr, error, "ConvertDBTable");
}
hr = ConvertDBExtensions(RequestId, pdb, prow, pcbbuf, ppbbuf);
_JumpIfError(hr, error, "ConvertDBExtensions");
hr = ConvertDBAttributes(RequestId, pdb, prow, pcbbuf, ppbbuf);
_JumpIfError(hr, error, "ConvertDBAttributes");
hr = ReleaseDBRow(prow, RR_COMMIT);
prow = NULL;
if (myJetHResult(JET_errKeyDuplicate) == hr)
{
CSASSERT(!"Discarding duplicate entry");
wprintf(myLoadResourceString(IDS_RED_SKIP_DUP), RequestId, pwszSerial);
wprintf(wszNewLine);
continue;
}
_JumpIfError(hr, error, "ReleaseDBRow");
g_crowConvert++;
}
_cprintf("\n");
hr = S_OK;
error:
if (NULL != pwszSerial && wszSerial != pwszSerial)
{
LocalFree(pwszSerial);
}
ReleaseDBRow(prow, RR_ABORT);
return(hr);
}
HRESULT
LoadCACertFromDB(
IN ICertDB *pdb,
OUT BYTE **ppbCACert,
OUT DWORD *pcbCACert,
OUT CERT_INFO **ppCACertInfo,
IN OUT DWORD *pcbbuf,
IN OUT BYTE **ppbbuf)
{
HRESULT hr;
ICertDBRow *prow = NULL;
DWORD cbCertInfo;
*ppbCACert = NULL;
*ppCACertInfo = NULL;
hr = pdb->OpenRow(
TRUE, // fReadOnly
1, // ReqId
NULL, // pwszSerialNumber
&prow);
_JumpIfError(hr, error, "OpenRow");
hr = GetDBPropertyAndReAlloc(
prow,
g_wszPropRawCertificate,
PROPTYPE_BINARY |
PROPCALLER_ADMIN |
PROPTABLE_CERTIFICATE,
pcbCACert,
pcbbuf,
ppbbuf);
_JumpIfError(hr, error, "GetDBPropertyAndReAlloc");
*ppbCACert = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbCACert);
if (NULL == *ppbCACert)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
CopyMemory(*ppbCACert, *ppbbuf, *pcbCACert);
// Decode certificate
cbCertInfo = 0;
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_CERT_TO_BE_SIGNED,
*ppbCACert,
*pcbCACert,
CERTLIB_USE_LOCALALLOC,
(VOID **) ppCACertInfo,
&cbCertInfo))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeObject");
}
error:
ReleaseDBRow(prow, RR_READONLY);
return(hr);
}
HRESULT
RedDBInit(
OUT WCHAR **ppwszAuthority)
{
HRESULT hr;
WCHAR *pwszServer = NULL;
WCHAR *pwszAuthority = NULL;
__try
{
InitializeCriticalSection(&g_DBEnumCriticalSection);
g_fDBEnumCSInit = TRUE;
hr = S_OK;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
}
_JumpIfError(hr, error, "InitializeCriticalSection");
InitializeListHead(&g_DBEnumHandleList);
hr = mySplitConfigString(g_pwszConfig, &pwszServer, &pwszAuthority);
_JumpIfError(hr, error, "mySplitConfigString");
if (NULL == pwszAuthority || L'\0' == *pwszAuthority)
{
wprintf(L"%ws\n", myLoadResourceString(IDS_INCOMPLETE_CONFIG)); // "Config string must include Authority name"
hr = E_INVALIDARG;
_JumpError(hr, error, "empty pwszAuthority");
}
// open old DB
hr = RedDBOpen(pwszAuthority);
if (S_OK != hr)
{
wprintf(L"%ws\n", myLoadResourceString(IDS_RED_CANNOT_OPEN_MDB)); // "Cannot open old MDB Database...."
_JumpError(hr, error, "RedDBOpen");
}
*ppwszAuthority = pwszAuthority;
pwszAuthority = NULL;
CSASSERT(S_OK == hr);
error:
if (NULL != pwszServer)
{
LocalFree(pwszServer);
}
if (NULL != pwszAuthority)
{
LocalFree(pwszAuthority);
}
return(hr);
}
HRESULT
verbConvertMDB(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszArg1,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszAuthority = NULL;
BOOL fRedDBOpened = FALSE;
DWORD i;
ICertDB *pdb = NULL;
BYTE *pbCACert = NULL;
DWORD cbCACert;
CERT_INFO *pCACertInfo = NULL;
DWORD cbbuf = 0;
BYTE *pbbuf = NULL;
// open old DB
hr = RedDBInit(&pwszAuthority);
_JumpIfError(hr, error, "RedDBInit");
fRedDBOpened = TRUE;
// new DB
hr = cuDBOpen(pwszAuthority, FALSE, &pdb);
_JumpIfError(hr, error, "cuDBOpen (new)");
hr = LoadCACertFromDB(
pdb,
&pbCACert,
&cbCACert,
&pCACertInfo,
&cbbuf,
&pbbuf);
_JumpIfError(hr, error, "LoadCACertFromDB");
hr = ConvertDB(pdb, pCACertInfo, &cbbuf, &pbbuf);
_JumpIfError(hr, error, "ConvertDB");
error:
if (NULL != pwszAuthority)
{
LocalFree(pwszAuthority);
}
if (NULL != pCACertInfo)
{
LocalFree(pCACertInfo);
}
if (NULL != pbCACert)
{
LocalFree(pbCACert);
}
if (NULL != pbbuf)
{
LocalFree(pbbuf);
}
// Take critical section to make sure we wait for CTL-C DB shutdown.
EnterCriticalSection(&g_DBCriticalSection);
if (cuDBIsShutDownInProgress())
{
if (myJetHResult(JET_errTermInProgress) == hr)
{
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
}
LeaveCriticalSection(&g_DBCriticalSection);
cuDBAbortShutDown(0);
// old DB
if (fRedDBOpened)
{
RedDBShutDown();
}
if (0 != g_crowSkipDuplicate)
{
wprintf(myLoadResourceString(IDS_RED_CROW_DUP), g_crowSkipDuplicate);
wprintf(wszNewLine);
}
if (0 != g_crowSkipWrongCA)
{
wprintf(myLoadResourceString(IDS_RED_CROW_BADCA), g_crowSkipWrongCA);
wprintf(wszNewLine);
}
wprintf(myLoadResourceString(IDS_RED_CROW_CONVERT), g_crowConvert);
wprintf(wszNewLine);
return(hr);
}
HRESULT
RegDBGetLongProperty(
IN LONG RequestId,
IN WCHAR const *pwszPropName,
IN DWORD dwTable,
OUT LONG *pLong)
{
HRESULT hr;
DWORD cbProp;
cbProp = sizeof(*pLong);
hr = RedDBGetPropertyW(
RequestId,
pwszPropName,
PROPTYPE_LONG | dwTable,
&cbProp,
(BYTE *) pLong);
_JumpIfError(hr, error, "RedDBGetPropertyW");
CSASSERT(sizeof(*pLong) == cbProp);
error:
return(hr);
}
HRESULT
verbExtractMDB(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszRequestId,
IN WCHAR const *pwszfnOut,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
WCHAR *pwszAuthority = NULL;
BOOL fRedDBOpened = FALSE;
DWORD cbbuf = 0;
BYTE *pbbuf = NULL;
LONG RequestId;
LONG l;
BOOL fEnumerate;
DWORD cbProp;
hr = cuGetLong(pwszRequestId, &RequestId);
_JumpIfError(hr, error, "cuGetLong");
if (0 > RequestId)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "bad RequestId arg");
}
hr = RedDBInit(&pwszAuthority);
_JumpIfError(hr, error, "RedDBInit");
fRedDBOpened = TRUE;
fEnumerate = FALSE;
if (0 == RequestId)
{
RequestId = 1;
fEnumerate = TRUE;
}
for ( ; ; RequestId++)
{
hr = RegDBGetLongProperty(
RequestId,
g_wszPropRequestRequestID,
PROPTABLE_REQUEST,
&l);
_JumpIfError(hr, error, "RegDBGetLongProperty");
if (l != RequestId)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "RequestId mismatch");
}
hr = RegDBGetLongProperty(
RequestId,
g_wszPropRequestDisposition,
PROPTABLE_REQUEST,
&l);
_JumpIfError(hr, error, "RegDBGetLongProperty");
if (ANCIENT_CR_DISP_ISSUED == l ||
ANCIENT_CR_DISP_ISSUED_OUT_OF_BAND == l ||
ANCIENT_CR_DISP_REVOKED == l)
{
break; // found an issued cert!
}
if (!fEnumerate)
{
hr = CERTSRV_E_PROPERTY_EMPTY;
_JumpError(hr, error, "no such cert");
}
}
hr = RedDBGetPropertyWAndReAlloc(
RequestId,
g_wszPropRawCertificate,
PROPTYPE_BINARY | PROPTABLE_CERTIFICATE,
&cbProp,
&cbbuf,
&pbbuf);
_JumpIfErrorStr(
hr,
error,
"RedDBGetPropertyWAndReAlloc",
g_wszPropRawCertificate);
if (NULL != pwszfnOut)
{
hr = EncodeToFileW(
pwszfnOut,
pbbuf,
cbProp,
CRYPT_STRING_BINARY | g_EncodeFlags);
_JumpIfError(hr, error, "EncodeToFileW");
}
if (g_fVerbose || NULL == pwszfnOut)
{
hr = cuDumpAsnBinary(pbbuf, cbProp, MAXDWORD);
_JumpIfError(hr, error, "cuDumpAsnBinary");
}
error:
if (NULL != pwszAuthority)
{
LocalFree(pwszAuthority);
}
if (NULL != pbbuf)
{
LocalFree(pbbuf);
}
if (fRedDBOpened)
{
RedDBShutDown();
}
return(hr);
}