|
|
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: db3.cpp
//
// Contents: Cert Server Database interface implementation
//
// History: 13-June-97 larrys created
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <stdio.h>
#include "csprop.h"
#define __dwFILE__ __dwFILE_CERTSRV_DB3_CPP__
ICertDB *g_pCertDB = NULL; BOOL g_fDBRecovered = FALSE;
WCHAR g_wszDatabase[MAX_PATH]; WCHAR g_wszLogDir[MAX_PATH]; WCHAR g_wszSystemDir[MAX_PATH];
const WCHAR g_wszCertSrvDotExe[] = L"certsrv.exe"; const int MAXDWORD_STRLEN = 11;
HRESULT dbCheckRecoveryState( IN HKEY hkeyConfig, IN DWORD cSession, IN DWORD DBFlags, IN WCHAR const *pwszEventSource, IN WCHAR const *pwszLogDir, IN WCHAR const *pwszSystemDir, IN WCHAR const *pwszTempDir);
typedef struct _REGDBDIR { WCHAR const *pwszRegName; BOOL fMustExist; WCHAR *pwszBuf; } REGDBDIR;
HRESULT dbGetRestoreDataDWORD( LPCWSTR pwszRestoreFile, LPCWSTR pwszName, DWORD* pdwData) { WCHAR buffer[MAXDWORD_STRLEN]; // large enough to fit MAXDWORD decimal (4294967295)
GetPrivateProfileString( wszRESTORE_SECTION, pwszName, L"", buffer, ARRAYSIZE(buffer), pwszRestoreFile);
if(0==wcscmp(buffer, L"")) { return S_FALSE; }
*pdwData = _wtoi(buffer);
return S_OK; }
HRESULT dbGetRestoreDataLPWSZ( LPCWSTR pwszRestoreFile, LPCWSTR pwszName, LPWSTR* ppwszData) { HRESULT hr = S_OK; WCHAR buffer[MAX_PATH+1];
GetPrivateProfileString( wszRESTORE_SECTION, pwszName, L"", buffer, ARRAYSIZE(buffer), pwszRestoreFile);
if(0==wcscmp(buffer, L"")) { return S_FALSE; }
*ppwszData = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(wcslen(buffer)+1)); _JumpIfAllocFailed(*ppwszData, error);
wcscpy(*ppwszData, buffer);
error: return hr; }
HRESULT dbGetRestoreDataMULTISZ( LPCWSTR pwszRestoreFile, LPCWSTR pwszName, LPWSTR *ppwszData, DWORD *pcbData) { HRESULT hr = S_OK; WCHAR buffer[MAX_PATH+1]; int cData; LPWSTR pwszFullName = NULL; DWORD cbData = 0; LPWSTR pwszData = NULL; WCHAR *pwszCrt = NULL; // no free
pwszFullName = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)* (wcslen(pwszName)+ wcslen(wszRESTORE_NEWLOGSUFFIX)+ MAXDWORD_STRLEN+1)); _JumpIfAllocFailed(pwszFullName, error);
wcscpy(pwszFullName, L"");
for(cbData=0, cData = 0;; cData++) { wsprintf(pwszFullName, L"%s%d", pwszName, cData);
GetPrivateProfileString( wszRESTORE_SECTION, pwszFullName, L"", buffer, ARRAYSIZE(buffer), pwszRestoreFile);
if(0==wcscmp(buffer, L"")) { if(0==cData) { hr = S_FALSE; _JumpErrorStr(hr, error, "no restore data", pwszRestoreFile); } else { break; } }
cbData += wcslen(buffer)+1;
wsprintf(pwszFullName, L"%s%s%d", pwszName, wszRESTORE_NEWLOGSUFFIX, cData);
GetPrivateProfileString( wszRESTORE_SECTION, pwszFullName, L"", buffer, ARRAYSIZE(buffer), pwszRestoreFile);
if(0==wcscmp(buffer, L"")) { hr = ERROR_INVALID_DATA; _JumpErrorStr(hr, error, "restore file contains inconsistent data", pwszRestoreFile); }
cbData += wcslen(buffer)+1; }
cbData++; // trailing zero
cbData *= sizeof(WCHAR);
pwszData = (LPWSTR)LocalAlloc(LMEM_FIXED, cbData); _JumpIfAllocFailed(pwszData, error);
for(pwszCrt=pwszData, cData = 0;; cData++) { wsprintf(pwszFullName, L"%s%d", pwszName, cData);
GetPrivateProfileString( wszRESTORE_SECTION, pwszFullName, L"", buffer, ARRAYSIZE(buffer), pwszRestoreFile);
if(0==wcscmp(buffer, L"")) { break; }
wcscpy(pwszCrt, buffer); pwszCrt += wcslen(buffer)+1;
wsprintf(pwszFullName, L"%s%s%d", pwszName, wszRESTORE_NEWLOGSUFFIX, cData);
GetPrivateProfileString( wszRESTORE_SECTION, pwszFullName, L"", buffer, ARRAYSIZE(buffer), pwszRestoreFile);
wcscpy(pwszCrt, buffer); pwszCrt += wcslen(buffer)+1; }
*pwszCrt = L'\0';
*ppwszData = pwszData; *pcbData = cbData;
error: LOCAL_FREE(pwszFullName); if(S_OK!=hr) { LOCAL_FREE(pwszData); } return hr; }
HRESULT dbRestoreRecoveryStateFromFile(LPCWSTR pwszLogDir) { HRESULT hr = S_OK; LPWSTR pwszRestoreFile = NULL; WCHAR buffer[256]; DWORD dwRestoreMapCount, dwRegLowLogNumber, dwRegHighLogNumber, dwDatabaseRecovered; LPWSTR pwszRestoreMap = NULL; DWORD cbRestoreMap = 0; LPWSTR pwszPath = NULL; HKEY hkey = NULL; DWORD dwDisposition; HKEY hkeyRestore = NULL; BOOL fDatabaseRecovered;
LPWSTR pwszBackupLogDir = NULL; LPWSTR pwszCheckpointFile = NULL; LPWSTR pwszLogPath = NULL;
CSASSERT(pwszLogDir);
pwszRestoreFile = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(wcslen(pwszLogDir)+wcslen(wszRESTORE_FILENAME)+2)); _JumpIfAllocFailed(pwszRestoreFile, error);
wcscpy(pwszRestoreFile, pwszLogDir); wcscat(pwszRestoreFile, L"\\"); wcscat(pwszRestoreFile, wszRESTORE_FILENAME);
// is there a restore state file?
if(-1 != GetFileAttributes(pwszRestoreFile)) { // check first if a restore is in progress
GetPrivateProfileString( wszRESTORE_SECTION, wszREGRESTORESTATUS, L"", buffer, ARRAYSIZE(buffer), pwszRestoreFile);
if(wcscmp(buffer, L"")) { // restore in progress, bail
hr = _wtoi(buffer); _JumpError(hr, error, "A restore is in progress"); }
hr = myRegOpenRelativeKey( NULL, L"", RORKF_CREATESUBKEYS, &pwszPath, NULL, // ppwszName
&hkey); _JumpIfError(hr, error, "myRegOpenRelativeKey");
hr = RegCreateKeyEx( hkey, wszREGKEYRESTOREINPROGRESS, 0, // Reserved
NULL, // lpClass
0, // dwOptions
KEY_ALL_ACCESS, NULL, &hkeyRestore, &dwDisposition); _JumpIfErrorStr(hr, error, "RegCreateKeyEx", wszREGKEYRESTOREINPROGRESS);
hr = dbGetRestoreDataDWORD( pwszRestoreFile, wszREGRESTOREMAPCOUNT, &dwRestoreMapCount); if(S_FALSE==hr) { // mandatory
hr = E_ABORT; } _JumpIfError(hr, error, "restore ini file invalid, wszREGRESTOREMAPCOUNT not found" );
hr = dbGetRestoreDataDWORD( pwszRestoreFile, wszREGLOWLOGNUMBER, &dwRegLowLogNumber); if(S_FALSE==hr) { // mandatory
hr = E_ABORT; } _JumpIfError(hr, error, "restore ini file invalid, wszREGLOWLOGNUMBER not found" );
hr = dbGetRestoreDataDWORD( pwszRestoreFile, wszREGHIGHLOGNUMBER, &dwRegHighLogNumber); if(S_FALSE==hr) { // mandatory
hr = E_ABORT; } _JumpIfError(hr, error, "restore ini file invalid, wszREGHIGHLOGNUMBER not found" );
hr = dbGetRestoreDataDWORD( pwszRestoreFile, wszREGDATABASERECOVERED, &dwDatabaseRecovered); if(S_FALSE==hr) { // mandatory
hr = E_ABORT; } _JumpIfError(hr, error, "restore ini file invalid, wszREGDATABASERECOVERED not found" );
fDatabaseRecovered = dwDatabaseRecovered?TRUE:FALSE;
hr = dbGetRestoreDataLPWSZ( pwszRestoreFile, wszREGBACKUPLOGDIRECTORY, &pwszBackupLogDir); if(S_FALSE==hr) { // optional
hr = S_OK; } _JumpIfErrorStr(hr, error, "dbGetRestoreDataLPWSZ", wszREGBACKUPLOGDIRECTORY );
hr = dbGetRestoreDataLPWSZ( pwszRestoreFile, wszREGCHECKPOINTFILE, &pwszCheckpointFile); if(S_FALSE==hr) { // optional
hr = S_OK; } _JumpIfErrorStr(hr, error, "dbGetRestoreDataLPWSZ", wszREGCHECKPOINTFILE );
hr = dbGetRestoreDataLPWSZ( pwszRestoreFile, wszREGLOGPATH, &pwszLogPath); if(S_FALSE==hr) { // optional
hr = S_OK; } _JumpIfErrorStr(hr, error, "dbGetRestoreDataLPWSZ", wszREGLOGPATH );
hr = dbGetRestoreDataMULTISZ( pwszRestoreFile, wszREGRESTOREMAP, &pwszRestoreMap, &cbRestoreMap); if(S_FALSE==hr) { // optional
hr = S_OK; } _JumpIfErrorStr(hr, error, "dbGetRestoreDataDWORD", L"wszRESTOREMAP");
hr = RegSetValueEx( hkeyRestore, wszREGRESTOREMAPCOUNT, 0, REG_DWORD, (BYTE *) &dwRestoreMapCount, sizeof(DWORD)); _JumpIfErrorStr(hr, error, "RegSetValueEx", wszREGRESTOREMAPCOUNT);
hr = RegSetValueEx( hkeyRestore, wszREGLOWLOGNUMBER, 0, REG_DWORD, (BYTE *) &dwRegLowLogNumber, sizeof(DWORD)); _JumpIfErrorStr(hr, error, "RegSetValueEx", wszREGLOWLOGNUMBER);
hr = RegSetValueEx( hkeyRestore, wszREGHIGHLOGNUMBER, 0, REG_DWORD, (BYTE *) &dwRegHighLogNumber, sizeof(DWORD)); _JumpIfErrorStr(hr, error, "RegSetValueEx", wszREGHIGHLOGNUMBER);
hr = RegSetValueEx( hkeyRestore, wszREGDATABASERECOVERED, 0, REG_BINARY, (BYTE *) &fDatabaseRecovered, sizeof(BOOLEAN)); _JumpIfError(hr, error, "RegSetValueEx");
if(pwszBackupLogDir) { hr = mySetRegistryLocalPathString( hkeyRestore, wszREGBACKUPLOGDIRECTORY, pwszBackupLogDir); _JumpIfErrorStr(hr, error, "mySetRegistryLocalPathString", wszREGBACKUPLOGDIRECTORY); }
if(pwszCheckpointFile) { hr = mySetRegistryLocalPathString( hkeyRestore, wszREGCHECKPOINTFILE, pwszCheckpointFile); _JumpIfErrorStr(hr, error, "mySetRegistryLocalPathString", wszREGCHECKPOINTFILE); }
if(pwszLogPath) { hr = mySetRegistryLocalPathString( hkeyRestore, wszREGLOGPATH, pwszLogPath); _JumpIfErrorStr(hr, error, "mySetRegistryLocalPathString", wszREGCHECKPOINTFILE); }
if(pwszRestoreMap) { hr = RegSetValueEx( hkeyRestore, wszREGRESTOREMAP, 0, REG_MULTI_SZ, (BYTE *) pwszRestoreMap, cbRestoreMap); _JumpIfErrorStr(hr, error, "RegSetValueEx", wszREGRESTOREMAP); }
if(!DeleteFile(pwszRestoreFile)) { _PrintError(myHLastError(), "DeleteFile restore file"); } } else { hr = myHLastError(); // no restore state file OK
if(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) hr = S_OK; _JumpIfErrorStr(hr, error, "GetFileAttributes", pwszRestoreFile); }
error: LOCAL_FREE(pwszRestoreFile); LOCAL_FREE(pwszRestoreMap); LOCAL_FREE(pwszPath); LOCAL_FREE(pwszBackupLogDir); LOCAL_FREE(pwszCheckpointFile); LOCAL_FREE(pwszLogPath); if(hkey) { RegCloseKey(hkey); } if(hkeyRestore) { RegCloseKey(hkeyRestore); } return hr; }
//+--------------------------------------------------------------------------
// DB file storage locations:
//
// wszREGDBDIRECTORY:
// Your Name.EDB from csregstr.h: wszDBFILENAMEEXT .edb
//
// wszREGDBLOGDIRECTORY:
// EDB.log from csregstr.h: wszDBBASENAMEPARM edb
// EDB00001.log from csregstr.h: wszDBBASENAMEPARM edb
// EDB00002.log from csregstr.h: wszDBBASENAMEPARM edb
// res1.log
// res2.log
//
// wszREGDBSYSDIRECTORY:
// EDB.chk from csregstr.h: wszDBBASENAMEPARM edb
//
// wszREGDBTEMPDIRECTORY:
// tmp.edb fixed name
//
// wszREGDBFLAGS:
// wszFlags DBFLAGS_*
//
// Backed up files:
// DB files (Attachments):
// wszREGDBDIRECTORY: Your Name.EDB -- CSBFT_CERTSERVER_DATABASE
//
// Log files:
// wszREGDBLOGDIRECTORY: EDB00001.log -- CSBFT_LOG
// wszREGDBLOGDIRECTORY: EDB00002.log -- CSBFT_LOG
// wszREGDBDIRECTORY: Your Name.pat -- CSBFT_PATCH_FILE
//
//+--------------------------------------------------------------------------
///// initialize database access
HRESULT DBOpen( WCHAR const *pwszSanitizedName) { HRESULT hr = S_OK; DWORD cb; DWORD i; DWORD dwState; HKEY hkey = NULL; WCHAR wszTempDir[MAX_PATH]; DWORD DBFlags; BOOL fRestarted;
REGDBDIR adbdir[] = { { wszREGDBDIRECTORY, TRUE, g_wszDatabase, }, { wszREGDBLOGDIRECTORY, TRUE, g_wszLogDir, }, { wszREGDBSYSDIRECTORY, TRUE, g_wszSystemDir, }, { wszREGDBTEMPDIRECTORY, TRUE, wszTempDir, }, };
// check machine setup status
hr = GetSetupStatus(NULL, &dwState); _JumpIfError(hr, error, "GetSetupStatus");
hr = RegOpenKey(HKEY_LOCAL_MACHINE, g_wszRegKeyConfigPath, &hkey); _JumpIfError(hr, error, "RegOpenKey(CAName)");
// get info from registry
for (i = 0; i < ARRAYSIZE(adbdir); i++) { cb = sizeof(WCHAR) * MAX_PATH; hr = RegQueryValueEx( hkey, adbdir[i].pwszRegName, NULL, NULL, (BYTE *) adbdir[i].pwszBuf, &cb); if ((HRESULT) ERROR_FILE_NOT_FOUND == hr && !adbdir[i].fMustExist) { adbdir[i].pwszBuf[0] = L'\0'; hr = S_OK; } _JumpIfError(hr, error, "RegQueryValueEx(DB*Dir)"); } if (wcslen(g_wszDatabase) + 1 + wcslen(pwszSanitizedName) + wcslen(wszDBFILENAMEEXT) >= ARRAYSIZE(g_wszDatabase)) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); _JumpErrorStr(hr, error, "g_wszDatabase", pwszSanitizedName); } wcscat(g_wszDatabase, L"\\"); wcscat(g_wszDatabase, pwszSanitizedName); wcscat(g_wszDatabase, wszDBFILENAMEEXT);
cb = sizeof(DBFlags); hr = RegQueryValueEx( hkey, wszREGDBFLAGS, NULL, NULL, (BYTE *) &DBFlags, &cb); if (S_OK != hr) { //_PrintErrorStr(hr, "RegQueryValueEx", wszREGDBFLAGS);
DBFlags = DBFLAGS_DEFAULT; } DBFlags &= ~(DBFLAGS_READONLY | DBFLAGS_DISABLESNAPSHOTBACKUP); if (g_fCreateDB || (SETUP_CREATEDB_FLAG & dwState)) { DBFlags |= DBFLAGS_CREATEIFNEEDED; } if (IF_NOSNAPSHOTBACKUP & g_InterfaceFlags) { DBFlags |= DBFLAGS_DISABLESNAPSHOTBACKUP; }
hr = dbCheckRecoveryState( hkey, 2, // cSession
DBFlags, g_wszCertSrvDotExe, // pwszEventSource
g_wszLogDir, // pwszLogDir
g_wszSystemDir, // pwszSystemDir
wszTempDir); // pwszTempDir
_JumpIfError(hr, error, "dbCheckRecoveryState");
CONSOLEPRINT1((DBG_SS_CERTSRV, "Opening Database %ws\n", g_wszDatabase));
__try { hr = CoCreateInstance( CLSID_CCertDB, NULL, // pUnkOuter
CLSCTX_INPROC_SERVER, IID_ICertDB, (VOID **) &g_pCertDB); _LeaveIfError(hr, "CoCreateInstance(ICertDB)");
// only perform Hash if the auditing is enabled
if (AUDIT_FILTER_STARTSTOP & g_dwAuditFilter) { hr = myComputeMAC(g_wszDatabase, &g_pwszDBFileHash); // db file does not exist when starting the CA first time
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { _PrintErrorStr(hr, "Database file not found, can't calculate hash", g_wszDatabase); hr = S_OK; } _LeaveIfErrorStr(hr, "myComputeMAC", g_wszDatabase); }
// S_FALSE means a DB schema change was made that requires a restart
// to take effect. Open the DB a second time if S_FALSE is returned.
fRestarted = FALSE; for (;;) { hr = g_pCertDB->Open( DBFlags, // Flags
g_dwSessionCount, // cSession
g_wszCertSrvDotExe, // pwszEventSource
g_wszDatabase, // pwszDBFile
g_wszLogDir, // pwszLogDir
g_wszSystemDir, // pwszSystemDir
wszTempDir); // pwszTempDir
if (S_OK == hr) { break; } if (S_FALSE == hr && fRestarted) { _PrintError(hr, "Open"); break; } if (S_FALSE != hr) { _LeaveError(hr, "Open"); } hr = g_pCertDB->ShutDown(0); _PrintIfError(hr, "DB ShutDown");
fRestarted = TRUE; } if (SETUP_CREATEDB_FLAG & dwState) { hr = SetSetupStatus(NULL, SETUP_CREATEDB_FLAG, FALSE); _LeaveIfError(hr, "SetSetupStatus"); } hr = S_OK; CONSOLEPRINT0((DBG_SS_CERTSRV, "Database open\n")); } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { }
error: if (S_OK != hr) { if (NULL != g_pCertDB) { g_pCertDB->Release(); g_pCertDB = NULL; } } if (NULL != hkey) { RegCloseKey(hkey); } return(hr); }
HRESULT DBShutDown( IN BOOL fPendingNotify) { HRESULT hr = S_OK;
if (NULL != g_pCertDB) { hr = g_pCertDB->ShutDown(fPendingNotify? CDBSHUTDOWN_PENDING : 0); if (!fPendingNotify) { g_pCertDB->Release(); g_pCertDB = NULL; } } return(hr); }
HRESULT dbRecoverAfterRestore( IN DWORD cSession, IN DWORD DBFlags, IN WCHAR const *pwszEventSource, IN WCHAR const *pwszLogDir, IN WCHAR const *pwszSystemDir, IN WCHAR const *pwszTempDir, IN WCHAR const *pwszCheckPointFile, IN WCHAR const *pwszLogPath, IN CSEDB_RSTMAPW rgrstmap[], IN LONG crstmap, IN WCHAR const *pwszBackupLogPath, IN DWORD genLow, IN DWORD genHigh) { HRESULT hr; ICertDBRestore *pCertDBRestore = NULL;
hr = S_OK; __try { WCHAR *apwsz[2];
hr = CoCreateInstance( CLSID_CCertDBRestore, NULL, // pUnkOuter
CLSCTX_INPROC_SERVER, IID_ICertDBRestore, (VOID **) &pCertDBRestore); _LeaveIfError(hr, "CoCreateInstance(ICertDBRestore)");
hr = pCertDBRestore->RecoverAfterRestore( cSession, DBFlags, pwszEventSource, pwszLogDir, pwszSystemDir, pwszTempDir, pwszCheckPointFile, pwszLogPath, rgrstmap, crstmap, pwszBackupLogPath, genLow, genHigh); _LeaveIfError(hr, "RecoverAfterRestore");
apwsz[0] = wszREGDBLASTFULLBACKUP; apwsz[1] = wszREGDBLASTINCREMENTALBACKUP; hr = CertSrvSetRegistryFileTimeValue( TRUE, wszREGDBLASTRECOVERY, ARRAYSIZE(apwsz), apwsz); _PrintIfError(hr, "CertSrvSetRegistryFileTimeValue"); hr = S_OK; } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { } if (NULL != pCertDBRestore) { pCertDBRestore->Release(); } return(hr); }
HRESULT dbPerformRecovery( IN DWORD cSession, IN DWORD DBFlags, IN WCHAR const *pwszEventSource, IN WCHAR const *pwszLogDir, IN WCHAR const *pwszSystemDir, IN WCHAR const *pwszTempDir, IN WCHAR const *pwszCheckPointFile, IN WCHAR const *pwszLogPath, IN CSEDB_RSTMAPW rgrstmap[], IN LONG crstmap, IN WCHAR const *pwszBackupLogPath, IN unsigned long genLow, IN unsigned long genHigh, IN OUT BOOLEAN *pfRecoverJetDatabase) { HRESULT hr = S_OK;
// Call into JET to let it munge the databases.
// Note that the JET interpretation of LogPath and BackupLogPath is
// totally wierd, and we want to pass in LogPath to both parameters.
if (!*pfRecoverJetDatabase) { hr = dbRecoverAfterRestore( cSession, DBFlags, pwszEventSource, pwszLogDir, pwszSystemDir, pwszTempDir, pwszCheckPointFile, pwszLogPath, rgrstmap, crstmap, pwszBackupLogPath, genLow, genHigh); _JumpIfError(hr, error, "dbRecoverAfterRestore"); }
// Ok, we were able to recover the database. Let the other side of the
// API know about it so it can do something "reasonable".
*pfRecoverJetDatabase = TRUE;
// Mark the DB as a restored version - Add any external notification here
error: return(hr); }
//+--------------------------------------------------------------------------
// dbCheckRecoveryState -- recover a database after a restore if necessary.
//
// Parameters:
// pwszParametersRoot - the root of the parameters section for the service in
// the registry.
//
// Returns: HRESULT - S_OK if successful; error code if not.
//
// The NTBACKUP program will place a key at the location:
// $(pwszParametersRoot)\Restore in Progress
//
// This key contains the following values:
// BackupLogPath - The full path for the logs after a backup
// CheckPointFilePath - The full path for the path that contains the checkpoint
// *HighLogNumber - The maximum log file number found.
// *LowLogNumber - The minimum log file number found.
// LogPath - The current path for the logs.
// JET_RstMap - Restore map for database - this is a REG_MULTISZ, where odd
// entries go into the pwszDatabase field, and the even entries go into the
// pwszNewDatabase field of a JET_RstMap
// *JET_RstMap Size - The number of entries in the restoremap.
//
// * - These entries are REG_DWORD's. All others are REG_SZ's (except where
// mentioned).
//---------------------------------------------------------------------------
HRESULT dbCheckRecoveryState( IN HKEY hkeyConfig, IN DWORD cSession, IN DWORD DBFlags, IN WCHAR const *pwszEventSource, IN WCHAR const *pwszLogDir, IN WCHAR const *pwszSystemDir, IN WCHAR const *pwszTempDir) { HRESULT hr; HKEY hkeyRestore = NULL; DWORD cb; WCHAR wszCheckPointFilePath[MAX_PATH]; WCHAR wszBackupLogPath[MAX_PATH]; WCHAR wszLogPath[MAX_PATH]; WCHAR *pwszCheckPointFilePath; WCHAR *pwszBackupLogPath; WCHAR *pwszLogPath; WCHAR *pwszRestoreMap = NULL; CSEDB_RSTMAPW *pRstMap = NULL; LONG cRstMap; LONG i; DWORD genLow; DWORD genHigh; WCHAR *pwsz; DWORD dwType; HRESULT hrRestoreError; BOOLEAN fDatabaseRecovered = FALSE; WCHAR wszActiveLogPath[MAX_PATH];
hr = dbRestoreRecoveryStateFromFile(pwszLogDir); _JumpIfError(hr, error, "dbRestoreRecoveryStateFromFile");
hr = RegOpenKey(HKEY_LOCAL_MACHINE, wszREGKEYCONFIGRESTORE, &hkeyRestore); if (S_OK != hr) { // We want to ignore file_not_found - it is ok.
if (hr == ERROR_FILE_NOT_FOUND) { hr = S_OK; } _PrintIfError(hr, "RegOpenKey"); goto error; }
CONSOLEPRINT0((DBG_SS_CERTSRV, "Started Database Recovery\n"));
// If there's a restore in progress, then fail to perform any other
// restore operations.
dwType = REG_DWORD; cb = sizeof(DWORD); hr = RegQueryValueEx( hkeyRestore, wszREGRESTORESTATUS, 0, &dwType, (BYTE *) &hrRestoreError, &cb); if (S_OK == hr) { hr = hrRestoreError; _JumpError(hr, error, "hrRestoreError"); }
cb = sizeof(wszActiveLogPath); hr = RegQueryValueEx( hkeyConfig, wszREGDBLOGDIRECTORY, NULL, NULL, (BYTE *) wszActiveLogPath, &cb); _JumpIfErrorStr(hr, error, "RegQueryValueEx", wszREGDBLOGDIRECTORY);
// We have now opened the restore-in-progress key. This means that we have
// something to do now. Find out what it is. First, let's get the backup
// log file path.
dwType = REG_SZ;
cb = sizeof(wszBackupLogPath); pwszBackupLogPath = wszBackupLogPath; hr = RegQueryValueEx( hkeyRestore, wszREGBACKUPLOGDIRECTORY, 0, &dwType, (BYTE *) wszBackupLogPath, &cb); if (S_OK != hr) { if (hr != ERROR_FILE_NOT_FOUND) { _JumpError(hr, error, "RegQueryValueEx"); } pwszBackupLogPath = NULL; }
// Then, the checkpoint file path.
cb = sizeof(wszCheckPointFilePath); pwszCheckPointFilePath = wszCheckPointFilePath; hr = RegQueryValueEx( hkeyRestore, wszREGCHECKPOINTFILE, 0, &dwType, (BYTE *) wszCheckPointFilePath, &cb); if (S_OK != hr) { if (hr != ERROR_FILE_NOT_FOUND) { _JumpError(hr, error, "RegQueryValueEx"); } pwszCheckPointFilePath = NULL; }
// Then, the Log path.
cb = sizeof(wszLogPath); pwszLogPath = wszLogPath; hr = RegQueryValueEx( hkeyRestore, wszREGLOGPATH, 0, &dwType, (BYTE *) wszLogPath, &cb); if (S_OK != hr) { if ((HRESULT) ERROR_FILE_NOT_FOUND != hr) { _JumpError(hr, error, "RegQueryValueEx"); } pwszLogPath = NULL; }
// Then, the low log number.
dwType = REG_DWORD; cb = sizeof(genLow); hr = RegQueryValueEx( hkeyRestore, wszREGLOWLOGNUMBER, 0, &dwType, (BYTE *) &genLow, &cb); _JumpIfError(hr, error, "RegQueryValueEx");
// And, the high log number.
cb = sizeof(genHigh); hr = RegQueryValueEx( hkeyRestore, wszREGHIGHLOGNUMBER, 0, &dwType, (BYTE *) &genHigh, &cb); _JumpIfError(hr, error, "RegQueryValueEx");
// Now determine if we had previously recovered the database.
dwType = REG_BINARY; cb = sizeof(fDatabaseRecovered);
hr = RegQueryValueEx( hkeyRestore, wszREGDATABASERECOVERED, 0, &dwType, &fDatabaseRecovered, &cb); if (S_OK != hr && (HRESULT) ERROR_FILE_NOT_FOUND != hr) { // If there was an error other than "value doesn't exist", bail.
_JumpError(hr, error, "RegQueryValueEx"); }
// Now the tricky one. We want to get the restore map.
// First we figure out how big it is.
dwType = REG_DWORD; cb = sizeof(cRstMap); hr = RegQueryValueEx( hkeyRestore, wszREGRESTOREMAPCOUNT, 0, &dwType, (BYTE *) &cRstMap, &cb); _JumpIfError(hr, error, "RegQueryValueEx");
pRstMap = (CSEDB_RSTMAPW *) LocalAlloc( LMEM_FIXED, sizeof(CSEDB_RSTMAPW) * cRstMap); if (NULL == pRstMap) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); }
// First find out how much memory is needed to hold the restore map.
dwType = REG_MULTI_SZ; hr = RegQueryValueEx( hkeyRestore, wszREGRESTOREMAP, 0, &dwType, NULL, &cb); if (S_OK != hr && (HRESULT) ERROR_MORE_DATA != hr) { _JumpError(hr, error, "RegQueryValueEx"); }
pwszRestoreMap = (WCHAR *) LocalAlloc(LMEM_FIXED, cb + 2 * sizeof(WCHAR)); if (NULL == pwszRestoreMap) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); }
hr = RegQueryValueEx( hkeyRestore, wszREGRESTOREMAP, 0, &dwType, (BYTE *) pwszRestoreMap, &cb); _JumpIfError(hr, error, "RegQueryValueEx"); pwszRestoreMap[cb / sizeof(WCHAR)] = L'\0'; pwszRestoreMap[cb / sizeof(WCHAR) + 1] = L'\0';
pwsz = pwszRestoreMap; for (i = 0; i < cRstMap; i++) { if (L'\0' == *pwsz) { break; } pRstMap[i].pwszDatabaseName = pwsz; pwsz += wcslen(pwsz) + 1;
if (L'\0' == *pwsz) { break; } pRstMap[i].pwszNewDatabaseName = pwsz; pwsz += wcslen(pwsz) + 1; } if (i < cRstMap || L'\0' != *pwsz) { hr = E_INVALIDARG; _JumpError(hr, error, "Restore Map"); }
{ CertSrv::CAuditEvent event(SE_AUDITID_CERTSRV_RESTORESTART, g_dwAuditFilter); hr = event.Report(); _JumpIfError(hr, error, "CAuditEvent::Report"); }
hr = dbPerformRecovery( cSession, DBFlags, pwszEventSource, pwszLogDir, pwszSystemDir, pwszTempDir, pwszCheckPointFilePath, NULL != pwszLogPath? pwszLogPath : wszActiveLogPath, pRstMap, cRstMap, NULL != pwszBackupLogPath? pwszBackupLogPath : wszActiveLogPath, genLow, genHigh, &fDatabaseRecovered); if (S_OK != hr) { // The recovery failed. If recovering the database succeeded, flag it
// in the registry so we don't try again. Ignore RegSetValueEx errors,
// because the recovery error is more important.
RegSetValueEx( hkeyRestore, wszREGDATABASERECOVERED, 0, REG_BINARY, (BYTE *) &fDatabaseRecovered, sizeof(fDatabaseRecovered)); _JumpError(hr, error, "dbPerformRecovery"); }
{ CertSrv::CAuditEvent event(SE_AUDITID_CERTSRV_RESTOREEND, g_dwAuditFilter); hr = event.Report(); _JumpIfError(hr, error, "CAuditEvent::Report"); }
CONSOLEPRINT0((DBG_SS_CERTSRV, "Completed Database Recovery\n"));
g_fDBRecovered = TRUE;
// Ok, we're all done. We can now delete the key, since we're done
// with it.
RegCloseKey(hkeyRestore); hkeyRestore = NULL;
hr = RegDeleteKey(HKEY_LOCAL_MACHINE, wszREGKEYCONFIGRESTORE); _JumpIfError(hr, error, "RegDeleteKey");
error: if (NULL != pwszRestoreMap) { LocalFree(pwszRestoreMap); } if (NULL != pRstMap) { LocalFree(pRstMap); } if (NULL != hkeyRestore) { RegCloseKey(hkeyRestore); } return(hr); }
|