|
|
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: certsrv.cpp
//
// Contents: Cert Server main & debug support
//
// History: 25-Jul-96 vich created
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <locale.h>
#include <io.h>
#include <fcntl.h>
#include <safeboot.h>
#include <authzi.h>
#include "elog.h"
#include "certlog.h"
#include "certsrvd.h"
#include "resource.h"
#include "csresstr.h"
#define __dwFILE__ __dwFILE_CERTSRV_CERTSRV_CPP__
HKEY g_hkeyCABase = 0;
BOOL g_fCreateDB = FALSE; BOOL g_fStartAsService = TRUE; BOOL g_fStarted; BOOL g_fStartInProgress; DWORD g_ServiceThreadId; HWND g_hwndMain; WCHAR g_wszAppName[] = L"CertSrv"; HINSTANCE g_hInstApp; DWORD g_dwDelay0; DWORD g_dwDelay1; DWORD g_dwDelay2; BOOL g_fCryptSilent = FALSE;
HANDLE g_hServiceThread = NULL; HANDLE g_hShutdownEvent = NULL;
CRITICAL_SECTION g_ShutdownCriticalSection; BOOL g_fShutdownCritSec = FALSE;
BOOL g_fRefuseIncoming = FALSE; LONG g_cCalls = 0; LONG g_cCallsActive = 0; BOOL g_fAdvancedServer = FALSE;
CAutoLPWSTR g_pwszDBFileHash;
SERVICE_TABLE_ENTRY steDispatchTable[] = { { const_cast<WCHAR *>(g_wszCertSrvServiceName), ServiceMain }, { NULL, NULL } };
WCHAR const g_wszRegKeyClassesCLSID[] = L"SOFTWARE\\Classes\\CLSID"; WCHAR const g_wszRegKeyInprocServer32[] = L"InprocServer32"; WCHAR const g_wszRegValueThreadingModel[] = L"ThreadingModel"; WCHAR const g_wszRegKeyAppId[] = L"SOFTWARE\\Classes\\AppId"; WCHAR const g_wszRegRunAs[] = L"RunAs"; WCHAR const g_wszRegValueInteractiveUser[] = L"Interactive User"; WCHAR const g_wszRegLocalService[] = L"LocalService";
// do not change the order, add new audit resources at the end
// g_pwszAllow,
// g_pwszDeny,
// g_pwszCAAdmin,
// g_pwszOfficer,
// g_pwszRead,
// g_pwszEnroll,
LPCWSTR g_pwszAuditResources[6];
using namespace CertSrv;
HRESULT OpenRegistryComKey( IN HKEY hKeyParent, IN CLSID const *pclsid, IN BOOL fWrite, OUT HKEY *phKey) { HRESULT hr; WCHAR *pwsz = NULL;
*phKey = NULL; hr = StringFromCLSID(*pclsid, &pwsz); _JumpIfError(hr, error, "StringFromCLSID");
hr = RegOpenKeyEx( hKeyParent, pwsz, 0, fWrite? KEY_ALL_ACCESS : KEY_READ, phKey); _JumpIfError(hr, error, "RegOpenKeyEx");
error: if (NULL != pwsz) { CoTaskMemFree(pwsz); } return(hr); }
BOOL IsMissingRegistryValue( IN HKEY hKey, IN WCHAR const *pwszRegValueName) { HRESULT hr; DWORD dwLen; DWORD dwType;
hr = RegQueryValueEx(hKey, pwszRegValueName, NULL, &dwType, NULL, &dwLen); if (S_OK != hr) { hr = myHError(hr); } _JumpIfError2( hr, error, "RegQueryValueEx", HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
error: return(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr); }
BOOL IsMatchingRegistryValue( IN HKEY hKey, IN WCHAR const *pwszRegValueName, IN WCHAR const *pwszRegValueString) { HRESULT hr; DWORD dwLen; DWORD dwType; BOOL fMatch = FALSE; WCHAR buf[MAX_PATH];
dwLen = sizeof(buf); hr = RegQueryValueEx( hKey, pwszRegValueName, NULL, &dwType, (BYTE *) buf, &dwLen); _JumpIfErrorStr(hr, error, "RegQueryValueEx", pwszRegValueName);
if (REG_SZ == dwType && 0 == lstrcmpi(buf, pwszRegValueString)) { fMatch = TRUE; }
error: return(fMatch); }
HRESULT SetRegistryStringValue( IN HKEY hKey, IN WCHAR const *pwszRegValueName, IN WCHAR const *pwszRegValueString) { HRESULT hr;
hr = RegSetValueEx( hKey, pwszRegValueName, 0, REG_SZ, (const BYTE *) pwszRegValueString, (wcslen(pwszRegValueString) + 1) * sizeof(WCHAR)); return(hr); }
HRESULT CertSrvSetRegistryFileTimeValue( IN BOOL fConfigLevel, IN WCHAR const *pwszRegValueName, IN DWORD cpwszDelete, OPTIONAL IN WCHAR const * const *papwszRegValueNameDelete) { HRESULT hr; HKEY hKey = NULL; HKEY hKey1 = NULL; WCHAR *pwszKey; FILETIME ftCurrent; DWORD i;
GetSystemTimeAsFileTime(&ftCurrent);
hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, wszREGKEYCONFIGPATH, 0, KEY_ALL_ACCESS, &hKey); _JumpIfError(hr, error, "RegOpenKeyEx");
if (!fConfigLevel) { hKey1 = hKey; hKey = NULL; hr = RegOpenKeyEx( hKey1, g_wszSanitizedName, 0, KEY_ALL_ACCESS, &hKey); _JumpIfError(hr, error, "RegOpenKeyEx"); }
hr = RegSetValueEx( hKey, pwszRegValueName, 0, REG_BINARY, (BYTE const *) &ftCurrent, sizeof(ftCurrent)); _JumpIfError(hr, error, "RegSetValueEx");
for (i = 0; i < cpwszDelete; i++) { hr = RegDeleteValue(hKey, papwszRegValueNameDelete[i]); _PrintIfError2(hr, "RegDeleteValue", ERROR_FILE_NOT_FOUND); } hr = S_OK;
error: if (NULL != hKey1) { RegCloseKey(hKey1); } if (NULL != hKey) { RegCloseKey(hKey); } return(myHError(hr)); }
HRESULT SetRegistryDcomConfig( IN BOOL fConsoleActive) { HRESULT hr; HKEY hKeyAppId = NULL; HKEY hKeyAdmin = NULL; HKEY hKeyRequest = NULL; DWORD cChanged = 0;
hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, g_wszRegKeyAppId, 0, KEY_ALL_ACCESS, &hKeyAppId); _JumpIfError(hr, error, "RegOpenKeyEx");
hr = OpenRegistryComKey(hKeyAppId, &CLSID_CCertAdminD, TRUE, &hKeyAdmin); _JumpIfError(hr, error, "OpenRegistryComKey");
hr = OpenRegistryComKey(hKeyAppId, &CLSID_CCertRequestD, TRUE, &hKeyRequest); _JumpIfError(hr, error, "OpenRegistryComKey");
if (fConsoleActive) { // Running in console mode:
// Delete both LocalService registry values
// Create both RunAs = InteractiveUser registry values
if (!IsMissingRegistryValue(hKeyAdmin, g_wszRegLocalService)) { cChanged++; hr = RegDeleteValue(hKeyAdmin, g_wszRegLocalService); _JumpIfError(hr, error, "RegDeleteValue"); } if (!IsMissingRegistryValue(hKeyRequest, g_wszRegLocalService)) { cChanged++; hr = RegDeleteValue(hKeyRequest, g_wszRegLocalService); _JumpIfError(hr, error, "RegDeleteValue"); }
if (!IsMatchingRegistryValue( hKeyAdmin, g_wszRegRunAs, g_wszRegValueInteractiveUser)) { cChanged++; hr = SetRegistryStringValue( hKeyAdmin, g_wszRegRunAs, g_wszRegValueInteractiveUser); _JumpIfError(hr, error, "SetRegistryStringValue"); } if (!IsMatchingRegistryValue( hKeyRequest, g_wszRegRunAs, g_wszRegValueInteractiveUser)) { cChanged++; hr = SetRegistryStringValue( hKeyRequest, g_wszRegRunAs, g_wszRegValueInteractiveUser); _JumpIfError(hr, error, "SetRegistryStringValue"); } if (0 != cChanged) { DBGPRINT(( DBG_SS_CERTSRV, "SetRegistryDcomConfig(%u): setting %ws=%ws\n", cChanged, g_wszRegRunAs, g_wszRegValueInteractiveUser)); } } else { // Running as a service:
// Delete both RunAs registry values
// Create both LocalService = CertSvc registry values
if (!IsMissingRegistryValue(hKeyAdmin, g_wszRegRunAs)) { cChanged++; hr = RegDeleteValue(hKeyAdmin, g_wszRegRunAs); _JumpIfError(hr, error, "RegDeleteValue"); } if (!IsMissingRegistryValue(hKeyRequest, g_wszRegRunAs)) { cChanged++; hr = RegDeleteValue(hKeyRequest, g_wszRegRunAs); _JumpIfError(hr, error, "RegDeleteValue"); }
if (!IsMatchingRegistryValue( hKeyAdmin, g_wszRegLocalService, g_wszCertSrvServiceName)) { cChanged++; hr = SetRegistryStringValue( hKeyAdmin, g_wszRegLocalService, g_wszCertSrvServiceName); _JumpIfError(hr, error, "SetRegistryStringValue"); } if (!IsMatchingRegistryValue( hKeyRequest, g_wszRegLocalService, g_wszCertSrvServiceName)) { cChanged++; hr = SetRegistryStringValue( hKeyRequest, g_wszRegLocalService, g_wszCertSrvServiceName); _JumpIfError(hr, error, "SetRegistryStringValue"); } if (0 != cChanged) { DBGPRINT(( DBG_SS_CERTSRV, "SetRegistryDcomConfig(%u): setting %ws=%ws\n", cChanged, g_wszRegLocalService, g_wszCertSrvServiceName)); } }
error: if (NULL != hKeyRequest) { RegCloseKey(hKeyRequest); } if (NULL != hKeyAdmin) { RegCloseKey(hKeyAdmin); } if (NULL != hKeyAppId) { RegCloseKey(hKeyAppId); } return(myHError(hr)); }
DWORD GetRegistryDwordValue( IN WCHAR const *pwszRegValueName) { HRESULT hr; HKEY hKeyConfig = NULL; DWORD dwVal; DWORD dwType; DWORD dwLen;
dwVal = 0;
hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, g_wszRegKeyConfigPath, 0, KEY_READ, &hKeyConfig); _JumpIfError(hr, error, "RegOpenKeyEx");
dwLen = sizeof(dwVal); hr = RegQueryValueEx( hKeyConfig, pwszRegValueName, NULL, &dwType, (BYTE *) &dwVal, &dwLen);
if (S_OK != hr || REG_DWORD != dwType || sizeof(dwVal) != dwLen) { dwVal = 0; goto error; }
error: if (NULL != hKeyConfig) { RegCloseKey(hKeyConfig); } return(dwVal); }
HRESULT CertSrvResetRegistryWatch( IN OUT HANDLE *phRegistryModified) { HRESULT hr; CSASSERT(NULL != phRegistryModified);
//////////////////////////////////////
// Initialization of registry events
if (NULL == g_hkeyCABase) { DWORD dwDisposition; LPWSTR pszCAPath; pszCAPath = (LPWSTR) LocalAlloc( LMEM_FIXED, (WSZARRAYSIZE(wszREGKEYCONFIGPATH_BS) + wcslen(g_wszSanitizedName) + 1) * sizeof(WCHAR)); if (NULL == pszCAPath) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pszCAPath, wszREGKEYCONFIGPATH_BS); wcscat(pszCAPath, g_wszSanitizedName); hr = RegCreateKeyEx( HKEY_LOCAL_MACHINE, pszCAPath, 0, // reserved
NULL, // class
0, // options
KEY_ALL_ACCESS, // sec desired
NULL, // sec attr
&g_hkeyCABase, // phk
&dwDisposition); LocalFree(pszCAPath); pszCAPath = NULL; _JumpIfError(hr, error, "RegCreateKeyEx base key"); } if (NULL == *phRegistryModified) { *phRegistryModified = CreateEvent( NULL, TRUE, // manual reset
FALSE, // initial state
L"Registry Modification Event"); if (NULL == *phRegistryModified) { hr = myHLastError(); _JumpError(hr, error, "CreateEvent registry watch"); } } else { // reset registry event
ResetEvent( *phRegistryModified ); }
// register our registry lookout trigger
hr = RegNotifyChangeKeyValue( g_hkeyCABase, FALSE, REG_NOTIFY_CHANGE_LAST_SET, *phRegistryModified, TRUE); _JumpIfError(hr, error, "RegNotifyChangeKeyValue on base key");
error: return(myHError(hr)); }
HRESULT CertSrvRegistryModificationEvent( IN FILETIME const *pftWait, IN OUT DWORD *pdwTimeOut) { HRESULT hr; DWORD dwVal; BOOL fDisabledNew; FILETIME ftCurrent; BOOL fSetEvent = FALSE; DWORD dwMSTimeOut;
// see if Base CRL publish enabled state has changed
hr = myGetCertRegDWValue( g_wszSanitizedName, NULL, NULL, wszREGCRLPERIODCOUNT, &dwVal); if (S_OK == hr) { fDisabledNew = 0 == dwVal; if (fDisabledNew != g_fCRLPublishDisabled) { fSetEvent = TRUE; } }
// see if Delta CRL publish enabled state has changed
hr = myGetCertRegDWValue( g_wszSanitizedName, NULL, NULL, wszREGCRLDELTAPERIODCOUNT, &dwVal); if (S_OK == hr) { fDisabledNew = 0 == dwVal; if (fDisabledNew != g_fDeltaCRLPublishDisabled) { fSetEvent = TRUE; } }
GetSystemTimeAsFileTime(&ftCurrent);
CRLComputeTimeOut(pftWait, &ftCurrent, &dwMSTimeOut); if (dwMSTimeOut >= *pdwTimeOut) { dwMSTimeOut = *pdwTimeOut; fSetEvent = TRUE; } *pdwTimeOut -= dwMSTimeOut;
if (fSetEvent) { SetEvent(g_hCRLManualPublishEvent); // pulse to get up-to-date
} return(hr); }
#if DBG_CERTSRV
WCHAR const * certsrvGetCurrentTimeWsz() { HRESULT hr; FILETIME ft; WCHAR *pwszTime = NULL; static WCHAR s_wszTime[128]; GetSystemTimeAsFileTime(&ft); hr = myGMTFileTimeToWszLocalTime(&ft, TRUE, &pwszTime); _PrintIfError(hr, "myGMTFileTimeToWszLocalTime"); s_wszTime[0] = L'\0'; if (NULL != pwszTime) { wcsncpy(s_wszTime, pwszTime, ARRAYSIZE(s_wszTime)); s_wszTime[ARRAYSIZE(s_wszTime) - 1] = L'\0'; LocalFree(pwszTime); } return(s_wszTime); } #endif
HRESULT CertSrvBlockThreadUntilStop() { HRESULT hr; HANDLE hRegistryModified = NULL; DWORD dwTimeOut;
// check CRL publish, get next timeout interval
hr = CRLPubWakeupEvent(&dwTimeOut); _PrintIfError(hr, "CRLPubWakeupEvent");
hr = CertSrvResetRegistryWatch(&hRegistryModified); _PrintIfError(hr, "CertSrvResetRegistryWatch");
while (TRUE) { FILETIME ftWait; DWORD dw; HANDLE hmultiObjects[] = { hRegistryModified, g_hServiceStoppingEvent, g_hCRLManualPublishEvent };
#if DBG_CERTSRV
{ LLFILETIME llft; WCHAR *pwszTimePeriod = NULL;
llft.ll = dwTimeOut; llft.ll *= (CVT_BASE / 1000); // convert msecs to 100ns
llft.ll = -llft.ll; hr = myFileTimePeriodToWszTimePeriod( &llft.ft, TRUE, // fExact
&pwszTimePeriod); _PrintIfError(hr, "myFileTimePeriodToWszTimePeriod");
DBGPRINT(( DBG_SS_CERTSRV, "WaitForMultipleObjects(%u ms) %ws @%ws\n", dwTimeOut, pwszTimePeriod, certsrvGetCurrentTimeWsz())); if (NULL != pwszTimePeriod) { LocalFree(pwszTimePeriod); } } #endif
GetSystemTimeAsFileTime(&ftWait); dw = WaitForMultipleObjects( ARRAYSIZE(hmultiObjects), hmultiObjects, FALSE, // any object will cause bailout
dwTimeOut);
DBGPRINT(( DBG_SS_CERTSRV, "WaitForMultipleObjects(%u ms)->%x, %ws\n", dwTimeOut, dw, certsrvGetCurrentTimeWsz()));
if (WAIT_FAILED == dw) { hr = GetLastError(); _JumpError(hr, error, "WaitForMultipleObjects worker"); }
if (dw == WAIT_TIMEOUT) // CRL
{ hr = CRLPubWakeupEvent(&dwTimeOut); _PrintIfError(hr, "Error during CRLPubWakeupEvent");
DBGPRINT((DBG_SS_CERTSRVI, "CRLPub: TimeOut %u ms\n", dwTimeOut)); } else if (dw == WAIT_OBJECT_0) // Registry modification
{ // In either case, determine if CRL needs to be published
hr = CertSrvRegistryModificationEvent(&ftWait, &dwTimeOut); _PrintIfError(hr, "Error during CertSrvRegistryModificationEvent");
// in registry case, reset registry trigger
DBGPRINT(( DBG_SS_CERTSRVI, "CRLPub: Registry change trigger, TimeOut=%u ms\n", dwTimeOut));
hr = CertSrvResetRegistryWatch(&hRegistryModified); _PrintIfError(hr, "Error during CertSrvResetRegistryWatch"); } else if (dw == WAIT_OBJECT_0 + 1) { // found "service done" event
DBGPRINT((DBG_SS_CERTSRV, "Service is pending stop request\n")); break; // exit wait loop
} else if (dw == WAIT_OBJECT_0 + 2) { // found "g_hCRLManualPublishEvent" event: recalc timeout
hr = CRLPubWakeupEvent(&dwTimeOut); _PrintIfError(hr, "Error during CRLPubWakeupEvent");
DBGPRINT(( DBG_SS_CERTSRVI, "CRLPub: Manual publish recalc, TimeOut=%u ms\n", dwTimeOut)); } else { CSASSERT(!"unexpected wait return"); hr = E_UNEXPECTED; _JumpError(hr, error, "WaitForMultipleObjects"); } } hr = S_OK;
error: CloseHandle(hRegistryModified); return hr; }
// returns TRUE if we shutdown correctly
BOOL CertSrvStopServer( IN BOOL fConsoleActive) { HRESULT hr; BOOL fCoInit = FALSE; BOOL fShutDown = FALSE;
if (!g_fStartInProgress) // ignore while starting the server
{ fShutDown = TRUE;
DBGPRINT(( DBG_SS_CERTSRV, "CertSrvStopServer(fConsoleActive=%u, tid=%d)\n", fConsoleActive, GetCurrentThreadId()));
SetEvent(g_hServiceStoppingEvent);
if (g_hkeyCABase) { RegCloseKey(g_hkeyCABase); g_hkeyCABase = NULL; }
hr = CoInitializeEx(NULL, GetCertsrvComThreadingModel()); if (S_OK != hr && S_FALSE != hr) { _JumpError(hr, error, "CoInitializeEx"); } fCoInit = TRUE;
// don't allow new callers in
hr = RPCTeardown(); _PrintIfError(hr, "RPCTeardown"); CertStopClassFactories();
CoreTerminate();
if (g_fStarted) { if (CERTLOG_TERSE <= g_dwLogLevel) { LogEventString( EVENTLOG_INFORMATION_TYPE, MSG_I_SERVER_STOPPED, g_wszCommonName); } CONSOLEPRINT0(( DBG_SS_CERTSRV, "Certification Authority Service Stopped\n"));
{ //only perform Hash if the auditing is enabled
if(AUDIT_FILTER_STARTSTOP & g_dwAuditFilter) { CertSrv::CAuditEvent event( SE_AUDITID_CERTSRV_SERVICESTOP, g_dwAuditFilter);
hr = ComputeMAC(g_wszDatabase, &g_pwszDBFileHash); _JumpIfErrorStr(hr, error, "ComputeMAC", g_wszDatabase);
hr = event.AddData(g_pwszDBFileHash); // %1 database hash
g_pwszDBFileHash.Cleanup(); _JumpIfError(hr, error, "CAuditEvent::AddData");
//
// ... add code for retrieving key usage count from CSP
//
hr = event.AddData((DWORD)0); // %2 key usage count
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = event.Report(); _JumpIfError(hr, error, "CAuditEvent::Report"); } } } g_fStarted = FALSE;
AuthzFreeResourceManager(g_AuthzCertSrvRM); g_AuthzCertSrvRM = NULL; g_CASD.Uninitialize(); g_OfficerRightsSD.Uninitialize();
// set "completely stopped" event
if (!fConsoleActive) { SetEvent(g_hServiceStoppedEvent); } }
error: if (fCoInit) { CoUninitialize(); } return(fShutDown); }
// Control-C handler
BOOL StopServer( IN DWORD dwCtrlType) { HRESULT hr;
// if successful shutdown
if (SendMessage(g_hwndMain, WM_STOPSERVER, 0, 0)) { if (!PostMessage(g_hwndMain, WM_SYNC_CLOSING_THREADS, S_OK, 0)) { hr = myHLastError(); _PrintError(hr, "PostMessage"); } SetConsoleCtrlHandler(StopServer, FALSE); } return(TRUE); }
HRESULT CertSrvEnterServer( OUT DWORD *pState) { HRESULT hr; BOOL fEntered = FALSE; *pState = 0; // Caller need not exit server
if (!g_fShutdownCritSec) { hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED); _JumpError(hr, error, "InitializeCriticalSection"); } EnterCriticalSection(&g_ShutdownCriticalSection); fEntered = TRUE;
hr = CertSrvTestServerState(); _JumpIfError(hr, error, "CertSrvTestServerState");
g_cCalls++; g_cCallsActive++; *pState = 1; // Caller must exit server
hr = S_OK;
error: if (fEntered) { LeaveCriticalSection(&g_ShutdownCriticalSection); } return(hr); }
HRESULT CertSrvTestServerState() { HRESULT hr; if (g_fRefuseIncoming) { hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS); _JumpError(hr, error, "g_fRefuseIncoming"); } hr = S_OK;
error: return(hr); }
HRESULT CertSrvLockServer( IN OUT DWORD *pState) { HRESULT hr; BOOL fEntered = FALSE;
// Eliminate this thread from the active thread count
CertSrvExitServer(*pState); *pState = 0; // Caller no longer needs to exit server
if (!g_fShutdownCritSec) { hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED); _JumpError(hr, error, "InitializeCriticalSection"); } EnterCriticalSection(&g_ShutdownCriticalSection); fEntered = TRUE;
g_fRefuseIncoming = TRUE; DBShutDown(TRUE); DBGPRINT((DBG_SS_CERTSRV, "LockServer(thread count = %u)\n", g_cCallsActive)); while (0 < g_cCallsActive) { LeaveCriticalSection(&g_ShutdownCriticalSection);
// Wait 15 seconds plus 2 seconds for each active call.
hr = WaitForSingleObject( g_hShutdownEvent, (15 + 2 * g_cCallsActive) * 1000); EnterCriticalSection(&g_ShutdownCriticalSection);
_PrintIfError(hr, "WaitForSingleObject"); if ((HRESULT) WAIT_OBJECT_0 == hr) { DBGPRINT((DBG_SS_CERTSRV, "LockServer(last thread exit event)\n")); } else if ((HRESULT) WAIT_TIMEOUT == hr) { DBGPRINT((DBG_SS_CERTSRV, "LockServer(timeout)\n")); break; } else if ((HRESULT) WAIT_ABANDONED == hr) { DBGPRINT((DBG_SS_CERTSRV, "LockServer(wait abandoned)\n")); } DBGPRINT((DBG_SS_CERTSRV, "LockServer(thread count = %u)\n", g_cCallsActive)); } DBGPRINT((DBG_SS_CERTSRV, "LockServer(done: thread count = %u)\n", g_cCallsActive)); hr = S_OK;
error: if (fEntered) { LeaveCriticalSection(&g_ShutdownCriticalSection); } return(hr); }
VOID CertSrvExitServer( IN DWORD State) { HRESULT hr; BOOL fEntered = FALSE;
if (!g_fShutdownCritSec) { hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED); _JumpError(hr, error, "InitializeCriticalSection"); } EnterCriticalSection(&g_ShutdownCriticalSection); fEntered = TRUE;
if (State) { CSASSERT(0 < g_cCallsActive); if (0 == --g_cCallsActive && g_fRefuseIncoming) { DBGPRINT((DBG_SS_CERTSRV, "ExitServer(set last thread exit event)\n")); SetEvent(g_hShutdownEvent); } }
error: if (fEntered) { LeaveCriticalSection(&g_ShutdownCriticalSection); } }
// Test for alignment faults in the C runtimes.
// If the bug hasn't been fixed yet, log an event during cert server startup.
VOID certsrvLogAlignmentFaultStatus() { HRESULT hr; HRESULT hr2; ULONG_PTR ExceptionAddress; WCHAR awcAddress[2 + 2 * cwcDWORDSPRINTF]; WCHAR const *apwsz[2]; WORD cpwsz; WCHAR awchr[cwcHRESULTSTRING]; WCHAR const *pwszStringErr = NULL; apwsz[1] = NULL; __try { fwprintf(stdout, L"."); // may fault if I/O buffer is odd aligned
fprintf(stdout, "."); fwprintf(stdout, L".\n"); // may fault if I/O buffer is odd aligned
hr = S_OK; } __except( ExceptionAddress = (ULONG_PTR) (GetExceptionInformation())->ExceptionRecord->ExceptionAddress, hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { _PrintError(hr, "certsrvLogAlignmentFaultStatus: Exception"); } if (S_OK != hr) { ALIGNIOB(stdout); // align the stdio buffer
wprintf(L"STDIO exception: 0x%x\n", hr);
wsprintf(awcAddress, L"0x%p", ExceptionAddress); CSASSERT(wcslen(awcAddress) < ARRAYSIZE(awcAddress));
apwsz[0] = awcAddress; pwszStringErr = myGetErrorMessageText(hr, TRUE); apwsz[1] = pwszStringErr; if (NULL == pwszStringErr) { apwsz[1] = myHResultToString(awchr, hr); } cpwsz = ARRAYSIZE(apwsz);
hr2 = LogEvent( EVENTLOG_WARNING_TYPE, MSG_E_STARTUP_EXCEPTION, cpwsz, apwsz); _JumpIfError(hr2, error, "LogEvent"); }
error: if (NULL != pwszStringErr) { LocalFree(const_cast<WCHAR *>(pwszStringErr)); } }
#define MSTOSEC(ms) (((ms) + 1000 - 1)/1000)
FNLOGEXCEPTION certsrvLogException;
HRESULT certsrvStartServer( IN BOOL fConsoleActive) { HRESULT hr; DWORD TimeStart; WCHAR awc[ARRAYSIZE(SAFEBOOT_DSREPAIR_STR_W)]; DWORD cwc; DWORD dwEventType = EVENTLOG_ERROR_TYPE; DWORD dwIdEvent = 0;
g_fStartInProgress = TRUE; DBGPRINT(( DBG_SS_CERTSRV, "StartServer(tid=%d, fConsoleActive=%u)\n", GetCurrentThreadId(), fConsoleActive)); TimeStart = GetTickCount();
if (fConsoleActive) { g_fStartAsService = FALSE; SetConsoleCtrlHandler(StopServer, TRUE); }
if (!FIsServer()) { // don't allow startup on non-server SKU
hr = HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION); _JumpError(hr, error, "FIsServer"); }
cwc = GetEnvironmentVariable(L"SAFEBOOT_OPTION", awc, ARRAYSIZE(awc)); if (0 != cwc && ARRAYSIZE(awc) > cwc && 0 == lstrcmpi(awc, SAFEBOOT_DSREPAIR_STR_W)) { // log an error to the event log and stop immediately
dwEventType = EVENTLOG_INFORMATION_TYPE; dwIdEvent = MSG_SAFEBOOT_DETECTED;
hr = HRESULT_FROM_WIN32(ERROR_RETRY); _JumpError(hr, error, "Not starting service: booted in DSRepair mode"); } g_fAdvancedServer = FIsAdvancedServer();
if (!AuthzInitializeResourceManager( 0, CallbackAccessCheck, NULL, NULL, L"CertSrv", &g_AuthzCertSrvRM)) { hr = myHLastError(); _PrintError(hr, "AuthzInitializeResourceManager"); if (E_INVALIDARG != hr || (2 > g_fAdvancedServer && IsWhistler())) { goto error; } }
hr = CoreInit(); if (S_OK != hr) { dwIdEvent = MAXDWORD; // Error event already logged
_JumpError(hr, error, "CoreInit"); } certsrvLogAlignmentFaultStatus(); myLogExceptionInit(certsrvLogException);
hr = RPCInit(); if (S_OK != hr) { dwIdEvent = MSG_E_RPC_INIT; _JumpError(hr, error, "RPCInit"); }
hr = SetRegistryDcomConfig(fConsoleActive); if (S_OK != hr) { dwIdEvent = MSG_E_REGISTRY_DCOM; _JumpError(hr, error, "SetRegistryDcomConfig"); }
hr = CertStartClassFactories(); if (S_OK != hr) { dwIdEvent = CO_E_WRONG_SERVER_IDENTITY == hr? MSG_E_SERVER_IDENTITY : MSG_E_CLASS_FACTORIES; _JumpError(hr, error, "CertStartClassFactories"); }
{ //only perform Hash if the auditing is enabled
if(AUDIT_FILTER_STARTSTOP & g_dwAuditFilter) { CertSrv::CAuditEvent event( SE_AUDITID_CERTSRV_SERVICESTART, g_dwAuditFilter);
hr = event.AddData(g_pwszDBFileHash); // %1 database hash
g_pwszDBFileHash.Cleanup(); _JumpIfError(hr, error, "CAuditEvent::AddData"); //
// ... add code for retrieving key usage count from CSP
//
hr = event.AddData((DWORD)0); // %2 key usage count
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = event.Report(); _JumpIfError(hr, error, "CAuditEvent::Report"); } }
{ CertSrv::CAuditEvent event( SE_AUDITID_CERTSRV_ROLESEPARATIONSTATE, g_dwAuditFilter);
hr = event.AddData(CAuditEvent::RoleSeparationIsEnabled()); // %1 is role separation enabled?
_JumpIfError(hr, error, "CAuditEvent::AddData"); hr = event.Report(); _JumpIfError(hr, error, "CAuditEvent::Report"); }
if (CERTLOG_TERSE <= g_dwLogLevel) { LogEventString( EVENTLOG_INFORMATION_TYPE, MSG_I_SERVER_STARTED, g_wszCommonName); } CONSOLEPRINT1(( DBG_SS_CERTSRV, "Certification Authority Service Ready (%us) ...\n", MSTOSEC(GetTickCount() - TimeStart))); g_fStarted = TRUE; CSASSERT(S_OK == hr);
error: if (S_OK != hr) { if (MAXDWORD != dwIdEvent) { if (0 == dwIdEvent) { dwIdEvent = MSG_E_GENERIC_STARTUP_FAILRE; } LogEventStringHResult( dwEventType, dwIdEvent, g_wszCommonName, EVENTLOG_INFORMATION_TYPE == dwEventType? S_OK : hr); }
CertSrvStopServer(fConsoleActive); // returning error here results in repost to scm
}
g_fStartInProgress = FALSE; return(hr); }
VOID certsrvLogException( IN HRESULT hrEvent, IN EXCEPTION_POINTERS const *pep, OPTIONAL IN char const *pszFileName, IN DWORD dwFile, IN DWORD dwLine) { HRESULT hr; WCHAR awcFile[2 + 3 * cwcDWORDSPRINTF]; WCHAR awcFlags[3 + cwcDWORDSPRINTF]; WCHAR awcAddress[2 + 2 * cwcDWORDSPRINTF]; WCHAR const *apwsz[4]; WORD cpwsz; WCHAR awchr[cwcHRESULTSTRING]; WCHAR const *pwszStringErr = NULL;
wsprintf(awcFile, L"%u.%u.%u", dwFile, dwLine, MSG_E_EXCEPTION); CSASSERT(wcslen(awcFile) < ARRAYSIZE(awcFile));
wsprintf(awcFlags, L"0x%08x", pep->ExceptionRecord->ExceptionFlags); CSASSERT(wcslen(awcFlags) < ARRAYSIZE(awcFlags));
wsprintf(awcAddress, L"0x%p", pep->ExceptionRecord->ExceptionAddress); CSASSERT(wcslen(awcAddress) < ARRAYSIZE(awcAddress));
apwsz[0] = awcFile; apwsz[1] = awcAddress; apwsz[2] = awcFlags; pwszStringErr = myGetErrorMessageText(hrEvent, TRUE); apwsz[3] = pwszStringErr; if (NULL == pwszStringErr) { apwsz[3] = myHResultToString(awchr, hrEvent); } cpwsz = ARRAYSIZE(apwsz);
hr = LogEvent(EVENTLOG_ERROR_TYPE, MSG_E_EXCEPTION, cpwsz, apwsz); _JumpIfError(hr, error, "LogEvent");
error: if (NULL != pwszStringErr) { LocalFree(const_cast<WCHAR *>(pwszStringErr)); } }
DWORD CertSrvStartServerThread( IN VOID *pvArg) { HRESULT hr = S_OK; DWORD Flags = (DWORD) (ULONG_PTR) pvArg; BOOL b; ULONG_PTR ulp;
// Anatomy of startup code
// if g_fStartAsService, just registers this new thread as the main
// thread and blocks until the ServiceMain fxn returns.
// We're in a non-rpc thread; check if we need to create VRoots. I would
// have liked to have moved this into CoreInit, but we're limited in where
// we can do this (can't be calling into RPC during RPC call).
//
// If the SetupStatus SETUP_ATTEMPT_VROOT_CREATE registry flag is clear,
// this call is a nop. A separate thread is created to access the IIS
// metabase. If it hangs, it will be nuked -- after the specified timeout.
// This call returns immediately, so the only detectable error is likely
// to be a thread creation problem.
// if we're doing anything other than starting the service controller,
// check to see if the vroots need to be created.
if (0 == (Flags & CSST_STARTSERVICECONTROLLER)) { WCHAR *pwszPath = NULL; DWORD cb = sizeof(ENUM_CATYPES); DWORD dwType; ENUM_CATYPES CAType = ENUM_UNKNOWN_CA; HKEY hkey = NULL;
hr = myRegOpenRelativeKey( NULL, L"ca", RORKF_CREATESUBKEYS, &pwszPath, NULL, // ppwszName
&hkey); _PrintIfError(hr, "myRegOpenRelativeKey"); if (S_OK == hr) { DBGPRINT((DBG_SS_CERTLIBI, "%ws\n", pwszPath)); cb = sizeof(CAType); hr = RegQueryValueEx( hkey, wszREGCATYPE, NULL, &dwType, (BYTE *) &CAType, &cb); _PrintIfErrorStr(hr, "RegQueryValueEx", wszREGCATYPE); } if (pwszPath) LocalFree(pwszPath); if (hkey) RegCloseKey(hkey);
hr = myModifyVirtualRootsAndFileShares( VFF_CREATEVROOTS | // Create VRoots
VFF_CREATEFILESHARES | // Create File Shares
VFF_CHECKREGFLAGFIRST | // Skip if reg flag clear
VFF_CLEARREGFLAGFIRST, // Clear flag before attempt
CAType, TRUE, // asynch call -- don't block
VFCSEC_TIMEOUT, // wait this long before giving up
NULL, NULL); if (S_OK != hr) { LogEventHResult( EVENTLOG_INFORMATION_TYPE, MSG_E_IIS_INTEGRATION_ERROR, hr); } }
// StartServiceCtrlDispatcher should hang until certsrv terminates
if ((CSST_STARTSERVICECONTROLLER & Flags) && !StartServiceCtrlDispatcher(steDispatchTable)) { hr = myHLastError(); if (HRESULT_FROM_WIN32(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) != hr) { _JumpError(hr, error, "StartServiceCtrlDispatcher"); } CONSOLEPRINT0(( DBG_SS_CERTSRV, "CertSrv: Failed to connect to service controller -- running in standalone mode\n"));
Flags &= ~CSST_STARTSERVICECONTROLLER; Flags |= CSST_CONSOLE; }
if (0 == (CSST_STARTSERVICECONTROLLER & Flags)) { DBGPRINT(( DBG_SS_CERTSRVI, "SendMessageTimeout(tid=%d, hwnd=0x%x, msg=0x%x)\n", GetCurrentThreadId(), g_hwndMain, WM_STARTSERVER));
b = SendMessageTimeout( g_hwndMain, WM_STARTSERVER, (CSST_CONSOLE & Flags)? TRUE : FALSE, // fConsoleActive
0, SMTO_BLOCK, MAXLONG, &ulp) != 0; if (!b) { hr = myHLastError(); _JumpError(hr, error, "SendMessageTimeout"); } else if (ulp != S_OK) { hr = (HRESULT) ulp; _JumpError(hr, error, "SendMessageTimeout"); } }
if (Flags & CSST_CONSOLE) { // we're running as console, and so don't have a CRL publishing thread.
// Use this one since no one cares if it returns
// if svc, we do this in the caller of this function
CertSrvBlockThreadUntilStop(); }
error:
// on return, this thread dies
return(hr); }
VOID Usage( IN BOOL fUsageInternal) { WCHAR awcUsage[2048];
if (LoadString(NULL, IDS_USAGE, awcUsage, ARRAYSIZE(awcUsage))) { CONSOLEPRINT1((MAXDWORD, "%ws", awcUsage)); } if (fUsageInternal) { if (LoadString(NULL, IDS_USAGE_FULL, awcUsage, ARRAYSIZE(awcUsage))) { CONSOLEPRINT1((MAXDWORD, "%ws", awcUsage)); } #if DBG_COMTEST
if (LoadString(NULL, IDS_USAGE_COMTEST, awcUsage, ARRAYSIZE(awcUsage))) { CONSOLEPRINT1((MAXDWORD, "%ws", awcUsage)); } #endif
} }
int ArgvParseCommandLine( IN int argc, IN WCHAR *argv[]) { HRESULT hr;
myVerifyResourceStrings(g_hInstApp);
hr = E_INVALIDARG; while (1 < argc && (L'-' == argv[1][0] || L'/' == argv[1][0])) { WCHAR *pwsz = argv[1]; BOOL fUsage = FALSE; BOOL fUsageInternal = FALSE;
while (*++pwsz != L'\0') { switch (*pwsz) { #if DBG_COMTEST
case L'C': case L'c': fComTest = TRUE; break; #endif
case L'N': case L'n': g_fCreateDB = TRUE; break;
case L'Z': case L'z': g_fStartAsService = FALSE; break;
case L'S': case L's': g_fCryptSilent = TRUE; break;
case L'?': case L'u': fUsage = TRUE; if (0 == lstrcmp(pwsz, L"uSAGE")) { fUsageInternal = TRUE; } // FALLTHROUGH
default: Usage(fUsageInternal); if (fUsage) { goto error; } _JumpError(hr, error, "bad command line option"); } } argc--; argv++; } if (argc != 1) { Usage(FALSE); _JumpError(hr, error, "extra args"); } hr = S_OK;
error: return(hr); }
typedef int (FNARGVMAIN)( IN int argc, IN WCHAR *argv[]);
//+------------------------------------------------------------------------
// FUNCTION: CertArgvMainDispatch
//
// NOTES: Takes a WCHAR * command line and chews it up into argc/argv
// form so it can be passed on to a traditional C-style main.
//-------------------------------------------------------------------------
int CertArgvMainDispatch( IN FNARGVMAIN *pfnMain, IN WCHAR *pwszAppName, IN WCHAR const *pwszCmdLine) { WCHAR buf[MAX_PATH]; WCHAR *apwszArg[20]; int cArg = 0; LPWSTR p = buf; WCHAR wcEnd;
apwszArg[cArg++] = pwszAppName; while (*pwszCmdLine != L'\0') { while (*pwszCmdLine == L' ') { pwszCmdLine++; } if (*pwszCmdLine != L'\0') { wcEnd = L' '; if (*pwszCmdLine == L'"') { wcEnd = *pwszCmdLine++; } apwszArg[cArg++] = p; while (*pwszCmdLine != L'\0' && *pwszCmdLine != wcEnd) { *p++ = *pwszCmdLine++; } *p++ = L'\0'; if (*pwszCmdLine != L'\0') { pwszCmdLine++; // skip blank or quote character
} } } apwszArg[cArg] = NULL;
return((*pfnMain)(cArg, apwszArg)); }
//+------------------------------------------------------------------------
// FUNCTION: MainWndProc(...)
//-------------------------------------------------------------------------
LRESULT APIENTRY MainWndProc( IN HWND hWnd, IN UINT msg, IN WPARAM wParam, IN LPARAM lParam) { WCHAR *pwszCmdLine; HRESULT hr; LPARAM lRet = 0; DBGPRINT(( DBG_SS_CERTSRVI, "MainWndProc(tid=%d) msg=0x%x, wp=0x%x, lp=0x%x\n", GetCurrentThreadId(), msg, wParam, lParam)); switch (msg) { case WM_CREATE: case WM_SIZE: break; case WM_DESTROY: if (!g_fStartAsService) PostQuitMessage(S_OK); break;
case WM_ENDSESSION: // only stop on a real shutdown,
// never look at this msg if running as svc
if (g_fStartAsService || (0 == wParam) || (0 != lParam)) { break; } // fall through
case WM_STOPSERVER: lRet = CertSrvStopServer(!g_fStartAsService);
break; case WM_SYNC_CLOSING_THREADS: hr = (HRESULT) lParam; // sync: wait for SCM to return control to exiting CertSrvStartServerThread
if (WAIT_OBJECT_0 != WaitForSingleObject(g_hServiceThread, 10 * 1000)) { hr = WAIT_TIMEOUT; } PostQuitMessage(hr); break; case WM_STARTSERVER: hr = CoInitializeEx(NULL, GetCertsrvComThreadingModel()); if (S_FALSE == hr) { hr = S_OK; } if (S_OK != hr) { LogEventString( EVENTLOG_ERROR_TYPE, MSG_E_OLE_INIT_FAILED, NULL); _PrintError(hr, "CoInitializeEx"); } else { hr = certsrvStartServer((BOOL) wParam); _PrintIfError(hr, "certsrvStartServer"); }
if (S_OK != hr) { if ((BOOL) wParam) // fConsoleActive
{ PostQuitMessage(hr); } lRet = hr; // set this so caller knows we failed
} break; case WM_SUSPENDSERVER: break; case WM_RESTARTSERVER: break;
default: lRet = DefWindowProc(hWnd, msg, wParam, lParam); } return(lRet); }
/*
Complete anatomy of certificate server startup/shutdown
WinMain(): | |g_hSvcThread = CreateThread(CertSrvStartServerThread(SVC_CONTROLLER)) | | |[MessageLoop \ | processing CertSrvStartServerThread(SVC_CONTROLLER): | until |StartSvcCtrlDispatcher(ServiceMain) | WM_QUIT] ||ServiceMain: | ||RegisterSvcCtrlHandler(ServiceControlHandler()) | ||hStartThread = CreateThread(CertSrvStartServerThread(0)) | || | | || \ | || CertSrvStartServerThread(0): | || |SendMessage(WM_STARTSERVER) | || \return // CertSrvStartServerThread(0)
| || (Thread Terminates) | ||WaitForSingleObject(hStartThread), pinging SCM | ||CertSrvBlockThreadUntilStop() | |||WaitForSingleObject(g_hSvcStoppingEvent) ***steady state*** | ||\return // CertSrvBlockThreadUntilStop()
| ||WaitForSingleObject(g_hSvcStoppedEvent), pinging SCM | ||PostMessage(WM_SYNC_CLOSING_THREADS) | |\return // StartSvcCtrlDispatcher(ServiceMain)
| \return // CertSrvStartServerThread(SVC_CONTROLLER)
| (Thread Terminates) | WM_QUIT: \ return (Process Terminates)
ServiceControlHandler special functions: SERVICE_CONTROL_STOP: |PostMessage(WM_STOPSERVER) \break
MessageLoop special functions:
WM_SYNC_CLOSING_THREADS: |WaitForSingleObject(g_hSvcThread) |PostQuitMessage() // WM_QUIT to msgloop
\break
WM_STOPSERVER: |CertSrvStopServer(): || Signal(g_hServiceStoppingEvent) || Signal(g_hServiceStoppedEvent) |\ return // CertSrvStopServer()
\break
*/
//+------------------------------------------------------------------------
// Function: wWinMain()
//
// Synopsis: Entry Point
//
// Arguments: [hInstance] -- Instance handle
// [hPrevInstance] -- Obsolete
// [lpCmdLine] -- App command line
// [nCmdShow] -- Starting show state
//-------------------------------------------------------------------------
extern "C" int APIENTRY wWinMain( IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPWSTR lpCmdLine, IN int nCmdShow) { MSG msg; WNDCLASSEX wcApp; ATOM atomClass; HRESULT hr; BOOL fCoInit = FALSE; WCHAR awchr[cwcHRESULTSTRING]; WCHAR const *pwszMsgAlloc; WCHAR const *pwszMsg; #if DBG_CERTSRV
WCHAR *pwszThreadModel = NULL; #endif
_setmode(_fileno(stdout), _O_TEXT); _wsetlocale(LC_ALL, L".OCP");
DBGPRINTINIT("+certsrv.log"); DBGPRINT((DBG_SS_CERTSRVI, "Main Thread = %x\n", GetCurrentThreadId()));
g_dwDelay0 = GetRegistryDwordValue(L"Delay0"); g_dwDelay1 = GetRegistryDwordValue(L"Delay1"); g_dwDelay2 = GetRegistryDwordValue(L"Delay2");
if (0 != g_dwDelay0) { DBGPRINT(( DBG_SS_CERTSRV, "wWinMain(0): sleeping %u seconds\n", g_dwDelay0)); Sleep(1000 * g_dwDelay0); }
// Save the current instance
g_hInstApp = hInstance; ZeroMemory(&wcApp, sizeof(wcApp));
// Set up the application's window class
wcApp.cbSize = sizeof(wcApp); wcApp.lpfnWndProc = MainWndProc; wcApp.hInstance = hInstance; wcApp.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcApp.hCursor = LoadCursor(NULL, IDC_ARROW); wcApp.hbrBackground = NULL; // try to not pull in GDI32
wcApp.lpszClassName = g_wszAppName;
atomClass = RegisterClassEx(&wcApp); if (!atomClass) { hr = myHLastError(); _JumpError(hr, error, "RegisterClassEx"); }
// Create Main Window
g_hwndMain = CreateWindowEx( 0, // dwExStyle
(WCHAR const *) atomClass, // lpClassName
L"Certification Authority",// lpWindowName
WS_OVERLAPPEDWINDOW, // dwStyle
//0, // dwStyle
CW_USEDEFAULT, // x
CW_USEDEFAULT, // y
CW_USEDEFAULT, // nWidth
CW_USEDEFAULT, // nHeight
NULL, // hWndParent
NULL, // hMenu
hInstance, // hInstance
NULL); // lpParam
if (NULL == g_hwndMain) { hr = myHLastError(); _JumpError(hr, error, "CreateWindowEx"); } DBGPRINT((DBG_SS_CERTSRVI, "Main Window = %x\n", g_hwndMain));
// Make window visible
// ShowWindow(g_hwndMain,nCmdShow);
hr = CertArgvMainDispatch(ArgvParseCommandLine, g_wszAppName, lpCmdLine); _JumpIfError2(hr, error, "CertArgvMainDispatch", E_INVALIDARG);
// Update window client area
// UpdateWindow(g_hwndMain);
if (0 != g_dwDelay1) { DBGPRINT(( DBG_SS_CERTSRV, "wWinMain(1): sleeping %u seconds\n", g_dwDelay1)); Sleep(1000 * g_dwDelay1); }
hr = CoInitializeEx(NULL, GetCertsrvComThreadingModel()); if (S_OK != hr && S_FALSE != hr) { LogEventStringHResult( EVENTLOG_ERROR_TYPE, MSG_E_CO_INITIALIZE, g_wszCommonName, hr); _JumpError(hr, error, "CoInitializeEx"); } fCoInit = TRUE;
g_hServiceStoppingEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (NULL == g_hServiceStoppingEvent) { hr = myHLastError(); _JumpError(hr, error, "CreateEvent"); } g_hServiceStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (NULL == g_hServiceStoppedEvent) { hr = myHLastError(); _JumpError(hr, error, "CreateEvent"); } g_hCRLManualPublishEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (NULL == g_hCRLManualPublishEvent) { hr = myHLastError(); _JumpError(hr, error, "CreateEvent"); } g_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (NULL == g_hShutdownEvent) { hr = myHLastError(); _JumpError(hr, error, "CreateEvent"); } __try { InitializeCriticalSection(&g_ShutdownCriticalSection); g_fShutdownCritSec = TRUE; hr = S_OK; } __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER) { } _JumpIfError(hr, error, "InitializeCriticalSection");
g_hServiceThread = CreateThread( NULL, // lpThreadAttributes (Security Attr)
0, // dwStackSize
CertSrvStartServerThread, (VOID *) UlongToPtr((g_fStartAsService ? CSST_STARTSERVICECONTROLLER : CSST_CONSOLE)), // lpParameter
0, // dwCreationFlags
&g_ServiceThreadId); if (NULL == g_hServiceThread) { hr = myHLastError(); LogEventStringHResult( EVENTLOG_ERROR_TYPE, MSG_E_SERVICE_THREAD, g_wszCommonName, hr); _JumpError(hr, error, "CreateThread"); } DBGPRINT((DBG_SS_CERTSRVI, "Service Thread = %x\n", g_ServiceThreadId));
// Message Loop
while (TRUE) { BOOL b;
b = GetMessage(&msg, NULL, 0, 0); if (!b) { hr = (HRESULT)msg.wParam; _JumpIfError(hr, error, "WM_QUIT"); break; } if (-1 == (LONG) b) { hr = myHLastError(); _JumpError(hr, error, "GetMessage"); } DBGPRINT(( DBG_SS_CERTSRVI, "DispatchMessage(tid=%d) msg=0x%x, wp=0x%x, lp=0x%x\n", GetCurrentThreadId(), msg.message, msg.wParam, msg.lParam)); DispatchMessage(&msg); }
error: if (fCoInit) { CoUninitialize(); } if (g_fShutdownCritSec) { DeleteCriticalSection(&g_ShutdownCriticalSection); g_fShutdownCritSec = FALSE; } if (NULL != g_hShutdownEvent) { CloseHandle(g_hShutdownEvent); } if (NULL != g_hServiceThread) { CloseHandle(g_hServiceThread); } if (NULL != g_hServiceStoppingEvent) { CloseHandle(g_hServiceStoppingEvent); } if (NULL != g_hServiceStoppedEvent) { CloseHandle(g_hServiceStoppedEvent); } if (NULL != g_hCRLManualPublishEvent) { CloseHandle(g_hCRLManualPublishEvent); } CAuditEvent::CleanupAuditEventTypeHandles();
pwszMsgAlloc = NULL; pwszMsg = L"S_OK"; if (S_OK != hr) { pwszMsgAlloc = myGetErrorMessageText(hr, TRUE); if (NULL != pwszMsgAlloc) { pwszMsg = pwszMsgAlloc; } else { pwszMsg = myHResultToString(awchr, hr); } } CONSOLEPRINT1((DBG_SS_CERTSRV, "Exit Status = %ws\n", pwszMsg)); if (NULL != pwszMsgAlloc) { LocalFree(const_cast<WCHAR *>(pwszMsgAlloc)); } myFreeResourceStrings("certsrv.exe"); myFreeColumnDisplayNames(); myRegisterMemDump(); return(hr); }
|