You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
672 lines
13 KiB
672 lines
13 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: debug.cpp
|
|
//
|
|
// Contents: Debug sub system APIs implementation
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
#define DBG_CERTSRV_DEBUG_PRINT
|
|
|
|
#ifdef DBG_CERTSRV_DEBUG_PRINT
|
|
|
|
#include <stdarg.h>
|
|
#include <ntverp.h>
|
|
#include <common.ver>
|
|
#include <psapi.h>
|
|
|
|
#define __dwFILE__ __dwFILE_CERTCLIB_DEBUG_CPP__
|
|
|
|
|
|
#define dwPRINTMASK_FREELOG (DWORD) (~(DBG_SS_INFO | DBG_SS_MODLOAD | DBG_SS_NOQUIET))
|
|
#if DBG_CERTSRV
|
|
#define dwPRINTMASK_DEFAULT dwPRINTMASK_FREELOG
|
|
#else
|
|
#define dwPRINTMASK_DEFAULT 0
|
|
#endif
|
|
|
|
DWORD g_dwPrintMask = dwPRINTMASK_DEFAULT;
|
|
|
|
CRITICAL_SECTION g_DBGCriticalSection;
|
|
BOOL g_fDBGCSInit = FALSE;
|
|
|
|
FILE *g_pfLog;
|
|
FNLOGSTRING *s_pfnLogString = NULL;
|
|
|
|
|
|
const char *
|
|
DbgGetSSString(
|
|
IN DWORD dwSubSystemId)
|
|
{
|
|
char const *psz = NULL;
|
|
|
|
if (MAXDWORD != dwSubSystemId)
|
|
{
|
|
switch (dwSubSystemId & ~DBG_SS_INFO)
|
|
{
|
|
case DBG_SS_ERROR: psz = "CertError"; break;
|
|
case DBG_SS_ASSERT: psz = "CertAssert"; break;
|
|
case DBG_SS_CERTHIER: psz = "CertHier"; break;
|
|
case DBG_SS_CERTREQ: psz = "CertReq"; break;
|
|
case DBG_SS_CERTUTIL: psz = "CertUtil"; break;
|
|
case DBG_SS_CERTSRV: psz = "CertSrv"; break;
|
|
case DBG_SS_CERTADM: psz = "CertAdm"; break;
|
|
case DBG_SS_CERTCLI: psz = "CertCli"; break;
|
|
case DBG_SS_CERTDB: psz = "CertDB"; break;
|
|
case DBG_SS_CERTENC: psz = "CertEnc"; break;
|
|
case DBG_SS_CERTEXIT: psz = "CertExit"; break;
|
|
case DBG_SS_CERTIF: psz = "CertIF"; break;
|
|
case DBG_SS_CERTMMC: psz = "CertMMC"; break;
|
|
case DBG_SS_CERTOCM: psz = "CertOCM"; break;
|
|
case DBG_SS_CERTPOL: psz = "CertPol"; break;
|
|
case DBG_SS_CERTVIEW: psz = "CertView"; break;
|
|
case DBG_SS_CERTBCLI: psz = "CertBCli"; break;
|
|
case DBG_SS_CERTJET: psz = "CertJet"; break;
|
|
case DBG_SS_CERTLIBXE: psz = "CertLibXE"; break;
|
|
case DBG_SS_CERTLIB: psz = "CertLib"; break;
|
|
case DBG_SS_AUDIT: psz = "CertAudit"; break;
|
|
default: psz = "Cert"; break;
|
|
}
|
|
}
|
|
return(psz);
|
|
}
|
|
|
|
|
|
DWORD
|
|
myatolx(
|
|
char const *psz)
|
|
{
|
|
DWORD dw = 0;
|
|
|
|
while (isxdigit(*psz))
|
|
{
|
|
char ch = *psz++;
|
|
|
|
if (isdigit(ch))
|
|
{
|
|
ch -= '0';
|
|
}
|
|
else if (isupper(ch))
|
|
{
|
|
ch += 10 - 'A';
|
|
}
|
|
else
|
|
{
|
|
ch += 10 - 'a';
|
|
}
|
|
dw = (dw << 4) | ch;
|
|
}
|
|
return(dw);
|
|
}
|
|
|
|
|
|
VOID
|
|
DbgLogDateTime(
|
|
IN CHAR const *pszPrefix)
|
|
{
|
|
if (NULL != g_pfLog)
|
|
{
|
|
WCHAR *pwszDate;
|
|
FILETIME ft;
|
|
SYSTEMTIME st;
|
|
|
|
fprintf(g_pfLog, "%hs: ", pszPrefix);
|
|
GetSystemTime(&st);
|
|
if (SystemTimeToFileTime(&st, &ft))
|
|
{
|
|
if (S_OK == myGMTFileTimeToWszLocalTime(&ft, TRUE, &pwszDate))
|
|
{
|
|
fprintf(g_pfLog, "%ws", pwszDate);
|
|
LocalFree(pwszDate);
|
|
}
|
|
}
|
|
fprintf(g_pfLog, "\n");
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DbgCloseLogFile()
|
|
{
|
|
if(g_fDBGCSInit)
|
|
{
|
|
EnterCriticalSection(&g_DBGCriticalSection);
|
|
if (NULL != g_pfLog)
|
|
{
|
|
DbgLogDateTime("Closed Log");
|
|
fflush(g_pfLog);
|
|
fclose(g_pfLog);
|
|
g_pfLog = NULL;
|
|
}
|
|
LeaveCriticalSection(&g_DBGCriticalSection);
|
|
}
|
|
}
|
|
|
|
|
|
char const szHeader[] = "\n========================================================================\n";
|
|
|
|
VOID
|
|
DbgOpenLogFile(
|
|
OPTIONAL IN CHAR const *pszFile)
|
|
{
|
|
if (NULL != pszFile)
|
|
{
|
|
BOOL fAppend = FALSE;
|
|
UINT cch;
|
|
char aszLogFile[MAX_PATH];
|
|
|
|
if ('+' == *pszFile)
|
|
{
|
|
pszFile++;
|
|
fAppend = TRUE;
|
|
}
|
|
if (NULL == strchr(pszFile, '\\'))
|
|
{
|
|
cch = GetWindowsDirectoryA(aszLogFile, ARRAYSIZE(aszLogFile));
|
|
if (0 != cch)
|
|
{
|
|
if (L'\\' != aszLogFile[cch - 1])
|
|
{
|
|
strcat(aszLogFile, "\\");
|
|
}
|
|
strcat(aszLogFile, pszFile);
|
|
pszFile = aszLogFile;
|
|
}
|
|
}
|
|
|
|
DbgCloseLogFile();
|
|
|
|
if (g_fDBGCSInit)
|
|
{
|
|
EnterCriticalSection(&g_DBGCriticalSection);
|
|
while (TRUE)
|
|
{
|
|
g_pfLog = fopen(pszFile, fAppend? "at" : "wt");
|
|
if (NULL == g_pfLog)
|
|
{
|
|
_PrintError(E_FAIL, "fopen(Log)");
|
|
}
|
|
else
|
|
{
|
|
if (fAppend)
|
|
{
|
|
DWORD cbLogMax = 0;
|
|
char const *pszEnvVar;
|
|
|
|
pszEnvVar = getenv(szCERTSRV_LOGMAX);
|
|
if (NULL != pszEnvVar)
|
|
{
|
|
cbLogMax = myatolx(pszEnvVar);
|
|
}
|
|
if (CBLOGMAXAPPEND > cbLogMax)
|
|
{
|
|
cbLogMax = CBLOGMAXAPPEND;
|
|
}
|
|
if (0 == fseek(g_pfLog, 0L, SEEK_END) &&
|
|
MAXDWORD != cbLogMax)
|
|
{
|
|
LONG lcbLog = ftell(g_pfLog);
|
|
|
|
if (0 > lcbLog || cbLogMax < (DWORD) lcbLog)
|
|
{
|
|
fclose(g_pfLog);
|
|
g_pfLog = NULL;
|
|
fAppend = FALSE;
|
|
continue;
|
|
}
|
|
}
|
|
fwrite(szHeader, SZARRAYSIZE(szHeader), 1, g_pfLog);
|
|
}
|
|
DbgLogDateTime("Opened Log");
|
|
fflush(g_pfLog);
|
|
}
|
|
break;
|
|
}
|
|
LeaveCriticalSection(&g_DBGCriticalSection);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static BOOL s_fFirst = TRUE;
|
|
|
|
VOID
|
|
DbgTerminate(VOID)
|
|
{
|
|
if (g_fDBGCSInit)
|
|
{
|
|
DeleteCriticalSection(&g_DBGCriticalSection);
|
|
g_fDBGCSInit = FALSE;
|
|
s_fFirst = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DbgInit(
|
|
IN BOOL fOpenDefaultLog,
|
|
IN BOOL fReinit)
|
|
{
|
|
if (fReinit || s_fFirst)
|
|
{
|
|
__try
|
|
{
|
|
char const *pszEnvVar;
|
|
WCHAR wszProcess[MAX_PATH];
|
|
|
|
if (s_fFirst)
|
|
{
|
|
InitializeCriticalSection(&g_DBGCriticalSection);
|
|
g_fDBGCSInit = TRUE;
|
|
s_fFirst = FALSE; // Prevent infinite recursion
|
|
}
|
|
|
|
wszProcess[0] = L'\0';
|
|
GetModuleBaseName(
|
|
GetCurrentProcess(),
|
|
GetModuleHandle(NULL),
|
|
wszProcess,
|
|
ARRAYSIZE(wszProcess));
|
|
wszProcess[ARRAYSIZE(wszProcess) - 1] = L'\0';
|
|
g_dwPrintMask = dwPRINTMASK_DEFAULT;
|
|
if (0 == _wcsicmp(wszProcess, L"sysocmgr.exe"))
|
|
{
|
|
g_dwPrintMask = dwPRINTMASK_FREELOG;
|
|
}
|
|
pszEnvVar = getenv(szCERTSRV_DEBUG);
|
|
if (NULL != pszEnvVar)
|
|
{
|
|
g_dwPrintMask = myatolx(pszEnvVar);
|
|
}
|
|
else
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszActiveCA = NULL;
|
|
DWORD PrintMask;
|
|
DWORD PrintMaskCA;
|
|
BOOL fRegSet = FALSE;
|
|
|
|
hr = myGetCertRegDWValue(
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
wszREGCERTSRVDEBUG,
|
|
&PrintMask);
|
|
if (S_OK == hr)
|
|
{
|
|
fRegSet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
PrintMask = 0;
|
|
}
|
|
PrintMaskCA = 0;
|
|
hr = myGetCertRegStrValue(
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
wszREGACTIVE,
|
|
&pwszActiveCA);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = myGetCertRegDWValue(
|
|
pwszActiveCA,
|
|
NULL,
|
|
NULL,
|
|
wszREGCERTSRVDEBUG,
|
|
&PrintMaskCA);
|
|
if (S_OK == hr)
|
|
{
|
|
fRegSet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
PrintMaskCA = 0;
|
|
}
|
|
LocalFree(pwszActiveCA);
|
|
}
|
|
if (fRegSet)
|
|
{
|
|
g_dwPrintMask = PrintMask | PrintMaskCA;
|
|
}
|
|
}
|
|
if (fOpenDefaultLog && NULL == g_pfLog)
|
|
{
|
|
pszEnvVar = getenv(szCERTSRV_LOGFILE);
|
|
DbgOpenLogFile(pszEnvVar);
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
DbgIsSSActive(
|
|
IN DWORD dwSSIn)
|
|
{
|
|
DbgInit(TRUE, FALSE);
|
|
if (MAXDWORD == dwSSIn)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
if ((DBG_SS_INFO & dwSSIn) && 0 == (DBG_SS_INFO & g_dwPrintMask))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
return(0 != (~DBG_SS_INFO & g_dwPrintMask & dwSSIn));
|
|
}
|
|
|
|
|
|
VOID
|
|
DbgLogStringInit(
|
|
IN FNLOGSTRING *pfnLogString)
|
|
{
|
|
if (NULL == s_pfnLogString)
|
|
{
|
|
s_pfnLogString = pfnLogString;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DbgPrintfInit(
|
|
OPTIONAL IN CHAR const *pszFile)
|
|
{
|
|
BOOL fOpenLog = TRUE;
|
|
|
|
if (NULL != pszFile)
|
|
{
|
|
if (0 == strcmp("+", pszFile)) // reinitialize debug print mask only
|
|
{
|
|
DbgInit(FALSE, TRUE);
|
|
fOpenLog = FALSE;
|
|
}
|
|
else if (0 == strcmp("-", pszFile)) // close log file only
|
|
{
|
|
DbgCloseLogFile();
|
|
fOpenLog = FALSE;
|
|
}
|
|
}
|
|
if (fOpenLog)
|
|
{
|
|
DbgInit(NULL == pszFile, FALSE);
|
|
DbgOpenLogFile(pszFile);
|
|
DbgLogFileVersion("certcli.dll", szCSVER_STR);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
fputsStripCR(
|
|
IN char const *psz,
|
|
IN FILE *pf)
|
|
{
|
|
while ('\0' != *psz)
|
|
{
|
|
DWORD i;
|
|
|
|
i = strcspn(psz, "\r");
|
|
if (0 != i)
|
|
{
|
|
fprintf(pf, "%.*hs", i, psz);
|
|
psz += i;
|
|
}
|
|
if ('\r' == *psz)
|
|
{
|
|
psz++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DbgConvertWszToSz(
|
|
IN UINT CodePage,
|
|
OUT CHAR *pchBuf,
|
|
IN LONG cchBuf,
|
|
IN WCHAR const *pwsz)
|
|
{
|
|
LONG cch;
|
|
|
|
CSASSERT(5 < cchBuf); // assumes room for at least "...\n\0"
|
|
cch = WideCharToMultiByte(
|
|
CodePage,
|
|
0, // dwFlags
|
|
pwsz,
|
|
-1, // cchWideChar, -1 => null terminated
|
|
pchBuf,
|
|
cchBuf,
|
|
NULL,
|
|
NULL);
|
|
if (0 == cch)
|
|
{
|
|
char *pchEnd = &pchBuf[cchBuf - 1];
|
|
char *pch = pchBuf;
|
|
|
|
for ( ; L'\0' != *pwsz; pwsz++)
|
|
{
|
|
WCHAR wc = *pwsz;
|
|
if (0xff00 & wc)
|
|
{
|
|
wc = L'?';
|
|
}
|
|
if (pch >= pchEnd)
|
|
{
|
|
pch -= 4;
|
|
strcpy(pch, "...\n");
|
|
break;
|
|
}
|
|
*pch++ = (char) wc;
|
|
}
|
|
*pch = '\0';
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DbgPrintf
|
|
//
|
|
// Synopsis: outputs debug info to stdout and debugger
|
|
//
|
|
// Returns: number of chars output
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#define CCH_DEBUGMAX 4096
|
|
|
|
int
|
|
DbgPrintfVW(
|
|
IN DWORD dwSubSystemId,
|
|
IN WCHAR const *pwszFmt,
|
|
va_list arglist)
|
|
{
|
|
char ach[CCH_DEBUGMAX];
|
|
int cwc = 0;
|
|
BOOL fCritSecEntered = FALSE;
|
|
|
|
ach[0] = '\0';
|
|
_try
|
|
{
|
|
WCHAR awc[CCH_DEBUGMAX];
|
|
DWORD cwcOut;
|
|
CHAR const *pszPrefix;
|
|
DWORD cwcPrefix;
|
|
BOOL fDebuggerPresent;
|
|
HANDLE hStdOut;
|
|
BOOL fRedirected = FALSE;
|
|
|
|
cwcPrefix = 0;
|
|
pszPrefix = DbgGetSSString(dwSubSystemId);
|
|
if (NULL != pszPrefix)
|
|
{
|
|
while ('\0' != *pszPrefix)
|
|
{
|
|
awc[cwcPrefix++] = (WCHAR) *pszPrefix++;
|
|
}
|
|
awc[cwcPrefix++] = L':';
|
|
awc[cwcPrefix++] = L' ';
|
|
}
|
|
awc[cwcPrefix] = L'\0';
|
|
|
|
cwc = _vsnwprintf(
|
|
&awc[cwcPrefix],
|
|
ARRAYSIZE(awc) - cwcPrefix,
|
|
pwszFmt,
|
|
arglist);
|
|
awc[ARRAYSIZE(awc) - 1] = L'\0';
|
|
if (0 > cwc)
|
|
{
|
|
wcscpy(&awc[ARRAYSIZE(awc) - 5], L"...\n");
|
|
cwc = ARRAYSIZE(awc) - 1;
|
|
}
|
|
else
|
|
{
|
|
cwc += cwcPrefix;
|
|
}
|
|
|
|
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
if (INVALID_HANDLE_VALUE != hStdOut)
|
|
{
|
|
// time for output -- where are we going, to a file or the console?
|
|
|
|
switch (~FILE_TYPE_REMOTE & GetFileType(hStdOut))
|
|
{
|
|
//case FILE_TYPE_PIPE:
|
|
//case FILE_TYPE_DISK:
|
|
default:
|
|
// if redirected to a pipe or file, don't use WriteConsole;
|
|
// it drops redirected output on the floor
|
|
fRedirected = TRUE;
|
|
break;
|
|
|
|
case FILE_TYPE_UNKNOWN:
|
|
hStdOut = INVALID_HANDLE_VALUE;
|
|
break;
|
|
|
|
case FILE_TYPE_CHAR:
|
|
break;
|
|
}
|
|
}
|
|
|
|
EnterCriticalSection(&g_DBGCriticalSection);
|
|
fCritSecEntered = TRUE;
|
|
fDebuggerPresent = IsDebuggerPresent();
|
|
if (!fDebuggerPresent)
|
|
{
|
|
if (hStdOut != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (!fRedirected)
|
|
{
|
|
WriteConsole(hStdOut, awc, cwc, &cwcOut, NULL);
|
|
}
|
|
else
|
|
{
|
|
// WriteConsole drops the output on the floor when stdout
|
|
// is redirected to a file.
|
|
|
|
DbgConvertWszToSz(GetACP(), ach, sizeof(ach), awc);
|
|
fputsStripCR(ach, stdout);
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Log files should be UTF8 (for both g_pfLog and (*s_pfnLogString)!)
|
|
|
|
DbgConvertWszToSz(CP_UTF8, ach, sizeof(ach), awc);
|
|
if (NULL != g_pfLog)
|
|
{
|
|
fputsStripCR(ach, g_pfLog);
|
|
fflush(g_pfLog);
|
|
}
|
|
|
|
// Suppress debug prints in free builds unless a debugger is attached:
|
|
|
|
if (fDebuggerPresent || 0 != dwPRINTMASK_DEFAULT)
|
|
{
|
|
OutputDebugString(awc);
|
|
}
|
|
}
|
|
_except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
// return failure
|
|
cwc = 0;
|
|
}
|
|
if (fCritSecEntered)
|
|
{
|
|
LeaveCriticalSection(&g_DBGCriticalSection);
|
|
}
|
|
|
|
// Log files should be UTF8 (for both g_pfLog and (*s_pfnLogString)!)
|
|
|
|
if ('\0' != ach[0] && NULL != s_pfnLogString)
|
|
{
|
|
(*s_pfnLogString)(ach);
|
|
}
|
|
return(cwc);
|
|
}
|
|
|
|
|
|
int WINAPIV
|
|
DbgPrintfW(
|
|
IN DWORD dwSubSystemId,
|
|
IN WCHAR const *pwszFmt,
|
|
...)
|
|
{
|
|
int cwc = 0;
|
|
DWORD dwErr;
|
|
va_list arglist;
|
|
|
|
dwErr = GetLastError();
|
|
if (DbgIsSSActive(dwSubSystemId))
|
|
{
|
|
va_start(arglist, pwszFmt);
|
|
cwc = DbgPrintfVW(dwSubSystemId, pwszFmt, arglist);
|
|
va_end(arglist);
|
|
}
|
|
SetLastError(dwErr);
|
|
return(cwc);
|
|
}
|
|
|
|
|
|
int WINAPIV
|
|
DbgPrintf(
|
|
IN DWORD dwSubSystemId,
|
|
IN LPCSTR pszFmt,
|
|
...)
|
|
{
|
|
int cch = 0;
|
|
DWORD dwErr;
|
|
va_list arglist;
|
|
WCHAR *pwszFmt = NULL;
|
|
|
|
dwErr = GetLastError();
|
|
if (DbgIsSSActive(dwSubSystemId))
|
|
{
|
|
if (myConvertSzToWsz(&pwszFmt, pszFmt, -1))
|
|
{
|
|
va_start(arglist, pszFmt);
|
|
cch = DbgPrintfVW(dwSubSystemId, pwszFmt, arglist);
|
|
va_end(arglist);
|
|
}
|
|
}
|
|
if (NULL != pwszFmt)
|
|
{
|
|
LocalFree(pwszFmt);
|
|
}
|
|
SetLastError(dwErr);
|
|
return(cch);
|
|
}
|
|
|
|
#endif // DBG_CERTSRV_DEBUG_PRINT
|