Leaked source code of windows server 2003
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.

513 lines
17 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: StandardDebug.cpp
  3. //
  4. // Copyright (c) 1999-2000, Microsoft Corporation
  5. //
  6. // This file defines standard debug helper functions for winlogon/GINA
  7. // projects for neptune.
  8. //
  9. // History: 1999-09-10 vtan created
  10. // 2000-01-31 vtan moved from Neptune to Whistler
  11. // --------------------------------------------------------------------------
  12. #include "StandardHeader.h"
  13. #include <stdio.h>
  14. #ifdef DBG
  15. // --------------------------------------------------------------------------
  16. // gLastResult
  17. //
  18. // Purpose: Temporary global that stores the last result.
  19. // --------------------------------------------------------------------------
  20. LONG gLastResult = ERROR_SUCCESS;
  21. // --------------------------------------------------------------------------
  22. // CDebug::sHasUserModeDebugger
  23. // CDebug::sHasKernelModeDebugger
  24. //
  25. // Purpose: Booleans that indicate debugger status on this machine for
  26. // Winlogon. ntdll!DebugBreak should only be invoked if either
  27. // debugger is present (ntsd piped to kd).
  28. // --------------------------------------------------------------------------
  29. bool CDebug::s_fHasUserModeDebugger = false;
  30. bool CDebug::s_fHasKernelModeDebugger = false;
  31. // --------------------------------------------------------------------------
  32. // CDebug::AttachUserModeDebugger
  33. //
  34. // Arguments: <none>
  35. //
  36. // Returns: <none>
  37. //
  38. // Purpose: Attaches a user mode debugger to the current process. Useful
  39. // if you can't start the process under a debugger but still
  40. // want to be able to debug the process.
  41. //
  42. // History: 2000-11-04 vtan created
  43. // --------------------------------------------------------------------------
  44. void CDebug::AttachUserModeDebugger (void)
  45. {
  46. HANDLE hEvent;
  47. STARTUPINFO startupInfo;
  48. PROCESS_INFORMATION processInformation;
  49. SECURITY_ATTRIBUTES sa;
  50. TCHAR szCommandLine[MAX_PATH];
  51. ZeroMemory(&startupInfo, sizeof(startupInfo));
  52. ZeroMemory(&processInformation, sizeof(processInformation));
  53. startupInfo.cb = sizeof(startupInfo);
  54. sa.nLength = sizeof(sa);
  55. sa.lpSecurityDescriptor = NULL;
  56. sa.bInheritHandle = TRUE;
  57. hEvent = CreateEvent(&sa, TRUE, FALSE, NULL);
  58. wsprintf(szCommandLine, TEXT("ntsd -dgGx -p %ld -e %ld"), GetCurrentProcessId(), hEvent);
  59. if (CreateProcess(NULL,
  60. szCommandLine,
  61. NULL,
  62. NULL,
  63. TRUE,
  64. 0,
  65. NULL,
  66. NULL,
  67. &startupInfo,
  68. &processInformation) != FALSE)
  69. {
  70. TBOOL(CloseHandle(processInformation.hThread));
  71. TBOOL(CloseHandle(processInformation.hProcess));
  72. (DWORD)WaitForSingleObject(hEvent, 10 * 1000);
  73. }
  74. TBOOL(CloseHandle(hEvent));
  75. }
  76. // --------------------------------------------------------------------------
  77. // CDebug::Break
  78. //
  79. // Arguments: <none>
  80. //
  81. // Returns: <none>
  82. //
  83. // Purpose: Breaks into the debugger if the hosting process has been
  84. // started with a debugger and kernel debugger is present.
  85. //
  86. // History: 2000-09-11 vtan created
  87. // --------------------------------------------------------------------------
  88. void CDebug::Break (void)
  89. {
  90. if (s_fHasUserModeDebugger || s_fHasKernelModeDebugger)
  91. {
  92. DebugBreak();
  93. }
  94. }
  95. // --------------------------------------------------------------------------
  96. // CDebug::BreakIfRequested
  97. //
  98. // Arguments: <none>
  99. //
  100. // Returns: <none>
  101. //
  102. // Purpose: If breakins are requested then breaks into the debugger if
  103. // present.
  104. //
  105. // This function explicitly uses Win32 Registry APIs to avoid
  106. // link dependencies on debug code with library code.
  107. //
  108. // History: 1999-09-13 vtan created
  109. // 1999-11-16 vtan removed library code dependency
  110. // 2001-02-21 vtan breaks have teeth
  111. // --------------------------------------------------------------------------
  112. void CDebug::BreakIfRequested (void)
  113. {
  114. #if 0
  115. Break();
  116. #else
  117. HKEY hKeySettings;
  118. // Keep retrieving this value form the registry so that it
  119. // can be altered without restarting the machine.
  120. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  121. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
  122. 0,
  123. KEY_READ,
  124. &hKeySettings))
  125. {
  126. DWORD dwBreakFlags, dwBreakFlagsSize;
  127. dwBreakFlagsSize = sizeof(dwBreakFlags);
  128. if ((ERROR_SUCCESS == RegQueryValueEx(hKeySettings,
  129. TEXT("BreakFlags"),
  130. NULL,
  131. NULL,
  132. reinterpret_cast<LPBYTE>(&dwBreakFlags),
  133. &dwBreakFlagsSize)) &&
  134. ((dwBreakFlags & FLAG_BREAK_ON_ERROR) != 0))
  135. {
  136. Break();
  137. }
  138. TW32(RegCloseKey(hKeySettings));
  139. }
  140. #endif
  141. }
  142. // --------------------------------------------------------------------------
  143. // CDebug::DisplayStandardPrefix
  144. //
  145. // Arguments: <none>
  146. //
  147. // Returns: <none>
  148. //
  149. // Purpose: Displays the standard prefix before any debug spew to help
  150. // identify the source.
  151. //
  152. // History: 1999-10-14 vtan created
  153. // --------------------------------------------------------------------------
  154. void CDebug::DisplayStandardPrefix (void)
  155. {
  156. TCHAR szModuleName[MAX_PATH];
  157. if (GetModuleFileName(NULL, szModuleName, ARRAYSIZE(szModuleName)) != 0)
  158. {
  159. TCHAR *pTC;
  160. pTC = szModuleName + lstrlen(szModuleName) - 1;
  161. while ((pTC >= szModuleName) && (*pTC != TEXT('\\')))
  162. {
  163. --pTC;
  164. }
  165. if (*pTC == TEXT('\\'))
  166. {
  167. ++pTC;
  168. }
  169. OutputDebugString(pTC);
  170. }
  171. else
  172. {
  173. OutputDebugString(TEXT("UNKNOWN IMAGE"));
  174. }
  175. OutputDebugStringA(": ");
  176. }
  177. // --------------------------------------------------------------------------
  178. // CDebug::DisplayError
  179. //
  180. // Arguments: eType = Type of error that occurred. This
  181. // determines what string is used.
  182. // code = Error code that occurred or zero if N/A.
  183. // pszFunction = Function that was invoked.
  184. // pszSource = Source file error occurred in.
  185. // iLine = Line number within the source file.
  186. //
  187. // Returns: <none>
  188. //
  189. // Purpose: Displays an error message specific the type of error that
  190. // occurred.
  191. //
  192. // History: 1999-09-13 vtan created
  193. // --------------------------------------------------------------------------
  194. void CDebug::DisplayError (TRACE_ERROR_TYPE eType, LONG code, const char *pszFunction, const char *pszSource, int iLine)
  195. {
  196. LONG lastError;
  197. char szOutput[1024];
  198. switch (eType)
  199. {
  200. case TRACE_ERROR_TYPE_WIN32:
  201. {
  202. lastError = code;
  203. sprintf(szOutput, "Unexpected Win32 (%d) for %s in %s at line %d\r\n", lastError, pszFunction, pszSource, iLine);
  204. break;
  205. }
  206. case TRACE_ERROR_TYPE_BOOL:
  207. {
  208. lastError = GetLastError();
  209. sprintf(szOutput, "Unexpected BOOL (GLE=%d) for %s in %s at line %d\r\n", lastError, pszFunction, pszSource, iLine);
  210. break;
  211. }
  212. case TRACE_ERROR_TYPE_HRESULT:
  213. {
  214. lastError = GetLastError();
  215. sprintf(szOutput, "Unexpected HRESULT (%08x:GLE=%d) for %s in %s at line %d\r\n", code, lastError, pszFunction, pszSource, iLine);
  216. break;
  217. }
  218. case TRACE_ERROR_TYPE_NTSTATUS:
  219. {
  220. const char *pszType;
  221. if (NT_ERROR(code))
  222. {
  223. pszType = "NT_ERROR";
  224. }
  225. else if (NT_WARNING(code))
  226. {
  227. pszType = "NT_WARNING";
  228. }
  229. else if (NT_INFORMATION(code))
  230. {
  231. pszType = "NT_INFORMATION";
  232. }
  233. else
  234. {
  235. pszType = "UNKNOWN";
  236. }
  237. sprintf(szOutput, "%s (%08x) for %s in %s at line %d\r\n", pszType, code, pszFunction, pszSource, iLine);
  238. break;
  239. }
  240. default:
  241. {
  242. lstrcpyA(szOutput, "\r\n");
  243. }
  244. }
  245. DisplayStandardPrefix();
  246. OutputDebugStringA(szOutput);
  247. BreakIfRequested();
  248. }
  249. // --------------------------------------------------------------------------
  250. // CDebug::DisplayMessage
  251. //
  252. // Arguments: pszMessage = Message to display.
  253. //
  254. // Returns: <none>
  255. //
  256. // Purpose: Displays the message - no break.
  257. //
  258. // History: 2000-12-05 vtan created
  259. // --------------------------------------------------------------------------
  260. void CDebug::DisplayMessage (const char *pszMessage)
  261. {
  262. DisplayStandardPrefix();
  263. OutputDebugStringA(pszMessage);
  264. OutputDebugStringA("\r\n");
  265. }
  266. // --------------------------------------------------------------------------
  267. // CDebug::DisplayAssert
  268. //
  269. // Arguments: pszMessage = Message to display in assertion failure.
  270. // fForceBreak = Forces break into debugger if present.
  271. //
  272. // Returns: <none>
  273. //
  274. // Purpose: Displays the assertion failure message and breaks into the
  275. // debugger if requested.
  276. //
  277. // History: 1999-09-13 vtan created
  278. // 2000-09-11 vtan add force break
  279. // --------------------------------------------------------------------------
  280. void CDebug::DisplayAssert (const char *pszMessage, bool fForceBreak)
  281. {
  282. DisplayMessage(pszMessage);
  283. if (fForceBreak)
  284. {
  285. Break();
  286. }
  287. else
  288. {
  289. BreakIfRequested();
  290. }
  291. }
  292. // --------------------------------------------------------------------------
  293. // CDebug::DisplayWarning
  294. //
  295. // Arguments: pszMessage = Message to display as a warning.
  296. //
  297. // Returns: <none>
  298. //
  299. // Purpose: Displays the warning message.
  300. //
  301. // History: 1999-09-13 vtan created
  302. // --------------------------------------------------------------------------
  303. void CDebug::DisplayWarning (const char *pszMessage)
  304. {
  305. DisplayStandardPrefix();
  306. OutputDebugStringA("WARNING: ");
  307. OutputDebugStringA(pszMessage);
  308. OutputDebugStringA("\r\n");
  309. }
  310. // --------------------------------------------------------------------------
  311. // CDebug::DisplayDACL
  312. //
  313. // Arguments: hObject = HANDLE to object to display DACL of.
  314. // seObjectType = Object type.
  315. //
  316. // Returns: <none>
  317. //
  318. // Purpose: Displays the discretionary access control list of the object
  319. // using the kernel debugger.
  320. //
  321. // History: 1999-10-15 vtan created
  322. // --------------------------------------------------------------------------
  323. void CDebug::DisplayDACL (HANDLE hObject, SE_OBJECT_TYPE seObjectType)
  324. {
  325. PACL pDACL;
  326. PSECURITY_DESCRIPTOR pSD;
  327. DisplayStandardPrefix();
  328. OutputDebugStringA("Display DACL\r\n");
  329. pSD = NULL;
  330. pDACL = NULL;
  331. if (ERROR_SUCCESS == GetSecurityInfo(hObject,
  332. seObjectType,
  333. DACL_SECURITY_INFORMATION,
  334. NULL,
  335. NULL,
  336. &pDACL,
  337. NULL,
  338. &pSD))
  339. {
  340. int i, iLimit;
  341. unsigned char *pUC;
  342. pUC = reinterpret_cast<unsigned char*>(pDACL + 1);
  343. iLimit = pDACL->AceCount;
  344. for (i = 0; i < iLimit; ++i)
  345. {
  346. ACE_HEADER *pAceHeader;
  347. char aszString[256];
  348. wsprintfA(aszString, "ACE #%d/%d:\r\n", i + 1, iLimit);
  349. OutputDebugStringA(aszString);
  350. pAceHeader = reinterpret_cast<ACE_HEADER*>(pUC);
  351. switch (pAceHeader->AceType)
  352. {
  353. case ACCESS_ALLOWED_ACE_TYPE:
  354. {
  355. ACCESS_ALLOWED_ACE *pAce;
  356. OutputDebugStringA("\tAccess ALLOWED ACE");
  357. pAce = reinterpret_cast<ACCESS_ALLOWED_ACE*>(pAceHeader);
  358. OutputDebugStringA("\t\tSID = ");
  359. DisplaySID(reinterpret_cast<PSID>(&pAce->SidStart));
  360. wsprintfA(aszString, "\t\tMask = %08x\r\n", pAce->Mask);
  361. OutputDebugStringA(aszString);
  362. wsprintfA(aszString, "\t\tFlags = %08x\r\n", pAce->Header.AceFlags);
  363. OutputDebugStringA(aszString);
  364. break;
  365. }
  366. case ACCESS_DENIED_ACE_TYPE:
  367. {
  368. ACCESS_DENIED_ACE *pAce;
  369. OutputDebugStringA("\tAccess DENIED ACE");
  370. pAce = reinterpret_cast<ACCESS_DENIED_ACE*>(pAceHeader);
  371. OutputDebugStringA("\t\tSID = ");
  372. DisplaySID(reinterpret_cast<PSID>(&pAce->SidStart));
  373. wsprintfA(aszString, "\t\tMask = %08x\r\n", pAce->Mask);
  374. OutputDebugStringA(aszString);
  375. wsprintfA(aszString, "\t\tFlags = %08x\r\n", pAce->Header.AceFlags);
  376. OutputDebugStringA(aszString);
  377. break;
  378. }
  379. default:
  380. OutputDebugStringA("\tOther ACE type\r\n");
  381. break;
  382. }
  383. pUC += pAceHeader->AceSize;
  384. }
  385. ReleaseMemory(pSD);
  386. }
  387. }
  388. // --------------------------------------------------------------------------
  389. // CDebug::StaticInitialize
  390. //
  391. // Arguments: <none>
  392. //
  393. // Returns: NTSTATUS
  394. //
  395. // Purpose: Establishes the presence of the kernel debugger or if the
  396. // current process is being debugged.
  397. //
  398. // History: 1999-09-13 vtan created
  399. // --------------------------------------------------------------------------
  400. NTSTATUS CDebug::StaticInitialize (void)
  401. {
  402. NTSTATUS status;
  403. HANDLE hDebugPort;
  404. SYSTEM_KERNEL_DEBUGGER_INFORMATION kdInfo;
  405. status = NtQuerySystemInformation(SystemKernelDebuggerInformation, &kdInfo, sizeof(kdInfo), NULL);
  406. if (NT_SUCCESS(status))
  407. {
  408. s_fHasKernelModeDebugger = (kdInfo.KernelDebuggerEnabled != FALSE);
  409. status = NtQueryInformationProcess(NtCurrentProcess(), ProcessDebugPort, reinterpret_cast<PVOID>(&hDebugPort), sizeof(hDebugPort), NULL);
  410. if (NT_SUCCESS(status))
  411. {
  412. s_fHasUserModeDebugger = (hDebugPort != NULL);
  413. }
  414. }
  415. return(status);
  416. }
  417. // --------------------------------------------------------------------------
  418. // CDebug::StaticTerminate
  419. //
  420. // Arguments: <none>
  421. //
  422. // Returns: NTSTATUS
  423. //
  424. // Purpose: Does nothing but should clean up allocated resources.
  425. //
  426. // History: 1999-09-13 vtan created
  427. // --------------------------------------------------------------------------
  428. NTSTATUS CDebug::StaticTerminate (void)
  429. {
  430. return(STATUS_SUCCESS);
  431. }
  432. // --------------------------------------------------------------------------
  433. // CDebug::DisplaySID
  434. //
  435. // Arguments: pSID = SID to display as a string.
  436. //
  437. // Returns: <none>
  438. //
  439. // Purpose: Converts the given SID to a string and displays it.
  440. //
  441. // History: 1999-10-15 vtan created
  442. // --------------------------------------------------------------------------
  443. void CDebug::DisplaySID (PSID pSID)
  444. {
  445. UNICODE_STRING sidString;
  446. RtlInitUnicodeString(&sidString, NULL);
  447. TSTATUS(RtlConvertSidToUnicodeString(&sidString, pSID, TRUE));
  448. sidString.Buffer[sidString.Length / sizeof(WCHAR)] = L'\0';
  449. OutputDebugStringW(sidString.Buffer);
  450. OutputDebugStringA("\r\n");
  451. RtlFreeUnicodeString(&sidString);
  452. }
  453. #endif /* DBG */