Source code of Windows XP (NT5)
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.

2707 lines
83 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. faultrep.cpp
  5. Abstract:
  6. Implements utility functions for fault reporting
  7. Revision History:
  8. created derekm 07/07/00
  9. ******************************************************************************/
  10. #include "stdafx.h"
  11. #include "dbghelp.h"
  12. #include "wtsapi32.h"
  13. #include "userenv.h"
  14. #include "frmc.h"
  15. #include "tlhelp32.h"
  16. #include "shimdb.h"
  17. ///////////////////////////////////////////////////////////////////////////////
  18. // typedefs
  19. typedef BOOL (STDAPICALLTYPE *DUMPWRITE_FN)(HANDLE, DWORD, HANDLE,
  20. MINIDUMP_TYPE,
  21. PMINIDUMP_EXCEPTION_INFORMATION,
  22. PMINIDUMP_USER_STREAM_INFORMATION,
  23. PMINIDUMP_CALLBACK_INFORMATION);
  24. typedef DWORD (WINAPI *pfn_GETMODULEFILENAMEEXW)(HANDLE, HMODULE, LPWSTR, DWORD);
  25. ///////////////////////////////////////////////////////////////////////////////
  26. // globals
  27. ///////////////////////////////////////////////////////////////////////////////
  28. // useful structs
  29. struct SLangCodepage
  30. {
  31. WORD wLanguage;
  32. WORD wCodePage;
  33. };
  34. ///////////////////////////////////////////////////////////////////////////////
  35. // misc utility functions
  36. // **************************************************************************
  37. HMODULE MySafeLoadLibrary(LPCWSTR wszModule)
  38. {
  39. HMODULE hmod = NULL;
  40. PVOID pvLdrLockCookie = NULL;
  41. ULONG ulLockState = 0;
  42. // make sure that no one else owns the loader lock because we
  43. // could otherwise deadlock
  44. LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY, &ulLockState,
  45. &pvLdrLockCookie);
  46. if (ulLockState == LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED)
  47. {
  48. __try { hmod = LoadLibraryExW(wszModule, NULL, 0); }
  49. __except(EXCEPTION_EXECUTE_HANDLER) { hmod = NULL; }
  50. LdrUnlockLoaderLock(0, pvLdrLockCookie);
  51. }
  52. return hmod;
  53. }
  54. // **************************************************************************
  55. static inline WCHAR itox(DWORD dw)
  56. {
  57. dw &= 0xf;
  58. return (WCHAR)((dw < 10) ? (L'0' + dw) : (L'A' + (dw - 10)));
  59. }
  60. // **************************************************************************
  61. BOOL IsASCII(LPCWSTR wszSrc)
  62. {
  63. const WCHAR *pwsz;
  64. // check and see if we need to hexify the string. This is determined
  65. // by whether the string contains all ASCII characters or not. Since
  66. // an ASCII character is defined as being in the range of 00 -> 7f, just
  67. // 'and' the wchar's value with ~0x7f and see if the result is 0. If it
  68. // is, then the whcar is an ASCII value.
  69. for (pwsz = wszSrc; *pwsz != L'\0'; pwsz++)
  70. {
  71. if ((*pwsz & ~0x7f) != 0)
  72. return FALSE;
  73. }
  74. return TRUE;
  75. }
  76. // **************************************************************************
  77. BOOL IsValidField(LPWSTR wsz)
  78. {
  79. WCHAR *pwsz;
  80. if (wsz == NULL)
  81. return FALSE;
  82. for(pwsz = wsz; *pwsz != L'\0'; pwsz++)
  83. {
  84. if (iswspace(*pwsz) == FALSE)
  85. return TRUE;
  86. }
  87. return FALSE;
  88. }
  89. // **************************************************************************
  90. BOOL TransformForWire(LPCWSTR wszSrc, LPWSTR wszDest, DWORD cchDest)
  91. {
  92. HRESULT hr = NOERROR;
  93. DWORD cch;
  94. USE_TRACING("TransformForWire");
  95. VALIDATEPARM(hr, (wszSrc == NULL || wszDest == NULL || cchDest < 5));
  96. if (FAILED(hr))
  97. goto done;
  98. if (cchDest > 5)
  99. {
  100. // darn! Gotta convert every character to a 4 char hex value cuz this
  101. // is what DW does and we have to match them
  102. for (cch = 0; *wszSrc != L'\0' && cch + 4 < cchDest; cch += 4, wszSrc++)
  103. {
  104. *wszDest++ = itox((*wszSrc & 0xf000) > 12);
  105. *wszDest++ = itox((*wszSrc & 0x0f00) > 8);
  106. *wszDest++ = itox((*wszSrc & 0x00f0) > 4);
  107. *wszDest++ = itox((*wszSrc & 0x000f));
  108. }
  109. // if we don't see this, then we've got too small of a buffer
  110. if (*wszSrc != L'\0' || cch >= cchDest)
  111. {
  112. hr = E_FAIL;
  113. goto done;
  114. }
  115. *wszDest = L'\0';
  116. }
  117. else
  118. {
  119. hr = E_FAIL;
  120. }
  121. done:
  122. return (SUCCEEDED(hr));
  123. }
  124. // ***************************************************************************
  125. LPWSTR MarshallString(LPCWSTR wszSrc, PBYTE pBase, ULONG cbMaxBuf,
  126. PBYTE *ppToWrite, DWORD *pcbWritten)
  127. {
  128. DWORD cb;
  129. PBYTE pwszNormalized;
  130. cb = (wcslen(wszSrc) + 1) * sizeof(WCHAR);
  131. if ((*pcbWritten + cb) > cbMaxBuf)
  132. return NULL;
  133. RtlMoveMemory(*ppToWrite, wszSrc, cb);
  134. // the normalized ptr is the current count
  135. pwszNormalized = (PBYTE)(*ppToWrite - pBase);
  136. // cb is always a mutliple of sizeof(WHCAR) so the pointer addition below
  137. // always produces a result that is 2byte aligned (assuming the input was
  138. // 2byte aligned of course)
  139. *ppToWrite += cb;
  140. *pcbWritten += cb;
  141. return (LPWSTR)pwszNormalized;
  142. }
  143. // **************************************************************************
  144. HRESULT GetVerName(LPWSTR wszModule, LPWSTR wszName, DWORD cchName,
  145. LPWSTR wszVer, DWORD cchVer,
  146. LPWSTR wszCompany, DWORD cchCompany,
  147. BOOL fAcceptUnicodeCP, BOOL fWantActualName)
  148. {
  149. USE_TRACING("GetVerName");
  150. VS_FIXEDFILEINFO *pffi;
  151. SLangCodepage *plc;
  152. HRESULT hr = NOERROR;
  153. WCHAR wszQuery[128], *pwszProp = NULL;
  154. WCHAR *pwszPropVal;
  155. DWORD cbFVI, dwJunk, dwMSWin = 0;
  156. PBYTE pbFVI = NULL;
  157. UINT cb, cbVerInfo, i;
  158. SLangCodepage rglc[] = { { 0, 0 }, // UI language if one exists
  159. { 0x409, 0x4B0 }, // unicode English
  160. { 0x409, 0x4E4 }, // English
  161. { 0x409, 0 }, // English, null codepage
  162. { 0 , 0x4E4 } }; // language neutral.
  163. VALIDATEPARM(hr, (wszModule == NULL || wszName == NULL || cchName == 0));
  164. if (FAILED(hr))
  165. goto done;
  166. if (wszCompany != NULL)
  167. *wszCompany = L'\0';
  168. if (wszVer != NULL)
  169. wcsncpy(wszVer, L"0.0.0.0", cchVer);
  170. if (fWantActualName)
  171. {
  172. *wszName = L'\0';
  173. }
  174. else
  175. {
  176. for(pwszPropVal = wszModule + wcslen(wszModule);
  177. pwszPropVal >= wszModule && *pwszPropVal != L'\\';
  178. pwszPropVal--);
  179. if (*pwszPropVal == L'\\')
  180. pwszPropVal++;
  181. wcsncpy(wszName, pwszPropVal, cchName);
  182. wszName[cchName - 1] = L'\0';
  183. }
  184. // dwJunk is a useful parameter. Gotta pass it in so the function call
  185. // set it to 0. Gee this would make a great (tho non-efficient)
  186. // way to set DWORDs to 0. Much better than saying dwJunk = 0 by itself.
  187. cbFVI = GetFileVersionInfoSizeW(wszModule, &dwJunk);
  188. TESTBOOL(hr, (cbFVI != 0));
  189. if (FAILED(hr))
  190. {
  191. // if it fails, assume the file doesn't have any version info &
  192. // return S_FALSE
  193. hr = S_FALSE;
  194. goto done;
  195. }
  196. // alloca only throws exceptions so gotta catch 'em here...
  197. __try
  198. {
  199. __try{ pbFVI = (PBYTE)_alloca(cbFVI); }
  200. __except(EXCEPTION_STACK_OVERFLOW) { pbFVI = NULL; }
  201. _ASSERT(pbFVI != NULL);
  202. hr = NOERROR;
  203. }
  204. __except(EXCEPTION_EXECUTE_HANDLER)
  205. {
  206. pbFVI = NULL;
  207. }
  208. VALIDATEEXPR(hr, (pbFVI == NULL), E_OUTOFMEMORY);
  209. if (FAILED(hr))
  210. goto done;
  211. cb = cbFVI;
  212. TESTBOOL(hr, GetFileVersionInfoW(wszModule, 0, cbFVI, (LPVOID *)pbFVI));
  213. if (FAILED(hr))
  214. {
  215. // if it fails, assume the file doesn't have any version info &
  216. // return S_FALSE
  217. hr = S_FALSE;
  218. goto done;
  219. }
  220. // determine if it's a MS app or windows componenet
  221. dwMSWin = IsMicrosoftApp(NULL, pbFVI, cbFVI);
  222. // get the real version info- apparently, the string can occasionally
  223. // be out of sync (so says the explorer.exe code that extracts ver info)
  224. if (wszVer != NULL &&
  225. VerQueryValueW(pbFVI, L"\\", (LPVOID *)&pffi, &cb) && cb != 0)
  226. {
  227. WCHAR wszVerTemp[64];
  228. swprintf(wszVerTemp, L"%d.%d.%d.%d", HIWORD(pffi->dwFileVersionMS),
  229. LOWORD(pffi->dwFileVersionMS), HIWORD(pffi->dwFileVersionLS),
  230. LOWORD(pffi->dwFileVersionLS));
  231. wcsncpy(wszVer, wszVerTemp, cchVer);
  232. wszVer[cchVer - 1] = L'\0';
  233. }
  234. // try to figure out what the appropriate langage...
  235. TESTBOOL(hr, VerQueryValueW(pbFVI, L"\\VarFileInfo\\Translation",
  236. (LPVOID *)&plc, &cbVerInfo));
  237. if (SUCCEEDED(hr))
  238. {
  239. LANGID langid;
  240. DWORD cLangs, iUni = (DWORD)-1;
  241. UINT uiACP;
  242. langid = GetUserDefaultUILanguage();
  243. cLangs = cbVerInfo / sizeof(SLangCodepage);
  244. uiACP = GetACP();
  245. // see if there's a language that matches the default
  246. for(i = 0; i < cLangs; i++)
  247. {
  248. // not sure what to do if there are multiple code pages for a
  249. // particular language. Just take the first, I guess...
  250. if (langid == plc[i].wLanguage && uiACP == plc[i].wCodePage)
  251. break;
  252. // if we can accept the unicode code page & we encounter a
  253. // launguage with it, then remember it. Note that we only
  254. // remember the first such instance we see or one that matches
  255. // the target language
  256. if (fAcceptUnicodeCP && plc[i].wCodePage == 1200 &&
  257. (iUni == (DWORD)-1 || langid == plc[i].wLanguage))
  258. iUni = i;
  259. }
  260. if (i >= cLangs && iUni != (DWORD)-1)
  261. i = iUni;
  262. if (i < cLangs)
  263. {
  264. rglc[0].wLanguage = plc[i].wLanguage;
  265. rglc[0].wCodePage = plc[i].wCodePage;
  266. }
  267. }
  268. for(i = 0; i < 5; i++)
  269. {
  270. if (rglc[i].wLanguage == 0 && rglc[i].wCodePage == 0)
  271. continue;
  272. swprintf(wszQuery, L"\\StringFileInfo\\%04x%04x\\FileVersion",
  273. rglc[i].wLanguage, rglc[i].wCodePage);
  274. // Retrieve file description for language and code page 'i'.
  275. TESTBOOL(hr, VerQueryValueW(pbFVI, wszQuery,
  276. (LPVOID *)&pwszPropVal, &cb));
  277. if (SUCCEEDED(hr) && cb != 0)
  278. {
  279. // want to get size of a normal char string & not a unicode
  280. // string cuz we'd have to / sizeof(WCHAR) otherwise
  281. pwszProp = wszQuery + sizeof("\\StringFileInfo\\%04x%04x\\") - 1;
  282. break;
  283. }
  284. }
  285. // if we still didn't find anything, then assume there's no version
  286. // resource. We've already set the defaults above, so we can bail...
  287. if (pwszProp == NULL)
  288. {
  289. hr = NOERROR;
  290. goto done;
  291. }
  292. if (wszCompany != NULL)
  293. {
  294. wcscpy(pwszProp, L"CompanyName");
  295. TESTBOOL(hr, VerQueryValueW(pbFVI, wszQuery, (LPVOID *)&pwszPropVal,
  296. &cb));
  297. if (SUCCEEDED(hr) && cb != 0)
  298. {
  299. wcsncpy(wszCompany, pwszPropVal, cchCompany);
  300. wszCompany[cchCompany - 1] = L'\0';
  301. }
  302. }
  303. // So to fix the case where Windows components did not properly update
  304. // the product strings, we have to look for the FileDescription first.
  305. // But since the OCA folks want only the description (convieniently
  306. // when the fWantActualName field is set) then we need to only read
  307. // the ProductName field.
  308. if (fWantActualName)
  309. {
  310. wcscpy(pwszProp, L"ProductName");
  311. TESTBOOL(hr, VerQueryValueW(pbFVI, wszQuery, (LPVOID *)&pwszPropVal,
  312. &cb));
  313. if (SUCCEEDED(hr) && cb != 0 && IsValidField(pwszPropVal))
  314. {
  315. wcsncpy(wszName, pwszPropVal, cchName);
  316. wszName[cchName - 1] = L'\0';
  317. goto done;
  318. }
  319. }
  320. else
  321. {
  322. wcscpy(pwszProp, L"FileDescription");
  323. TESTBOOL(hr, VerQueryValueW(pbFVI, wszQuery, (LPVOID *)&pwszPropVal,
  324. &cb));
  325. if (SUCCEEDED(hr) && cb != 0 && IsValidField(pwszPropVal))
  326. {
  327. wcsncpy(wszName, pwszPropVal, cchName);
  328. wszName[cchName - 1] = L'\0';
  329. goto done;
  330. }
  331. if ((dwMSWin & APP_WINCOMP) == 0)
  332. {
  333. wcscpy(pwszProp, L"ProductName");
  334. TESTBOOL(hr, VerQueryValueW(pbFVI, wszQuery,
  335. (LPVOID *)&pwszPropVal, &cb));
  336. if (SUCCEEDED(hr) && cb != 0 && IsValidField(pwszPropVal))
  337. {
  338. wcsncpy(wszName, pwszPropVal, cchName);
  339. wszName[cchName - 1] = L'\0';
  340. goto done;
  341. }
  342. }
  343. wcscpy(pwszProp, L"InternalName");
  344. TESTBOOL(hr, VerQueryValueW(pbFVI, wszQuery,
  345. (LPVOID *)&pwszPropVal, &cb));
  346. if (SUCCEEDED(hr) && cb != 0 && IsValidField(pwszPropVal))
  347. {
  348. wcsncpy(wszName, pwszPropVal, cchName);
  349. wszName[cchName - 1] = L'\0';
  350. goto done;
  351. }
  352. }
  353. // We didn't find a name string but we've defaulted
  354. // the name and we may have other valid data, so
  355. // return success.
  356. hr = S_OK;
  357. done:
  358. return hr;
  359. }
  360. // **************************************************************************
  361. HRESULT BuildManifestURLs(LPWSTR wszAppName, LPWSTR wszModName,
  362. WORD rgAppVer[4], WORD rgModVer[4], UINT64 pvOffset,
  363. BOOL f64Bit, LPWSTR *ppwszS1, LPWSTR *ppwszS2,
  364. LPWSTR *ppwszCP, BYTE **ppb)
  365. {
  366. HRESULT hr = NOERROR;
  367. LPWSTR pwszApp, pwszMod;
  368. LPWSTR wszStage1, wszStage2, wszCorpPath;
  369. DWORD cbNeeded, cch;
  370. WCHAR *pwsz;
  371. BYTE *pbBuf = NULL;
  372. USE_TRACING("BuildManifestURLs");
  373. VALIDATEPARM(hr, (wszAppName == NULL || wszModName == NULL ||
  374. ppwszS1 == NULL || ppwszS2 == NULL || ppwszCP == NULL ||
  375. ppb == NULL));
  376. if (FAILED(hr))
  377. goto done;
  378. *ppb = NULL;
  379. *ppwszS1 = NULL;
  380. *ppwszS2 = NULL;
  381. *ppwszCP = NULL;
  382. // hexify the app name if necessary
  383. if (IsASCII(wszAppName))
  384. {
  385. pwszApp = wszAppName;
  386. }
  387. else
  388. {
  389. cch = (4 * wcslen(wszAppName) + 1);
  390. __try { pwszApp = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  391. __except(EXCEPTION_STACK_OVERFLOW) { pwszApp = NULL; }
  392. if (pwszApp != NULL)
  393. {
  394. if (TransformForWire(wszAppName, pwszApp, cch) == FALSE)
  395. *pwszApp = L'\0';
  396. }
  397. else
  398. {
  399. pwszApp = wszAppName;
  400. }
  401. }
  402. // hexify the module name if necessary
  403. if (IsASCII(wszModName))
  404. {
  405. pwszMod = wszModName;
  406. }
  407. else
  408. {
  409. cch = (4 * wcslen(wszModName) + 1);
  410. __try { pwszMod = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  411. __except(EXCEPTION_STACK_OVERFLOW) { pwszMod = NULL; }
  412. if (pwszMod != NULL)
  413. {
  414. if (TransformForWire(wszModName, pwszMod, cch) == FALSE)
  415. *pwszMod = L'\0';
  416. }
  417. else
  418. {
  419. pwszMod = wszModName;
  420. }
  421. }
  422. // determine how big of a buffer we need & alloc it
  423. #ifdef _WIN64
  424. if (f64Bit)
  425. cbNeeded = c_cbFaultBlob64 + 3 * (wcslen(pwszMod) + wcslen(pwszApp)) * sizeof(WCHAR);
  426. else
  427. #endif
  428. cbNeeded = c_cbFaultBlob32 + 3 * (wcslen(pwszMod) + wcslen(pwszApp)) * sizeof(WCHAR);
  429. pbBuf = (BYTE *)MyAlloc(cbNeeded);
  430. VALIDATEEXPR(hr, (pbBuf == NULL), E_OUTOFMEMORY);
  431. if (FAILED(hr))
  432. goto done;
  433. // write out the actual strings
  434. #ifdef _WIN64
  435. if (f64Bit)
  436. {
  437. wszStage1 = (WCHAR *)pbBuf;
  438. cch = swprintf(wszStage1, c_wszManFS164,
  439. pwszApp,
  440. rgAppVer[0], rgAppVer[1], rgAppVer[2], rgAppVer[3],
  441. pwszMod,
  442. rgModVer[0], rgModVer[1], rgModVer[2], rgModVer[3],
  443. pvOffset);
  444. wszStage2 = wszStage1 + cch + 1;
  445. cch = swprintf(wszStage2, c_wszManFS264,
  446. pwszApp,
  447. rgAppVer[0], rgAppVer[1], rgAppVer[2], rgAppVer[3],
  448. pwszMod,
  449. rgModVer[0], rgModVer[1], rgModVer[2], rgModVer[3],
  450. pvOffset);
  451. wszCorpPath = wszStage2 + cch + 1;
  452. cch = swprintf(wszCorpPath, c_wszManFCP64,
  453. pwszApp,
  454. rgAppVer[0], rgAppVer[1], rgAppVer[2], rgAppVer[3],
  455. pwszMod,
  456. rgModVer[0], rgModVer[1], rgModVer[2], rgModVer[3],
  457. pvOffset);
  458. }
  459. else
  460. #endif
  461. {
  462. wszStage1 = (WCHAR *)pbBuf;
  463. cch = swprintf(wszStage1, c_wszManFS132,
  464. pwszApp,
  465. rgAppVer[0], rgAppVer[1], rgAppVer[2], rgAppVer[3],
  466. pwszMod,
  467. rgModVer[0], rgModVer[1], rgModVer[2], rgModVer[3],
  468. (LPVOID)pvOffset);
  469. wszStage2 = wszStage1 + cch + 1;
  470. cch = swprintf(wszStage2, c_wszManFS232,
  471. pwszApp,
  472. rgAppVer[0], rgAppVer[1], rgAppVer[2], rgAppVer[3],
  473. pwszMod,
  474. rgModVer[0], rgModVer[1], rgModVer[2], rgModVer[3],
  475. (LPVOID)pvOffset);
  476. wszCorpPath = wszStage2 + cch + 1;
  477. cch = swprintf(wszCorpPath, c_wszManFCP32,
  478. pwszApp,
  479. rgAppVer[0], rgAppVer[1], rgAppVer[2], rgAppVer[3],
  480. pwszMod,
  481. rgModVer[0], rgModVer[1], rgModVer[2], rgModVer[3],
  482. (LPVOID)pvOffset);
  483. }
  484. // need to convert all '.'s to '_'s cuz URLs don't like dots.
  485. for (pwsz = wszStage1; *pwsz != L'\0'; pwsz++)
  486. {
  487. if (*pwsz == L'.')
  488. *pwsz = L'_';
  489. }
  490. // ok, on the end of the stage 1 URL is a .htm, and we really don't want to
  491. // convert that '.' to a '_', so back up and reconvert it back to a '.'
  492. pwsz -= 4;
  493. if (*pwsz == L'_')
  494. *pwsz = L'.';
  495. *ppwszS1 = wszStage1;
  496. *ppwszS2 = wszStage2;
  497. *ppwszCP = wszCorpPath;
  498. *ppb = pbBuf;
  499. pbBuf = NULL;
  500. done:
  501. if (pbBuf != NULL)
  502. MyFree(pbBuf);
  503. return hr;
  504. }
  505. // **************************************************************************
  506. HRESULT GetExePath(HANDLE hProc, LPWSTR wszPath, DWORD cchPath)
  507. {
  508. USE_TRACING("GetExePath");
  509. pfn_GETMODULEFILENAMEEXW pfn;
  510. HRESULT hr = NOERROR;
  511. HMODULE hmod = NULL;
  512. DWORD dw;
  513. VALIDATEPARM(hr, (wszPath == NULL || hProc == NULL || cchPath < MAX_PATH));
  514. if (FAILED(hr))
  515. goto done;
  516. hmod = MySafeLoadLibrary(L"psapi.dll");
  517. TESTBOOL(hr, (hmod != NULL));
  518. if (FAILED(hr))
  519. goto done;
  520. pfn = (pfn_GETMODULEFILENAMEEXW)GetProcAddress(hmod, "GetModuleFileNameExW");
  521. TESTBOOL(hr, (pfn != NULL));
  522. if (FAILED(hr))
  523. goto done;
  524. TESTBOOL(hr, ((*pfn)(hProc, NULL, wszPath, cchPath) != 0));
  525. if (FAILED(hr))
  526. goto done;
  527. done:
  528. dw = GetLastError();
  529. if (hmod != NULL)
  530. FreeLibrary(hmod);
  531. SetLastError(dw);
  532. return hr;
  533. }
  534. // ***************************************************************************
  535. DWORD GetAppCompatFlag(LPCWSTR wszPath, LPCWSTR wszSysDir, LPWSTR wszBuffer)
  536. {
  537. LPWSTR pwszFile, wszSysDirLocal = NULL, pwszDir = NULL;
  538. DWORD dwOpt = (DWORD)-1;
  539. DWORD cchPath, cch;
  540. UINT uiDrive;
  541. if (wszPath == NULL || wszBuffer == NULL || wszSysDir == NULL)
  542. goto done;
  543. // can't be a valid path if it's less than 3 characters long
  544. cchPath = wcslen(wszPath);
  545. if (cchPath < 3)
  546. goto done;
  547. // do we have a UNC path?
  548. if (wszPath[0] == L'\\' && wszPath[1] == L'\\')
  549. {
  550. dwOpt = GRABMI_FILTER_THISFILEONLY;
  551. goto done;
  552. }
  553. // ok, maybe a remote mapped path or system32?
  554. wcscpy(wszBuffer, wszPath);
  555. for(pwszFile = wszBuffer + cchPath;
  556. *pwszFile != L'\\' && pwszFile > wszBuffer;
  557. pwszFile--);
  558. if (*pwszFile == L'\\')
  559. *pwszFile = L'\0';
  560. else
  561. goto done;
  562. cch = wcslen(wszSysDir) + 1;
  563. __try { wszSysDirLocal = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  564. __except(EXCEPTION_EXECUTE_HANDLER) { wszSysDirLocal = NULL; }
  565. if (wszSysDirLocal == NULL)
  566. goto done;
  567. // see if it's in system32 or in any parent folder of it.
  568. wcscpy(wszSysDirLocal, wszSysDir);
  569. pwszDir = wszSysDirLocal + cch;
  570. do
  571. {
  572. if (_wcsicmp(wszBuffer, wszSysDirLocal) == 0)
  573. {
  574. dwOpt = GRABMI_FILTER_SYSTEM;
  575. goto done;
  576. }
  577. for(;
  578. *pwszDir != L'\\' && pwszDir > wszSysDirLocal;
  579. pwszDir--);
  580. if (*pwszDir == L'\\')
  581. *pwszDir = L'\0';
  582. }
  583. while (pwszDir > wszSysDirLocal);
  584. // is the file sitting in the root of a drive?
  585. if (pwszFile <= &wszBuffer[3])
  586. {
  587. dwOpt = GRABMI_FILTER_THISFILEONLY;
  588. goto done;
  589. }
  590. // well, if we've gotten this far, then the path is in the form of
  591. // X:\<something>, so cut off the <something> and find out if we're on
  592. // a mapped drive or not
  593. *pwszFile = L'\\';
  594. wszBuffer[3] = L'\0';
  595. switch(GetDriveTypeW(wszBuffer))
  596. {
  597. case DRIVE_UNKNOWN:
  598. case DRIVE_NO_ROOT_DIR:
  599. goto done;
  600. case DRIVE_REMOTE:
  601. dwOpt = GRABMI_FILTER_THISFILEONLY;
  602. goto done;
  603. }
  604. dwOpt = GRABMI_FILTER_PRIVACY;
  605. done:
  606. return dwOpt;
  607. }
  608. // ***************************************************************************
  609. typedef BOOL (APIENTRY *pfn_SDBGRABMATCHINGINFOW)(LPCWSTR, DWORD, LPCWSTR);
  610. BOOL GetAppCompatData(LPCWSTR wszAppPath, LPCWSTR wszModPath, LPCWSTR wszFile)
  611. {
  612. pfn_SDBGRABMATCHINGINFOW pfn = NULL;
  613. HMODULE hmod = NULL;
  614. LPWSTR pwszPath = NULL, pwszFile = NULL;
  615. WCHAR *pwsz;
  616. DWORD cchSysDir, cchNeed, cchApp = 0, cchMod = 0;
  617. DWORD dwModOpt = (DWORD)-1, dwAppOpt = (DWORD)-1;
  618. DWORD dwOpt;
  619. BOOL fRet = FALSE;
  620. HRESULT hr;
  621. USE_TRACING("GetAppCompatData");
  622. VALIDATEPARM(hr, (wszAppPath == NULL || wszFile == NULL ||
  623. wszAppPath[0] == L'\0' || wszFile[0] == L'\0'));
  624. if (FAILED(hr))
  625. {
  626. SetLastError(ERROR_INVALID_PARAMETER);
  627. goto done;
  628. }
  629. // load the apphelp dll.
  630. cchNeed = GetSystemDirectoryW(NULL, 0);
  631. if (cchNeed == 0)
  632. goto done;
  633. if (sizeofSTRW(L"\\apphelp.dll") > sizeofSTRW(L"\\kernel32.dll"))
  634. cchNeed += (sizeofSTRW(L"\\apphelp.dll") + 8);
  635. else
  636. cchNeed += (sizeofSTRW(L"\\kernel32.dll") + 8);
  637. __try { pwszPath = (WCHAR *)_alloca(cchNeed * sizeof(WCHAR)); }
  638. __except(EXCEPTION_STACK_OVERFLOW) { pwszPath = NULL; }
  639. if (pwszPath == NULL)
  640. {
  641. SetLastError(ERROR_OUTOFMEMORY);
  642. goto done;
  643. }
  644. cchSysDir = GetSystemDirectoryW(pwszPath, cchNeed);
  645. if (cchSysDir == 0)
  646. goto done;
  647. cchApp = wcslen(wszAppPath);
  648. if (wszModPath != NULL)
  649. cchMod = wcslen(wszModPath);
  650. cchNeed = MyMax(cchApp, cchMod) + 8;
  651. __try { pwszFile = (WCHAR *)_alloca(cchNeed * sizeof(WCHAR)); }
  652. __except(EXCEPTION_STACK_OVERFLOW) { pwszFile = NULL; }
  653. if (pwszFile == NULL)
  654. {
  655. SetLastError(ERROR_OUTOFMEMORY);
  656. goto done;
  657. }
  658. // find out the app & module option flag
  659. dwAppOpt = GetAppCompatFlag(wszAppPath, pwszPath, pwszFile);
  660. if (wszModPath != NULL && wszModPath[0] != L'\0' &&
  661. _wcsicmp(wszModPath, wszAppPath) != 0)
  662. {
  663. #if 0
  664. dwModOpt = GetAppCompatFlag(wszModPath, pwszPath, pwszFile);
  665. // no need to grab system data twice. If we're already grabbing
  666. // it for the app, don't grab it for the module. Yes, we may end
  667. // up grabbing the mod twice if it happens to be one of the system
  668. // modules, but that's ok.
  669. if (dwModOpt == GRABMI_FILTER_SYSTEM &&
  670. dwAppOpt == GRABMI_FILTER_SYSTEM)
  671. dwModOpt = GRABMI_FILTER_THISFILEONLY;
  672. #else
  673. dwModOpt = GRABMI_FILTER_THISFILEONLY;
  674. #endif
  675. }
  676. // load the libarary
  677. wcscpy(&pwszPath[cchSysDir], L"\\apphelp.dll");
  678. hmod = MySafeLoadLibrary(pwszPath);
  679. if (hmod == NULL)
  680. goto done;
  681. // if we don't find the function, then just bail...
  682. pfn = (pfn_SDBGRABMATCHINGINFOW)GetProcAddress(hmod, "SdbGrabMatchingInfo");
  683. if (pfn == NULL)
  684. goto done;
  685. // call the function to get the app data
  686. if (dwAppOpt != (DWORD)-1)
  687. {
  688. dwOpt = dwAppOpt;
  689. if (dwModOpt != (DWORD)-1 ||
  690. (dwModOpt != GRABMI_FILTER_SYSTEM &&
  691. dwAppOpt != GRABMI_FILTER_SYSTEM))
  692. dwOpt |= GRABMI_FILTER_NOCLOSE;
  693. __try { fRet = (*pfn)(wszAppPath, dwOpt, wszFile); }
  694. __except(EXCEPTION_EXECUTE_HANDLER) { fRet = FALSE; DBG_MSG("GrabAppData crashed");}
  695. if (fRet == FALSE)
  696. goto done;
  697. }
  698. // call the function to get the mod data
  699. if (dwModOpt != (DWORD)-1)
  700. {
  701. dwOpt = dwModOpt;
  702. if (dwAppOpt != (DWORD)-1)
  703. dwOpt |= GRABMI_FILTER_APPEND;
  704. if (dwAppOpt != GRABMI_FILTER_SYSTEM &&
  705. dwModOpt != GRABMI_FILTER_SYSTEM)
  706. dwOpt |= GRABMI_FILTER_NOCLOSE;
  707. __try { fRet = (*pfn)(wszModPath, dwOpt, wszFile); }
  708. __except(EXCEPTION_EXECUTE_HANDLER) { fRet = FALSE; DBG_MSG("GrabModData crashed");}
  709. if (fRet == FALSE)
  710. goto done;
  711. }
  712. // call the function to get the data for kernel32
  713. if (dwModOpt != GRABMI_FILTER_SYSTEM &&
  714. dwAppOpt != GRABMI_FILTER_SYSTEM)
  715. {
  716. wcscpy(&pwszPath[cchSysDir], L"\\kernel32.dll");
  717. dwOpt = GRABMI_FILTER_THISFILEONLY;
  718. if (dwModOpt != (DWORD)-1 || dwAppOpt != (DWORD)-1)
  719. dwOpt |= GRABMI_FILTER_APPEND;
  720. __try { fRet = (*pfn)(pwszPath, dwOpt, wszFile); }
  721. __except(EXCEPTION_EXECUTE_HANDLER) { fRet = FALSE; DBG_MSG("GrabKrnlData crashed");}
  722. if (fRet == FALSE)
  723. goto done;
  724. }
  725. done:
  726. if (fRet == FALSE)
  727. DeleteFileW(wszFile);
  728. if (hmod != NULL)
  729. {
  730. __try { FreeLibrary(hmod); }
  731. __except(EXCEPTION_EXECUTE_HANDLER) { }
  732. }
  733. return fRet;
  734. }
  735. //////////////////////////////////////////////////////////////////////////////
  736. // ThreadStuff
  737. // ***************************************************************************
  738. BOOL FreezeAllThreads(DWORD dwpid, DWORD dwtidFilter, SSuspendThreads *pst)
  739. {
  740. THREADENTRY32 te;
  741. HANDLE hTokenImp = NULL;
  742. HANDLE hsnap = (HANDLE)-1, hth = NULL;
  743. HANDLE *rgh = NULL;
  744. DWORD dwtid = GetCurrentThreadId();
  745. DWORD cThreads = 0, cSlots = 0, dw;
  746. BOOL fContinue = FALSE, fRet = FALSE;
  747. if (pst == NULL)
  748. {
  749. SetLastError(ERROR_INVALID_PARAMETER);
  750. goto done;
  751. }
  752. pst->rghThreads = NULL;
  753. pst->cThreads = 0;
  754. // if we have an impersonation token on this thread, revert it back to
  755. // full access cuz otherwise we could fail in the OpenThread API below.
  756. // Even if we fail, we'll still try all the rest of the stuff below.
  757. if (OpenThreadToken(GetCurrentThread(), TOKEN_READ | TOKEN_IMPERSONATE,
  758. TRUE, &hTokenImp))
  759. RevertToSelf();
  760. hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwpid);
  761. if (hsnap == (HANDLE)-1)
  762. goto done;
  763. ZeroMemory(&te, sizeof(te));
  764. te.dwSize = sizeof(te);
  765. fContinue = Thread32First(hsnap, &te);
  766. while(fContinue)
  767. {
  768. // only want to freeze threads in my process (not including the
  769. // currently executing one, of course, since that would bring
  770. // everything to a grinding halt.)
  771. if (te.th32OwnerProcessID == dwpid && te.th32ThreadID != dwtidFilter)
  772. {
  773. hth = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID);
  774. if (hth != NULL)
  775. {
  776. if (cSlots == cThreads)
  777. {
  778. HANDLE *rghNew = NULL;
  779. DWORD cNew = (cSlots == 0) ? 8 : cSlots * 2;
  780. rghNew = (HANDLE *)MyAlloc(cNew * sizeof(HANDLE));
  781. if (rghNew == NULL)
  782. {
  783. SetLastError(ERROR_OUTOFMEMORY);
  784. goto done;
  785. }
  786. if (rgh != NULL)
  787. CopyMemory(rghNew, rgh, cSlots * sizeof(HANDLE));
  788. MyFree(rgh);
  789. rgh = rghNew;
  790. cSlots = cNew;
  791. }
  792. // if the suspend fails, then just don't add it to the
  793. // list...
  794. if (SuspendThread(hth) == (DWORD)-1)
  795. CloseHandle(hth);
  796. else
  797. rgh[cThreads++] = hth;
  798. hth = NULL;
  799. }
  800. }
  801. fContinue = Thread32Next(hsnap, &te);
  802. }
  803. pst->rghThreads = rgh;
  804. pst->cThreads = cThreads;
  805. SetLastError(0);
  806. fRet = TRUE;
  807. done:
  808. dw = GetLastError();
  809. if (hTokenImp != NULL)
  810. {
  811. SetThreadToken(NULL, hTokenImp);
  812. CloseHandle(hTokenImp);
  813. }
  814. if (fRet == FALSE && rgh != NULL)
  815. {
  816. DWORD i;
  817. for (i = 0; i < cThreads; i++)
  818. {
  819. if (rgh[i] != NULL)
  820. {
  821. ResumeThread(rgh[i]);
  822. CloseHandle(rgh[i]);
  823. }
  824. }
  825. MyFree(rgh);
  826. }
  827. // MSDN says to use CloseToolhelp32Snapshot() to close the snapshot.
  828. // the tlhelp32.h header file says to use CloseHandle & doens't provide
  829. // a CloseToolhelp32Snapshot() function. Hence, I'm using CloseHandle
  830. // for now.
  831. if (hsnap != (HANDLE)-1)
  832. CloseHandle(hsnap);
  833. SetLastError(dw);
  834. return fRet;
  835. }
  836. // ***************************************************************************
  837. BOOL ThawAllThreads(SSuspendThreads *pst)
  838. {
  839. DWORD i;
  840. if (pst == NULL)
  841. {
  842. SetLastError(ERROR_INVALID_PARAMETER);
  843. return FALSE;
  844. }
  845. if (pst->rghThreads == NULL)
  846. return TRUE;
  847. for (i = 0; i < pst->cThreads; i++)
  848. {
  849. if (pst->rghThreads[i] != NULL)
  850. {
  851. ResumeThread(pst->rghThreads[i]);
  852. CloseHandle(pst->rghThreads[i]);
  853. }
  854. }
  855. MyFree(pst->rghThreads);
  856. pst->rghThreads = NULL;
  857. pst->cThreads = 0;
  858. SetLastError(0);
  859. return TRUE;
  860. }
  861. //////////////////////////////////////////////////////////////////////////////
  862. // Minidump
  863. // ***************************************************************************
  864. BOOL WINAPI MDCallback(void *pvCallbackParam,
  865. CONST PMINIDUMP_CALLBACK_INPUT pCallbackInput,
  866. PMINIDUMP_CALLBACK_OUTPUT pCallbackOutput)
  867. {
  868. // USE_TRACING("MDCallback");
  869. SMDumpOptions *psmdo = (SMDumpOptions *)pvCallbackParam;
  870. if (pCallbackInput == NULL || pCallbackOutput == NULL || psmdo == NULL)
  871. return TRUE;
  872. // what did we get called back for?
  873. switch(pCallbackInput->CallbackType)
  874. {
  875. case ModuleCallback:
  876. pCallbackOutput->ModuleWriteFlags = psmdo->ulMod;
  877. // only need to do this extra work if we're getting a minidump
  878. if ((psmdo->dfOptions & dfCollectSig) != 0)
  879. {
  880. MINIDUMP_MODULE_CALLBACK *pmmc = &pCallbackInput->Module;
  881. LPWSTR pwsz = NULL;
  882. // err, if we don't have a path, can't do squat, so skip it
  883. if (pmmc->FullPath != NULL && pmmc->FullPath[0] != L'\0')
  884. {
  885. // is it the app?
  886. if (_wcsicmp(pmmc->FullPath, psmdo->wszAppFullPath) == 0)
  887. {
  888. pCallbackOutput->ModuleWriteFlags |= ModuleWriteDataSeg;
  889. psmdo->rgAppVer[0] = HIWORD(pmmc->VersionInfo.dwFileVersionMS);
  890. psmdo->rgAppVer[1] = LOWORD(pmmc->VersionInfo.dwFileVersionMS);
  891. psmdo->rgAppVer[2] = HIWORD(pmmc->VersionInfo.dwFileVersionLS);
  892. psmdo->rgAppVer[3] = LOWORD(pmmc->VersionInfo.dwFileVersionLS);
  893. // get a pointer to the end of the modulename string
  894. for(pwsz = pmmc->FullPath + wcslen(pmmc->FullPath);
  895. *pwsz != L'\\' && pwsz > pmmc->FullPath;
  896. pwsz--);
  897. if (*pwsz == L'\\')
  898. pwsz++;
  899. // get the app name, if we can make it fit
  900. if (wcslen(pwsz) < sizeofSTRW(psmdo->wszApp))
  901. wcscpy(psmdo->wszApp, pwsz);
  902. else
  903. wcscpy(psmdo->wszApp, L"unknown");
  904. }
  905. }
  906. // is it the module?
  907. if (psmdo->pvFaultAddr >= pmmc->BaseOfImage &&
  908. psmdo->pvFaultAddr <= pmmc->BaseOfImage + pmmc->SizeOfImage)
  909. {
  910. pCallbackOutput->ModuleWriteFlags |= ModuleWriteDataSeg;
  911. psmdo->rgModVer[0] = HIWORD(pmmc->VersionInfo.dwFileVersionMS);
  912. psmdo->rgModVer[1] = LOWORD(pmmc->VersionInfo.dwFileVersionMS);
  913. psmdo->rgModVer[2] = HIWORD(pmmc->VersionInfo.dwFileVersionLS);
  914. psmdo->rgModVer[3] = LOWORD(pmmc->VersionInfo.dwFileVersionLS);
  915. if (pwsz == NULL)
  916. {
  917. // get a pointer to the end of the modulename string
  918. for(pwsz = pmmc->FullPath + wcslen(pmmc->FullPath);
  919. *pwsz != L'\\' && pwsz > pmmc->FullPath;
  920. pwsz--);
  921. if (*pwsz == L'\\')
  922. pwsz++;
  923. }
  924. if (pwsz != NULL && wcslen(pwsz) < sizeofSTRW(psmdo->wszMod))
  925. {
  926. // get the full path if we can make it fit
  927. if (wcslen(pmmc->FullPath) < sizeofSTRW(psmdo->wszModFullPath))
  928. wcscpy(psmdo->wszModFullPath, pmmc->FullPath);
  929. else
  930. psmdo->wszModFullPath[0] = L'\0';
  931. // get the module name, if we can make it fit
  932. if (wcslen(pwsz) < sizeofSTRW(psmdo->wszMod))
  933. wcscpy(psmdo->wszMod, pwsz);
  934. else
  935. wcscpy(psmdo->wszMod, L"unknown");
  936. psmdo->pvOffset = psmdo->pvFaultAddr - pmmc->BaseOfImage;
  937. }
  938. }
  939. }
  940. break;
  941. case ThreadCallback:
  942. // are we collecting info for a single thread only?
  943. if ((psmdo->dfOptions & dfFilterThread) != 0)
  944. {
  945. if (psmdo->dwThreadID == pCallbackInput->Thread.ThreadId)
  946. pCallbackOutput->ThreadWriteFlags = psmdo->ulThread;
  947. else
  948. pCallbackOutput->ThreadWriteFlags = 0;
  949. }
  950. // or are we collecting special info for a single thread?
  951. else if ((psmdo->dfOptions & dfFilterThreadEx) != 0)
  952. {
  953. if (psmdo->dwThreadID == pCallbackInput->Thread.ThreadId)
  954. pCallbackOutput->ThreadWriteFlags = psmdo->ulThreadEx;
  955. else
  956. pCallbackOutput->ThreadWriteFlags = psmdo->ulThread;
  957. }
  958. // or maybe we're just getting a generic ol' minidump...
  959. else
  960. {
  961. pCallbackOutput->ThreadWriteFlags = psmdo->ulThread;
  962. }
  963. break;
  964. default:
  965. break;
  966. }
  967. return TRUE;
  968. }
  969. // **************************************************************************
  970. #ifndef MANIFEST_HEAP
  971. BOOL InternalGenerateMinidump(HANDLE hProc, DWORD dwpid, HANDLE hFile,
  972. SMDumpOptions *psmdo, LPCWSTR wszPath)
  973. #else
  974. BOOL InternalGenerateMinidumpEx(HANDLE hProc, DWORD dwpid, HANDLE hFile,
  975. SMDumpOptions *psmdo, LPCWSTR wszPath, BOOL f64bit)
  976. #endif // MANIFEST_HEAP
  977. {
  978. #ifdef _WIN64
  979. USE_TRACING("InternalGenerateMinidumpEx64(handle)");
  980. #else
  981. USE_TRACING("InternalGenerateMinidumpEx(handle)");
  982. #endif
  983. SMDumpOptions smdo;
  984. HRESULT hr = NULL;
  985. LPWSTR wszMod = NULL;
  986. DWORD cch, cchNeed;
  987. BOOL fRet = FALSE;
  988. VALIDATEPARM(hr, (hProc == NULL || hFile == NULL ||
  989. hFile == INVALID_HANDLE_VALUE));
  990. if (FAILED(hr))
  991. {
  992. SetLastError(ERROR_INVALID_PARAMETER);
  993. return FALSE;
  994. }
  995. cchNeed = GetSystemDirectoryW(NULL, 0);
  996. if (cchNeed == 0)
  997. return FALSE;
  998. cchNeed += (sizeofSTRW(c_wszDbgHelpDll) + 8);
  999. __try { wszMod = (LPWSTR)_alloca(cchNeed * sizeof(WCHAR)); }
  1000. __except(EXCEPTION_EXECUTE_HANDLER) { wszMod = NULL; }
  1001. if (wszMod == NULL)
  1002. {
  1003. SetLastError(ERROR_OUTOFMEMORY);
  1004. goto done;
  1005. }
  1006. cch = GetSystemDirectoryW(wszMod, cchNeed);
  1007. if (cch == 0)
  1008. return FALSE;
  1009. if (*(wszMod + cch - 1) == L'\\')
  1010. *(wszMod + cch - 1) = L'\0';
  1011. // default is to write everything for everything
  1012. if (psmdo == NULL)
  1013. {
  1014. ZeroMemory(&smdo, sizeof(smdo));
  1015. smdo.ulThread = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext;
  1016. smdo.ulMod = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteDataSeg;
  1017. psmdo = &smdo;
  1018. }
  1019. // if we're in the same process, we can't call the minidump APIs directly
  1020. // cuz we'll hang the process.
  1021. if (dwpid == GetCurrentProcessId())
  1022. {
  1023. PROCESS_INFORMATION pi;
  1024. STARTUPINFOW si;
  1025. LPWSTR wszCmdLine = NULL;
  1026. HANDLE hmem = NULL;
  1027. LPVOID pvmem = NULL;
  1028. DWORD dw;
  1029. if (wszPath == NULL)
  1030. {
  1031. SetLastError(ERROR_INVALID_PARAMETER);
  1032. goto done;
  1033. }
  1034. // 32 is the max size of a 64 bit decimal # & a 32 bit decimal #
  1035. cchNeed = sizeofSTRW(c_wszDRCmdLineMD) + cch + wcslen(wszPath) + 32;
  1036. __try { wszCmdLine = (LPWSTR)_alloca(cchNeed * sizeof(WCHAR)); }
  1037. __except(EXCEPTION_STACK_OVERFLOW) { wszCmdLine = NULL; }
  1038. TESTBOOL(hr, wszCmdLine != NULL);
  1039. if (FAILED(hr))
  1040. {
  1041. SetLastError(ERROR_OUTOFMEMORY);
  1042. goto done;
  1043. }
  1044. hmem = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
  1045. 0, sizeof(smdo), NULL);
  1046. TESTBOOL(hr, hmem != NULL);
  1047. if (FAILED(hr))
  1048. goto done;
  1049. ZeroMemory(&pi, sizeof(pi));
  1050. ZeroMemory(&si, sizeof(si));
  1051. pvmem = MapViewOfFile(hmem, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0);
  1052. TESTBOOL(hr, pvmem != NULL);
  1053. if (FAILED(hr))
  1054. goto doneProcSpawn;
  1055. si.cb = sizeof(si);
  1056. swprintf(wszCmdLine, c_wszDRCmdLineMD, wszMod, dwpid, wszPath, hmem);
  1057. if (CreateProcessW(NULL, wszCmdLine, NULL, NULL, TRUE, 0, NULL,
  1058. wszMod, &si, &pi))
  1059. {
  1060. if (pi.hThread != NULL)
  1061. CloseHandle(pi.hThread);
  1062. if (!pi.hProcess)
  1063. {
  1064. DWORD dwAwShit = GetLastError();
  1065. ErrorTrace(0, "Spawned process died: \'%S\', err=0x%x", wszCmdLine, dwAwShit);
  1066. SetLastError(dwAwShit);
  1067. }
  1068. // wait 2m for the dump to be complete
  1069. if (pi.hProcess != NULL &&
  1070. WaitForSingleObject(pi.hProcess, 120000) == WAIT_OBJECT_0)
  1071. fRet = TRUE;
  1072. }
  1073. doneProcSpawn:
  1074. dw = GetLastError();
  1075. if (pvmem != NULL)
  1076. UnmapViewOfFile(pvmem);
  1077. if (hmem != NULL)
  1078. CloseHandle(hmem);
  1079. if (pi.hProcess != NULL)
  1080. CloseHandle(pi.hProcess);
  1081. SetLastError(dw);
  1082. }
  1083. else
  1084. {
  1085. MINIDUMP_EXCEPTION_INFORMATION mei, *pmei = NULL;
  1086. MINIDUMP_CALLBACK_INFORMATION mci;
  1087. DUMPWRITE_FN pfn;
  1088. HMODULE hmod = NULL;
  1089. ZeroMemory(&mci, sizeof(mci));
  1090. mci.CallbackRoutine = MDCallback;
  1091. mci.CallbackParam = psmdo;
  1092. // if we got exception paramters in the blob, use 'em...
  1093. if (psmdo->pEP != NULL)
  1094. {
  1095. ZeroMemory(&mei, sizeof(mei));
  1096. mei.ExceptionPointers = (PEXCEPTION_POINTERS)(DWORD_PTR)psmdo->pEP;
  1097. mei.ClientPointers = psmdo->fEPClient;
  1098. mei.ThreadId = psmdo->dwThreadID;
  1099. pmei = &mei;
  1100. }
  1101. wcscat(wszMod, c_wszDbgHelpDll);
  1102. hmod = MySafeLoadLibrary(wszMod);
  1103. if (hmod != NULL)
  1104. {
  1105. pfn = (DUMPWRITE_FN)GetProcAddress(hmod, "MiniDumpWriteDump");
  1106. if (pfn != NULL)
  1107. {
  1108. DWORD dwEC;
  1109. MINIDUMP_TYPE MiniDumpType = MiniDumpNormal;
  1110. #ifdef MANIFEST_HEAP
  1111. if (psmdo->fIncludeHeap)
  1112. {
  1113. MiniDumpType = (MINIDUMP_TYPE) (MiniDumpWithDataSegs |
  1114. MiniDumpWithProcessThreadData |
  1115. MiniDumpWithHandleData |
  1116. MiniDumpWithPrivateReadWriteMemory |
  1117. MiniDumpWithUnloadedModules);
  1118. } else
  1119. {
  1120. MiniDumpType = (MINIDUMP_TYPE) (MiniDumpWithDataSegs |
  1121. MiniDumpWithUnloadedModules);
  1122. }
  1123. #endif // MANIFEST_HEAP
  1124. fRet = (pfn)(hProc, dwpid, hFile, MiniDumpType,
  1125. pmei, NULL, &mci);
  1126. if (!fRet)
  1127. {
  1128. ErrorTrace(0, "MiniDumpWriteDump failed: DumpType=0x%x, err=0x%x", MiniDumpType, GetLastError());
  1129. fRet = FALSE;
  1130. }
  1131. }
  1132. FreeLibrary(hmod);
  1133. }
  1134. }
  1135. done:
  1136. return fRet;
  1137. }
  1138. // **************************************************************************
  1139. #ifndef MANIFEST_HEAP
  1140. BOOL InternalGenerateMinidump(HANDLE hProc, DWORD dwpid, LPCWSTR wszPath,
  1141. SMDumpOptions *psmdo)
  1142. #else
  1143. BOOL InternalGenerateMinidump(HANDLE hProc, DWORD dwpid, LPCWSTR wszPath,
  1144. SMDumpOptions *psmdo, BOOL f64bit)
  1145. #endif
  1146. {
  1147. #ifdef _WIN64
  1148. USE_TRACING("InternalGenerateMinidump64(path)");
  1149. #else
  1150. USE_TRACING("InternalGenerateMinidump(path)");
  1151. #endif
  1152. HRESULT hr = NOERROR;
  1153. HANDLE hFile = INVALID_HANDLE_VALUE;
  1154. BOOL fRet = FALSE;
  1155. VALIDATEPARM(hr, (hProc == NULL || wszPath == NULL));
  1156. if (FAILED(hr))
  1157. {
  1158. SetLastError(ERROR_INVALID_PARAMETER);
  1159. return FALSE;
  1160. }
  1161. hFile = CreateFileW(wszPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0,
  1162. NULL);
  1163. TESTBOOL(hr, (hFile != INVALID_HANDLE_VALUE));
  1164. if (FAILED(hr))
  1165. return FALSE;
  1166. #ifdef MANIFEST_HEAP
  1167. fRet = InternalGenerateMinidumpEx(hProc, dwpid, hFile, psmdo, wszPath, f64bit);
  1168. #else
  1169. fRet = InternalGenerateMinidump(hProc, dwpid, hFile, psmdo, wszPath);
  1170. #endif
  1171. CloseHandle(hFile);
  1172. return fRet;
  1173. }
  1174. #ifdef MANIFEST_HEAP
  1175. // This generates a triage minidump on the given wszPath and then generates a
  1176. // full minidump on wszPath with c_wszHeapDumpSuffix
  1177. BOOL
  1178. InternalGenFullAndTriageMinidumps(HANDLE hProc, DWORD dwpid, LPCWSTR wszPath,
  1179. HANDLE hFile, SMDumpOptions *psmdo, BOOL f64bit)
  1180. {
  1181. #ifdef _WIN64
  1182. USE_TRACING("InternalGenFullAndTriageMinidumps(path)");
  1183. #else
  1184. USE_TRACING("InternalGenFullAndTriageMinidumps(path)");
  1185. #endif
  1186. HRESULT hr = NOERROR;
  1187. BOOL fRet = FALSE;
  1188. LPWSTR wszFullMinidump = NULL;
  1189. DWORD cch;
  1190. SMDumpOptions smdoFullMini;
  1191. VALIDATEPARM(hr, (hProc == NULL || wszPath == NULL));
  1192. if (FAILED(hr))
  1193. {
  1194. SetLastError(ERROR_INVALID_PARAMETER);
  1195. return FALSE;
  1196. }
  1197. if (hFile)
  1198. {
  1199. fRet = InternalGenerateMinidumpEx(hProc, dwpid, hFile, psmdo, wszPath, f64bit);
  1200. } else
  1201. {
  1202. fRet = InternalGenerateMinidump(hProc, dwpid, wszPath, psmdo, f64bit);
  1203. }
  1204. if (!fRet)
  1205. {
  1206. return fRet;
  1207. }
  1208. cch = wcslen(wszPath) + sizeofSTRW(c_wszHeapDumpSuffix);
  1209. __try { wszFullMinidump = (WCHAR *)_alloca(cch * sizeof(WCHAR)); }
  1210. __except(EXCEPTION_STACK_OVERFLOW) { wszFullMinidump = NULL; }
  1211. if (wszFullMinidump)
  1212. {
  1213. LPWSTR wszFileExt = NULL;
  1214. ZeroMemory(&smdoFullMini, sizeof(SMDumpOptions));
  1215. memcpy(&smdoFullMini, psmdo, sizeof(SMDumpOptions));
  1216. // Build Dump-with-heap path
  1217. wcsncpy(wszFullMinidump, wszPath, cch);
  1218. wszFileExt = wszFullMinidump + wcslen(wszFullMinidump) - sizeofSTRW(c_wszDumpSuffix) + 1;
  1219. if (!wcscmp(wszFileExt, c_wszDumpSuffix))
  1220. {
  1221. *wszFileExt = L'\0';
  1222. }
  1223. wcsncat(wszFullMinidump, c_wszHeapDumpSuffix, cch);
  1224. smdoFullMini.fIncludeHeap = TRUE;
  1225. fRet = InternalGenerateMinidump(hProc, dwpid, wszFullMinidump, &smdoFullMini, f64bit);
  1226. }
  1227. return fRet;
  1228. }
  1229. BOOL
  1230. CopyFullAndTriageMiniDumps(
  1231. LPWSTR pwszTriageDumpFrom,
  1232. LPWSTR pwszTriageDumpTo
  1233. )
  1234. {
  1235. BOOL fRet;
  1236. LPWSTR wszFullMinidumpFrom = NULL, wszFullMinidumpTo = NULL;
  1237. DWORD cch;
  1238. fRet = CopyFileW(pwszTriageDumpFrom, pwszTriageDumpTo, FALSE);
  1239. if (fRet)
  1240. {
  1241. LPWSTR wszFileExt;
  1242. cch = wcslen(pwszTriageDumpFrom) + sizeofSTRW(c_wszHeapDumpSuffix);
  1243. __try { wszFullMinidumpFrom = (WCHAR *)_alloca(cch * sizeof(WCHAR)); }
  1244. __except(EXCEPTION_STACK_OVERFLOW) { wszFullMinidumpFrom = NULL; }
  1245. if (wszFullMinidumpFrom)
  1246. {
  1247. wcsncpy(wszFullMinidumpFrom, pwszTriageDumpFrom, cch);
  1248. wszFileExt = wszFullMinidumpFrom + wcslen(wszFullMinidumpFrom) -
  1249. sizeofSTRW(c_wszDumpSuffix) + 1;
  1250. if (!wcscmp(wszFileExt, c_wszDumpSuffix))
  1251. {
  1252. *wszFileExt = L'\0';
  1253. }
  1254. wcsncat(wszFullMinidumpFrom, c_wszHeapDumpSuffix, cch);
  1255. }
  1256. cch = wcslen(pwszTriageDumpTo) + sizeofSTRW(c_wszHeapDumpSuffix);
  1257. __try { wszFullMinidumpTo = (WCHAR *)_alloca(cch * sizeof(WCHAR)); }
  1258. __except(EXCEPTION_STACK_OVERFLOW) { wszFullMinidumpTo = NULL; }
  1259. if (wszFullMinidumpTo)
  1260. {
  1261. wcsncpy(wszFullMinidumpTo, pwszTriageDumpTo, cch);
  1262. wszFileExt = wszFullMinidumpTo + wcslen(wszFullMinidumpTo) -
  1263. sizeofSTRW(c_wszDumpSuffix) + 1;
  1264. if (!wcscmp(wszFileExt, c_wszDumpSuffix))
  1265. {
  1266. *wszFileExt = L'\0';
  1267. }
  1268. wcsncat(wszFullMinidumpTo, c_wszHeapDumpSuffix, cch);
  1269. if (wszFullMinidumpFrom)
  1270. {
  1271. fRet = CopyFileW(wszFullMinidumpFrom, wszFullMinidumpTo, FALSE);
  1272. }
  1273. }
  1274. }
  1275. return fRet;
  1276. }
  1277. HRESULT
  1278. FindFullMinidump(
  1279. LPWSTR pwszDumpFileList,
  1280. LPWSTR pwszFullMiniDump,
  1281. ULONG cchwszFullMiniDump
  1282. )
  1283. //
  1284. // This Grabs dump file name from pwszDumpFileList and then derives the fullminidump name.
  1285. // The full dump is returned in pwszFullMiniDump.
  1286. //
  1287. {
  1288. LPWSTR wszSrch, wszFiles;
  1289. LPWSTR wszOriginalDump = NULL;
  1290. DWORD cchOriginalDump = 0;
  1291. DWORD cchFile, cch;
  1292. HRESULT Hr, hr;
  1293. HANDLE hFile = INVALID_HANDLE_VALUE;
  1294. USE_TRACING("FindFullMinidump");
  1295. VALIDATEPARM(hr, (pwszFullMiniDump == NULL ||
  1296. pwszDumpFileList == NULL ||
  1297. !cchwszFullMiniDump));
  1298. if (FAILED(hr))
  1299. {
  1300. return E_INVALIDARG;
  1301. }
  1302. pwszFullMiniDump[0] = L'\0';
  1303. // Look through file list to find minidump file
  1304. wszFiles = pwszDumpFileList;
  1305. while (wszFiles && *wszFiles)
  1306. {
  1307. wszSrch = wcschr(wszFiles, DW_FILESEP);
  1308. if (!wszSrch)
  1309. {
  1310. wszSrch = wszFiles + wcslen(wszFiles);
  1311. }
  1312. // wszSrch now points after end of first file in wszFiles
  1313. if (!wcsncmp(wszSrch - sizeofSTRW(c_wszDumpSuffix) + 1,
  1314. c_wszDumpSuffix, sizeofSTRW(c_wszDumpSuffix) - 1))
  1315. {
  1316. // its the dump file
  1317. cchOriginalDump = (DWORD) wcslen(wszFiles) - wcslen(wszSrch);
  1318. __try { wszOriginalDump = (WCHAR *)_alloca((cchOriginalDump+1) * sizeof(WCHAR)); }
  1319. __except(EXCEPTION_STACK_OVERFLOW) { wszOriginalDump = NULL; DBG_MSG("out of stack");}
  1320. if (wszOriginalDump)
  1321. wcsncpy(wszOriginalDump, wszFiles, cchOriginalDump);
  1322. break;
  1323. }
  1324. wszFiles = wszSrch;
  1325. if (*wszFiles == L'\0')
  1326. {
  1327. break;
  1328. }
  1329. wszFiles++;
  1330. }
  1331. VALIDATEPARM(hr, ((wszOriginalDump == NULL) || (cchOriginalDump == 0)));
  1332. if (FAILED(hr))
  1333. {
  1334. return E_INVALIDARG;
  1335. }
  1336. // Now build the full dump file name
  1337. wcscpy(pwszFullMiniDump, wszOriginalDump);
  1338. pwszFullMiniDump[cchOriginalDump - sizeofSTRW(c_wszDumpSuffix) + 1] = L'\0';
  1339. wcscat(pwszFullMiniDump, c_wszHeapDumpSuffix);
  1340. // check if the dump exists. although we cannot do much if dump doesn't
  1341. // exist.
  1342. hFile = CreateFileW(pwszFullMiniDump, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0,
  1343. NULL);
  1344. VALIDATEPARM(hr, (hFile != INVALID_HANDLE_VALUE));
  1345. if (FAILED(hr))
  1346. {
  1347. Hr = S_OK;
  1348. CloseHandle( hFile );
  1349. hFile = NULL;
  1350. } else
  1351. {
  1352. ErrorTrace(0, "Could not open \'%S\'", pwszFullMiniDump);
  1353. Hr = E_FAIL;
  1354. }
  1355. return Hr;
  1356. }
  1357. #endif // MANIFEST_HEAP
  1358. //////////////////////////////////////////////////////////////////////////////
  1359. // DW manifest mode utils
  1360. // **************************************************************************
  1361. EFaultRepRetVal StartDWManifest(CPFFaultClientCfg &oCfg, SDWManifestBlob &dwmb,
  1362. LPWSTR wszManifestIn, BOOL fAllowSend,
  1363. DWORD dwTimeout)
  1364. {
  1365. USE_TRACING("StartDWManifest");
  1366. OSVERSIONINFOEXW ovi;
  1367. EFaultRepRetVal frrvRet = frrvErrNoDW;
  1368. STARTUPINFOW si;
  1369. HRESULT hr = NOERROR;
  1370. LPCWSTR pwszServer, pwszCorpPath;
  1371. LPCWSTR wszBrand;
  1372. HANDLE hManifest = INVALID_HANDLE_VALUE;
  1373. WCHAR wszManifestTU[MAX_PATH+16], wszDir[MAX_PATH];
  1374. WCHAR wszBuffer[1025];
  1375. #ifdef MANIFEST_HEAP
  1376. LPWSTR pwszMiniDump = NULL;
  1377. #endif
  1378. DWORD cbToWrite, dw, dwFlags;
  1379. VALIDATEPARM(hr, (dwmb.wszStage2 == NULL ||
  1380. (dwmb.nidTitle == 0 && dwmb.wszTitle == NULL)));
  1381. if (FAILED(hr))
  1382. {
  1383. SetLastError(ERROR_INVALID_PARAMETER);
  1384. goto done;
  1385. }
  1386. // if we get passed a manifest file & we can use it, then do so.
  1387. if (wszManifestIn != NULL && wszManifestIn[0] != L'\0' &&
  1388. wcslen(wszManifestIn) < sizeofSTRW(wszManifestTU))
  1389. {
  1390. wcscpy(wszManifestTU, wszManifestIn);
  1391. }
  1392. // ok, figure out the temp dir & then generate the filename
  1393. else
  1394. {
  1395. GetTempPathW(sizeofSTRW(wszDir), wszDir);
  1396. GetTempFileNameW(wszDir, L"DWM", 0, wszManifestTU);
  1397. }
  1398. hManifest = CreateFileW(wszManifestTU, GENERIC_WRITE, FILE_SHARE_READ,
  1399. NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN,
  1400. NULL);
  1401. TESTBOOL(hr, (hManifest != INVALID_HANDLE_VALUE));
  1402. if (FAILED(hr))
  1403. goto done;
  1404. // write the leading 0xFFFE out to the file
  1405. wszBuffer[0] = 0xFEFF;
  1406. TESTBOOL(hr, WriteFile(hManifest, wszBuffer, sizeof(wszBuffer[0]), &dw,
  1407. NULL));
  1408. if (FAILED(hr))
  1409. goto done;
  1410. // write out the server, LCID, Brand, Flags, & title
  1411. // Server=<server>
  1412. // UI LCID=GetSystemDefaultLCID()
  1413. // Flags=fDWWhister + fDWUserHKLM + headless if necessary
  1414. // Brand=<Brand> ("WINDOWS" by default)
  1415. // TitleName=<title>
  1416. wszBrand = (dwmb.wszBrand != NULL) ? dwmb.wszBrand : c_wszDWBrand;
  1417. // determine what server we're going to send the data to.
  1418. pwszServer = oCfg.get_DefaultServer(NULL, 0);
  1419. if (pwszServer == NULL || *pwszServer == L'\0')
  1420. {
  1421. pwszServer = (oCfg.get_UseInternal() == 1) ? c_wszDWDefServerI :
  1422. c_wszDWDefServerE;
  1423. }
  1424. if (oCfg.get_ShowUI() == eedDisabled)
  1425. {
  1426. DBG_MSG("Headless mode");
  1427. dwFlags = fDwWhistler | fDwHeadless | fDwUseHKLM | fDwAllowSuspend | fDwMiniDumpWithUnloadedModules;
  1428. }
  1429. else
  1430. dwFlags = fDwWhistler | fDwUseHKLM | fDwAllowSuspend | fDwMiniDumpWithUnloadedModules;
  1431. if (fAllowSend == FALSE)
  1432. dwFlags |= fDwNoReporting;
  1433. // if it's a MS app, set the flag that says we can have 'please help Microsoft'
  1434. // text in DW.
  1435. if (dwmb.fIsMSApp == FALSE)
  1436. dwFlags |= fDwUseLitePlea;
  1437. if ((dwmb.dwOptions & emoUseIEforURLs) == emoUseIEforURLs)
  1438. dwFlags |= fDwUseIE;
  1439. if ((dwmb.dwOptions & emoSupressBucketLogs) == emoSupressBucketLogs)
  1440. dwFlags |= fDwSkipBucketLog;
  1441. if ((dwmb.dwOptions & emoNoDefCabLimit) == emoNoDefCabLimit)
  1442. dwFlags |= fDwNoDefaultCabLimit;
  1443. if ((dwmb.dwOptions & emoShowDebugButton) == emoShowDebugButton)
  1444. dwFlags |= fDwManifestDebug;
  1445. cbToWrite = swprintf(wszBuffer, c_wszManMisc, pwszServer,
  1446. GetUserDefaultUILanguage(), dwFlags, wszBrand);
  1447. cbToWrite *= sizeof(WCHAR);
  1448. TESTBOOL(hr, WriteFile(hManifest, wszBuffer, cbToWrite, &dw, NULL));
  1449. if (FAILED(hr))
  1450. goto done;
  1451. // write out the title text
  1452. {
  1453. LPCWSTR wszOut;
  1454. if (dwmb.wszTitle != NULL)
  1455. {
  1456. wszOut = dwmb.wszTitle;
  1457. cbToWrite = wcslen(wszOut);
  1458. }
  1459. else
  1460. {
  1461. wszOut = wszBuffer;
  1462. cbToWrite = LoadStringW(g_hInstance, dwmb.nidTitle, wszBuffer,
  1463. sizeofSTRW(wszBuffer));
  1464. if (cbToWrite == 0)
  1465. {
  1466. SetLastError(ERROR_INVALID_PARAMETER);
  1467. goto done;
  1468. }
  1469. }
  1470. cbToWrite *= sizeof(WCHAR);
  1471. TESTBOOL(hr, WriteFile(hManifest, wszOut, cbToWrite, &dw, NULL));
  1472. if (FAILED(hr))
  1473. goto done;
  1474. }
  1475. // write out dig PID path
  1476. // DigPidRegPath=HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\DigitalProductId
  1477. TESTBOOL(hr, WriteFile(hManifest, c_wszManPID,
  1478. sizeof(c_wszManPID) - sizeof(WCHAR), &dw,
  1479. NULL));
  1480. if (FAILED(hr))
  1481. goto done;
  1482. // write out the registry subpath for policy info
  1483. // RegSubPath==Microsoft\\PCHealth\\ErrorReporting\\DW
  1484. TESTBOOL(hr, WriteFile(hManifest, c_wszManSubPath,
  1485. sizeof(c_wszManSubPath) - sizeof(WCHAR), &dw,
  1486. NULL));
  1487. if (FAILED(hr))
  1488. goto done;
  1489. // write out the error message if we have one
  1490. // ErrorText=<error text read from resource>
  1491. if (dwmb.wszErrMsg != NULL || dwmb.nidErrMsg != 0)
  1492. {
  1493. LPCWSTR wszOut;
  1494. TESTBOOL(hr, WriteFile(hManifest, c_wszManErrText,
  1495. sizeof(c_wszManErrText) - sizeof(WCHAR), &dw,
  1496. NULL));
  1497. if (FAILED(hr))
  1498. goto done;
  1499. if (dwmb.wszErrMsg != NULL)
  1500. {
  1501. wszOut = dwmb.wszErrMsg;
  1502. cbToWrite = wcslen(wszOut);
  1503. }
  1504. else
  1505. {
  1506. wszOut = wszBuffer;
  1507. cbToWrite = LoadStringW(g_hInstance, dwmb.nidErrMsg, wszBuffer,
  1508. sizeofSTRW(wszBuffer));
  1509. if (cbToWrite == 0)
  1510. {
  1511. SetLastError(ERROR_INVALID_PARAMETER);
  1512. goto done;
  1513. }
  1514. }
  1515. cbToWrite *= sizeof(WCHAR);
  1516. TESTBOOL(hr, WriteFile(hManifest, wszOut, cbToWrite, &dw, NULL));
  1517. if (FAILED(hr))
  1518. goto done;
  1519. }
  1520. // write out the header text if we have one
  1521. // HeaderText=<header text read from resource>
  1522. if (dwmb.wszHdr != NULL || dwmb.nidHdr != 0)
  1523. {
  1524. LPCWSTR wszOut;
  1525. TESTBOOL(hr, WriteFile(hManifest, c_wszManHdrText,
  1526. sizeof(c_wszManHdrText) - sizeof(WCHAR), &dw,
  1527. NULL));
  1528. if (FAILED(hr))
  1529. goto done;
  1530. if (dwmb.wszHdr != NULL)
  1531. {
  1532. wszOut = dwmb.wszHdr;
  1533. cbToWrite = wcslen(wszOut);
  1534. }
  1535. else
  1536. {
  1537. wszOut = wszBuffer;
  1538. cbToWrite = LoadStringW(g_hInstance, dwmb.nidHdr, wszBuffer,
  1539. sizeofSTRW(wszBuffer));
  1540. if (cbToWrite == 0)
  1541. {
  1542. SetLastError(ERROR_INVALID_PARAMETER);
  1543. goto done;
  1544. }
  1545. }
  1546. cbToWrite *= sizeof(WCHAR);
  1547. TESTBOOL(hr, WriteFile(hManifest, wszOut, cbToWrite, &dw, NULL));
  1548. if (FAILED(hr))
  1549. goto done;
  1550. }
  1551. // write out the plea text if we have one
  1552. // Plea=<plea text>
  1553. if (dwmb.wszPlea != NULL)
  1554. {
  1555. TESTBOOL(hr, WriteFile(hManifest, c_wszManPleaText,
  1556. sizeof(c_wszManPleaText) - sizeof(WCHAR), &dw,
  1557. NULL));
  1558. if (FAILED(hr))
  1559. goto done;
  1560. cbToWrite = wcslen(dwmb.wszPlea) * sizeof(WCHAR);
  1561. TESTBOOL(hr, WriteFile(hManifest, dwmb.wszPlea, cbToWrite, &dw, NULL));
  1562. if (FAILED(hr))
  1563. goto done;
  1564. }
  1565. // write out the plea text if we have one
  1566. // ReportButton=<button text>
  1567. if (dwmb.wszSendBtn != NULL && dwmb.wszSendBtn[0] != L'\0')
  1568. {
  1569. TESTBOOL(hr, WriteFile(hManifest, c_wszManSendText,
  1570. sizeof(c_wszManSendText) - sizeof(WCHAR), &dw,
  1571. NULL));
  1572. if (FAILED(hr))
  1573. goto done;
  1574. cbToWrite = wcslen(dwmb.wszSendBtn) * sizeof(WCHAR);
  1575. TESTBOOL(hr, WriteFile(hManifest, dwmb.wszSendBtn, cbToWrite, &dw, NULL));
  1576. if (FAILED(hr))
  1577. goto done;
  1578. }
  1579. // write out the plea text if we have one
  1580. // NoReportButton=<button text>
  1581. if (dwmb.wszNoSendBtn != NULL && dwmb.wszNoSendBtn[0] != L'\0')
  1582. {
  1583. TESTBOOL(hr, WriteFile(hManifest, c_wszManNSendText,
  1584. sizeof(c_wszManNSendText) - sizeof(WCHAR), &dw,
  1585. NULL));
  1586. if (FAILED(hr))
  1587. goto done;
  1588. cbToWrite = wcslen(dwmb.wszNoSendBtn) * sizeof(WCHAR);
  1589. TESTBOOL(hr, WriteFile(hManifest, dwmb.wszNoSendBtn, cbToWrite, &dw, NULL));
  1590. if (FAILED(hr))
  1591. goto done;
  1592. }
  1593. // write out the plea text if we have one
  1594. // EventLogSource=<button text>
  1595. if (dwmb.wszEventSrc != NULL && dwmb.wszEventSrc[0] != L'\0')
  1596. {
  1597. TESTBOOL(hr, WriteFile(hManifest, c_wszManEventSrc,
  1598. sizeof(c_wszManEventSrc) - sizeof(WCHAR), &dw,
  1599. NULL));
  1600. if (FAILED(hr))
  1601. goto done;
  1602. cbToWrite = wcslen(dwmb.wszEventSrc) * sizeof(WCHAR);
  1603. TESTBOOL(hr, WriteFile(hManifest, dwmb.wszEventSrc, cbToWrite, &dw, NULL));
  1604. if (FAILED(hr))
  1605. goto done;
  1606. }
  1607. // write out the stage 1 URL if there is one
  1608. // Stage1URL=<stage 1 URL>
  1609. if (dwmb.wszStage1 != NULL && dwmb.wszStage1[0] != L'\0')
  1610. {
  1611. TESTBOOL(hr, WriteFile(hManifest, c_wszManStageOne,
  1612. sizeof(c_wszManStageOne) - sizeof(WCHAR), &dw,
  1613. NULL));
  1614. if (FAILED(hr))
  1615. goto done;
  1616. cbToWrite = wcslen(dwmb.wszStage1) * sizeof(WCHAR);
  1617. TESTBOOL(hr, WriteFile(hManifest, dwmb.wszStage1, cbToWrite, &dw, NULL));
  1618. if (FAILED(hr))
  1619. goto done;
  1620. }
  1621. // write out the stage 2 URL
  1622. // Stage2URL=<stage 2 URL>
  1623. TESTBOOL(hr, WriteFile(hManifest, c_wszManStageTwo,
  1624. sizeof(c_wszManStageTwo) - sizeof(WCHAR), &dw,
  1625. NULL));
  1626. if (FAILED(hr))
  1627. goto done;
  1628. cbToWrite = wcslen(dwmb.wszStage2) * sizeof(WCHAR);
  1629. TESTBOOL(hr, WriteFile(hManifest, dwmb.wszStage2, cbToWrite, &dw, NULL));
  1630. if (FAILED(hr))
  1631. goto done;
  1632. // write out files to collect if we have any
  1633. // DataFiles=<list of files to include in cab>
  1634. if (dwmb.wszFileList != NULL && dwmb.wszFileList[0] != L'\0')
  1635. {
  1636. TESTBOOL(hr, WriteFile(hManifest, c_wszManFiles,
  1637. sizeof(c_wszManFiles) - sizeof(WCHAR), &dw,
  1638. NULL));
  1639. if (FAILED(hr))
  1640. goto done;
  1641. cbToWrite = wcslen(dwmb.wszFileList) * sizeof(WCHAR);
  1642. TESTBOOL(hr, WriteFile(hManifest, dwmb.wszFileList, cbToWrite, &dw, NULL));
  1643. if (FAILED(hr))
  1644. goto done;
  1645. }
  1646. #ifdef MANIFEST_HEAP
  1647. // write out dump file with heap info if we have any
  1648. // Heap=<dump file which has heap info>
  1649. __try { pwszMiniDump = (LPWSTR)_alloca((wcslen(dwmb.wszFileList) + 1) * sizeof(WCHAR)); }
  1650. __except(EXCEPTION_STACK_OVERFLOW) { pwszMiniDump = NULL; DBG_MSG("Out of stack");}
  1651. if (pwszMiniDump)
  1652. {
  1653. TESTHR(hr, FindFullMinidump((LPWSTR)dwmb.wszFileList, pwszMiniDump,
  1654. wcslen(dwmb.wszFileList) + 1));
  1655. if (SUCCEEDED(hr))
  1656. {
  1657. if (pwszMiniDump != NULL && pwszMiniDump[0] != L'\0')
  1658. {
  1659. TESTBOOL(hr, WriteFile(hManifest, c_wszManHeapDump,
  1660. sizeof(c_wszManHeapDump) - sizeof(WCHAR), &dw,
  1661. NULL));
  1662. if (FAILED(hr))
  1663. goto done;
  1664. cbToWrite = wcslen(pwszMiniDump) * sizeof(WCHAR);
  1665. TESTBOOL(hr, WriteFile(hManifest, pwszMiniDump, cbToWrite, &dw, NULL));
  1666. if (FAILED(hr))
  1667. goto done;
  1668. }
  1669. }
  1670. }
  1671. #endif // MANIFEST_HEAP
  1672. // write out corporate mode subpath
  1673. // ErrorSubPath=<subpath for the error signature>
  1674. pwszCorpPath = oCfg.get_DumpPath(NULL, 0);
  1675. if (pwszCorpPath != NULL && pwszCorpPath != L'\0' &&
  1676. dwmb.wszCorpPath != NULL && dwmb.wszCorpPath[0] != L'\0')
  1677. {
  1678. TESTBOOL(hr, WriteFile(hManifest, c_wszManCorpPath,
  1679. sizeof(c_wszManCorpPath) - sizeof(WCHAR), &dw,
  1680. NULL));
  1681. if (FAILED(hr))
  1682. goto done;
  1683. cbToWrite = wcslen(dwmb.wszCorpPath) * sizeof(WCHAR);
  1684. TESTBOOL(hr, WriteFile(hManifest, dwmb.wszCorpPath, cbToWrite, &dw, NULL));
  1685. if (FAILED(hr))
  1686. goto done;
  1687. }
  1688. // write out the final "\r\n"
  1689. wszBuffer[0] = L'\r';
  1690. wszBuffer[1] = L'\n';
  1691. TESTBOOL(hr, WriteFile(hManifest, wszBuffer, 2 * sizeof(wszBuffer[0]), &dw,
  1692. NULL));
  1693. if (FAILED(hr))
  1694. goto done;
  1695. CloseHandle(hManifest);
  1696. hManifest = INVALID_HANDLE_VALUE;
  1697. // create the process
  1698. GetSystemDirectoryW(wszDir, sizeofSTRW(wszDir));
  1699. swprintf(wszBuffer, c_wszDWCmdLineKH, wszDir, wszManifestTU);
  1700. ZeroMemory(&si, sizeof(si));
  1701. si.cb = sizeof(si);
  1702. // check and see if the system is shutting down. If so, CreateProcess is
  1703. // gonna pop up some annoying UI that we can't get rid of, so we don't
  1704. // want to call it if we know it's gonna happen.
  1705. if (GetSystemMetrics(SM_SHUTTINGDOWN))
  1706. {
  1707. DBG_MSG("shutting down");
  1708. goto done;
  1709. }
  1710. // we're creating the process in the same user context that we're in
  1711. if (dwmb.hToken == NULL)
  1712. {
  1713. ErrorTrace(0, "starting CreateProcessW(\'%S\')", wszBuffer);
  1714. si.lpDesktop = L"Winsta0\\Default";
  1715. TESTBOOL(hr, CreateProcessW(NULL, wszBuffer, NULL, NULL, TRUE,
  1716. CREATE_DEFAULT_ERROR_MODE |
  1717. NORMAL_PRIORITY_CLASS,
  1718. NULL, wszDir, &si, &dwmb.pi));
  1719. if (FAILED(hr))
  1720. goto done;
  1721. // don't need the thread handle & we gotta close it, so close it now
  1722. CloseHandle(dwmb.pi.hThread);
  1723. // wait 5 minutes for DW to close. If it doesn't close by then, just
  1724. // return.
  1725. dw = WaitForSingleObject(dwmb.pi.hProcess, dwTimeout);
  1726. CloseHandle(dwmb.pi.hProcess);
  1727. switch (dw)
  1728. {
  1729. case WAIT_FAILED:
  1730. ErrorTrace(0, "Wait error: 0x%x", GetLastError());
  1731. break;
  1732. case WAIT_TIMEOUT:
  1733. DBG_MSG("wait timeout");
  1734. frrvRet = frrvErrTimeout;
  1735. goto done;
  1736. break;
  1737. case WAIT_OBJECT_0:
  1738. DBG_MSG("DW finished OK");
  1739. GetExitCodeProcess(dwmb.pi.hProcess, &dw);
  1740. ErrorTrace(0, "DW finished OK, exit code=0x%x", dw);
  1741. break;
  1742. default:
  1743. ErrorTrace(0, "Something bad happened, lasterr=0x%x", GetLastError());
  1744. break;
  1745. }
  1746. }
  1747. else
  1748. {
  1749. // we're creating DW in a different user context. Note that we pretty
  1750. // much have to be running as local system for this to work.
  1751. // Note that the access check that CreateProcessAsUser makes appears to
  1752. // use the process token, so we do not need to remove any impersonation
  1753. // tokens at this point.
  1754. ErrorTrace(0, "starting CreateProcessAsUserW(\'%S\')", wszBuffer);
  1755. TESTBOOL(hr, CreateProcessAsUserW(dwmb.hToken, NULL, wszBuffer, NULL,
  1756. NULL, FALSE, NORMAL_PRIORITY_CLASS |
  1757. CREATE_UNICODE_ENVIRONMENT |
  1758. CREATE_DEFAULT_ERROR_MODE,
  1759. dwmb.pvEnv, wszDir, &si, &dwmb.pi));
  1760. if (FAILED(hr))
  1761. goto done;
  1762. }
  1763. frrvRet = frrvOk;
  1764. done:
  1765. // preserve the error code so that the following calls don't overwrite it
  1766. dw = GetLastError();
  1767. if (hManifest != INVALID_HANDLE_VALUE)
  1768. CloseHandle(hManifest);
  1769. if (FAILED(hr) || wszManifestIn == NULL)
  1770. DeleteFileW(wszManifestTU);
  1771. SetLastError(dw);
  1772. ErrorTrace(0, "LastError=0x%x", GetLastError());
  1773. return frrvRet;
  1774. }
  1775. //////////////////////////////////////////////////////////////////////////////
  1776. // Security
  1777. // **************************************************************************
  1778. #define ER_WINSTA_ALL WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS | \
  1779. WINSTA_CREATEDESKTOP | WINSTA_ENUMDESKTOPS | \
  1780. WINSTA_ENUMERATE | WINSTA_EXITWINDOWS | \
  1781. WINSTA_READATTRIBUTES | WINSTA_READSCREEN | \
  1782. WINSTA_WRITEATTRIBUTES
  1783. BOOL CheckAccessToWinSta0(void)
  1784. {
  1785. HWINSTA hwinsta;
  1786. // attempt to open winsta0
  1787. hwinsta = OpenWindowStationW(L"winsta0", FALSE, ER_WINSTA_ALL);
  1788. if (hwinsta == NULL)
  1789. return FALSE;
  1790. CloseWindowStation(hwinsta);
  1791. return TRUE;
  1792. }
  1793. // **************************************************************************
  1794. BOOL DoUserContextsMatch(void)
  1795. {
  1796. SID_NAME_USE snu;
  1797. TOKEN_USER *ptuProc = NULL;
  1798. HRESULT hr = NOERROR;
  1799. LPWSTR wszName = NULL, wszDom = NULL;
  1800. HANDLE hTokenProc = NULL, hTokenImp = NULL;
  1801. WCHAR wszFullName[MAX_PATH], wszSidDom[MAX_PATH];
  1802. DWORD cb, cchDom;
  1803. PSID psidUser = NULL;
  1804. USE_TRACING("DoUserContextsMatch");
  1805. // always get the following info in the context of the process & not
  1806. // the context of the thread. Also, if we don't do this, then we
  1807. // could fail later on when we try to open the process token.
  1808. TESTBOOL(hr, OpenThreadToken(GetCurrentThread(),
  1809. TOKEN_READ | TOKEN_IMPERSONATE, TRUE,
  1810. &hTokenImp));
  1811. if (FAILED(hr) && GetLastError() != ERROR_NO_TOKEN)
  1812. goto done;
  1813. RevertToSelf();
  1814. // get the name of the currently logged on user to this session. If this
  1815. // fails, then we just assume that we can't report in this context
  1816. TESTBOOL(hr, WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE,
  1817. WTS_CURRENT_SESSION, WTSUserName,
  1818. &wszName, &cb));
  1819. if (FAILED(hr))
  1820. goto done;
  1821. VALIDATEEXPR(hr, (wszName == NULL || *wszName == L'\0'),
  1822. Err2HR(ERROR_ACCESS_DENIED));
  1823. if (FAILED(hr))
  1824. {
  1825. SetLastError(ERROR_ACCESS_DENIED);
  1826. goto done;
  1827. }
  1828. // get the domain of the currently logged on user to this session. If this
  1829. // fails, then we just assume that we can't report in this context
  1830. TESTBOOL(hr, WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE,
  1831. WTS_CURRENT_SESSION, WTSDomainName,
  1832. &wszDom, &cb));
  1833. if (FAILED(hr))
  1834. goto done;
  1835. VALIDATEEXPR(hr, (wszDom == NULL || *wszDom == L'\0'),
  1836. Err2HR(ERROR_ACCESS_DENIED));
  1837. if (FAILED(hr))
  1838. {
  1839. SetLastError(ERROR_ACCESS_DENIED);
  1840. goto done;
  1841. }
  1842. wcscpy(wszFullName, wszDom);
  1843. wcscat(wszFullName, L"\\");
  1844. wcscat(wszFullName, wszName);
  1845. // since a SID is a variable length structure, query for the # of bytes
  1846. // we need to store it.
  1847. cchDom = sizeofSTRW(wszSidDom);
  1848. cb = 0;
  1849. LookupAccountNameW(NULL, wszFullName, NULL, &cb, wszSidDom, &cchDom, &snu);
  1850. __try { psidUser = (PSID)_alloca(cb); }
  1851. __except(EXCEPTION_EXECUTE_HANDLER) { psidUser = NULL; }
  1852. VALIDATEEXPR(hr, (psidUser == NULL), E_OUTOFMEMORY);
  1853. if (FAILED(hr))
  1854. {
  1855. SetLastError(ERROR_OUTOFMEMORY);
  1856. goto done;
  1857. }
  1858. // get the SID for the user
  1859. TESTBOOL(hr, LookupAccountNameW(NULL, wszFullName, psidUser, &cb, wszSidDom,
  1860. &cchDom, &snu));
  1861. if (FAILED(hr))
  1862. goto done;
  1863. // fetch the token for the current process
  1864. TESTBOOL(hr, OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hTokenProc));
  1865. if (FAILED(hr))
  1866. goto done;
  1867. // fetch the sid for the user of the current process
  1868. GetTokenInformation(hTokenProc, TokenUser, NULL, 0, &cb);
  1869. __try { ptuProc = (TOKEN_USER *)_alloca(cb); }
  1870. __except(EXCEPTION_STACK_OVERFLOW) { ptuProc = NULL; }
  1871. VALIDATEEXPR(hr, (ptuProc == NULL), E_OUTOFMEMORY);
  1872. if (FAILED(hr))
  1873. {
  1874. SetLastError(ERROR_OUTOFMEMORY);
  1875. goto done;
  1876. }
  1877. TESTBOOL(hr, GetTokenInformation(hTokenProc, TokenUser, (LPVOID)ptuProc,
  1878. cb, &cb));
  1879. if (FAILED(hr))
  1880. goto done;
  1881. TESTBOOL(hr, IsValidSid(ptuProc->User.Sid));
  1882. if (FAILED(hr))
  1883. goto done;
  1884. // are they equal?
  1885. VALIDATEEXPR(hr, (EqualSid(ptuProc->User.Sid, psidUser) == FALSE),
  1886. Err2HR(ERROR_ACCESS_DENIED));
  1887. if (FAILED(hr))
  1888. {
  1889. SetLastError(ERROR_ACCESS_DENIED);
  1890. goto done;
  1891. }
  1892. // ok, so if the SIDs matched, then determine if this process has access
  1893. // to winsta0 (cuz otherwise it won't be able to launch DW in it)
  1894. VALIDATEEXPR(hr, (CheckAccessToWinSta0() == FALSE),
  1895. Err2HR(ERROR_ACCESS_DENIED));
  1896. if (FAILED(hr))
  1897. {
  1898. SetLastError(ERROR_ACCESS_DENIED);
  1899. goto done;
  1900. }
  1901. done:
  1902. if (hTokenImp != NULL)
  1903. {
  1904. SetThreadToken(NULL, hTokenImp);
  1905. CloseHandle(hTokenImp);
  1906. }
  1907. if (wszName != NULL)
  1908. WTSFreeMemory(wszName);
  1909. if (wszDom != NULL)
  1910. WTSFreeMemory(wszDom);
  1911. if (hTokenProc != NULL)
  1912. CloseHandle(hTokenProc);
  1913. return SUCCEEDED(hr);
  1914. }
  1915. // ***************************************************************************
  1916. BOOL DoWinstaDesktopMatch(void)
  1917. {
  1918. HWINSTA hwinsta = NULL;
  1919. HRESULT hr = NOERROR;
  1920. LPWSTR wszWinsta = NULL;
  1921. DWORD cbNeed = 0, cbGot;
  1922. BOOL fRet = FALSE;
  1923. USE_TRACING("DoWinstaDesktopMatch");
  1924. hwinsta = GetProcessWindowStation();
  1925. TESTBOOL(hr, (hwinsta != NULL));
  1926. if (FAILED(hr))
  1927. goto done;
  1928. fRet = GetUserObjectInformationW(hwinsta, UOI_NAME, NULL, 0, &cbNeed);
  1929. TESTBOOL(hr, (cbNeed != 0));
  1930. if (FAILED(hr))
  1931. {
  1932. fRet = FALSE;
  1933. goto done;
  1934. }
  1935. cbNeed += sizeof(WCHAR);
  1936. __try { wszWinsta = (LPWSTR)_alloca(cbNeed); }
  1937. __except(EXCEPTION_STACK_OVERFLOW) { wszWinsta = NULL; }
  1938. TESTBOOL(hr, (wszWinsta != NULL));
  1939. if (FAILED(hr))
  1940. {
  1941. fRet = FALSE;
  1942. goto done;
  1943. }
  1944. cbGot = 0;
  1945. fRet = GetUserObjectInformationW(hwinsta, UOI_NAME, wszWinsta, cbNeed,
  1946. &cbGot);
  1947. TESTBOOL(hr, (fRet != FALSE));
  1948. if (FAILED(hr))
  1949. goto done;
  1950. ErrorTrace(0, "WinSta = %S", wszWinsta);
  1951. // 'Winsta0' should be the interactive window station for a given session
  1952. fRet = (_wcsicmp(wszWinsta, L"WinSta0") == 0);
  1953. done:
  1954. return fRet;
  1955. }
  1956. // ***************************************************************************
  1957. BOOL AmIPrivileged(BOOL fOnlyCheckLS)
  1958. {
  1959. SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
  1960. TOKEN_USER *ptu = NULL, *ptuImp = NULL;
  1961. HANDLE hToken = NULL, hTokenImp = NULL;
  1962. DWORD cb, cbGot, i;
  1963. PSID psid = NULL;
  1964. BOOL fRet = FALSE, fThread;
  1965. // local system has to be the first RID in this array. Otherwise, the
  1966. // loop logic below needs to be changed.
  1967. DWORD rgRIDs[3] = { SECURITY_LOCAL_SYSTEM_RID,
  1968. SECURITY_LOCAL_SERVICE_RID,
  1969. SECURITY_NETWORK_SERVICE_RID };
  1970. // gotta have a token to get the SID
  1971. fThread = OpenThreadToken(GetCurrentThread(),
  1972. TOKEN_READ | TOKEN_IMPERSONATE, TRUE,
  1973. &hTokenImp);
  1974. if (fThread == FALSE && GetLastError() != ERROR_NO_TOKEN)
  1975. goto done;
  1976. // revert back to base user acct so we can fetch the process token &
  1977. // extract all the nifty stuff out of it.
  1978. RevertToSelf();
  1979. fRet = OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken);
  1980. if (fRet == FALSE)
  1981. goto done;
  1982. // figure out the SID
  1983. fRet = GetTokenInformation(hToken, TokenUser, NULL, 0, &cb);
  1984. if (fRet != FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  1985. {
  1986. fRet = FALSE;
  1987. goto done;
  1988. }
  1989. __try { ptu = (TOKEN_USER *)_alloca(cb); }
  1990. __except(EXCEPTION_STACK_OVERFLOW) { ptu = NULL; }
  1991. if (ptu == NULL)
  1992. {
  1993. SetLastError(ERROR_OUTOFMEMORY);
  1994. fRet = FALSE;
  1995. goto done;
  1996. }
  1997. fRet = GetTokenInformation(hToken, TokenUser, (LPVOID)ptu, cb, &cbGot);
  1998. if (fRet == FALSE)
  1999. goto done;
  2000. fRet = IsValidSid(ptu->User.Sid);
  2001. if (fRet == FALSE)
  2002. goto done;
  2003. if (fThread)
  2004. {
  2005. // figure out the SID
  2006. fRet = GetTokenInformation(hTokenImp, TokenUser, NULL, 0, &cb);
  2007. if (fRet != FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  2008. {
  2009. fRet = FALSE;
  2010. goto done;
  2011. }
  2012. __try { ptuImp = (TOKEN_USER *)_alloca(cb); }
  2013. __except(EXCEPTION_STACK_OVERFLOW) { ptuImp = NULL; }
  2014. if (ptuImp == NULL)
  2015. {
  2016. SetLastError(ERROR_OUTOFMEMORY);
  2017. fRet = FALSE;
  2018. goto done;
  2019. }
  2020. fRet = GetTokenInformation(hTokenImp, TokenUser, (LPVOID)ptuImp, cb,
  2021. &cbGot);
  2022. if (fRet == FALSE)
  2023. goto done;
  2024. fRet = IsValidSid(ptuImp->User.Sid);
  2025. if (fRet == FALSE)
  2026. goto done;
  2027. }
  2028. // loop thru & check against the SIDs we are interested in
  2029. for (i = 0; i < 3; i++)
  2030. {
  2031. fRet = AllocateAndInitializeSid(&siaNT, 1, rgRIDs[i], 0, 0, 0, 0, 0, 0,
  2032. 0, &psid);
  2033. if (fRet == FALSE)
  2034. goto done;
  2035. fRet = IsValidSid(psid);
  2036. if (fRet == FALSE)
  2037. goto done;
  2038. fRet = EqualSid(psid, ptu->User.Sid);
  2039. if (fRet)
  2040. {
  2041. // set this to false so that the code below will correctly change
  2042. // it to TRUE
  2043. fRet = FALSE;
  2044. goto done;
  2045. }
  2046. if (fThread)
  2047. {
  2048. fRet = EqualSid(psid, ptuImp->User.Sid);
  2049. if (fRet)
  2050. {
  2051. // set this to false so that the code below will correctly
  2052. // change it to TRUE
  2053. fRet = FALSE;
  2054. goto done;
  2055. }
  2056. }
  2057. FreeSid(psid);
  2058. psid = NULL;
  2059. // if we only need to check for local system, can bail now (we've
  2060. // already done it if we've gone thru this loop once)
  2061. if (fOnlyCheckLS)
  2062. break;
  2063. }
  2064. // only way to get here is to fail all the SID checks above. So set the
  2065. // result to TRUE so the code below correclty changes it to FALSE
  2066. fRet = TRUE;
  2067. done:
  2068. if (fThread && hTokenImp != NULL)
  2069. {
  2070. if (SetThreadToken(NULL, hTokenImp) == FALSE)
  2071. fRet = FALSE;
  2072. }
  2073. // if anything failed above, we want to return TRUE (cuz this puts us
  2074. // down the most secure code path), so need to negate the result. Since
  2075. // we set the fallthru case to TRUE, we'll correctly negate it to FALSE
  2076. // here.
  2077. fRet = !fRet;
  2078. // if we had an impersonation token on the thread, put it back in place.
  2079. if (hToken != NULL)
  2080. CloseHandle(hToken);
  2081. if (hTokenImp != NULL)
  2082. CloseHandle(hTokenImp);
  2083. if (fRet == TRUE && GetLastError() == ERROR_SUCCESS)
  2084. SetLastError(ERROR_ACCESS_DENIED);
  2085. if (psid != NULL)
  2086. FreeSid(psid);
  2087. return fRet;
  2088. }
  2089. // **************************************************************************
  2090. BOOL FindAdminSession(DWORD *pdwSession, HANDLE *phToken)
  2091. {
  2092. USE_TRACING("FindAdminSession");
  2093. WINSTATIONUSERTOKEN wsut;
  2094. LOGONIDW *rgSesn = NULL;
  2095. HRESULT hr = NOERROR;
  2096. DWORD i, cSesn, cb;
  2097. ZeroMemory(&wsut, sizeof(wsut));
  2098. VALIDATEPARM(hr, (pdwSession == NULL || phToken == NULL));
  2099. if (FAILED(hr))
  2100. goto done;
  2101. *pdwSession = (DWORD)-1;
  2102. *phToken = NULL;
  2103. TESTBOOL(hr, WinStationEnumerateW(SERVERNAME_CURRENT, &rgSesn, &cSesn));
  2104. if (FAILED(hr))
  2105. goto done;
  2106. wsut.ProcessId = LongToHandle(GetCurrentProcessId());
  2107. wsut.ThreadId = LongToHandle(GetCurrentThreadId());
  2108. for(i = 0; i < cSesn; i++)
  2109. {
  2110. if (rgSesn[i].State != State_Active)
  2111. continue;
  2112. TESTBOOL(hr, WinStationQueryInformationW(SERVERNAME_CURRENT,
  2113. rgSesn[i].SessionId,
  2114. WinStationUserToken,
  2115. &wsut, sizeof(wsut), &cb));
  2116. if (FAILED(hr))
  2117. continue;
  2118. if (wsut.UserToken != NULL)
  2119. {
  2120. if (IsUserAnAdmin(wsut.UserToken))
  2121. break;
  2122. CloseHandle(wsut.UserToken);
  2123. wsut.UserToken = NULL;
  2124. }
  2125. }
  2126. if (i < cSesn)
  2127. {
  2128. hr = NOERROR;
  2129. *pdwSession = rgSesn[i].SessionId;
  2130. *phToken = wsut.UserToken;
  2131. }
  2132. else
  2133. {
  2134. hr = E_FAIL;
  2135. }
  2136. done:
  2137. if (rgSesn != NULL)
  2138. WinStationFreeMemory(rgSesn);
  2139. return SUCCEEDED(hr);
  2140. }
  2141. //////////////////////////////////////////////////////////////////////////////
  2142. // Logging
  2143. // **************************************************************************
  2144. HRESULT LogEvent(LPCWSTR wszSrc, WORD wCat, DWORD dwEventID, WORD cStrs,
  2145. DWORD cbBlob, LPCWSTR *rgwszStrs, LPVOID pvBlob)
  2146. {
  2147. USE_TRACING("LogEvent");
  2148. HRESULT hr = NOERROR;
  2149. HANDLE hLog = NULL;
  2150. VALIDATEPARM(hr, (wszSrc == NULL));
  2151. if (FAILED(hr))
  2152. goto done;
  2153. hLog = RegisterEventSourceW(NULL, wszSrc);
  2154. TESTBOOL(hr, (hLog != NULL));
  2155. if (FAILED(hr))
  2156. goto done;
  2157. TESTBOOL(hr, ReportEventW(hLog, EVENTLOG_ERROR_TYPE, wCat, dwEventID,
  2158. NULL, cStrs, cbBlob, rgwszStrs, pvBlob));
  2159. if (FAILED(hr))
  2160. goto done;
  2161. done:
  2162. if (hLog != NULL)
  2163. DeregisterEventSource(hLog);
  2164. return hr;
  2165. }
  2166. // **************************************************************************
  2167. HRESULT LogHang(LPCWSTR wszApp, WORD *rgAppVer, LPCWSTR wszMod, WORD *rgModVer,
  2168. ULONG64 ulOffset, BOOL f64bit)
  2169. {
  2170. USE_TRACING("LogHang");
  2171. HRESULT hr = NOERROR;
  2172. LPCWSTR rgwsz[5];
  2173. WCHAR wszAppVer[32], wszModVer[32], wszOffset[32];
  2174. char szBlobLog[1024];
  2175. VALIDATEPARM(hr, (wszApp == NULL || rgAppVer == NULL || wszMod == NULL ||
  2176. rgModVer == NULL));
  2177. if (FAILED(hr))
  2178. return hr;
  2179. swprintf(wszAppVer, L"%d.%d.%d.%d", rgAppVer[0], rgAppVer[1], rgAppVer[2], rgAppVer[3]);
  2180. swprintf(wszModVer, L"%d.%d.%d.%d", rgModVer[0], rgModVer[1], rgModVer[2], rgModVer[3]);
  2181. if (f64bit)
  2182. swprintf(wszOffset, L"%016I64x", ulOffset);
  2183. else
  2184. swprintf(wszOffset, L"%08x", (DWORD)ulOffset);
  2185. sprintf(szBlobLog, "Application Hang %S %S in %S %S at offset %S",
  2186. wszApp, wszAppVer, wszMod, wszModVer, wszOffset);
  2187. rgwsz[0] = wszApp;
  2188. rgwsz[1] = wszAppVer;
  2189. rgwsz[2] = wszMod;
  2190. rgwsz[3] = wszModVer;
  2191. rgwsz[4] = wszOffset;
  2192. return LogEvent(c_wszHangEventSrc, ER_HANG_CATEGORY, ER_HANG_LOG, 5,
  2193. strlen(szBlobLog), rgwsz, szBlobLog);
  2194. }
  2195. // **************************************************************************
  2196. HRESULT LogUser(LPCWSTR wszApp, WORD *rgAppVer, LPCWSTR wszMod, WORD *rgModVer,
  2197. ULONG64 ulOffset, BOOL f64bit, DWORD dwEventID)
  2198. {
  2199. USE_TRACING("LogUser");
  2200. HRESULT hr = NOERROR;
  2201. LPCWSTR rgwsz[5];
  2202. WCHAR wszAppVer[32], wszModVer[32], wszOffset[32];
  2203. char szBlobLog[1024];
  2204. VALIDATEPARM(hr, (wszApp == NULL || rgAppVer == NULL || wszMod == NULL ||
  2205. rgModVer == NULL));
  2206. if (FAILED(hr))
  2207. return hr;
  2208. swprintf(wszAppVer, L"%d.%d.%d.%d", rgAppVer[0], rgAppVer[1], rgAppVer[2], rgAppVer[3]);
  2209. swprintf(wszModVer, L"%d.%d.%d.%d", rgModVer[0], rgModVer[1], rgModVer[2], rgModVer[3]);
  2210. if (f64bit)
  2211. swprintf(wszOffset, L"%016I64x", ulOffset);
  2212. else
  2213. swprintf(wszOffset, L"%08x", (DWORD)ulOffset);
  2214. sprintf(szBlobLog, "Application Failure %S %S in %S %S at offset %S",
  2215. wszApp, wszAppVer, wszMod, wszModVer, wszOffset);
  2216. rgwsz[0] = wszApp;
  2217. rgwsz[1] = wszAppVer;
  2218. rgwsz[2] = wszMod;
  2219. rgwsz[3] = wszModVer;
  2220. rgwsz[4] = wszOffset;
  2221. return LogEvent(c_wszUserEventSrc, ER_USERFAULT_CATEGORY, dwEventID,
  2222. 5, strlen(szBlobLog), rgwsz, szBlobLog);
  2223. }
  2224. // **************************************************************************
  2225. #ifndef _WIN64
  2226. HRESULT LogKrnl(ULONG ulBCCode, ULONG ulBCP1, ULONG ulBCP2, ULONG ulBCP3,
  2227. ULONG ulBCP4)
  2228. #else
  2229. HRESULT LogKrnl(ULONG ulBCCode, ULONG64 ulBCP1, ULONG64 ulBCP2, ULONG64 ulBCP3,
  2230. ULONG64 ulBCP4)
  2231. #endif
  2232. {
  2233. USE_TRACING("LogKrnl");
  2234. HRESULT hr = NOERROR;
  2235. LPCWSTR rgwsz[5];
  2236. WCHAR wszBCC[32], wszBCP1[32], wszBCP2[32], wszBCP3[32], wszBCP4[32];
  2237. char szBlobLog[1024];
  2238. #ifndef _WIN64
  2239. swprintf(wszBCC, L"%08x", ulBCCode);
  2240. swprintf(wszBCP1, L"%08x", ulBCP1);
  2241. swprintf(wszBCP2, L"%08x", ulBCP2);
  2242. swprintf(wszBCP3, L"%08x", ulBCP3);
  2243. swprintf(wszBCP4, L"%08x", ulBCP4);
  2244. #else
  2245. swprintf(wszBCC, L"%016I64x", ulBCCode);
  2246. swprintf(wszBCP1, L"%016I64x", ulBCP1);
  2247. swprintf(wszBCP2, L"%016I64x", ulBCP2);
  2248. swprintf(wszBCP3, L"%016I64x", ulBCP3);
  2249. swprintf(wszBCP4, L"%016I64x", ulBCP4);
  2250. #endif
  2251. sprintf(szBlobLog, "System Error Error code %S Parameters %S, %S, %S, %S",
  2252. wszBCC, wszBCP1, wszBCP2, wszBCP3, wszBCP4);
  2253. rgwsz[0] = wszBCC;
  2254. rgwsz[1] = wszBCP1;
  2255. rgwsz[2] = wszBCP2;
  2256. rgwsz[3] = wszBCP3;
  2257. rgwsz[4] = wszBCP4;
  2258. return LogEvent(c_wszKrnlEventSrc, ER_KRNLFAULT_CATEGORY, ER_KRNLCRASH_LOG,
  2259. 5, strlen(szBlobLog), rgwsz, szBlobLog);
  2260. }