|
|
// --------------------------------------------------------------------------
// Module Name: StandardDebug.cpp
//
// Copyright (c) 1999-2000, Microsoft Corporation
//
// This file defines standard debug helper functions for winlogon/GINA
// projects for neptune.
//
// History: 1999-09-10 vtan created
// 2000-01-31 vtan moved from Neptune to Whistler
// --------------------------------------------------------------------------
#include "StandardHeader.h"
#include <stdio.h>
#ifdef DBG
// --------------------------------------------------------------------------
// gLastResult
//
// Purpose: Temporary global that stores the last result.
// --------------------------------------------------------------------------
LONG gLastResult = ERROR_SUCCESS;
// --------------------------------------------------------------------------
// CDebug::sHasUserModeDebugger
// CDebug::sHasKernelModeDebugger
//
// Purpose: Booleans that indicate debugger status on this machine for
// Winlogon. ntdll!DebugBreak should only be invoked if either
// debugger is present (ntsd piped to kd).
// --------------------------------------------------------------------------
bool CDebug::s_fHasUserModeDebugger = false; bool CDebug::s_fHasKernelModeDebugger = false;
// --------------------------------------------------------------------------
// CDebug::AttachUserModeDebugger
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Attaches a user mode debugger to the current process. Useful
// if you can't start the process under a debugger but still
// want to be able to debug the process.
//
// History: 2000-11-04 vtan created
// --------------------------------------------------------------------------
void CDebug::AttachUserModeDebugger (void)
{ HANDLE hEvent; STARTUPINFO startupInfo; PROCESS_INFORMATION processInformation; SECURITY_ATTRIBUTES sa; TCHAR szCommandLine[MAX_PATH];
ZeroMemory(&startupInfo, sizeof(startupInfo)); ZeroMemory(&processInformation, sizeof(processInformation)); startupInfo.cb = sizeof(startupInfo); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; hEvent = CreateEvent(&sa, TRUE, FALSE, NULL); wsprintf(szCommandLine, TEXT("ntsd -dgGx -p %ld -e %ld"), GetCurrentProcessId(), hEvent); if (CreateProcess(NULL, szCommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &processInformation) != FALSE) { TBOOL(CloseHandle(processInformation.hThread)); TBOOL(CloseHandle(processInformation.hProcess)); (DWORD)WaitForSingleObject(hEvent, 10 * 1000); } TBOOL(CloseHandle(hEvent)); }
// --------------------------------------------------------------------------
// CDebug::Break
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Breaks into the debugger if the hosting process has been
// started with a debugger and kernel debugger is present.
//
// History: 2000-09-11 vtan created
// --------------------------------------------------------------------------
void CDebug::Break (void)
{ if (s_fHasUserModeDebugger || s_fHasKernelModeDebugger) { DebugBreak(); } }
// --------------------------------------------------------------------------
// CDebug::BreakIfRequested
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: If breakins are requested then breaks into the debugger if
// present.
//
// This function explicitly uses Win32 Registry APIs to avoid
// link dependencies on debug code with library code.
//
// History: 1999-09-13 vtan created
// 1999-11-16 vtan removed library code dependency
// 2001-02-21 vtan breaks have teeth
// --------------------------------------------------------------------------
void CDebug::BreakIfRequested (void)
{ #if 0
Break(); #else
HKEY hKeySettings;
// Keep retrieving this value form the registry so that it
// can be altered without restarting the machine.
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), 0, KEY_READ, &hKeySettings)) { DWORD dwBreakFlags, dwBreakFlagsSize;
dwBreakFlagsSize = sizeof(dwBreakFlags); if ((ERROR_SUCCESS == RegQueryValueEx(hKeySettings, TEXT("BreakFlags"), NULL, NULL, reinterpret_cast<LPBYTE>(&dwBreakFlags), &dwBreakFlagsSize)) && ((dwBreakFlags & FLAG_BREAK_ON_ERROR) != 0)) { Break(); } TW32(RegCloseKey(hKeySettings)); } #endif
}
// --------------------------------------------------------------------------
// CDebug::DisplayStandardPrefix
//
// Arguments: <none>
//
// Returns: <none>
//
// Purpose: Displays the standard prefix before any debug spew to help
// identify the source.
//
// History: 1999-10-14 vtan created
// --------------------------------------------------------------------------
void CDebug::DisplayStandardPrefix (void)
{ TCHAR szModuleName[MAX_PATH];
if (GetModuleFileName(NULL, szModuleName, ARRAYSIZE(szModuleName)) != 0) { TCHAR *pTC;
pTC = szModuleName + lstrlen(szModuleName) - 1; while ((pTC >= szModuleName) && (*pTC != TEXT('\\'))) { --pTC; } if (*pTC == TEXT('\\')) { ++pTC; } OutputDebugString(pTC); } else { OutputDebugString(TEXT("UNKNOWN IMAGE")); } OutputDebugStringA(": "); }
// --------------------------------------------------------------------------
// CDebug::DisplayError
//
// Arguments: eType = Type of error that occurred. This
// determines what string is used.
// code = Error code that occurred or zero if N/A.
// pszFunction = Function that was invoked.
// pszSource = Source file error occurred in.
// iLine = Line number within the source file.
//
// Returns: <none>
//
// Purpose: Displays an error message specific the type of error that
// occurred.
//
// History: 1999-09-13 vtan created
// --------------------------------------------------------------------------
void CDebug::DisplayError (TRACE_ERROR_TYPE eType, LONG code, const char *pszFunction, const char *pszSource, int iLine)
{ LONG lastError; char szOutput[1024];
switch (eType) { case TRACE_ERROR_TYPE_WIN32: { lastError = code; sprintf(szOutput, "Unexpected Win32 (%d) for %s in %s at line %d\r\n", lastError, pszFunction, pszSource, iLine); break; } case TRACE_ERROR_TYPE_BOOL: { lastError = GetLastError(); sprintf(szOutput, "Unexpected BOOL (GLE=%d) for %s in %s at line %d\r\n", lastError, pszFunction, pszSource, iLine); break; } case TRACE_ERROR_TYPE_HRESULT: { lastError = GetLastError(); sprintf(szOutput, "Unexpected HRESULT (%08x:GLE=%d) for %s in %s at line %d\r\n", code, lastError, pszFunction, pszSource, iLine); break; } case TRACE_ERROR_TYPE_NTSTATUS: { const char *pszType;
if (NT_ERROR(code)) { pszType = "NT_ERROR"; } else if (NT_WARNING(code)) { pszType = "NT_WARNING"; } else if (NT_INFORMATION(code)) { pszType = "NT_INFORMATION"; } else { pszType = "UNKNOWN"; } sprintf(szOutput, "%s (%08x) for %s in %s at line %d\r\n", pszType, code, pszFunction, pszSource, iLine); break; } default: { lstrcpyA(szOutput, "\r\n"); } } DisplayStandardPrefix(); OutputDebugStringA(szOutput); BreakIfRequested(); }
// --------------------------------------------------------------------------
// CDebug::DisplayMessage
//
// Arguments: pszMessage = Message to display.
//
// Returns: <none>
//
// Purpose: Displays the message - no break.
//
// History: 2000-12-05 vtan created
// --------------------------------------------------------------------------
void CDebug::DisplayMessage (const char *pszMessage)
{ DisplayStandardPrefix(); OutputDebugStringA(pszMessage); OutputDebugStringA("\r\n"); }
// --------------------------------------------------------------------------
// CDebug::DisplayAssert
//
// Arguments: pszMessage = Message to display in assertion failure.
// fForceBreak = Forces break into debugger if present.
//
// Returns: <none>
//
// Purpose: Displays the assertion failure message and breaks into the
// debugger if requested.
//
// History: 1999-09-13 vtan created
// 2000-09-11 vtan add force break
// --------------------------------------------------------------------------
void CDebug::DisplayAssert (const char *pszMessage, bool fForceBreak)
{ DisplayMessage(pszMessage); if (fForceBreak) { Break(); } else { BreakIfRequested(); } }
// --------------------------------------------------------------------------
// CDebug::DisplayWarning
//
// Arguments: pszMessage = Message to display as a warning.
//
// Returns: <none>
//
// Purpose: Displays the warning message.
//
// History: 1999-09-13 vtan created
// --------------------------------------------------------------------------
void CDebug::DisplayWarning (const char *pszMessage)
{ DisplayStandardPrefix(); OutputDebugStringA("WARNING: "); OutputDebugStringA(pszMessage); OutputDebugStringA("\r\n"); }
// --------------------------------------------------------------------------
// CDebug::DisplayDACL
//
// Arguments: hObject = HANDLE to object to display DACL of.
// seObjectType = Object type.
//
// Returns: <none>
//
// Purpose: Displays the discretionary access control list of the object
// using the kernel debugger.
//
// History: 1999-10-15 vtan created
// --------------------------------------------------------------------------
void CDebug::DisplayDACL (HANDLE hObject, SE_OBJECT_TYPE seObjectType)
{ PACL pDACL; PSECURITY_DESCRIPTOR pSD;
DisplayStandardPrefix(); OutputDebugStringA("Display DACL\r\n"); pSD = NULL; pDACL = NULL; if (ERROR_SUCCESS == GetSecurityInfo(hObject, seObjectType, DACL_SECURITY_INFORMATION, NULL, NULL, &pDACL, NULL, &pSD)) { int i, iLimit; unsigned char *pUC;
pUC = reinterpret_cast<unsigned char*>(pDACL + 1); iLimit = pDACL->AceCount; for (i = 0; i < iLimit; ++i) { ACE_HEADER *pAceHeader; char aszString[256];
wsprintfA(aszString, "ACE #%d/%d:\r\n", i + 1, iLimit); OutputDebugStringA(aszString); pAceHeader = reinterpret_cast<ACE_HEADER*>(pUC); switch (pAceHeader->AceType) { case ACCESS_ALLOWED_ACE_TYPE: { ACCESS_ALLOWED_ACE *pAce;
OutputDebugStringA("\tAccess ALLOWED ACE"); pAce = reinterpret_cast<ACCESS_ALLOWED_ACE*>(pAceHeader); OutputDebugStringA("\t\tSID = "); DisplaySID(reinterpret_cast<PSID>(&pAce->SidStart)); wsprintfA(aszString, "\t\tMask = %08x\r\n", pAce->Mask); OutputDebugStringA(aszString); wsprintfA(aszString, "\t\tFlags = %08x\r\n", pAce->Header.AceFlags); OutputDebugStringA(aszString); break; } case ACCESS_DENIED_ACE_TYPE: { ACCESS_DENIED_ACE *pAce;
OutputDebugStringA("\tAccess DENIED ACE"); pAce = reinterpret_cast<ACCESS_DENIED_ACE*>(pAceHeader); OutputDebugStringA("\t\tSID = "); DisplaySID(reinterpret_cast<PSID>(&pAce->SidStart)); wsprintfA(aszString, "\t\tMask = %08x\r\n", pAce->Mask); OutputDebugStringA(aszString); wsprintfA(aszString, "\t\tFlags = %08x\r\n", pAce->Header.AceFlags); OutputDebugStringA(aszString); break; } default: OutputDebugStringA("\tOther ACE type\r\n"); break; } pUC += pAceHeader->AceSize; } ReleaseMemory(pSD); } }
// --------------------------------------------------------------------------
// CDebug::StaticInitialize
//
// Arguments: <none>
//
// Returns: NTSTATUS
//
// Purpose: Establishes the presence of the kernel debugger or if the
// current process is being debugged.
//
// History: 1999-09-13 vtan created
// --------------------------------------------------------------------------
NTSTATUS CDebug::StaticInitialize (void)
{ NTSTATUS status; HANDLE hDebugPort; SYSTEM_KERNEL_DEBUGGER_INFORMATION kdInfo;
status = NtQuerySystemInformation(SystemKernelDebuggerInformation, &kdInfo, sizeof(kdInfo), NULL); if (NT_SUCCESS(status)) { s_fHasKernelModeDebugger = (kdInfo.KernelDebuggerEnabled != FALSE); status = NtQueryInformationProcess(NtCurrentProcess(), ProcessDebugPort, reinterpret_cast<PVOID>(&hDebugPort), sizeof(hDebugPort), NULL); if (NT_SUCCESS(status)) { s_fHasUserModeDebugger = (hDebugPort != NULL); } } return(status); }
// --------------------------------------------------------------------------
// CDebug::StaticTerminate
//
// Arguments: <none>
//
// Returns: NTSTATUS
//
// Purpose: Does nothing but should clean up allocated resources.
//
// History: 1999-09-13 vtan created
// --------------------------------------------------------------------------
NTSTATUS CDebug::StaticTerminate (void)
{ return(STATUS_SUCCESS); }
// --------------------------------------------------------------------------
// CDebug::DisplaySID
//
// Arguments: pSID = SID to display as a string.
//
// Returns: <none>
//
// Purpose: Converts the given SID to a string and displays it.
//
// History: 1999-10-15 vtan created
// --------------------------------------------------------------------------
void CDebug::DisplaySID (PSID pSID)
{ UNICODE_STRING sidString;
RtlInitUnicodeString(&sidString, NULL); TSTATUS(RtlConvertSidToUnicodeString(&sidString, pSID, TRUE)); sidString.Buffer[sidString.Length / sizeof(WCHAR)] = L'\0'; OutputDebugStringW(sidString.Buffer); OutputDebugStringA("\r\n"); RtlFreeUnicodeString(&sidString); }
#endif /* DBG */
|