// -------------------------------------------------------------------------- // 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 #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: // // Returns: // // 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: // // Returns: // // 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: // // Returns: // // 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(&dwBreakFlags), &dwBreakFlagsSize)) && ((dwBreakFlags & FLAG_BREAK_ON_ERROR) != 0)) { Break(); } TW32(RegCloseKey(hKeySettings)); } #endif } // -------------------------------------------------------------------------- // CDebug::DisplayStandardPrefix // // Arguments: // // Returns: // // 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: // // 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: // // 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: // // 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: // // 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: // // 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(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(pUC); switch (pAceHeader->AceType) { case ACCESS_ALLOWED_ACE_TYPE: { ACCESS_ALLOWED_ACE *pAce; OutputDebugStringA("\tAccess ALLOWED ACE"); pAce = reinterpret_cast(pAceHeader); OutputDebugStringA("\t\tSID = "); DisplaySID(reinterpret_cast(&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(pAceHeader); OutputDebugStringA("\t\tSID = "); DisplaySID(reinterpret_cast(&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: // // 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(&hDebugPort), sizeof(hDebugPort), NULL); if (NT_SUCCESS(status)) { s_fHasUserModeDebugger = (hDebugPort != NULL); } } return(status); } // -------------------------------------------------------------------------- // CDebug::StaticTerminate // // Arguments: // // 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: // // 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 */