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.

2069 lines
70 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. fruser.cpp
  5. Abstract:
  6. Implements user fault reporting for unhandled exceptions
  7. Revision History:
  8. created derekm 07/07/00
  9. ******************************************************************************/
  10. /////////////////////////////////////////////////////////////////////////////
  11. // tracing
  12. #include "stdafx.h"
  13. #include "wtsapi32.h"
  14. #include "pchrexec.h"
  15. #include "frmc.h"
  16. #include "Tlhelp32.h"
  17. #ifdef THIS_FILE
  18. #undef THIS_FILE
  19. #endif
  20. static char __szTraceSourceFile[] = __FILE__;
  21. #define THIS_FILE __szTraceSourceFile
  22. // the size of the following buffer must be evenly divisible by 2 or an
  23. // alignment fault could occur on win64.
  24. struct SQueuedFaultBlob
  25. {
  26. DWORD cbTotal;
  27. DWORD cbFB;
  28. DWORD_PTR dwpAppPath;
  29. DWORD_PTR dwpModPath;
  30. UINT64 pvOffset;
  31. WORD rgAppVer[4];
  32. WORD rgModVer[4];
  33. BOOL fIs64bit;
  34. SYSTEMTIME stFault;
  35. };
  36. struct SQueuePruneData
  37. {
  38. LPWSTR wszVal;
  39. FILETIME ftFault;
  40. };
  41. #ifndef ARRAYSIZE
  42. #define ARRAYSIZE(x) sizeof(x)/sizeof(x[0])
  43. #endif
  44. ///////////////////////////////////////////////////////////////////////////////
  45. // utility functions
  46. // **************************************************************************
  47. BOOL GetFaultingModuleFilename(LPVOID pvFaultAddr, LPWSTR wszMod,
  48. DWORD cchMod)
  49. {
  50. USE_TRACING("GetFaultingModuleFilename");
  51. MODULEENTRY32W mod;
  52. HRESULT hr = NOERROR;
  53. HANDLE hSnap = INVALID_HANDLE_VALUE;
  54. LPVOID pvEnd;
  55. DWORD dwFlags = 0, iMod,cch;
  56. BOOL fRet = FALSE;
  57. VALIDATEPARM(hr, (pvFaultAddr == 0 || wszMod == NULL || cchMod == 0));
  58. if (FAILED(hr))
  59. goto done;
  60. *wszMod = L'\0';
  61. hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
  62. TESTBOOL(hr, (hSnap != NULL));
  63. if (FAILED(hr))
  64. goto done;
  65. ZeroMemory(&mod, sizeof(mod));
  66. mod.dwSize = sizeof(mod);
  67. TESTBOOL(hr, Module32FirstW(hSnap, &mod));
  68. if (FAILED(hr))
  69. goto done;
  70. do
  71. {
  72. pvEnd = mod.modBaseAddr + mod.modBaseSize;
  73. if (pvFaultAddr >= mod.modBaseAddr && pvFaultAddr < pvEnd)
  74. {
  75. if (cchMod > wcslen(mod.szExePath))
  76. {
  77. StringCchCopyW(wszMod, cchMod, mod.szExePath);
  78. fRet = TRUE;
  79. }
  80. else
  81. {
  82. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  83. fRet = FALSE;
  84. }
  85. break;
  86. }
  87. }
  88. while(Module32NextW(hSnap, &mod));
  89. done:
  90. if (hSnap != NULL)
  91. CloseHandle(hSnap);
  92. return fRet;
  93. }
  94. // **************************************************************************
  95. EFaultRepRetVal StartDWException(LPEXCEPTION_POINTERS pep, DWORD dwOpt,
  96. DWORD dwFlags, LPCSTR szServer,
  97. DWORD dwTimeToWait)
  98. {
  99. USE_TRACING("StartDWException");
  100. SECURITY_ATTRIBUTES sa;
  101. PROCESS_INFORMATION pi;
  102. EFaultRepRetVal frrvRet = frrvErrNoDW;
  103. DWSharedMem15 *pdwsm = NULL;
  104. STARTUPINFOW si;
  105. HRESULT hr = NOERROR;
  106. HANDLE hevDone = NULL, hevAlive = NULL, hmut = NULL;
  107. HANDLE hfmShared = NULL, hProc = NULL;
  108. HANDLE rghWait[2];
  109. LPWSTR wszAppCompat = NULL;
  110. WCHAR *pwszCmdLine, wszDir[MAX_PATH], *pwszAppName;
  111. WCHAR wszAppName[MAX_PATH];
  112. DWORD dw, dwStart, cch, cchNeed;
  113. BOOL fDWRunning = TRUE;
  114. ZeroMemory(&pi, sizeof(pi));
  115. VALIDATEPARM(hr, (pep == NULL));
  116. if (FAILED(hr))
  117. goto done;
  118. dwFlags |= (fDwWhistler | fDwUseHKLM | fDwAllowSuspend | fDwMiniDumpWithUnloadedModules);
  119. // we need the following things to be inheritable, so create a SD that
  120. // says it can be.
  121. ZeroMemory(&sa, sizeof(sa));
  122. sa.nLength = sizeof(sa);
  123. sa.bInheritHandle = TRUE;
  124. // create the necessary events & mutexes
  125. hevDone = CreateEvent(&sa, FALSE, FALSE, NULL);
  126. TESTBOOL(hr, (hevDone != NULL));
  127. if (FAILED(hr))
  128. goto done;
  129. hevAlive = CreateEvent(&sa, FALSE, FALSE, NULL);
  130. TESTBOOL(hr, (hevAlive != NULL));
  131. if (FAILED(hr))
  132. goto done;
  133. hmut = CreateMutex(&sa, FALSE, NULL);
  134. TESTBOOL(hr, (hmut != NULL));
  135. if (FAILED(hr))
  136. goto done;
  137. TESTBOOL(hr, DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
  138. GetCurrentProcess(), &hProc,
  139. PROCESS_ALL_ACCESS, TRUE, 0));
  140. if (FAILED(hr))
  141. goto done;
  142. // create the shared memory region & map it
  143. hfmShared = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0,
  144. sizeof(DWSharedMem), NULL);
  145. TESTBOOL(hr, (hfmShared != NULL));
  146. if (FAILED(hr))
  147. goto done;
  148. pdwsm = (DWSharedMem *)MapViewOfFile(hfmShared,
  149. FILE_MAP_READ | FILE_MAP_WRITE, 0, 0,
  150. 0);
  151. TESTBOOL(hr, (pdwsm != NULL));
  152. if (FAILED(hr))
  153. goto done;
  154. // populate all the stuff that DW needs
  155. ZeroMemory(pdwsm, sizeof(DWSharedMem15));
  156. pdwsm->dwSize = sizeof(DWSharedMem15);
  157. pdwsm->pid = GetCurrentProcessId();
  158. pdwsm->tid = GetCurrentThreadId();
  159. pdwsm->eip = (DWORD_PTR)pep->ExceptionRecord->ExceptionAddress;
  160. pdwsm->pep = pep;
  161. pdwsm->hEventDone = hevDone;
  162. pdwsm->hEventNotifyDone = NULL;
  163. pdwsm->hEventAlive = hevAlive;
  164. pdwsm->hMutex = hmut;
  165. pdwsm->hProc = hProc;
  166. pdwsm->bfDWBehaviorFlags = dwFlags;
  167. pdwsm->msoctdsResult = msoctdsNull;
  168. pdwsm->fReportProblem = FALSE;
  169. pdwsm->bfmsoctdsOffer = msoctdsQuit;
  170. pdwsm->bfmsoctdsNotify = 0;
  171. if (dwOpt == 1)
  172. pdwsm->bfmsoctdsOffer |= msoctdsDebug;
  173. pdwsm->bfmsoctdsLetRun = pdwsm->bfmsoctdsOffer;
  174. pdwsm->iPingCurrent = 0;
  175. pdwsm->iPingEnd = 0;
  176. pdwsm->lcidUI = GetUserDefaultUILanguage();
  177. StringCbCopyA(pdwsm->szServer, sizeof(pdwsm->szServer), szServer);
  178. StringCbCopyA(pdwsm->szRegSubPath, sizeof(pdwsm->szRegSubPath), c_szDWRegSubPath);
  179. StringCbCopyA(pdwsm->szBrand, sizeof(pdwsm->szBrand), c_szDWBrand);
  180. StringCbCopyA(pdwsm->szPIDRegKey, sizeof(pdwsm->szPIDRegKey), c_szRKVDigPid);
  181. if (!GetModuleFileNameW(NULL, pdwsm->wzModuleFileName, DW_MAX_PATH))
  182. {
  183. goto done;
  184. }
  185. TESTHR(hr, GetVerName(pdwsm->wzModuleFileName, wszAppName,
  186. sizeofSTRW(wszAppName), NULL, 0, NULL, 0,
  187. TRUE, FALSE));
  188. if (FAILED(hr))
  189. goto done;
  190. cch = CreateTempDirAndFile(NULL, c_wszACFileName, &wszAppCompat);
  191. TESTBOOL(hr, (cch != 0));
  192. if (SUCCEEDED(hr))
  193. {
  194. WCHAR wszMod[MAX_PATH], *pwszMod = NULL;
  195. TESTBOOL(hr, GetFaultingModuleFilename(pep->ExceptionRecord->ExceptionAddress,
  196. wszMod, sizeofSTRW(wszMod)));
  197. if (SUCCEEDED(hr))
  198. pwszMod = wszMod;
  199. TESTBOOL(hr, GetAppCompatData(pdwsm->wzModuleFileName, pwszMod,
  200. wszAppCompat));
  201. if (SUCCEEDED(hr) && wszAppCompat != NULL &&
  202. wcslen(wszAppCompat) < sizeofSTRW(pdwsm->wzAdditionalFile))
  203. StringCbCopyW(pdwsm->wzAdditionalFile, sizeof(pdwsm->wzAdditionalFile), wszAppCompat);
  204. }
  205. wszAppName[sizeofSTRW(wszAppName) - 1] = L'\0';
  206. StringCbCopyW(pdwsm->wzFormalAppName, sizeof(pdwsm->wzFormalAppName), wszAppName);
  207. // Since we zero out the structure above, don't need to worry about
  208. // appending an extra L'\0' to the end of this (since DW requires a
  209. // double NULL terminator at the end of this string)
  210. // Include only faulting app, since that is what we do when generating minidump ourselves
  211. // StringCbCopyW(pdwsm->wzDotDataDlls, sizeof(pdwsm->wzDotDataDlls), L"*"); // use L"*" for including all
  212. pdwsm->wzDotDataDlls[0] = L'\0';
  213. /*
  214. // need to figure out what should go in the following valies
  215. strcpy(pdwsm->szLCIDKeyValue, "");
  216. wcscpy(pdwsm->wzErrorMessage, "");
  217. */
  218. cch = GetSystemDirectoryW(wszDir, sizeofSTRW(wszDir));
  219. if (cch == 0 || cch > sizeofSTRW(wszDir))
  220. goto done;
  221. cchNeed = cch + wcslen(wszDir) + sizeofSTRW(c_wszDWExeU) + 1;
  222. __try { pwszAppName = (WCHAR *)_alloca(cchNeed * sizeof(WCHAR)); }
  223. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  224. {
  225. pwszAppName = NULL;
  226. }
  227. if (pwszAppName == NULL)
  228. {
  229. SetLastError(ERROR_OUTOFMEMORY);
  230. goto done;
  231. }
  232. StringCchPrintfW(pwszAppName, cchNeed, c_wszDWExeU, wszDir);
  233. // the +12 is for the max size of an integer in decimal
  234. cchNeed = cch + wcslen(wszDir) + sizeofSTRW(c_wszDWCmdLineU) + 12;
  235. __try { pwszCmdLine = (WCHAR *)_alloca(cchNeed * sizeof(WCHAR)); }
  236. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  237. {
  238. pwszCmdLine = NULL;
  239. }
  240. if (pwszCmdLine == NULL)
  241. {
  242. SetLastError(ERROR_OUTOFMEMORY);
  243. goto done;
  244. }
  245. StringCchPrintfW(pwszCmdLine, cchNeed, c_wszDWCmdLineU, hfmShared);
  246. // create the process
  247. ZeroMemory(&si, sizeof(si));
  248. ZeroMemory(&pi, sizeof(pi));
  249. // always want to launch this in the interactive workstation
  250. si.cb = sizeof(si);
  251. si.lpDesktop = L"Winsta0\\Default";
  252. DBG_MSG("Starting DW");
  253. TESTBOOL(hr, CreateProcessW(pwszAppName, pwszCmdLine, NULL, NULL, TRUE,
  254. CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS,
  255. NULL, wszDir, &si, &pi));
  256. if (FAILED(hr))
  257. goto done;
  258. // don't need the thread handle & we gotta close it, so close it now
  259. CloseHandle(pi.hThread);
  260. // assume we succeed from here on...
  261. if ((dwFlags & fDwHeadless) == fDwHeadless)
  262. frrvRet = frrvOkHeadless;
  263. else
  264. frrvRet = frrvOk;
  265. rghWait[0] = hevAlive;
  266. rghWait[1] = pi.hProcess;
  267. dwStart = GetTickCount();
  268. while(fDWRunning)
  269. {
  270. // gotta periodically get the Alive signal from DW.
  271. switch(WaitForMultipleObjects(2, rghWait, FALSE, 300000))
  272. {
  273. case WAIT_OBJECT_0:
  274. /*
  275. * The user clicked something (Send or Dont) so we know that DW
  276. * will be shutting down soon.
  277. */
  278. if (WaitForSingleObject(hevDone, 0) == WAIT_OBJECT_0)
  279. fDWRunning = FALSE;
  280. /*
  281. * If the user doesn't respond, and there is a JIT debugger,
  282. * then we need to make certain that DW is killed before returning.
  283. */
  284. else if (dwOpt != (DWORD)0 &&
  285. RolloverSubtract(GetTickCount(), dwStart) > 300000)
  286. {
  287. frrvRet = frrvErrTimeout;
  288. fDWRunning = FALSE;
  289. LocalKill(pi.hProcess);
  290. pi.hProcess = 0;
  291. }
  292. continue;
  293. case WAIT_OBJECT_0 + 1:
  294. fDWRunning = FALSE;
  295. continue;
  296. }
  297. switch(WaitForSingleObject(hmut, DW_TIMEOUT_VALUE))
  298. {
  299. // yay! we got the mutex. Try to detemine if DW finally responded
  300. // while we were grabbing the mutex.
  301. case WAIT_OBJECT_0:
  302. switch(WaitForMultipleObjects(2, rghWait, FALSE, 0))
  303. {
  304. // If it hasn't responded, tell it to go away & fall thru
  305. // into the 'it died' case.
  306. case WAIT_TIMEOUT:
  307. SetEvent(hevDone);
  308. // It died. Clean up.
  309. case WAIT_OBJECT_0 + 1:
  310. fDWRunning = FALSE;
  311. frrvRet = frrvErrNoDW;
  312. continue;
  313. }
  314. // ok, it responded. Is it done?
  315. if (WaitForSingleObject(hevDone, 0) == WAIT_OBJECT_0)
  316. fDWRunning = FALSE;
  317. ReleaseMutex(hmut);
  318. break;
  319. // if the wait was abandoned, it means DW has gone to the great bit
  320. // bucket in the sky without cleaning up. So release the mutex and
  321. // fall into the default case
  322. case WAIT_ABANDONED:
  323. ReleaseMutex(hmut);
  324. // if we timed out or otherwise failed, just die.
  325. default:
  326. frrvRet = frrvErrNoDW;
  327. fDWRunning = FALSE;
  328. break;
  329. }
  330. }
  331. if (frrvRet != frrvOk)
  332. {
  333. goto done;
  334. }
  335. // if user told us to debug, return that back to the
  336. if (pdwsm->msoctdsResult == msoctdsDebug)
  337. frrvRet = frrvLaunchDebugger;
  338. done:
  339. // preserve the error code so that the following calls don't overwrite it
  340. dw = GetLastError();
  341. if (wszAppCompat != NULL)
  342. {
  343. if (pi.hProcess)
  344. WaitForSingleObject(pi.hProcess, 300000);
  345. DeleteTempDirAndFile(wszAppCompat, TRUE);
  346. MyFree(wszAppCompat);
  347. }
  348. if (pi.hProcess)
  349. CloseHandle(pi.hProcess);
  350. if (pdwsm != NULL)
  351. UnmapViewOfFile(pdwsm);
  352. if (hfmShared != NULL)
  353. CloseHandle(hfmShared);
  354. if (hevDone != NULL)
  355. CloseHandle(hevDone);
  356. if (hevAlive != NULL)
  357. CloseHandle(hevAlive);
  358. if (hmut != NULL)
  359. CloseHandle(hmut);
  360. if (hProc != NULL)
  361. CloseHandle(hProc);
  362. SetLastError(dw);
  363. return frrvRet;
  364. }
  365. // **************************************************************************
  366. EFaultRepRetVal StartManifestReport(LPEXCEPTION_POINTERS pep, LPWSTR wszExe,
  367. DWORD dwOpt, DWORD dwTimeToWait)
  368. {
  369. USE_TRACING("StartManifestReport");
  370. SPCHExecServFaultRequest *pesdwreq = NULL;
  371. SPCHExecServFaultReply *pesrep = NULL;
  372. EFaultRepRetVal frrvRet = frrvErrNoDW;
  373. HRESULT hr = NOERROR;
  374. DWORD cbReq, cbRead;
  375. WCHAR wszName[MAX_PATH];
  376. BYTE Buf[ERRORREP_PIPE_BUF_SIZE], *pBuf;
  377. BYTE BufRep[ERRORREP_PIPE_BUF_SIZE];
  378. VALIDATEPARM(hr, (wszExe == NULL));
  379. if (FAILED(hr))
  380. goto done;
  381. ZeroMemory(Buf, sizeof(Buf));
  382. pesdwreq = (SPCHExecServFaultRequest *)Buf;
  383. // the following calculation ensures that pBuf is always aligned on a
  384. // sizeof(WCHAR) boundry...
  385. cbReq = sizeof(SPCHExecServFaultRequest) +
  386. sizeof(SPCHExecServFaultRequest) % sizeof(WCHAR);
  387. pBuf = Buf + cbReq;
  388. pesdwreq->cbESR = sizeof(SPCHExecServFaultRequest);
  389. pesdwreq->pidReqProcess = GetCurrentProcessId();
  390. pesdwreq->thidFault = GetCurrentThreadId();
  391. pesdwreq->pvFaultAddr = (UINT64)pep->ExceptionRecord->ExceptionAddress;
  392. pesdwreq->pEP = (UINT64)pep;
  393. #ifdef _WIN64
  394. pesdwreq->fIs64bit = TRUE;
  395. #else
  396. pesdwreq->fIs64bit = FALSE;
  397. #endif
  398. // marshal in the strings
  399. pesdwreq->wszExe = (UINT64)MarshallString(wszExe, Buf, sizeof(Buf), &pBuf,
  400. &cbReq);
  401. if (pesdwreq->wszExe == 0)
  402. goto done;
  403. pesdwreq->cbTotal = cbReq;
  404. // check and see if the system is shutting down. If so, CreateProcess is
  405. // gonna pop up some annoying UI that we can't get rid of, so we don't
  406. // want to call it if we know it's gonna happen.
  407. if (GetSystemMetrics(SM_SHUTTINGDOWN))
  408. goto done;
  409. // Send the buffer out to the server- wait at most 2m for this to
  410. // succeed. If it times out, bail. BTW, need to zero out BufRep here
  411. // cuz the call to the named pipe CAN fail & we don't want to start
  412. // processing garbage results...
  413. ZeroMemory(BufRep, sizeof(BufRep));
  414. StringCbCopyW(wszName, sizeof(wszName), ERRORREP_FAULT_PIPENAME);
  415. TESTHR(hr, MyCallNamedPipe(wszName, Buf, cbReq, BufRep, sizeof(BufRep),
  416. &cbRead, 120000, 120000));
  417. if (FAILED(hr))
  418. {
  419. // determine the error code that indicates whether we've timed out so
  420. // we can set the return code appropriately.
  421. goto done;
  422. }
  423. pesrep = (SPCHExecServFaultReply *)BufRep;
  424. // did the call succeed?
  425. VALIDATEEXPR(hr, (pesrep->ess == essErr), Err2HR(pesrep->dwErr));
  426. if (FAILED(hr))
  427. {
  428. SetLastError(pesrep->dwErr);
  429. goto done;
  430. }
  431. // this is only necessary if we actually launched DW. If we just queued
  432. // the fault for later, then we obviously can't wait on DW.
  433. if (pesrep->ess == essOk)
  434. {
  435. DWORD dwExitCode = msoctdsNull;
  436. // gotta wait for DW to be done before we nuke the manifest file, but
  437. // if it hasn't parsed it in 5 minutes, something's wrong with it.
  438. if (pesrep->hProcess != NULL)
  439. {
  440. DWORD dwTimeout;
  441. // so, if we're going to pop up the JIT debugger dialog if we timeout,
  442. // then maybe we should just not bother timeing out...
  443. dwTimeout = (dwOpt == froDebug) ? INFINITE : 300000;
  444. if (WaitForSingleObject(pesrep->hProcess, dwTimeout) == WAIT_TIMEOUT)
  445. frrvRet = frrvErrTimeout;
  446. // see if we need to debug the process
  447. else if (GetExitCodeProcess(pesrep->hProcess, &dwExitCode) == FALSE)
  448. dwExitCode = msoctdsNull;
  449. CloseHandle(pesrep->hProcess);
  450. pesrep->hProcess = NULL;
  451. }
  452. // we're only going to delete the files if DW has finished with them.
  453. // Yes this means we can leave stray files in the temp dir, but this
  454. // is better than having DW randomly fail while sending...
  455. if (frrvRet != frrvErrTimeout)
  456. {
  457. LPWSTR pwsz, pwszEnd;
  458. if (pesrep->wszDir != 0)
  459. {
  460. if (pesrep->wszDir < cbRead &&
  461. pesrep->wszDir >= sizeof(SPCHExecServFaultReply))
  462. pesrep->wszDir += (UINT64)pesrep;
  463. else
  464. pesrep->wszDir = 0;
  465. }
  466. if (pesrep->wszDumpName != 0)
  467. {
  468. if (pesrep->wszDumpName < cbRead &&
  469. pesrep->wszDumpName >= sizeof(SPCHExecServFaultReply))
  470. pesrep->wszDumpName += (UINT64)pesrep;
  471. else
  472. pesrep->wszDumpName = 0;
  473. }
  474. // make sure that there is a NULL terminator for each string
  475. // before the end of the buffer...
  476. pwszEnd = (LPWSTR)((BYTE *)pesrep + cbRead);
  477. if (pesrep->wszDumpName != 0)
  478. {
  479. for (pwsz = (LPWSTR)pesrep->wszDumpName;
  480. pwsz < pwszEnd && *pwsz != L'\0';
  481. pwsz++);
  482. if (*pwsz != L'\0')
  483. pesrep->wszDumpName = 0;
  484. }
  485. if (pesrep->wszDir != 0)
  486. {
  487. for (pwsz = (LPWSTR)pesrep->wszDir;
  488. pwsz < pwszEnd && *pwsz != L'\0';
  489. pwsz++);
  490. if (*pwsz != L'\0')
  491. pesrep->wszDir = 0;
  492. }
  493. }
  494. frrvRet = (dwExitCode == msoctdsDebug) ? frrvLaunchDebugger :
  495. frrvOkManifest;
  496. }
  497. // if we queued it, set the appropriate return code (duh)
  498. else if (pesrep->ess == essOkQueued)
  499. {
  500. frrvRet = frrvOkQueued;
  501. }
  502. SetLastError(0);
  503. done:
  504. if ((frrvRet == frrvOkManifest || frrvRet == frrvLaunchDebugger) &&
  505. pesrep != NULL && pesrep->wszDir != 0)
  506. {
  507. LPWSTR wszToDel = NULL;
  508. DWORD cchDir = 0, cchFile = 0;
  509. cchDir = wcslen((LPWSTR)pesrep->wszDir);
  510. if (pesrep->wszDumpName != 0)
  511. cchFile = wcslen((LPWSTR)pesrep->wszDumpName);
  512. if (cchFile < sizeofSTRW(c_wszACFileName))
  513. cchFile = sizeofSTRW(c_wszACFileName);
  514. if (cchFile < sizeofSTRW(c_wszManFileName))
  515. cchFile = sizeofSTRW(c_wszACFileName);
  516. __try { wszToDel = (LPWSTR)_alloca((cchFile + cchDir + 4) * sizeof(WCHAR)); }
  517. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  518. {
  519. wszToDel = NULL;
  520. }
  521. if (wszToDel != NULL)
  522. {
  523. LPWSTR pwszToDel;
  524. StringCchCopyW(wszToDel, cchDir + cchFile + 4, (LPWSTR)pesrep->wszDir);
  525. pwszToDel = wszToDel + cchDir;
  526. *pwszToDel++ = L'\\';
  527. if (pesrep->wszDumpName != 0)
  528. {
  529. StringCchCopyW(pwszToDel, cchFile + 1, (LPWSTR)pesrep->wszDumpName);
  530. DeleteFullAndTriageMiniDumps(wszToDel);
  531. }
  532. StringCchCopyW(pwszToDel, cchFile + 1, c_wszACFileName);
  533. DeleteFileW(wszToDel);
  534. StringCchCopyW(pwszToDel, cchFile + 1, c_wszManFileName);
  535. DeleteFileW(wszToDel);
  536. }
  537. DeleteTempDirAndFile((LPWSTR)pesrep->wszDir, FALSE);
  538. }
  539. ErrorTrace(1, "StartManifestReport returns %d", frrvRet);
  540. return frrvRet;
  541. }
  542. // **************************************************************************
  543. HRESULT PruneQ(HKEY hkeyQ, DWORD cQSize, DWORD cMaxQSize, DWORD cchMaxVal,
  544. DWORD cbMaxData)
  545. {
  546. USE_TRACING("PruneQ");
  547. SQueuedFaultBlob *psqfb = NULL;
  548. SQueuePruneData *pqpd = NULL;
  549. FILETIME ft;
  550. HRESULT hr = NOERROR;
  551. LPWSTR pwsz, pwszCurrent = NULL;
  552. DWORD cchVal, cbData, dwType, cToDel = 0, cInDelList = 0;
  553. DWORD i, iEntry, dw, cValid = 0;
  554. VALIDATEPARM(hr, (hkeyQ == NULL));
  555. if (FAILED(hr))
  556. goto done;
  557. if (cMaxQSize > cQSize)
  558. goto done;
  559. cToDel = cQSize - cMaxQSize + 1;
  560. // alloc the various buffers that we'll need:
  561. // the delete list
  562. // the current file we're working with
  563. // the data blob associated with the current file
  564. cbData = (sizeof(SQueuePruneData) + (cchMaxVal * sizeof(WCHAR))) * cToDel;
  565. pwszCurrent = (LPWSTR)MyAlloc(cchMaxVal * sizeof(WCHAR));
  566. psqfb = (SQueuedFaultBlob *)MyAlloc(cbMaxData);
  567. pqpd = (SQueuePruneData *)MyAlloc(cbData);
  568. if (psqfb == NULL || pwszCurrent == NULL || pqpd == NULL)
  569. {
  570. SetLastError(ERROR_OUTOFMEMORY);
  571. hr = E_OUTOFMEMORY;
  572. goto done;
  573. }
  574. // intiailize all the string pointers in the delete list
  575. pwsz = (LPWSTR)((BYTE *)pqpd + (sizeof(SQueuePruneData) * cToDel));
  576. for (i = 0; i < cToDel; i++)
  577. {
  578. pqpd[i].ftFault.dwHighDateTime = 0;
  579. pqpd[i].ftFault.dwLowDateTime = 0;
  580. pqpd[i].wszVal = pwsz;
  581. pqpd[i].wszVal[0] = L'\0';
  582. pwsz += cchMaxVal;
  583. }
  584. // ok, get a list of all the valid items and build an array in sorted order
  585. // so that we can easily pick off the top n items
  586. for(iEntry = 0; iEntry < cQSize; iEntry++)
  587. {
  588. cchVal = cchMaxVal;
  589. cbData = cbMaxData;
  590. dw = RegEnumValueW(hkeyQ, iEntry, pwszCurrent, &cchVal, 0, &dwType,
  591. (PBYTE)psqfb, &cbData);
  592. if (dw == ERROR_NO_MORE_ITEMS)
  593. break;
  594. else if (dw != ERROR_SUCCESS)
  595. continue;
  596. else if (dwType != REG_BINARY ||
  597. cbData < sizeof(SQueuedFaultBlob) ||
  598. psqfb->cbFB != sizeof(SQueuedFaultBlob) ||
  599. psqfb->cbTotal != cbData)
  600. {
  601. DeleteFileW(pwszCurrent);
  602. RegDeleteValueW(hkeyQ, pwszCurrent);
  603. continue;
  604. }
  605. SystemTimeToFileTime(&psqfb->stFault, &ft);
  606. for (i = 0; i < cInDelList; i++)
  607. {
  608. if ((ft.dwHighDateTime < pqpd[i].ftFault.dwHighDateTime) ||
  609. (ft.dwHighDateTime == pqpd[i].ftFault.dwHighDateTime &&
  610. ft.dwLowDateTime < pqpd[i].ftFault.dwLowDateTime))
  611. break;
  612. }
  613. // if it's in the middle of the current list, then we gotta move
  614. // stuff around
  615. if (cInDelList > 0 && i < cInDelList - 1)
  616. {
  617. LPWSTR pwszTemp = pqpd[cInDelList - 1].wszVal;
  618. MoveMemory(&pqpd[i], &pqpd[i + 1],
  619. (cInDelList - i) * sizeof(SQueuePruneData));
  620. pqpd[i].wszVal = pwszTemp;
  621. }
  622. if (i < cToDel)
  623. {
  624. // note that this copy is safe cuz each string slot is the same
  625. // size as the buffer pointed to by pwszCurrent and that buffer is
  626. // protected from overflow by the size we pass into
  627. // RegEnumValueW()
  628. StringCchCopyW(pqpd[i].wszVal, wcslen(pwszCurrent)+1, pwszCurrent);
  629. pqpd[i].ftFault = ft;
  630. if (cInDelList < cToDel)
  631. cInDelList++;
  632. }
  633. cValid++;
  634. }
  635. // if there aren't enuf valid entries to warrant a purge, then don't purge
  636. if (cValid < cMaxQSize)
  637. goto done;
  638. cToDel = MyMin(cToDel, cValid - cMaxQSize + 1);
  639. // purge enuf entries that we go down to 1 below our max (since we have to
  640. // be adding 1 to get here- don't want that 1 to drive us over the limit
  641. for(i = 0; i < cToDel; i++)
  642. {
  643. if (pqpd[i].wszVal != NULL)
  644. {
  645. DeleteFullAndTriageMiniDumps(pqpd[i].wszVal);
  646. RegDeleteValueW(hkeyQ, pqpd[i].wszVal);
  647. }
  648. }
  649. done:
  650. if (pqpd != NULL)
  651. MyFree(pqpd);
  652. if (psqfb != NULL)
  653. MyFree(psqfb);
  654. if (pwszCurrent != NULL)
  655. MyFree(pwszCurrent);
  656. return hr;
  657. }
  658. // **************************************************************************
  659. HRESULT CheckQSizeAndPrune(HKEY hkeyQ)
  660. {
  661. USE_TRACING("CheckQueueSizeAndPrune");
  662. HRESULT hr = NOERROR;
  663. HANDLE hmut = NULL;
  664. DWORD cMaxQSize = 0, cDefMaxQSize = 10;
  665. DWORD cQSize, cchMaxVal, cbMaxData;
  666. DWORD cb, dw;
  667. HKEY hkey = NULL;
  668. VALIDATEPARM(hr, (hkeyQ == NULL));
  669. if (FAILED(hr))
  670. goto done;
  671. // find out the max Q size
  672. TESTHR(hr, OpenRegKey(HKEY_LOCAL_MACHINE, c_wszRPCfg, 0, &hkey));
  673. if (SUCCEEDED(hr))
  674. {
  675. cb = sizeof(cMaxQSize);
  676. TESTHR(hr, ReadRegEntry(hkey, c_wszRVMaxQueueSize, NULL, (PBYTE)&cMaxQSize,
  677. &cb, (PBYTE)&cDefMaxQSize, sizeof(cDefMaxQSize)));
  678. RegCloseKey(hkey);
  679. hkey = NULL;
  680. }
  681. // find out the max Q size in policy
  682. TESTHR(hr, OpenRegKey(HKEY_LOCAL_MACHINE, c_wszRPCfgPolicy, 0, &hkey));
  683. if (SUCCEEDED(hr))
  684. {
  685. cb = sizeof(cMaxQSize);
  686. TESTHR(hr, ReadRegEntry(hkey, c_wszRVMaxQueueSize, NULL, (PBYTE)&cMaxQSize,
  687. &cb, (PBYTE)&cMaxQSize, sizeof(cMaxQSize)));
  688. RegCloseKey(hkey);
  689. hkey = NULL;
  690. }
  691. // if the Q size is 0, then we are effectively disabled for Qing faults.
  692. // Return S_FALSE to indicate this
  693. if (cMaxQSize == 0)
  694. {
  695. hr = S_FALSE;
  696. goto done;
  697. }
  698. else if (cMaxQSize > c_cMaxQueue)
  699. cMaxQSize = c_cMaxQueue;
  700. hmut = OpenMutexW(SYNCHRONIZE, FALSE, c_wszMutUserName);
  701. TESTBOOL(hr, (hmut != NULL));
  702. if (FAILED(hr))
  703. goto done;
  704. // wait for 5s for the mutex to become available- this should be enuf time
  705. // for anyone else to add something to the queue dir. It could take longer
  706. // if someone is processing the dir, but then items are being removed
  707. // anyway...
  708. dw = WaitForSingleObject(hmut, 5000);
  709. if (dw != WAIT_OBJECT_0)
  710. {
  711. // if the wait timed out, then someone is already going thru the faults
  712. // so it's likely to be reduced sometime soon
  713. if (dw == WAIT_TIMEOUT)
  714. hr = NOERROR;
  715. else
  716. hr = Err2HR(GetLastError());
  717. goto done;
  718. }
  719. __try
  720. {
  721. // determine what the Q size is.
  722. TESTERR(hr, RegQueryInfoKey(hkeyQ, NULL, NULL, NULL, NULL, NULL, NULL,
  723. &cQSize, &cchMaxVal, &cbMaxData, NULL, NULL));
  724. if (SUCCEEDED(hr) && (cQSize >= cMaxQSize))
  725. {
  726. cchMaxVal++;
  727. TESTHR(hr, PruneQ(hkeyQ, cQSize, cMaxQSize, cchMaxVal, cbMaxData));
  728. }
  729. else
  730. {
  731. hr = NOERROR;
  732. }
  733. }
  734. __except(EXCEPTION_EXECUTE_HANDLER)
  735. {
  736. }
  737. done:
  738. if (hmut != NULL)
  739. {
  740. ReleaseMutex(hmut);
  741. CloseHandle(hmut);
  742. }
  743. return hr;
  744. }
  745. ///////////////////////////////////////////////////////////////////////////////
  746. // exported functions
  747. // **************************************************************************
  748. EFaultRepRetVal APIENTRY ReportFaultFromQueue(LPWSTR wszDump, BYTE *pbData,
  749. DWORD cbData)
  750. {
  751. USE_TRACING("ReportFaultFromQueue");
  752. CPFFaultClientCfg oCfg;
  753. SQueuedFaultBlob *pqfb = (SQueuedFaultBlob *)pbData;
  754. EFaultRepRetVal frrvRet = frrvErrNoDW;
  755. SDWManifestBlob dwmb;
  756. SYSTEMTIME stLocal;
  757. FILETIME ft, ftLocal;
  758. HRESULT hr = NOERROR;
  759. LPWSTR wszAppPath, wszModPath;
  760. LPWSTR wszModName, wszAppName, pwszApp, pwszEnd;
  761. LPWSTR wszStage1, wszStage2, wszCorpPath, wszHdr, wszErrMsg, wszErrorSig = NULL;
  762. LPWSTR wszNewDump = NULL, wszDir = NULL;
  763. LPWSTR wszManifest = NULL, pwszAppCompat = NULL;
  764. WCHAR wszDate[128], wszTime[128], *pwsz;
  765. WCHAR *pwch;
  766. WCHAR wszAppFriendlyName[MAX_PATH];
  767. WCHAR wszBuffer[160];
  768. WCHAR wszUnknown[] = L"unknown";
  769. DWORD dw, cchTotal, cchSep = 0, cch, cchDir, cchBfr, cchNewDump;
  770. BYTE *pbBuf = NULL;
  771. BOOL fMSApp = FALSE, fAllowSend = TRUE, fOkCopy = FALSE;
  772. VALIDATEPARM(hr, (wszDump == NULL || pbData == NULL) ||
  773. cbData < sizeof(SQueuedFaultBlob) ||
  774. pqfb->cbFB != sizeof(SQueuedFaultBlob) ||
  775. pqfb->cbTotal != cbData ||
  776. pqfb->dwpAppPath >= cbData ||
  777. pqfb->dwpModPath >= cbData);
  778. if (FAILED(hr))
  779. goto done;
  780. wszAppPath = (LPWSTR)(pqfb->dwpAppPath + pbData);
  781. wszModPath = (LPWSTR)(pqfb->dwpModPath + pbData);
  782. pwszEnd = (LPWSTR)(pbData + cbData);
  783. // make sure there's a NULL terminator on the ModPath string before the end
  784. // of the buffer...
  785. for (pwch = wszModPath; pwch < pwszEnd && *pwch != L'\0'; pwch++);
  786. if (pwch >= pwszEnd)
  787. {
  788. SetLastError(ERROR_INVALID_PARAMETER);
  789. goto done;
  790. }
  791. // convieniently, pwch is now at the end of ModPath string, so we can
  792. // parse back to find the first backslash & get the module name
  793. for(pwch -= 1; pwch >= wszModPath && *pwch != L'\\'; pwch--);
  794. if (*pwch == L'\\')
  795. wszModName = pwch + 1;
  796. else
  797. wszModName = wszModPath;
  798. if (*wszModName == L'\0')
  799. wszModName = wszUnknown;
  800. // make sure there's a NULL terminator on the AppPath string before the end
  801. // of the buffer...
  802. for (pwch = wszAppPath; pwch < wszModPath && *pwch != L'\0'; pwch++);
  803. if (pwch >= wszModPath)
  804. {
  805. SetLastError(ERROR_INVALID_PARAMETER);
  806. goto done;
  807. }
  808. // convieniently, pwch is now at the end of AppPath string, so we can
  809. // parse back to find the first backslash & get the module name
  810. for(pwch -= 1; pwch >= wszAppPath && *pwch != L'\\'; pwch--);
  811. if (*pwch == L'\\')
  812. wszAppName = pwch + 1;
  813. else
  814. wszAppName = wszAppPath;
  815. if (*wszAppName == L'\0')
  816. {
  817. SetLastError(ERROR_INVALID_PARAMETER);
  818. goto done;
  819. }
  820. // get the config info
  821. TESTHR(hr, oCfg.Read(eroPolicyRO));
  822. if (FAILED(hr))
  823. goto done;
  824. if (oCfg.get_ShowUI() == eedDisabled && oCfg.get_DoReport() == eedDisabled)
  825. goto done;
  826. // figure out how we're reporting / notifying the user
  827. if (oCfg.get_DoReport() == eedDisabled ||
  828. oCfg.ShouldCollect(wszAppPath, &fMSApp) == FALSE)
  829. fAllowSend = FALSE;
  830. if (oCfg.get_ShowUI() == eedDisabled)
  831. {
  832. LPCWSTR wszULPath = oCfg.get_DumpPath(NULL, 0);
  833. // check and make sure that we have a corporate path specified. If we
  834. // don't, bail
  835. if (wszULPath == NULL || *wszULPath == L'\0')
  836. goto done;
  837. }
  838. // log an event- don't care if it fails or not.
  839. TESTHR(hr, LogUser(wszAppName, pqfb->rgAppVer, wszModName, pqfb->rgModVer,
  840. pqfb->pvOffset, pqfb->fIs64bit, ER_QUEUEREPORT_LOG));
  841. if (CreateTempDirAndFile(NULL, NULL, &wszDir) == 0)
  842. goto done;
  843. cchDir = wcslen(wszDir);
  844. cch = cchDir + sizeofSTRW(c_wszManFileName) + 4;
  845. __try { wszManifest = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  846. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  847. {
  848. wszManifest = NULL;
  849. }
  850. if (wszManifest == NULL)
  851. {
  852. SetLastError(ERROR_OUTOFMEMORY);
  853. goto done;
  854. }
  855. StringCchCopyW(wszManifest, cch, wszDir);
  856. wszManifest[cchDir] = L'\\';
  857. wszManifest[cchDir + 1] = L'\0';
  858. StringCchCatNW(wszManifest, cch, c_wszManFileName, cch - wcslen(wszManifest));
  859. cchDir = wcslen(wszDir);
  860. cchBfr = cch = 2 * cchDir + wcslen(wszDump) + sizeofSTRW(c_wszACFileName) + 4;
  861. __try { wszNewDump = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  862. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  863. {
  864. wszNewDump = NULL;
  865. }
  866. if (wszNewDump == NULL)
  867. {
  868. SetLastError(ERROR_OUTOFMEMORY);
  869. goto done;
  870. }
  871. cchNewDump = cch;
  872. StringCchCopyW(wszNewDump, cch, wszDir);
  873. wszNewDump[cchDir] = L'\\';
  874. wszNewDump[cchDir + 1] = L'\0';
  875. fOkCopy = FALSE;
  876. for (pwsz = wszDump + wcslen(wszDump);
  877. *pwsz != L'\\' && pwsz > wszDump;
  878. pwsz--);
  879. if (*pwsz == L'\\')
  880. {
  881. pwsz++;
  882. StringCchCatNW(wszNewDump, cch, pwsz, cch - wcslen(wszNewDump));
  883. for (pwsz = wszNewDump + wcslen(wszNewDump);
  884. *pwsz != L'.' && pwsz > wszNewDump;
  885. pwsz--);
  886. if (*pwsz == L'.' && pwsz > wszNewDump &&
  887. _wcsicmp(pwsz, c_wszDumpSuffix) == 0)
  888. {
  889. pwsz--;
  890. for(;
  891. *pwsz != L'.' && pwsz > wszNewDump;
  892. pwsz--);
  893. if (*pwsz == L'.' && pwsz > wszNewDump)
  894. {
  895. StringCchCopyW(pwsz, cch - (ULONG) ((ULONG_PTR)pwsz - (ULONG_PTR)wszNewDump)/sizeof(WCHAR), c_wszDumpSuffix);
  896. fOkCopy = CopyFullAndTriageMiniDumps(wszDump, wszNewDump);
  897. }
  898. }
  899. }
  900. if (fOkCopy == FALSE)
  901. StringCchCopyW(wszNewDump, cch, wszDump);
  902. // generate all the URLs / filepaths that we need...
  903. TESTHR(hr, BuildManifestURLs(wszAppName, wszModName, pqfb->rgAppVer,
  904. pqfb->rgModVer, pqfb->pvOffset,
  905. pqfb->fIs64bit, &wszStage1, &wszStage2,
  906. &wszCorpPath, &pbBuf));
  907. if (FAILED(hr))
  908. goto done;
  909. TESTHR(hr, GetErrorSignature(wszAppName, wszModName, pqfb->rgAppVer,
  910. pqfb->rgModVer, pqfb->pvOffset,
  911. pqfb->fIs64bit, &wszErrorSig, 0));
  912. if (FAILED(hr))
  913. goto done;
  914. // get the friendly name for the app
  915. TESTHR(hr, GetVerName(wszAppPath, wszAppFriendlyName,
  916. sizeofSTRW(wszAppFriendlyName), NULL, 0, NULL, 0,
  917. TRUE, FALSE));
  918. if (FAILED(hr))
  919. goto done;
  920. wszAppFriendlyName[sizeofSTRW(wszAppFriendlyName) - 1] = L'\0';
  921. // build the header string
  922. dw = LoadStringW(g_hInstance, IDS_FQHDRTXT, wszBuffer,
  923. sizeofSTRW(wszBuffer));
  924. if (dw == 0)
  925. goto done;
  926. cchTotal = dw + wcslen(wszAppFriendlyName) + 1;
  927. __try { wszHdr = (LPWSTR)_alloca(cchTotal * sizeof(WCHAR)); }
  928. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  929. {
  930. wszHdr = NULL;
  931. }
  932. if (wszHdr == NULL)
  933. {
  934. SetLastError(ERROR_OUTOFMEMORY);
  935. goto done;
  936. }
  937. StringCchPrintfW(wszHdr, cchTotal, wszBuffer, wszAppFriendlyName);
  938. // need to convert the time of the fault to a local time (cuz
  939. // GetSystemTime() returns a UTC time), but unfortunately, only filetimes
  940. // can be converted back and forth between UTC & local, so we have to do
  941. // all of this stuff...
  942. SystemTimeToFileTime(&pqfb->stFault, &ft);
  943. FileTimeToLocalFileTime(&ft, &ftLocal);
  944. FileTimeToSystemTime(&ftLocal, &stLocal);
  945. // build the error message string
  946. dw = LoadStringW(g_hInstance, IDS_FQERRMSG, wszBuffer,
  947. sizeofSTRW(wszBuffer));
  948. if (dw == 0)
  949. goto done;
  950. cchTotal = dw;
  951. dw = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &stLocal,
  952. NULL, wszDate, sizeofSTRW(wszDate));
  953. if (dw == 0)
  954. goto done;
  955. cchTotal += dw;
  956. dw = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &stLocal, NULL, wszTime,
  957. sizeofSTRW(wszTime));
  958. if (dw == 0)
  959. goto done;
  960. cchTotal += dw;
  961. cchTotal++;
  962. __try { wszErrMsg = (LPWSTR)_alloca(cchTotal * sizeof(WCHAR)); }
  963. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  964. {
  965. wszErrMsg = NULL;
  966. }
  967. if (wszErrMsg == NULL)
  968. {
  969. SetLastError(ERROR_OUTOFMEMORY);
  970. goto done;
  971. }
  972. StringCchPrintfW(wszErrMsg, cchTotal, wszBuffer, wszDate, wszTime);
  973. // we created the wszDump buffer above big enuf to hold both the
  974. // dumpfile path as well as the app compat filename. So make
  975. // use of that right now.
  976. cchSep = wcslen(wszNewDump);
  977. pwszAppCompat = wszNewDump + cchSep + 1;
  978. StringCchCopyW(pwszAppCompat, cchNewDump - cchSep -1, wszDir);
  979. pwszAppCompat[cchDir] = L'\\';
  980. pwszAppCompat[cchDir + 1] = L'\0';
  981. StringCchCatNW(pwszAppCompat, cchNewDump - cchSep -1, c_wszACFileName, cchBfr-cchSep-cchDir-2);
  982. // if we succeed, turn the NULL following the dump file path into
  983. // the DW separator character
  984. TESTBOOL(hr, GetAppCompatData(wszAppPath, wszModPath, pwszAppCompat));
  985. if (SUCCEEDED(hr))
  986. wszNewDump[cchSep] = DW_FILESEP;
  987. ZeroMemory(&dwmb, sizeof(dwmb));
  988. dwmb.wszTitle = wszAppFriendlyName;
  989. dwmb.wszErrMsg = wszErrMsg;
  990. dwmb.wszHdr = wszHdr;
  991. dwmb.wszStage1 = wszStage1;
  992. dwmb.wszStage2 = wszStage2;
  993. dwmb.wszErrorSig = wszErrorSig;
  994. dwmb.wszBrand = c_wszDWBrand;
  995. dwmb.wszFileList = wszNewDump;
  996. dwmb.fIsMSApp = fMSApp;
  997. dwmb.wszCorpPath = wszCorpPath;
  998. // check and see if the system is shutting down. If so, CreateProcess is
  999. // gonna pop up some annoying UI that we can't get rid of, so we don't
  1000. // want to call it if we know it's gonna happen.
  1001. if (GetSystemMetrics(SM_SHUTTINGDOWN))
  1002. goto done;
  1003. // we get back the name of the manifest file here.
  1004. frrvRet = StartDWManifest(oCfg, dwmb, wszManifest, fAllowSend);
  1005. done:
  1006. dw = GetLastError();
  1007. if (pbBuf != NULL)
  1008. MyFree(pbBuf);
  1009. if (wszErrorSig != NULL)
  1010. MyFree(wszErrorSig);
  1011. /*
  1012. * Always delete the temp files, since we can recreate them if needed.
  1013. * Fix for 668913
  1014. */
  1015. if (1)
  1016. {
  1017. if (wszNewDump != NULL)
  1018. {
  1019. if (pwszAppCompat != NULL)
  1020. {
  1021. wszNewDump[cchSep] = L'\0';
  1022. DeleteFileW(pwszAppCompat);
  1023. }
  1024. DeleteFullAndTriageMiniDumps(wszNewDump);
  1025. }
  1026. if (wszManifest != NULL)
  1027. DeleteFileW(wszManifest);
  1028. if (wszDir != NULL)
  1029. {
  1030. DeleteTempDirAndFile(wszDir, FALSE);
  1031. MyFree(wszDir);
  1032. }
  1033. }
  1034. SetLastError(dw);
  1035. return frrvRet;
  1036. }
  1037. BOOL SetPrivilege(
  1038. LPWSTR lpszPrivilege, // name of privilege to enable/disable
  1039. BOOL bEnablePrivilege // to enable or disable privilege
  1040. )
  1041. {
  1042. TOKEN_PRIVILEGES tp;
  1043. LUID luid;
  1044. HANDLE hToken;
  1045. HRESULT hr;
  1046. USE_TRACING("SetPrivilege");
  1047. TESTBOOL(hr, LookupPrivilegeValueW(
  1048. NULL, // lookup privilege on local system
  1049. lpszPrivilege, // privilege to lookup
  1050. &luid ) ) ;
  1051. if (FAILED(hr))
  1052. {
  1053. return FALSE;
  1054. }
  1055. TESTBOOL(hr, OpenThreadToken(GetCurrentThread(), TOKEN_READ | TOKEN_ADJUST_PRIVILEGES, FALSE, &hToken));
  1056. if (FAILED(hr) && GetLastError() == ERROR_NO_TOKEN)
  1057. {
  1058. TESTBOOL(hr, OpenProcessToken(GetCurrentProcess(), TOKEN_READ | TOKEN_ADJUST_PRIVILEGES, &hToken));
  1059. if (FAILED(hr))
  1060. return FALSE;
  1061. }
  1062. tp.PrivilegeCount = 1;
  1063. tp.Privileges[0].Luid = luid;
  1064. if (bEnablePrivilege)
  1065. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1066. else
  1067. tp.Privileges[0].Attributes = 0;
  1068. // Enable the privilege or disable all privileges.
  1069. TESTBOOL(hr, AdjustTokenPrivileges(
  1070. hToken,
  1071. FALSE,
  1072. &tp,
  1073. sizeof(TOKEN_PRIVILEGES),
  1074. (PTOKEN_PRIVILEGES) NULL,
  1075. (PDWORD) NULL));
  1076. CloseHandle(hToken);
  1077. if (FAILED(hr) || GetLastError() == ERROR_NOT_ALL_ASSIGNED)
  1078. {
  1079. DBG_MSG("Failed to adjust priveleges");
  1080. return FALSE;
  1081. }
  1082. return TRUE;
  1083. }
  1084. // **************************************************************************
  1085. #define ER_ALL_RIGHTS GENERIC_ALL | STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL
  1086. EFaultRepRetVal APIENTRY ReportFaultToQueue(SFaultRepManifest *pfrm)
  1087. {
  1088. USE_TRACING("ReportFaultToQueue");
  1089. SECURITY_ATTRIBUTES sa;
  1090. SECURITY_DESCRIPTOR sd;
  1091. SQueuedFaultBlob *pqfb;
  1092. EFaultRepRetVal frrvRet = frrvErrNoDW;
  1093. SMDumpOptions smdo;
  1094. SYSTEMTIME st;
  1095. HRESULT hr = NOERROR;
  1096. LPWSTR pwsz, pwszAppName = NULL, pwszDump = NULL;
  1097. HANDLE hFile = INVALID_HANDLE_VALUE;
  1098. HANDLE hProc = NULL;
  1099. USHORT usCompress;
  1100. DWORD cch, cchNeed, cb, dw;
  1101. WCHAR wszDump[MAX_PATH];
  1102. HKEY hkeyQ = NULL, hkeyRun = NULL;
  1103. WORD iFile = 0;
  1104. ZeroMemory(&sa, sizeof(sa));
  1105. wszDump[0] = L'\0';
  1106. VALIDATEPARM(hr, (pfrm == NULL || pfrm->wszExe == NULL ||
  1107. pfrm->pidReqProcess == 0));
  1108. if (FAILED(hr))
  1109. goto done;
  1110. // get the SD for the file we need to create
  1111. TESTBOOL(hr, AllocSD(&sd, ER_ALL_RIGHTS, ER_ALL_RIGHTS, 0));
  1112. if (FAILED(hr))
  1113. goto done;
  1114. sa.nLength = sizeof(sa);
  1115. sa.lpSecurityDescriptor = &sd;
  1116. sa.bInheritHandle = FALSE;
  1117. // get the name of the faulting application
  1118. for (pwszAppName = pfrm->wszExe + wcslen(pfrm->wszExe) - 1;
  1119. *pwszAppName != L'\\' && pwszAppName >= pfrm->wszExe;
  1120. pwszAppName--);
  1121. if (*pwszAppName == L'\\')
  1122. pwszAppName++;
  1123. // generate the filename
  1124. cch = GetSystemWindowsDirectoryW(wszDump, sizeofSTRW(wszDump));
  1125. if (cch == 0)
  1126. goto done;
  1127. // compute minimum required buffer size needed (the '5 * 6' at the end is
  1128. // to allow for the 6 WORD values that will be inserted)
  1129. cchNeed = cch + wcslen(pwszAppName) + 5 * 6 + sizeofSTRW(c_wszQFileName);
  1130. if (cchNeed > sizeofSTRW(wszDump))
  1131. {
  1132. __try { pwszDump = (LPWSTR)_alloca(cchNeed * sizeof(WCHAR)); }
  1133. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1134. {
  1135. pwszDump = NULL;
  1136. }
  1137. if (pwszDump == NULL)
  1138. {
  1139. SetLastError(ERROR_OUTOFMEMORY);
  1140. goto done;
  1141. }
  1142. if (cch > sizeofSTRW(wszDump))
  1143. cch = GetSystemWindowsDirectoryW(wszDump, cchNeed);
  1144. else
  1145. StringCchCopyW(pwszDump, cchNeed, wszDump);
  1146. }
  1147. else
  1148. {
  1149. pwszDump = wszDump;
  1150. cchNeed = sizeofSTRW(wszDump);
  1151. }
  1152. pwsz = pwszDump + cch - 1;
  1153. if (*pwsz != L'\\')
  1154. {
  1155. *(++pwsz) = L'\\';
  1156. *(++pwsz) = L'\0';
  1157. }
  1158. StringCchCopyW(pwsz, cchNeed - cch - 1, c_wszQSubdir);
  1159. pwsz += (sizeofSTRW(c_wszQSubdir) - 1);
  1160. GetSystemTime(&st);
  1161. StringCchPrintfW(pwsz, cchNeed - cch - sizeofSTRW(c_wszQSubdir), c_wszQFileName, pwszAppName, st.wYear, st.wMonth, st.wDay,
  1162. st.wHour, st.wMinute, st.wSecond);
  1163. // set pwsz to point to the 00 at the end of the above string...
  1164. pwsz += (wcslen(pwsz) - 7);
  1165. // do this in this section to make sure we can open these keys
  1166. TESTHR(hr, OpenRegKey(HKEY_LOCAL_MACHINE, c_wszRKUser, orkWantWrite,
  1167. &hkeyQ));
  1168. if (FAILED(hr))
  1169. goto done;
  1170. // set the proper security
  1171. TESTHR(hr, RegSetKeySecurity(hkeyQ, DACL_SECURITY_INFORMATION,
  1172. &sd));
  1173. TESTHR(hr, OpenRegKey(HKEY_LOCAL_MACHINE, c_wszRKRun, orkWantWrite,
  1174. &hkeyRun));
  1175. if (FAILED(hr))
  1176. goto done;
  1177. // check the size of the file Q and purge it if necessary
  1178. TESTHR(hr, CheckQSizeAndPrune(hkeyQ));
  1179. if (FAILED(hr) || hr == S_FALSE)
  1180. goto done;
  1181. for(iFile = 1; iFile <= 100; iFile++)
  1182. {
  1183. hFile = CreateFileW(pwszDump, GENERIC_WRITE | GENERIC_READ, 0, &sa,
  1184. CREATE_NEW, 0, NULL);
  1185. if (hFile != INVALID_HANDLE_VALUE)
  1186. break;
  1187. if (hFile == INVALID_HANDLE_VALUE &&
  1188. GetLastError() != ERROR_FILE_EXISTS)
  1189. break;
  1190. *pwsz = L'0' + (WCHAR)(iFile / 10);
  1191. *(pwsz + 1) = L'0' + (WCHAR)(iFile % 10);
  1192. }
  1193. if (hFile == INVALID_HANDLE_VALUE)
  1194. goto done;
  1195. // get a handle to the target process
  1196. hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
  1197. pfrm->pidReqProcess);
  1198. if (hProc == NULL)
  1199. goto done;
  1200. // Close the handle since dump could be created by a separate dumprep.exe
  1201. // and there are access problems for file opened as CREATE_NEW
  1202. CloseHandle(hFile);
  1203. hFile = INVALID_HANDLE_VALUE;
  1204. // generate the minidump
  1205. ZeroMemory(&smdo, sizeof(smdo));
  1206. smdo.ulThread = c_ulThreadWriteDefault;
  1207. smdo.ulMod = c_ulModuleWriteDefault;
  1208. smdo.dwThreadID = pfrm->thidFault;
  1209. smdo.dfOptions = dfCollectSig;
  1210. smdo.pvFaultAddr = pfrm->pvFaultAddr;
  1211. smdo.pEP = pfrm->pEP;
  1212. smdo.fEPClient = TRUE;
  1213. smdo.wszModFullPath[0] = L'\0';
  1214. StringCbCopyW(smdo.wszAppFullPath, sizeof(smdo.wszAppFullPath), pfrm->wszExe);
  1215. StringCbCopyW(smdo.wszMod, sizeof(smdo.wszMod), L"unknown");
  1216. TESTBOOL(hr, InternalGenFullAndTriageMinidumps(hProc, pfrm->pidReqProcess,
  1217. pwszDump, NULL, &smdo, pfrm->fIs64bit));
  1218. if (FAILED(hr))
  1219. goto done;
  1220. // log an event- don't care if it fails or not.
  1221. TESTHR(hr, LogUser(smdo.wszApp, smdo.rgAppVer, smdo.wszMod, smdo.rgModVer,
  1222. smdo.pvOffset, pfrm->fIs64bit, ER_USERCRASH_LOG));
  1223. // build the blob we'll store with the filename in the registry
  1224. cch = wcslen(smdo.wszAppFullPath) + 1;
  1225. cb = sizeof(SQueuedFaultBlob) +
  1226. (cch + wcslen(smdo.wszModFullPath) + 2) * sizeof(WCHAR);
  1227. __try { pqfb = (SQueuedFaultBlob *)_alloca(cb); }
  1228. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1229. {
  1230. pqfb = NULL;
  1231. }
  1232. if (pqfb == NULL)
  1233. {
  1234. SetLastError(ERROR_OUTOFMEMORY);
  1235. goto done;
  1236. }
  1237. CopyMemory(&pqfb->rgAppVer, &smdo.rgAppVer, 4 * sizeof(DWORD));
  1238. CopyMemory(&pqfb->rgModVer, &smdo.rgModVer, 4 * sizeof(DWORD));
  1239. CopyMemory(&pqfb->stFault, &st, sizeof(st));
  1240. pqfb->cbFB = sizeof(SQueuedFaultBlob);
  1241. pqfb->cbTotal = cb;
  1242. pqfb->fIs64bit = pfrm->fIs64bit;
  1243. pqfb->pvOffset = smdo.pvOffset;
  1244. pwsz = (WCHAR *)((BYTE *)pqfb + sizeof(SQueuedFaultBlob));
  1245. pqfb->dwpAppPath = sizeof(SQueuedFaultBlob);
  1246. pqfb->dwpModPath = sizeof(SQueuedFaultBlob) + cch * sizeof(WCHAR);
  1247. CopyMemory(pwsz, smdo.wszAppFullPath, cch * sizeof(WCHAR));
  1248. pwsz += cch;
  1249. StringCchCopyW(pwsz, cb - cch - sizeof(SQueuedFaultBlob)/sizeof(WCHAR), smdo.wszModFullPath);
  1250. // write out the value to our 'queue' in the registry.
  1251. TESTERR(hr, RegSetValueExW(hkeyQ, pwszDump, 0, REG_BINARY, (LPBYTE)pqfb,
  1252. cb));
  1253. if (FAILED(hr))
  1254. goto done;
  1255. // write out our app to the 'run' key so that the next admin to log
  1256. // in will see that a fault has occurred.
  1257. TESTERR(hr, RegSetValueExW(hkeyRun, c_wszRVUFC, 0, REG_EXPAND_SZ,
  1258. (LPBYTE)c_wszRVVUFC, sizeof(c_wszRVVUFC)));
  1259. if (FAILED(hr))
  1260. {
  1261. RegDeleteValueW(hkeyQ, pwszDump);
  1262. goto done;
  1263. }
  1264. frrvRet = frrvOkQueued;
  1265. #ifdef GUI_MODE_SETUP
  1266. /*
  1267. * This is a special case here. If we are in GUI mode, then we must also
  1268. * write this data to the backup registry files kept by the Whistler setup
  1269. * in case of a catastrophic failure.
  1270. */
  1271. DWORD dwSetup = SetupIsInProgress();
  1272. if (dwSetup == SIIP_GUI_SETUP)
  1273. {
  1274. HKEY hBackupHive = NULL, hTmpKey = NULL;
  1275. WCHAR *wszTmpName = L"WERTempHive\0";
  1276. WCHAR *wszConfigFile = L"\\config\\software.sav";
  1277. WCHAR *wszBackupHiveFile = NULL;
  1278. WCHAR wszDir[MAX_PATH*2];
  1279. DBG_MSG("Accessing setup registry files");
  1280. // get the system directory
  1281. cch = GetSystemDirectoryW(wszDir, sizeof(wszDir)/ sizeof(wszDir[0]));
  1282. if (cch == 0)
  1283. {
  1284. DBG_MSG("system dir not found");
  1285. goto done;
  1286. }
  1287. if (*(wszDir + cch - 1) == L'\\')
  1288. *(wszDir + cch - 1) = L'\0';
  1289. StringCbCatNW(wszDir, sizeof(wszDir), wszConfigFile, ARRAYSIZE(wszDir)-wcslen(wszDir));
  1290. TESTBOOL(hr, SetPrivilege(L"SeRestorePrivilege", TRUE));
  1291. if (FAILED(hr))
  1292. goto done;
  1293. TESTERR(hr, RegLoadKeyW(HKEY_LOCAL_MACHINE, wszTmpName, wszDir));
  1294. if (FAILED(hr))
  1295. {
  1296. ErrorTrace(0, "could not load setup reg file [%S] to HKLM,[%S]", wszDir, wszTmpName);
  1297. }
  1298. else
  1299. {
  1300. TESTERR(hr, RegOpenKeyExW( HKEY_LOCAL_MACHINE,
  1301. wszTmpName,
  1302. 0,
  1303. KEY_WRITE,
  1304. &hBackupHive ));
  1305. if (SUCCEEDED(hr))
  1306. {
  1307. // Create UserFaults key
  1308. TESTERR(hr, RegCreateKeyExW(hBackupHive, c_wszTmpRKUser, 0, NULL, 0,
  1309. KEY_WRITE, NULL, &hTmpKey, NULL));
  1310. if (SUCCEEDED(hr))
  1311. {
  1312. HKEY hSubKey;
  1313. // set the proper security
  1314. TESTERR(hr, RegSetKeySecurity(hTmpKey, DACL_SECURITY_INFORMATION,
  1315. &sd));
  1316. // write the UserFaults key
  1317. TESTERR(hr, RegSetValueExW(hTmpKey, pwszDump, 0, REG_BINARY, (LPBYTE)pqfb, cb));
  1318. // create our value in the RunOnce key so that we can report the
  1319. // next time someone logs in.
  1320. TESTERR(hr, RegCreateKeyExW(hBackupHive, c_wszTmpRKRun, 0, NULL, 0,
  1321. KEY_WRITE, NULL, &hSubKey, NULL));
  1322. if (SUCCEEDED(hr))
  1323. {
  1324. RegSetValueExW(hSubKey, c_wszRVUFC, 0, REG_EXPAND_SZ,
  1325. (LPBYTE)c_wszRVVUFC, sizeof(c_wszRVVUFC));
  1326. RegCloseKey(hSubKey);
  1327. }
  1328. RegCloseKey(hTmpKey);
  1329. }
  1330. RegCloseKey(hBackupHive);
  1331. }
  1332. RegUnLoadKeyW(HKEY_LOCAL_MACHINE, wszTmpName);
  1333. }
  1334. TESTBOOL(hr, SetPrivilege(L"SeRestorePrivilege", FALSE));
  1335. }
  1336. #endif
  1337. done:
  1338. dw = GetLastError();
  1339. // if we failed, then clean everything up.
  1340. if (hFile != INVALID_HANDLE_VALUE)
  1341. CloseHandle(hFile);
  1342. if (frrvRet != frrvOkQueued && iFile <= 100 && pwszDump != NULL)
  1343. DeleteFileW(pwszDump);
  1344. if (sa.lpSecurityDescriptor != NULL)
  1345. FreeSD((SECURITY_DESCRIPTOR *)sa.lpSecurityDescriptor);
  1346. if (hkeyQ != NULL)
  1347. RegCloseKey(hkeyQ);
  1348. if (hkeyRun != NULL)
  1349. RegCloseKey(hkeyRun);
  1350. if (hProc != NULL)
  1351. CloseHandle(hProc);
  1352. SetLastError(dw);
  1353. return frrvRet;
  1354. }
  1355. // **************************************************************************
  1356. EFaultRepRetVal APIENTRY ReportFaultDWM(SFaultRepManifest *pfrm,
  1357. LPCWSTR wszDir, HANDLE hToken,
  1358. LPVOID pvEnv, PROCESS_INFORMATION *ppi,
  1359. LPWSTR wszDumpFile)
  1360. {
  1361. USE_TRACING("ReportFaultDWM");
  1362. CPFFaultClientCfg oCfg;
  1363. EFaultRepRetVal frrvRet = frrvErrNoDW;
  1364. SDWManifestBlob dwmb;
  1365. SMDumpOptions smdo;
  1366. HRESULT hr = NOERROR;
  1367. HANDLE hProc = NULL;
  1368. LPWSTR wszStage1, wszStage2, wszCorpPath, wszErrorSig=NULL;
  1369. LPWSTR wszManifest = NULL, wszDump = NULL, pwszAppCompat = NULL;
  1370. DWORD dw, cch, cchDir, cchSep = 0;
  1371. WCHAR wszAppName[MAX_PATH];
  1372. HKEY hkeyDebug = NULL;
  1373. BOOL fAllowSend = TRUE, fMSApp = FALSE, fShowDebug = FALSE;
  1374. BYTE *pbBuf = NULL;
  1375. VALIDATEPARM(hr, (pfrm == NULL || pfrm->wszExe == NULL || ppi == NULL ||
  1376. wszDir == NULL || hToken == NULL || wszDumpFile == NULL ||
  1377. wszDir[0] == L'\0'));
  1378. if (FAILED(hr))
  1379. {
  1380. frrvRet = frrvErr;
  1381. SetLastError(ERROR_INVALID_PARAMETER);
  1382. goto done;
  1383. }
  1384. // Check to see if directory exists
  1385. dw = GetFileAttributesW(wszDir);
  1386. if (dw == INVALID_FILE_ATTRIBUTES || !(dw & FILE_ATTRIBUTE_DIRECTORY))
  1387. {
  1388. frrvRet = frrvErr;
  1389. SetLastError(ERROR_INVALID_PARAMETER);
  1390. ErrorTrace(1, "wszDir not valid, dw=0x%x, err=0x%x", dw, GetLastError());
  1391. goto done;
  1392. }
  1393. ErrorTrace(1, "hToken = 0x%x", hToken);
  1394. ErrorTrace(1, "wszDir = [%S]", wszDir);
  1395. // get the config info
  1396. TESTHR(hr, oCfg.Read(eroPolicyRO));
  1397. if (FAILED(hr))
  1398. goto done;
  1399. if (oCfg.get_ShowUI() == eedDisabled && oCfg.get_DoReport() == eedDisabled)
  1400. goto done;
  1401. // figure out how we're reporting / notifying the user
  1402. if (oCfg.get_DoReport() == eedDisabled ||
  1403. oCfg.ShouldCollect(pfrm->wszExe, &fMSApp) == FALSE)
  1404. fAllowSend = FALSE;
  1405. if (oCfg.get_ShowUI() == eedDisabled)
  1406. {
  1407. LPCWSTR wszULPath = oCfg.get_DumpPath(NULL, 0);
  1408. // check and make sure that we have a corporate path specified. If we
  1409. // don't, bail
  1410. if (wszULPath == NULL || *wszULPath == L'\0')
  1411. goto done;
  1412. }
  1413. cchDir = wcslen(wszDir);
  1414. cch = cchDir + sizeofSTRW(c_wszManFileName) + 4;
  1415. __try { wszManifest = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  1416. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1417. {
  1418. wszManifest = NULL;
  1419. }
  1420. if (wszManifest == NULL)
  1421. {
  1422. SetLastError(ERROR_OUTOFMEMORY);
  1423. goto done;
  1424. }
  1425. StringCchCopyW(wszManifest, cch, wszDir);
  1426. wszManifest[cchDir] = L'\\';
  1427. wszManifest[cchDir + 1] = L'\0';
  1428. StringCchCatNW(wszManifest, cch, c_wszManFileName, cch - wcslen(wszManifest));
  1429. cchDir = wcslen(wszDir);
  1430. cch = 2 * cchDir + wcslen(wszDumpFile) + sizeofSTRW(c_wszACFileName) + 4;
  1431. __try { wszDump = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  1432. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1433. {
  1434. wszDump = NULL;
  1435. }
  1436. if (wszDump == NULL)
  1437. {
  1438. SetLastError(ERROR_OUTOFMEMORY);
  1439. goto done;
  1440. }
  1441. StringCchCopyW(wszDump, cch, wszDir);
  1442. wszDump[cchDir] = L'\\';
  1443. wszDump[cchDir + 1] = L'\0';
  1444. StringCchCatNW(wszDump, cch, wszDumpFile, cch-wcslen(wszDump));
  1445. // checlk and see if we need to put a debug button on the DW dialog
  1446. dw = RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRKAeDebug, 0, KEY_READ,
  1447. &hkeyDebug);
  1448. if (dw == ERROR_SUCCESS)
  1449. {
  1450. LPWSTR wszDebugger;
  1451. WCHAR wszAuto[32];
  1452. DWORD dwType, cbNeed;
  1453. cbNeed = sizeof(wszAuto);
  1454. dw = RegQueryValueExW(hkeyDebug, c_wszRVAuto, NULL, &dwType,
  1455. (LPBYTE)wszAuto, &cbNeed);
  1456. if (dw != ERROR_SUCCESS || cbNeed == 0 || dwType != REG_SZ)
  1457. goto doneDebugCheck;
  1458. // only way to get here if Auto == 1 is if drwtsn32 is the JIT debugger
  1459. if (wszAuto[0] == L'1')
  1460. goto doneDebugCheck;
  1461. cbNeed = 0;
  1462. dw = RegQueryValueExW(hkeyDebug, c_wszRVDebugger, NULL, &dwType, NULL,
  1463. &cbNeed);
  1464. if (dw != ERROR_SUCCESS || cbNeed == 0 || dwType != REG_SZ)
  1465. goto doneDebugCheck;
  1466. cbNeed += sizeof(WCHAR);
  1467. __try { wszDebugger = (LPWSTR)_alloca(cbNeed); }
  1468. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1469. {
  1470. wszDebugger = NULL;
  1471. }
  1472. if (wszDebugger == NULL)
  1473. goto doneDebugCheck;
  1474. dw = RegQueryValueExW(hkeyDebug, c_wszRVDebugger, NULL, NULL,
  1475. (LPBYTE)wszDebugger, &cbNeed);
  1476. if (dw != ERROR_SUCCESS)
  1477. goto doneDebugCheck;
  1478. if (wszDebugger[0] != L'\0')
  1479. fShowDebug = TRUE;
  1480. doneDebugCheck:
  1481. RegCloseKey(hkeyDebug);
  1482. hkeyDebug = NULL;
  1483. }
  1484. // get a handle to the target process
  1485. hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
  1486. pfrm->pidReqProcess);
  1487. if (hProc == NULL)
  1488. goto done;
  1489. // generate the minidump
  1490. ZeroMemory(&smdo, sizeof(smdo));
  1491. smdo.ulThread = c_ulThreadWriteDefault;
  1492. smdo.ulMod = c_ulModuleWriteDefault;
  1493. smdo.dwThreadID = pfrm->thidFault;
  1494. smdo.dfOptions = dfCollectSig;
  1495. smdo.pvFaultAddr = pfrm->pvFaultAddr;
  1496. smdo.pEP = pfrm->pEP;
  1497. smdo.fEPClient = TRUE;
  1498. smdo.wszModFullPath[0] = L'\0';
  1499. StringCbCopyW(smdo.wszAppFullPath, sizeof(smdo.wszAppFullPath), pfrm->wszExe);
  1500. StringCbCopyW(smdo.wszMod, sizeof(smdo.wszMod), L"unknown");
  1501. TESTBOOL(hr, InternalGenFullAndTriageMinidumps(hProc, pfrm->pidReqProcess,
  1502. wszDump, NULL, &smdo, pfrm->fIs64bit));
  1503. if (FAILED(hr))
  1504. goto done;
  1505. // log an event- don't care if it fails or not.
  1506. TESTHR(hr, LogUser(smdo.wszApp, smdo.rgAppVer, smdo.wszMod, smdo.rgModVer,
  1507. smdo.pvOffset, pfrm->fIs64bit, ER_USERCRASH_LOG));
  1508. // generate all the URLs & file paths we'll need for reporting
  1509. TESTHR(hr, BuildManifestURLs(smdo.wszApp, smdo.wszMod, smdo.rgAppVer,
  1510. smdo.rgModVer, smdo.pvOffset,
  1511. pfrm->fIs64bit, &wszStage1, &wszStage2,
  1512. &wszCorpPath, &pbBuf));
  1513. if (FAILED(hr))
  1514. goto done;
  1515. TESTHR(hr, GetErrorSignature(smdo.wszApp, smdo.wszMod, smdo.rgAppVer,
  1516. smdo.rgModVer, smdo.pvOffset,
  1517. pfrm->fIs64bit, &wszErrorSig, 0));
  1518. if (FAILED(hr))
  1519. goto done;
  1520. TESTHR(hr, GetVerName(smdo.wszAppFullPath, wszAppName,
  1521. sizeofSTRW(wszAppName), NULL, 0, NULL, 0,
  1522. TRUE, FALSE));
  1523. if (FAILED(hr))
  1524. goto done;
  1525. wszAppName[sizeofSTRW(wszAppName) - 1] = L'\0';
  1526. // we created the wszDump buffer above big enuf to hold both the
  1527. // dumpfile path as well as the app compat filename. So make
  1528. // use of that right now.
  1529. cchSep = wcslen(wszDump);
  1530. pwszAppCompat = wszDump + cchSep + 1;
  1531. StringCchCopyW(pwszAppCompat, cch - cchSep -1, wszDir);
  1532. pwszAppCompat[cchDir] = L'\\';
  1533. pwszAppCompat[cchDir + 1] = L'\0';
  1534. StringCchCatNW(pwszAppCompat, cch - cchSep -1, c_wszACFileName, cch - cchSep - cchDir - 2);
  1535. // if we succeed, turn the NULL following the dump file path into
  1536. // the DW separator character
  1537. TESTBOOL(hr, GetAppCompatData(smdo.wszAppFullPath, smdo.wszAppFullPath,
  1538. pwszAppCompat));
  1539. if (SUCCEEDED(hr))
  1540. wszDump[cchSep] = DW_FILESEP;
  1541. ZeroMemory(&dwmb, sizeof(dwmb));
  1542. dwmb.wszTitle = wszAppName;
  1543. dwmb.nidErrMsg = IDS_FERRMSG;
  1544. dwmb.wszStage1 = wszStage1;
  1545. dwmb.wszStage2 = wszStage2;
  1546. dwmb.wszBrand = c_wszDWBrand;
  1547. dwmb.wszFileList = wszDump;
  1548. dwmb.wszErrorSig = wszErrorSig;
  1549. dwmb.hToken = hToken;
  1550. dwmb.pvEnv = pvEnv;
  1551. dwmb.fIsMSApp = fMSApp;
  1552. dwmb.wszCorpPath = wszCorpPath;
  1553. if (fShowDebug)
  1554. dwmb.dwOptions = emoShowDebugButton;
  1555. // check and see if the system is shutting down. If so, CreateProcess is
  1556. // gonna pop up some annoying UI that we can't get rid of, so we don't
  1557. // want to call it if we know it's gonna happen.
  1558. if (GetSystemMetrics(SM_SHUTTINGDOWN))
  1559. goto done;
  1560. // we get back the name of the manifest file here. it will be up to the client to
  1561. // delete it.
  1562. frrvRet = StartDWManifest(oCfg, dwmb, wszManifest, fAllowSend, TRUE);
  1563. CopyMemory(ppi, &dwmb.pi, sizeof(PROCESS_INFORMATION));
  1564. done:
  1565. dw = GetLastError();
  1566. if (pbBuf != NULL)
  1567. MyFree(pbBuf);
  1568. if (wszErrorSig != NULL)
  1569. MyFree(wszErrorSig);
  1570. if (hProc != NULL)
  1571. CloseHandle(hProc);
  1572. if (frrvRet != frrvOk)
  1573. {
  1574. if (wszDump != NULL)
  1575. {
  1576. if (pwszAppCompat != NULL)
  1577. {
  1578. wszDump[cchSep] = L'\0';
  1579. DeleteFileW(pwszAppCompat);
  1580. }
  1581. DeleteFullAndTriageMiniDumps(wszDump);
  1582. }
  1583. if (wszManifest != NULL)
  1584. DeleteFileW(wszManifest);
  1585. }
  1586. SetLastError(dw);
  1587. return frrvRet;
  1588. }
  1589. // **************************************************************************
  1590. EFaultRepRetVal APIENTRY ReportFault(LPEXCEPTION_POINTERS pep, DWORD dwOpt)
  1591. {
  1592. USE_TRACING("ReportFault");
  1593. CPFFaultClientCfg oCfg;
  1594. EFaultRepRetVal frrvRet = frrvErr;
  1595. HRESULT hr = NOERROR;
  1596. WCHAR wszFile[MAX_PATH], *pwsz;
  1597. DWORD dwFlags = 0, dw;
  1598. // HKEY hkey = NULL;
  1599. BOOL fUseExceptionMode = TRUE, fMSApp = FALSE, fInstallerRunning=FALSE;
  1600. __try
  1601. {
  1602. VALIDATEPARM(hr, (pep == NULL));
  1603. if (FAILED(hr))
  1604. {
  1605. frrvRet = frrvErr;
  1606. goto done;
  1607. }
  1608. VALIDATEPARM(hr, (pep->ExceptionRecord == NULL));
  1609. if (FAILED(hr))
  1610. {
  1611. frrvRet = frrvErr;
  1612. goto done;
  1613. }
  1614. // this is to help validate the pep pointer. If it is bad, we
  1615. // hit the exception handler below...
  1616. dw = pep->ExceptionRecord->ExceptionCode;
  1617. // get the config info
  1618. TESTHR(hr, oCfg.Read(eroPolicyRO));
  1619. if (FAILED(hr))
  1620. {
  1621. frrvRet = frrvErr;
  1622. goto done;
  1623. }
  1624. frrvRet = frrvErrNoDW;
  1625. if (oCfg.get_TextLog() == eedEnabled)
  1626. {
  1627. if (!GetModuleFileNameW(NULL, wszFile, sizeofSTRW(wszFile)))
  1628. {
  1629. wszFile[0] = 0;
  1630. }
  1631. wszFile[sizeofSTRW(wszFile)-1] = 0;
  1632. TextLogOut("User fault %08x in %ls\r\n",
  1633. pep->ExceptionRecord->ExceptionCode, wszFile);
  1634. wszFile[0] = L'\0';
  1635. }
  1636. // if reporting and notification are both disabled, then there's nothing of
  1637. // great value that we're gonna do here, so bail.
  1638. // Return frrvErrNoDW to indicate that we didn't do squat
  1639. if (oCfg.get_ShowUI() == eedDisabled && oCfg.get_DoReport() == eedDisabled)
  1640. goto done;
  1641. if (oCfg.get_ShowUI() == eedDisabled)
  1642. {
  1643. LPCWSTR wszULPath = oCfg.get_DumpPath(NULL, 0);
  1644. ErrorTrace(0, "CER mode- path=%S", wszULPath? wszULPath : L"<none>");
  1645. fUseExceptionMode = TRUE;
  1646. dwFlags |= fDwHeadless;
  1647. // check and make sure that we have a corporate path specified. If
  1648. // we don't, bail
  1649. if (wszULPath == NULL || *wszULPath == L'\0')
  1650. {
  1651. ErrorTrace(0, "CER mode- bogus path error");
  1652. goto done;
  1653. }
  1654. }
  1655. // don't want to go into this if we're already in the middle of reporting
  1656. if (g_fAlreadyReportingFault)
  1657. goto done;
  1658. g_fAlreadyReportingFault = TRUE;
  1659. // make sure we're not trying to report for DW or dumprep-
  1660. if (!GetModuleFileNameW(NULL, wszFile, sizeofSTRW(wszFile)-1))
  1661. {
  1662. goto done;
  1663. }
  1664. wszFile[sizeofSTRW(wszFile)-1]=0;
  1665. GetLongPathNameW(wszFile, wszFile, sizeofSTRW(wszFile)-1);
  1666. for(pwsz = wszFile + wcslen(wszFile);
  1667. pwsz >= wszFile && *pwsz != L'\\';
  1668. pwsz--);
  1669. if (*pwsz == L'\\')
  1670. pwsz++;
  1671. if (_wcsicmp(pwsz, L"dwwin.exe") == 0 ||
  1672. _wcsicmp(pwsz, L"dumprep.exe") == 0)
  1673. goto done;
  1674. // figure out how we're reporting / notifying the user
  1675. if (oCfg.get_DoReport() == eedDisabled ||
  1676. oCfg.ShouldCollect(wszFile, &fMSApp) == FALSE)
  1677. dwFlags |= fDwNoReporting;
  1678. // if it's a MS app, set the flag that says we can have 'please help
  1679. // Microsoft' text in DW.
  1680. if (fMSApp == FALSE)
  1681. dwFlags |= fDwUseLitePlea;
  1682. // if we're not headless, then we have to see if we have the correct
  1683. // security context to launch DW directly. The correct security context
  1684. // is defined as the current process having the same security context as
  1685. // the user currently logged on interactively to the current session
  1686. if (oCfg.get_ShowUI() != eedDisabled)
  1687. {
  1688. if (oCfg.get_ForceQueueMode())
  1689. {
  1690. fUseExceptionMode = FALSE;
  1691. }
  1692. else
  1693. {
  1694. fUseExceptionMode = DoUserContextsMatch();
  1695. if (fUseExceptionMode == FALSE)
  1696. fUseExceptionMode = DoWinstaDesktopMatch() &&
  1697. (AmIPrivileged(FALSE) == FALSE);
  1698. }
  1699. ErrorTrace(0, "not CER mode, fUseExceptionMode = %s", fUseExceptionMode?"TRUE":"FALSE");
  1700. }
  1701. if (SetupIsInProgress())
  1702. {
  1703. // force this to Q mode
  1704. fUseExceptionMode = FALSE;
  1705. }
  1706. // if we can use exception mode, then just go ahead and use the normal
  1707. // reporting mechanism (shared memory block, etc)
  1708. if (fUseExceptionMode)
  1709. {
  1710. LPCWSTR pwszServer = oCfg.get_DefaultServer(NULL, 0);
  1711. LPCSTR szServer;
  1712. char szBuf[MAX_PATH];
  1713. // determine what server we're going to send the data to.
  1714. szBuf[0] = '\0';
  1715. if (pwszServer != NULL && *pwszServer != L'\0')
  1716. WideCharToMultiByte(CP_ACP, 0, pwszServer, -1, szBuf,
  1717. sizeof(szBuf), NULL, NULL);
  1718. if (szBuf[0] != '\0')
  1719. szServer = szBuf;
  1720. else
  1721. szServer = (oCfg.get_UseInternal() == 1) ? c_szDWDefServerI :
  1722. c_szDWDefServerE;
  1723. frrvRet = StartDWException(pep, dwOpt, dwFlags, szServer, -1);
  1724. }
  1725. // otherwise, have to use manifest, which of course means generating the
  1726. // minidump ourselves, parsing it for the signature, and everything else
  1727. // that DW does automatically for us... Sigh...
  1728. else // if (!(dwFlags & fDwNoReporting)) for BUG 538311
  1729. {
  1730. frrvRet = StartManifestReport(pep, wszFile, dwOpt, -1);
  1731. }
  1732. }
  1733. __except(SetLastError(GetExceptionCode()), EXCEPTION_EXECUTE_HANDLER)
  1734. {
  1735. }
  1736. done:
  1737. g_fAlreadyReportingFault = FALSE;
  1738. return frrvRet;
  1739. }