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.

1639 lines
55 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. faultrep.cpp
  5. Abstract:
  6. Implements kernel fault reporting
  7. Revision History:
  8. created derekm 07/07/00
  9. ******************************************************************************/
  10. #include "stdafx.h"
  11. #include "ntiodump.h"
  12. #include "userenv.h"
  13. //#include <shlwapi.h>
  14. #include <setupapi.h>
  15. #ifdef THIS_FILE
  16. #undef THIS_FILE
  17. #endif
  18. static char __szTraceSourceFile[] = __FILE__;
  19. #define THIS_FILE __szTraceSourceFile
  20. extern BOOL SetPrivilege(LPWSTR lpszPrivilege, BOOL bEnablePrivilege );
  21. ///////////////////////////////////////////////////////////////////////////////
  22. // utilities
  23. #define ARRAYSIZE(sz) (sizeof(sz)/sizeof(sz[0]))
  24. #define WRITE_CWSZ(hr, hFile, wsz, cb) \
  25. TESTBOOL(hr, WriteFile(hFile, wsz, sizeof(wsz) - sizeof(WCHAR), \
  26. &(cb), NULL)); \
  27. if (FAILED(hr)) goto done; else 0
  28. // **************************************************************************
  29. #ifndef _WIN64
  30. HRESULT ExtractBCInfo(LPCWSTR wszMiniDump, ULONG *pulBCCode, ULONG *pulBCP1,
  31. ULONG *pulBCP2, ULONG *pulBCP3, ULONG *pulBCP4)
  32. #else
  33. HRESULT ExtractBCInfo(LPCWSTR wszMiniDump, ULONG *pulBCCode, ULONG64 *pulBCP1,
  34. ULONG64 *pulBCP2, ULONG64 *pulBCP3, ULONG64 *pulBCP4)
  35. #endif
  36. {
  37. USE_TRACING("ExtractBCInfo");
  38. #ifndef _WIN64
  39. DUMP_HEADER32 *pdmp = NULL;
  40. #else
  41. DUMP_HEADER64 *pdmp = NULL;
  42. #endif
  43. HRESULT hr = NOERROR;
  44. DWORD dw;
  45. VALIDATEPARM(hr, (wszMiniDump == NULL || pulBCCode == NULL ||
  46. pulBCP1 == NULL || pulBCP2 == NULL || pulBCP3 == NULL ||
  47. pulBCP4 == NULL));
  48. if (FAILED(hr))
  49. {
  50. SetLastError(ERROR_INVALID_PARAMETER);
  51. goto done;
  52. }
  53. TESTHR(hr, OpenFileMapped((LPWSTR)wszMiniDump, (LPVOID *)&pdmp, &dw));
  54. if (FAILED(hr))
  55. goto done;
  56. // make sure the file is at least the appropriate # of bytes for a dump
  57. // header.
  58. // Then make sure it's the appropriate type of minidump cuz the code below
  59. // will only handle dumps for the platform it's compiled for (win64 vs x86)
  60. #ifndef _WIN64
  61. if (dw < sizeof(DUMP_HEADER32) ||
  62. pdmp->Signature != DUMP_SIGNATURE32 ||
  63. pdmp->ValidDump != DUMP_VALID_DUMP32 ||
  64. #else
  65. if (dw < sizeof(DUMP_HEADER64) ||
  66. pdmp->Signature != DUMP_SIGNATURE64 ||
  67. pdmp->ValidDump != DUMP_VALID_DUMP64 ||
  68. #endif
  69. pdmp->DumpType != DUMP_TYPE_TRIAGE)
  70. {
  71. SetLastError(ERROR_INVALID_PARAMETER);
  72. hr = Err2HR(ERROR_INVALID_PARAMETER);
  73. goto done;
  74. }
  75. *pulBCCode = pdmp->BugCheckCode;
  76. *pulBCP1 = pdmp->BugCheckParameter1;
  77. *pulBCP2 = pdmp->BugCheckParameter2;
  78. *pulBCP3 = pdmp->BugCheckParameter3;
  79. *pulBCP4 = pdmp->BugCheckParameter4;
  80. done:
  81. dw = GetLastError();
  82. if (pdmp != NULL)
  83. UnmapViewOfFile(pdmp);
  84. SetLastError(dw);
  85. return hr;
  86. }
  87. BOOL NewIsUserAdmin(VOID)
  88. /*++
  89. Routine Description: This routine returns TRUE if the caller's process is a member of the Administrators local group.
  90. Caller is NOT expected to be impersonating anyone and is expected to be able to open their own process and process token.
  91. Arguments: None.
  92. Return Value:
  93. TRUE - Caller has Administrators local group.
  94. FALSE - Caller does not have Administrators local group. --
  95. */
  96. {
  97. BOOL b;
  98. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  99. PSID AdministratorsGroup;
  100. WCHAR wszUserName[400];
  101. DWORD dwSize = ARRAYSIZE(wszUserName)-1;
  102. USE_TRACING("NewIsUserAdmin");
  103. b = AllocateAndInitializeSid(
  104. &NtAuthority,
  105. 2,
  106. SECURITY_BUILTIN_DOMAIN_RID,
  107. DOMAIN_ALIAS_RID_ADMINS,
  108. 0, 0, 0, 0, 0, 0,
  109. &AdministratorsGroup);
  110. if(b)
  111. {
  112. if (!CheckTokenMembership( NULL, AdministratorsGroup, &b))
  113. {
  114. b = FALSE;
  115. }
  116. FreeSid(AdministratorsGroup);
  117. }
  118. if (b)
  119. {
  120. /*
  121. * We can often be called at a time when a normal user is not logged on
  122. * Usually this is because we get called too early in the login process
  123. * and before a proiper user context is set up yet, when we are still
  124. * operating under the auspices of "Local_System". Here I look for
  125. * that case, and return false, since what we are really looking for here
  126. * is to return true only if we have a REAL USER with admin privs.
  127. */
  128. if (GetUserNameW(wszUserName, &dwSize))
  129. {
  130. wszUserName[ARRAYSIZE(wszUserName)-1] = 0;
  131. if (0 == wcscmp(wszUserName, L"SYSTEM"))
  132. b = FALSE;
  133. }
  134. else
  135. {
  136. wszUserName[0]=0;
  137. b = FALSE;
  138. }
  139. }
  140. DebugTrace(0, "User \'%S\' is%san admin", wszUserName, b ? " " : " not ");
  141. return(b);
  142. }
  143. // **************************************************************************
  144. DWORD XMLEncodeString(LPCWSTR wszSrc, LPWSTR wszDest, DWORD cchDest)
  145. {
  146. WCHAR *pwch = (WCHAR *)wszSrc;
  147. WCHAR *pwchDest = wszDest;
  148. DWORD cch = 0, cchNeed = 0;
  149. // determine how much space we need & if the buffer supports it
  150. for(; *pwch != L'\0'; pwch++)
  151. {
  152. switch(*pwch)
  153. {
  154. case L'&': cchNeed += 5; break;
  155. case L'>': // fall thru
  156. case L'<': cchNeed += 4; break;
  157. case L'\'': // fall thru
  158. case L'\"': cchNeed += 6; break;
  159. default: cchNeed += 1;
  160. }
  161. }
  162. if (cchNeed >= cchDest || cchNeed == 0)
  163. return 0;
  164. // do the conversion
  165. for(pwch = (WCHAR *)wszSrc; *pwch != L'\0'; pwch++)
  166. {
  167. switch(*pwch)
  168. {
  169. case L'&': StringCchCopyW(pwchDest, cchDest, L"&amp;"); pwchDest += 5; break;
  170. case L'>': StringCchCopyW(pwchDest, cchDest, L"&gt;"); pwchDest += 4; break;
  171. case L'<': StringCchCopyW(pwchDest, cchDest, L"&lt;"); pwchDest += 4; break;
  172. case L'\'': StringCchCopyW(pwchDest, cchDest, L"&apos;"); pwchDest += 6; break;
  173. case L'\"': StringCchCopyW(pwchDest, cchDest, L"&quot;"); pwchDest += 6; break;
  174. default: *pwchDest = *pwch; pwchDest += 1; break;
  175. }
  176. }
  177. *pwchDest = L'\0';
  178. return cchNeed;
  179. }
  180. // **************************************************************************
  181. HRESULT GetDevicePropertyW(HDEVINFO hDevInfo,
  182. PSP_DEVINFO_DATA pDevInfoData,
  183. ULONG ulProperty,
  184. ULONG ulRequiredType,
  185. PBYTE pData,
  186. ULONG ulDataSize)
  187. {
  188. ULONG ulPropType;
  189. USE_TRACING("GetDeviceProperty");
  190. // The data returned is often string data so leave some
  191. // extra room for forced termination.
  192. if (SetupDiGetDeviceRegistryPropertyW(hDevInfo,
  193. pDevInfoData,
  194. ulProperty,
  195. &ulPropType,
  196. pData,
  197. ulDataSize - 2 * sizeof(WCHAR),
  198. &ulDataSize))
  199. {
  200. // Got the data, verify the type.
  201. if (ulPropType != ulRequiredType)
  202. {
  203. return E_INVALIDARG;
  204. }
  205. // Force a double terminator at the end to make sure
  206. // that all strings and multistrings are terminated.
  207. ZeroMemory(pData + ulDataSize, 2 * sizeof(WCHAR));
  208. return S_OK;
  209. }
  210. else
  211. {
  212. return HRESULT_FROM_WIN32(GetLastError());
  213. }
  214. }
  215. // **************************************************************************
  216. struct DEVICE_DATA_STRINGS
  217. {
  218. //
  219. // The device description and service names have fixed
  220. // maximum lengths. The hardware ID data can be arbitrarily
  221. // large, however in practice it is rarely more than
  222. // a few hundred characters. We just make
  223. // a single allocation with nice roomy buffers and
  224. // use that for every device rather than doing allocations
  225. // per device.
  226. //
  227. WCHAR wszDeviceDesc[LINE_LEN];
  228. WCHAR wszHardwareId[8192];
  229. WCHAR wszService[MAX_SERVICE_NAME_LEN];
  230. WCHAR wszServiceImage[MAX_PATH];
  231. // We only need the first string of the hardware ID multi-sz
  232. // so this translation temporary buffer doesn't need
  233. // to be as large as the whole multi-sz.
  234. WCHAR wszXml[1024];
  235. };
  236. HRESULT GetDeviceData(HANDLE hFile)
  237. {
  238. HRESULT hr;
  239. HDEVINFO hDevInfo;
  240. DEVICE_DATA_STRINGS* pStrings = NULL;
  241. SC_HANDLE hSCManager = NULL;
  242. USE_TRACING("GetDeviceData");
  243. hDevInfo = SetupDiGetClassDevsW(NULL, NULL, NULL, DIGCF_ALLCLASSES);
  244. if (hDevInfo == INVALID_HANDLE_VALUE)
  245. {
  246. return HRESULT_FROM_WIN32(GetLastError());
  247. }
  248. pStrings = (DEVICE_DATA_STRINGS*)MyAlloc(sizeof(*pStrings));
  249. if (!pStrings)
  250. {
  251. hr = E_OUTOFMEMORY;
  252. goto done;
  253. }
  254. SP_DEVINFO_DATA DevInfoData;
  255. ULONG ulDevIndex;
  256. ulDevIndex = 0;
  257. DevInfoData.cbSize = sizeof(DevInfoData);
  258. while (SetupDiEnumDeviceInfo(hDevInfo, ulDevIndex, &DevInfoData))
  259. {
  260. ULONG cb;
  261. //
  262. // If we can't get a required property for this device
  263. // we skip the device and continue on and try to
  264. // get as much device data as possible.
  265. //
  266. if (GetDevicePropertyW(hDevInfo, &DevInfoData,
  267. SPDRP_DEVICEDESC, REG_SZ,
  268. (PBYTE)pStrings->wszDeviceDesc,
  269. sizeof(pStrings->wszDeviceDesc)) == S_OK &&
  270. GetDevicePropertyW(hDevInfo, &DevInfoData,
  271. SPDRP_HARDWAREID, REG_MULTI_SZ,
  272. (PBYTE)pStrings->wszHardwareId,
  273. sizeof(pStrings->wszHardwareId)) == S_OK)
  274. {
  275. PWSTR pwszStr;
  276. ULONG cbOut;
  277. // Default to no service image name.
  278. pStrings->wszServiceImage[0] = 0;
  279. // The Service property is optional.
  280. if (GetDevicePropertyW(hDevInfo, &DevInfoData,
  281. SPDRP_SERVICE, REG_SZ,
  282. (PBYTE)pStrings->wszService,
  283. sizeof(pStrings->wszService)) != S_OK)
  284. {
  285. pStrings->wszService[0] = 0;
  286. }
  287. else
  288. {
  289. SC_HANDLE hService;
  290. LPQUERY_SERVICE_CONFIGW lpqscBuf;
  291. DWORD dwBytes;
  292. //
  293. // If we found the service, open it, and retrieve the image
  294. // name so we can map to the drivers list in the XML.
  295. //
  296. if (hSCManager == NULL)
  297. {
  298. hSCManager = OpenSCManagerW(NULL, NULL,
  299. SC_MANAGER_ENUMERATE_SERVICE);
  300. }
  301. if (hSCManager != NULL)
  302. {
  303. hService = OpenServiceW(hSCManager, pStrings->wszService,
  304. SERVICE_QUERY_CONFIG);
  305. if (hService != NULL)
  306. {
  307. #define SERVICE_CONFIG_QUERY_SIZE 8192
  308. lpqscBuf = (LPQUERY_SERVICE_CONFIGW)
  309. MyAlloc(SERVICE_CONFIG_QUERY_SIZE);
  310. if (lpqscBuf != NULL)
  311. {
  312. if (QueryServiceConfigW(hService, lpqscBuf,
  313. SERVICE_CONFIG_QUERY_SIZE,
  314. &dwBytes))
  315. {
  316. WCHAR *wcpBuf;
  317. //
  318. // Remove the path information and just store
  319. // the image name.
  320. //
  321. wcpBuf =
  322. wcsrchr(lpqscBuf->lpBinaryPathName, '\\');
  323. if (wcpBuf)
  324. {
  325. StringCchCopyW(pStrings->wszServiceImage,
  326. sizeofSTRW(pStrings->
  327. wszServiceImage),
  328. wcpBuf + 1);
  329. }
  330. else
  331. {
  332. StringCchCopyW(pStrings->wszServiceImage,
  333. sizeofSTRW(pStrings->
  334. wszServiceImage),
  335. lpqscBuf->lpBinaryPathName);
  336. }
  337. }
  338. MyFree(lpqscBuf);
  339. }
  340. CloseServiceHandle(hService);
  341. }
  342. }
  343. }
  344. WRITE_CWSZ(hr, hFile, c_wszXMLOpenDevice, cb);
  345. WRITE_CWSZ(hr, hFile, c_wszXMLOpenDevDesc, cb);
  346. cbOut = XMLEncodeString(pStrings->wszDeviceDesc,
  347. pStrings->wszXml,
  348. sizeofSTRW(pStrings->wszXml));
  349. cbOut *= sizeof(WCHAR);
  350. TESTBOOL(hr, WriteFile(hFile, pStrings->wszXml, cbOut, &cb, NULL));
  351. if (FAILED(hr))
  352. {
  353. goto done;
  354. }
  355. WRITE_CWSZ(hr, hFile, c_wszXMLCloseDevDesc, cb);
  356. //
  357. // The hardware ID is a multistring but we
  358. // only need the first string.
  359. //
  360. WRITE_CWSZ(hr, hFile, c_wszXMLOpenDevHwId, cb);
  361. cbOut = XMLEncodeString(pStrings->wszHardwareId,
  362. pStrings->wszXml,
  363. sizeofSTRW(pStrings->wszXml));
  364. cbOut *= sizeof(WCHAR);
  365. TESTBOOL(hr, WriteFile(hFile, pStrings->wszXml, cbOut, &cb, NULL));
  366. if (FAILED(hr))
  367. {
  368. goto done;
  369. }
  370. WRITE_CWSZ(hr, hFile, c_wszXMLCloseDevHwId, cb);
  371. if (pStrings->wszService[0])
  372. {
  373. WRITE_CWSZ(hr, hFile, c_wszXMLOpenDevService, cb);
  374. cbOut = XMLEncodeString(pStrings->wszService,
  375. pStrings->wszXml,
  376. sizeofSTRW(pStrings->wszXml));
  377. cbOut *= sizeof(WCHAR);
  378. TESTBOOL(hr, WriteFile(hFile, pStrings->wszXml, cbOut,
  379. &cb, NULL));
  380. if (FAILED(hr))
  381. {
  382. goto done;
  383. }
  384. WRITE_CWSZ(hr, hFile, c_wszXMLCloseDevService, cb);
  385. }
  386. if (pStrings->wszServiceImage[0])
  387. {
  388. WRITE_CWSZ(hr, hFile, c_wszXMLOpenDevImage, cb);
  389. cbOut = XMLEncodeString(pStrings->wszServiceImage,
  390. pStrings->wszXml,
  391. sizeofSTRW(pStrings->wszXml));
  392. cbOut *= sizeof(WCHAR);
  393. TESTBOOL(hr, WriteFile(hFile, pStrings->wszXml, cbOut,
  394. &cb, NULL));
  395. if (FAILED(hr))
  396. {
  397. goto done;
  398. }
  399. WRITE_CWSZ(hr, hFile, c_wszXMLCloseDevImage, cb);
  400. }
  401. WRITE_CWSZ(hr, hFile, c_wszXMLCloseDevice, cb);
  402. }
  403. ulDevIndex++;
  404. }
  405. hr = S_OK;
  406. done:
  407. SetupDiDestroyDeviceInfoList(hDevInfo);
  408. if (pStrings)
  409. {
  410. MyFree(pStrings);
  411. }
  412. if (hSCManager)
  413. {
  414. CloseServiceHandle(hSCManager);
  415. }
  416. return hr;
  417. }
  418. // **************************************************************************
  419. HRESULT WriteDriverRecord(HANDLE hFile, LPWSTR wszFile)
  420. {
  421. WIN32_FILE_ATTRIBUTE_DATA w32fad;
  422. SYSTEMTIME st;
  423. HRESULT hr = NOERROR;
  424. LPWSTR pwszFileName;
  425. DWORD cb, cbOut;
  426. WCHAR wsz[1025], wszVer[MAX_PATH], wszCompany[MAX_PATH];
  427. WCHAR wszName[MAX_PATH];
  428. USE_TRACING("WriteDriverRecord");
  429. TESTBOOL(hr, GetFileAttributesExW(wszFile, GetFileExInfoStandard,
  430. (LPVOID *)&w32fad));
  431. if (FAILED(hr))
  432. goto done;
  433. // <DRIVER>
  434. // <FILENAME>...
  435. TESTBOOL(hr, WriteFile(hFile, c_wszXMLDriver1,
  436. sizeof(c_wszXMLDriver1) - sizeof(WCHAR), &cb, NULL));
  437. if (FAILED(hr))
  438. goto done;
  439. // ...[filename data]...
  440. for(pwszFileName = wszFile + wcslen(wszFile);
  441. *pwszFileName != L'\\' && pwszFileName > wszFile;
  442. pwszFileName--);
  443. if (*pwszFileName == L'\\')
  444. pwszFileName++;
  445. wsz[0] = L'\0';
  446. cbOut = XMLEncodeString(pwszFileName, wsz, sizeofSTRW(wsz));
  447. cbOut *= sizeof(WCHAR);
  448. TESTBOOL(hr, WriteFile(hFile, wsz, cbOut, &cb, NULL));
  449. if (FAILED(hr))
  450. goto done;
  451. // ...</FILENAME>
  452. // <FILESIZE>[file size data]</FILESIZE>
  453. // <CREATIONDATE>MM-DD-YYYY HH:MM:SS</CREATIONDATE>
  454. // <VERSION>...
  455. FileTimeToSystemTime(&w32fad.ftCreationTime, &st);
  456. if (StringCbPrintfW(wsz, sizeof(wsz), c_wszXMLDriver2, w32fad.nFileSizeLow, st.wMonth,
  457. st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond) == S_OK)
  458. {
  459. cbOut = wcslen(wsz) * sizeof(WCHAR);
  460. } else
  461. {
  462. cbOut = 0;
  463. }
  464. TESTBOOL(hr, WriteFile(hFile, wsz, cbOut, &cb, NULL));
  465. if (FAILED(hr))
  466. goto done;
  467. wsz[0] = L'\0';
  468. TESTHR(hr, GetVerName(wszFile, wszName, sizeofSTRW(wszName),
  469. wszVer, sizeofSTRW(wszVer),
  470. wszCompany, sizeofSTRW(wszCompany), TRUE, TRUE));
  471. if (FAILED(hr))
  472. goto done;
  473. wszCompany[sizeofSTRW(wszCompany) - 1] = L'\0';
  474. wszName[sizeofSTRW(wszName) - 1] = L'\0';
  475. wszVer[sizeofSTRW(wszVer) - 1] = L'\0';
  476. // ...[version data]...
  477. wsz[0] = L'\0';
  478. cbOut = XMLEncodeString(wszVer, wsz, sizeofSTRW(wsz));
  479. cbOut *= sizeof(WCHAR);
  480. TESTBOOL(hr, WriteFile(hFile, wsz, cbOut, &cb, NULL));
  481. if (FAILED(hr))
  482. goto done;
  483. // ...</VERSION>
  484. // <MANUFACTURER>...
  485. TESTBOOL(hr, WriteFile(hFile, c_wszXMLDriver3,
  486. sizeof(c_wszXMLDriver3) - sizeof(WCHAR), &cb, NULL));
  487. if (FAILED(hr))
  488. goto done;
  489. // ...[manufacturer data]...
  490. wsz[0] = L'\0';
  491. cbOut = XMLEncodeString(wszCompany, wsz, sizeofSTRW(wsz));
  492. cbOut *= sizeof(WCHAR);
  493. TESTBOOL(hr, WriteFile(hFile, wsz, cbOut, &cb, NULL));
  494. if (FAILED(hr))
  495. goto done;
  496. // ...</MANUFACTURER>
  497. // <PRODUCTNAME>...
  498. TESTBOOL(hr, WriteFile(hFile, c_wszXMLDriver4,
  499. sizeof(c_wszXMLDriver4) - sizeof(WCHAR), &cb, NULL));
  500. if (FAILED(hr))
  501. goto done;
  502. // ...[product name data]...
  503. wsz[0] = L'\0';
  504. cbOut = XMLEncodeString(wszName, wsz, sizeofSTRW(wsz));
  505. cbOut *= sizeof(WCHAR);
  506. TESTBOOL(hr, WriteFile(hFile, wsz, cbOut, &cb, NULL));
  507. if (FAILED(hr))
  508. goto done;
  509. // ...</PRODUCTNAME>
  510. // <DRIVER>
  511. TESTBOOL(hr, WriteFile(hFile, c_wszXMLDriver5,
  512. sizeof(c_wszXMLDriver5) - sizeof(WCHAR), &cb, NULL));
  513. if (FAILED(hr))
  514. goto done;
  515. done:
  516. return hr;
  517. }
  518. // **************************************************************************
  519. void GrovelDriverDir(HANDLE hFile, LPWSTR wszDrivers)
  520. {
  521. WIN32_FIND_DATAW wfd;
  522. HRESULT hr = NOERROR;
  523. HANDLE hFind = INVALID_HANDLE_VALUE;
  524. WCHAR *wszFind, *pwszFind;
  525. DWORD cchNeed;
  526. USE_TRACING("GrovelDriverDir");
  527. if (hFile == NULL || hFile == INVALID_HANDLE_VALUE || wszDrivers == NULL)
  528. return;
  529. cchNeed = wcslen(wszDrivers) + MAX_PATH + 2;
  530. __try { wszFind = (LPWSTR)_alloca(cchNeed * sizeof(WCHAR)); }
  531. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  532. {
  533. wszFind = NULL;
  534. }
  535. if (wszFind == NULL)
  536. goto done;
  537. StringCchCopyW(wszFind, cchNeed, wszDrivers);
  538. StringCchCatNW(wszFind, cchNeed, L"\\*", cchNeed-wcslen(wszFind));
  539. pwszFind = wszFind + wcslen(wszFind) - 1;
  540. // add the driver info to the file
  541. ZeroMemory(&wfd, sizeof(wfd));
  542. hFind = FindFirstFileW(wszFind, &wfd);
  543. if (hFind != NULL)
  544. {
  545. do
  546. {
  547. if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0 &&
  548. wcslen(wfd.cFileName) < MAX_PATH)
  549. {
  550. StringCchCopyW(pwszFind, cchNeed, wfd.cFileName);
  551. TESTHR(hr, WriteDriverRecord(hFile, wszFind));
  552. if (FAILED(hr))
  553. goto done;
  554. }
  555. }
  556. while(FindNextFileW(hFind, &wfd));
  557. }
  558. done:
  559. if (hFind != INVALID_HANDLE_VALUE)
  560. FindClose(hFind);
  561. }
  562. // **************************************************************************
  563. HRESULT GetDriverData(HANDLE hFile)
  564. {
  565. FILETIME ft;
  566. HRESULT hr = NOERROR;
  567. LPWSTR wszKey = NULL;
  568. DWORD iKey, dw, cchKeyMax, dwSvcType, cb, cchNeed, cchSysDir, cch;
  569. WCHAR wszSvcPath[1024], *pwszSysDir, *pwszFile;
  570. HKEY hkeySvc = NULL, hkey = NULL;
  571. USE_TRACING("GetDriverData");
  572. VALIDATEPARM(hr, (hFile == NULL));
  573. if (FAILED(hr))
  574. goto done;
  575. cchNeed = GetSystemDirectoryW(NULL, 0);
  576. if (cchNeed == 0)
  577. goto done;
  578. // according to MSDN, a service name can not be longer than 256 chars
  579. cchNeed += 32;
  580. __try { pwszSysDir = (LPWSTR)_alloca(cchNeed * sizeof(WCHAR)); }
  581. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  582. {
  583. pwszSysDir = NULL;
  584. }
  585. if (pwszSysDir == NULL)
  586. {
  587. SetLastError(ERROR_OUTOFMEMORY);
  588. goto done;
  589. }
  590. cchSysDir = GetSystemDirectoryW(pwszSysDir, cchNeed);
  591. if (cchSysDir == 0)
  592. goto done;
  593. if (pwszSysDir[cchSysDir - 1] != L'\\')
  594. {
  595. pwszSysDir[cchSysDir++] = L'\\';
  596. pwszSysDir[cchSysDir] = L'\0';
  597. }
  598. StringCchCopyW(&pwszSysDir[cchSysDir], cchNeed - cchSysDir, L"drivers");
  599. cchSysDir += sizeofSTRW(L"drivers");
  600. // get all the drivers that live in the default drivers directory
  601. GrovelDriverDir(hFile, pwszSysDir);
  602. // start grovelling the registry
  603. TESTERR(hr, RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRPSvc, 0, KEY_READ,
  604. &hkeySvc));
  605. if (FAILED(hr))
  606. goto done;
  607. TESTERR(hr, RegQueryInfoKey(hkeySvc, NULL, NULL, NULL, NULL, &cchKeyMax,
  608. NULL, NULL, NULL, NULL, NULL, NULL));
  609. if (FAILED(hr) || cchKeyMax == 0)
  610. goto done;
  611. cchKeyMax += 8;
  612. __try { wszKey = (LPWSTR)_alloca(cchKeyMax * sizeof(WCHAR)); }
  613. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  614. {
  615. wszKey = NULL;
  616. }
  617. if (wszKey == NULL)
  618. {
  619. SetLastError(ERROR_OUTOFMEMORY);
  620. hr = E_OUTOFMEMORY;
  621. goto done;
  622. }
  623. // loop thru the services reg key & extract out all the driver entries
  624. for(iKey = 0; ; iKey++)
  625. {
  626. cch = cchKeyMax;
  627. TESTERR(hr, RegEnumKeyExW(hkeySvc, iKey, wszKey, &cch, NULL, NULL,
  628. NULL, &ft));
  629. if (FAILED(hr))
  630. {
  631. if (hr == Err2HR(ERROR_NO_MORE_ITEMS))
  632. break;
  633. else if (hr == Err2HR(ERROR_MORE_DATA))
  634. continue;
  635. else
  636. goto done;
  637. }
  638. TESTERR(hr, RegOpenKeyExW(hkeySvc, wszKey, 0, KEY_READ, &hkey));
  639. if (FAILED(hr))
  640. continue;
  641. cb = sizeof(dwSvcType);
  642. dw = RegQueryValueExW(hkey, c_wszRVSvcType, NULL, NULL,
  643. (LPBYTE)&dwSvcType, &cb);
  644. if (dw != ERROR_SUCCESS)
  645. goto doneLoop;
  646. // only care about drivers
  647. if ((dwSvcType & SERVICE_DRIVER) == 0)
  648. goto doneLoop;
  649. // get the ImagePath to the driver. If none is present, then create
  650. // the following path: "%windir%\system32\drivers\<name>.sys" because
  651. // that's what the OS does if no ImagePath field is present.
  652. cb = sizeof(wszSvcPath);
  653. dw = RegQueryValueExW(hkey, c_wszRVSvcPath, NULL, NULL,
  654. (LPBYTE)wszSvcPath, &cb);
  655. if (dw != ERROR_SUCCESS)
  656. {
  657. hr = Err2HR(dw);
  658. goto doneLoop;
  659. }
  660. // don't want to gather the info if we already did above, so check if
  661. // the file lives in the drivers directory
  662. for(pwszFile = wszSvcPath + wcslen(wszSvcPath);
  663. *pwszFile != L'\\' && pwszFile > wszSvcPath;
  664. pwszFile--);
  665. if (*pwszFile != L'\\')
  666. goto doneLoop;
  667. *pwszFile = L'\0';
  668. if (_wcsicmp(pwszSysDir, wszSvcPath) == 0)
  669. goto doneLoop;
  670. // make sure we have a full path
  671. if ((wszSvcPath[0] != L'\\' || wszSvcPath[1] != L'\\') &&
  672. (wszSvcPath[1] != L':' || wszSvcPath[2] != L'\\'))
  673. goto doneLoop;
  674. *pwszFile = L'\\';
  675. // do the actual writing of the info.
  676. TESTHR(hr, WriteDriverRecord(hFile, wszSvcPath));
  677. if (FAILED(hr))
  678. goto done;
  679. doneLoop:
  680. if (hkey != NULL)
  681. {
  682. RegCloseKey(hkey);
  683. hkey = NULL;
  684. }
  685. }
  686. hr = NOERROR;
  687. done:
  688. if (hkeySvc != NULL)
  689. RegCloseKey(hkeySvc);
  690. if (hkey != NULL)
  691. RegCloseKey(hkey);
  692. return hr;
  693. }
  694. // **************************************************************************
  695. HRESULT GetExtraReportInfo(LPCWSTR wszFile, OSVERSIONINFOEXW &osvi)
  696. {
  697. WIN32_FIND_DATAW wfd;
  698. HRESULT hr = NOERROR;
  699. HANDLE hFile = INVALID_HANDLE_VALUE;
  700. WCHAR wszFind[MAX_PATH], *pwszFind, *pwsz;
  701. WCHAR wszBuf[1025], *pwszProd;
  702. WCHAR wszSku[200];
  703. WCHAR cchEmpty = L'\0';
  704. DWORD cb, cbOut, cch, cchNeed;
  705. HKEY hkey = NULL;
  706. USE_TRACING("GetExtraReportInfo");
  707. VALIDATEPARM(hr, (wszFile == NULL));
  708. if (FAILED(hr))
  709. {
  710. SetLastError(ERROR_INVALID_PARAMETER);
  711. goto done;
  712. }
  713. // create the file
  714. hFile = CreateFileW(wszFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0,
  715. NULL);
  716. TESTBOOL(hr, (hFile != INVALID_HANDLE_VALUE));
  717. if (FAILED(hr))
  718. goto done;
  719. // determine the SKU
  720. wszSku[0]=0;
  721. // we could have an embedded srv or wks installation here...
  722. if ((osvi.wSuiteMask & VER_SUITE_EMBEDDEDNT) != 0)
  723. StringCbCatNW(wszSku, sizeof(wszSku), L"Embedded ", ARRAYSIZE(wszSku));
  724. if (osvi.wProductType == VER_NT_WORKSTATION)
  725. {
  726. if ((osvi.wSuiteMask & VER_SUITE_PERSONAL) != 0)
  727. StringCbCatNW(wszSku, sizeof(wszSku), L"Home Edition", ARRAYSIZE(wszSku));
  728. else
  729. StringCbCatNW(wszSku, sizeof(wszSku), L"Professional", ARRAYSIZE(wszSku));
  730. }
  731. else
  732. {
  733. if ((osvi.wSuiteMask & VER_SUITE_DATACENTER) != 0)
  734. StringCbCatNW(wszSku, sizeof(wszSku), L"DataCenter Server", ARRAYSIZE(wszSku));
  735. else if ((osvi.wSuiteMask & VER_SUITE_ENTERPRISE) != 0)
  736. StringCbCatNW(wszSku, sizeof(wszSku), L"Advanced Server", ARRAYSIZE(wszSku));
  737. else if ((osvi.wSuiteMask & VER_SUITE_BLADE) != 0)
  738. StringCbCatNW(wszSku, sizeof(wszSku), L"Web Server", ARRAYSIZE(wszSku));
  739. else if ((osvi.wSuiteMask & VER_SUITE_BACKOFFICE) != 0)
  740. StringCbCatNW(wszSku, sizeof(wszSku), L"Back Office Server", ARRAYSIZE(wszSku));
  741. else if ((osvi.wSuiteMask & VER_SUITE_SMALLBUSINESS) != 0)
  742. StringCbCatNW(wszSku, sizeof(wszSku), L"Small Business Server", ARRAYSIZE(wszSku));
  743. else if ((osvi.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED) != 0)
  744. StringCbCatNW(wszSku, sizeof(wszSku), L"Small Business Server (restricted)", ARRAYSIZE(wszSku));
  745. else if ((osvi.wSuiteMask & VER_SUITE_COMMUNICATIONS) != 0)
  746. StringCbCatNW(wszSku, sizeof(wszSku), L"Communications Server", ARRAYSIZE(wszSku));
  747. else
  748. StringCbCatNW(wszSku, sizeof(wszSku), L"Server", ARRAYSIZE(wszSku));
  749. }
  750. // fetch the product ID from the registry
  751. pwszProd = &cchEmpty;
  752. TESTHR(hr, OpenRegKey(HKEY_LOCAL_MACHINE, c_wszRKWNTCurVer, FALSE, &hkey));
  753. if (SUCCEEDED(hr))
  754. {
  755. cb = sizeofSTRW(wszBuf);
  756. TESTHR(hr, ReadRegEntry(hkey, c_wszRVProdName, NULL, (LPBYTE)wszBuf,
  757. &cb, NULL, 0));
  758. if (SUCCEEDED(hr))
  759. {
  760. cb = wcslen(wszBuf) * sizeof(WCHAR) * 6 + sizeof(WCHAR);
  761. __try { pwszProd = (WCHAR *)_alloca(cb); }
  762. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  763. {
  764. pwszProd = NULL;
  765. }
  766. if (pwszProd == NULL)
  767. goto done;
  768. XMLEncodeString(wszBuf, pwszProd, cb / sizeof(WCHAR));
  769. }
  770. else
  771. {
  772. pwszProd = &cchEmpty;
  773. }
  774. RegCloseKey(hkey);
  775. hkey = NULL;
  776. }
  777. // <SYSTEMINFO>
  778. // <SYSTEM>
  779. // <OSNAME>[os product name] [os sku name]</OSNAME>
  780. // <OSVER>[major.minor.build SPmajor.SPminor]</OSVER>
  781. // <OSLANGUAGE>[system LCID]</OSLANGUAGE>
  782. wszBuf[0] = 0xfeff;
  783. if (StringCbPrintfW(wszBuf + 1, sizeof(wszBuf) - sizeof(WCHAR),
  784. c_wszXMLHeader, pwszProd, wszSku,
  785. osvi.dwMajorVersion, osvi.dwMinorVersion,
  786. osvi.dwBuildNumber, osvi.wServicePackMajor,
  787. osvi.wServicePackMinor, GetSystemDefaultLangID()) == S_OK)
  788. {
  789. cbOut = wcslen(wszBuf) * sizeof(WCHAR);
  790. } else
  791. {
  792. cbOut = 0;
  793. }
  794. TESTBOOL(hr, WriteFile(hFile, wszBuf, cbOut, &cb, NULL));
  795. if (FAILED(hr))
  796. goto done;
  797. WRITE_CWSZ(hr, hFile, c_wszXMLCloseSystem, cb);
  798. WRITE_CWSZ(hr, hFile, c_wszXMLOpenDevices, cb);
  799. TESTHR(hr, GetDeviceData(hFile));
  800. WRITE_CWSZ(hr, hFile, c_wszXMLCloseDevices, cb);
  801. WRITE_CWSZ(hr, hFile, c_wszXMLOpenDrivers, cb);
  802. TESTHR(hr, GetDriverData(hFile));
  803. // </DRIVERS>
  804. // </SYSTEMINFO>
  805. WRITE_CWSZ(hr, hFile, c_wszXMLFooter, cb);
  806. done:
  807. if (hFile != INVALID_HANDLE_VALUE)
  808. CloseHandle(hFile);
  809. if (hkey != NULL)
  810. RegCloseKey(hkey);
  811. return hr;
  812. }
  813. // **************************************************************************
  814. BOOL DoImmediateEventReport(HANDLE hToken, EEventType eet)
  815. {
  816. USE_TRACING("DoImmediateEventReport");
  817. PROCESS_INFORMATION pi = { NULL, NULL, 0, 0 };
  818. STARTUPINFOW si;
  819. LPWSTR pwszSysDir, pwszCmdLine, pwszAppName;
  820. LPVOID pvEnv = NULL;
  821. DWORD cch, cchNeed;
  822. BOOL fRet = FALSE;
  823. if (hToken == NULL ||
  824. (eet != eetKernelFault && eet != eetShutdown))
  825. {
  826. SetLastError(ERROR_INVALID_PARAMETER);
  827. goto done;
  828. }
  829. // get the system directory
  830. cch = GetSystemDirectoryW(NULL, 0);
  831. if (cch == 0)
  832. goto done;
  833. cch++;
  834. __try { pwszSysDir = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  835. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  836. {
  837. pwszSysDir = NULL;
  838. }
  839. if (pwszSysDir == NULL)
  840. {
  841. SetLastError(ERROR_OUTOFMEMORY);
  842. goto done;
  843. }
  844. cch = GetSystemDirectoryW(pwszSysDir, cch);
  845. if (cch == 0)
  846. goto done;
  847. if (*(pwszSysDir + cch - 1) == L'\\')
  848. *(pwszSysDir + cch - 1) = L'\0';
  849. // create the App name
  850. cchNeed = cch + sizeofSTRW(c_wszKrnlAppName) + 1;
  851. __try { pwszAppName = (LPWSTR)_alloca(cchNeed * sizeof(WCHAR)); }
  852. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  853. {
  854. pwszAppName = NULL;
  855. }
  856. if (pwszAppName == NULL)
  857. {
  858. SetLastError(ERROR_OUTOFMEMORY);
  859. goto done;
  860. }
  861. StringCchPrintfW(pwszAppName, cchNeed, c_wszKrnlAppName, pwszSysDir);
  862. // create the full command line
  863. if (eet == eetKernelFault)
  864. pwszCmdLine = (LPWSTR) c_wszKrnlCmdLine;
  865. else
  866. pwszCmdLine = (LPWSTR) c_wszShutCmdLine;
  867. // get the environment block for the user
  868. fRet = CreateEnvironmentBlock(&pvEnv, hToken, FALSE);
  869. if (fRet == FALSE)
  870. pvEnv = NULL;
  871. ZeroMemory(&si, sizeof(si));
  872. si.cb = sizeof(si);
  873. fRet = CreateProcessAsUserW(hToken, pwszAppName, pwszCmdLine, NULL, NULL, FALSE,
  874. CREATE_UNICODE_ENVIRONMENT, pvEnv, pwszSysDir,
  875. &si, &pi);
  876. if (fRet)
  877. {
  878. if (pi.hProcess != NULL)
  879. CloseHandle(pi.hProcess);
  880. if (pi.hThread != NULL)
  881. CloseHandle(pi.hThread);
  882. }
  883. done:
  884. if (pvEnv != NULL)
  885. DestroyEnvironmentBlock(pvEnv);
  886. return fRet;
  887. }
  888. ///////////////////////////////////////////////////////////////////////////////
  889. // exported functions
  890. // **************************************************************************
  891. EFaultRepRetVal APIENTRY ReportEREvent(EEventType eet, LPCWSTR wszDump,
  892. SEventInfoW *pei)
  893. {
  894. USE_TRACING("ReportEREvent");
  895. CPFFaultClientCfg oCfg;
  896. EFaultRepRetVal frrvRet = frrvErrNoDW;
  897. DWORD dw;
  898. WCHAR wszDir[MAX_PATH];
  899. HKEY hkey = NULL;
  900. HRESULT hr;
  901. if (eet != eetKernelFault && eet != eetShutdown && eet != eetUseEventInfo)
  902. {
  903. frrvRet = frrvErr;
  904. DBG_MSG("Bad params- eet");
  905. SetLastError(ERROR_INVALID_PARAMETER);
  906. goto done;
  907. }
  908. if (eet == eetUseEventInfo &&
  909. (pei == NULL || pei->wszTitle == NULL || pei->wszStage2 == NULL ||
  910. pei->wszEventName == NULL))
  911. {
  912. frrvRet = frrvErr;
  913. if (!pei)
  914. DBG_MSG("Bad params- pei");
  915. else if (!pei->wszTitle)
  916. DBG_MSG("Bad params- pei.Title");
  917. else if (!pei->wszStage2)
  918. DBG_MSG("Bad params- pei.wszStage2");
  919. else if (!pei->wszEventName)
  920. DBG_MSG("Bad params- pei.wszEventName");
  921. else
  922. DBG_MSG("Way bad param");
  923. SetLastError(ERROR_INVALID_PARAMETER);
  924. goto done;
  925. }
  926. if (((eet == eetKernelFault || eet == eetShutdown) && wszDump == NULL))
  927. {
  928. frrvRet = frrvErr;
  929. DBG_MSG("Bad params- eetKernelFault");
  930. SetLastError(ERROR_INVALID_PARAMETER);
  931. goto done;
  932. }
  933. if (FAILED(oCfg.Read(eroPolicyRO)))
  934. goto done;
  935. if (oCfg.get_TextLog() == eedEnabled)
  936. {
  937. LPCWSTR wszEvent = NULL;
  938. if (eet == eetUseEventInfo)
  939. wszEvent = pei->wszEventName;
  940. if (wszEvent == NULL)
  941. wszEvent = c_rgwszEvents[eet];
  942. if (wcslen(wszEvent) > MAX_PATH)
  943. wszEvent = c_wszUnknown;
  944. TextLogOut("(notifying) %ls\r\n", wszEvent);
  945. }
  946. DWORD dwSetup = SetupIsInProgress();
  947. #ifndef GUI_MODE_SETUP
  948. // revert to our old behaviour- no setup reporting at all.
  949. if (dwSetup != SIIP_NO_SETUP)
  950. goto done;
  951. #endif
  952. // if we are in silent mode or are not reporting one of the two special
  953. // case items (kernel fault & unplanned shutdown), then just go ahead and
  954. // report directly unless we are in any setup mode. In that case we always queue
  955. frrvRet = frrvErr;
  956. if (dwSetup == SIIP_NO_SETUP &&
  957. ((oCfg.get_ShowUI() == eedDisabled &&
  958. oCfg.get_DoReport() == eedEnabled) ||
  959. (eet == eetUseEventInfo)))
  960. {
  961. // notice that if this call fails, we will try to queue the event
  962. frrvRet = ReportEREventDW(eet, wszDump, pei);
  963. }
  964. if (frrvRet == frrvErr && eet != eetUseEventInfo)
  965. {
  966. LPCWSTR wszRK = ((eet == eetShutdown) ? c_wszRKShut : c_wszRKKrnl);
  967. HANDLE hToken = NULL;
  968. DWORD dwSession;
  969. BOOL fFoundAdmin = FALSE;
  970. FILETIME ft;
  971. ZeroMemory(&ft, sizeof(ft));
  972. GetSystemTimeAsFileTime(&ft);
  973. // create the fault key (if it isn't there) and add this one to the list
  974. TESTERR(hr, RegCreateKeyExW(HKEY_LOCAL_MACHINE, wszRK, 0, NULL, 0,
  975. KEY_WRITE, NULL, &hkey, NULL));
  976. if (SUCCEEDED(hr))
  977. {
  978. DWORD cbData;
  979. cbData = sizeof(ft);
  980. TESTERR(hr, RegSetValueExW(hkey, wszDump, 0, REG_BINARY, (LPBYTE)&ft,
  981. cbData));
  982. RegCloseKey(hkey);
  983. hkey = NULL;
  984. // no point in going on if we aren't priviledged cuz we won't be
  985. // able to launch processes or fetch the user token,
  986. // and if we are in setup, we have to queue anyway.
  987. if (dwSetup == SIIP_NO_SETUP && AmIPrivileged(TRUE))
  988. fFoundAdmin = FindAdminSession(&dwSession, &hToken);
  989. if (fFoundAdmin)
  990. fFoundAdmin = DoImmediateEventReport(hToken, eet);
  991. // there is no admin logged on, so add the value to the run key
  992. /*
  993. * Notice that we only queue for shutdowns and bluescreens
  994. * There is no concept of queued reporting for generic reports
  995. */
  996. if (fFoundAdmin == FALSE && eet != eetUseEventInfo)
  997. {
  998. // create our value in the RunOnce key so that we can report the
  999. // next time someone logs in.
  1000. TESTERR(hr, RegCreateKeyExW(HKEY_LOCAL_MACHINE, c_wszRKRun, 0, NULL, 0,
  1001. KEY_WRITE, NULL, &hkey, NULL));
  1002. if (SUCCEEDED(hr))
  1003. {
  1004. LPCWSTR wszRV = NULL;
  1005. LPCWSTR wszRVD = NULL;
  1006. DWORD cbRVD = NULL;
  1007. if (eet == eetShutdown)
  1008. {
  1009. wszRV = c_wszRVSEC;
  1010. wszRVD = c_wszRVVSEC;
  1011. cbRVD = sizeof(c_wszRVVSEC) - sizeof(WCHAR);
  1012. DBG_MSG("Added Shutdown Event report to the queue");
  1013. }
  1014. else
  1015. {
  1016. wszRV = c_wszRVKFC;
  1017. wszRVD = c_wszRVVKFC;
  1018. cbRVD = sizeof(c_wszRVVKFC) - sizeof(WCHAR);
  1019. DBG_MSG("Added Kernel Fault report to the queue");
  1020. }
  1021. RegSetValueExW(hkey, wszRV, 0, REG_EXPAND_SZ,
  1022. (LPBYTE)wszRVD, cbRVD);
  1023. RegCloseKey(hkey);
  1024. }
  1025. }
  1026. else
  1027. {
  1028. /* since we could not find an admin to report to, we admit failure */
  1029. frrvRet = frrvErr;
  1030. goto done;
  1031. }
  1032. }
  1033. else
  1034. {
  1035. /* since we could not create a fault key, admit failure */
  1036. frrvRet = frrvErr;
  1037. goto done;
  1038. }
  1039. #ifdef GUI_MODE_SETUP
  1040. /*
  1041. * This is a special case here. If we are in GUI mode, then we must also
  1042. * write this data to the backup registry files kept by the Whistler setup
  1043. * in case of a catastrophic failure.
  1044. */
  1045. if (dwSetup == SIIP_GUI_SETUP && eet != eetUseEventInfo)
  1046. {
  1047. HKEY hBackupHive = NULL;
  1048. WCHAR *wszTmpName = L"WERTempHive";
  1049. WCHAR *wszConfigFile = L"\\config\\software.sav";
  1050. WCHAR *wszBackupHiveFile = NULL;
  1051. DWORD cch, cchNeed;
  1052. HRESULT hr;
  1053. // get the system directory
  1054. cch = GetSystemDirectoryW(wszDir, ARRAYSIZE(wszDir));
  1055. if (cch == 0)
  1056. goto done;
  1057. if (*(wszDir + cch - 1) == L'\\')
  1058. *(wszDir + cch - 1) = L'\0';
  1059. wcsncat(wszDir, wszConfigFile, ARRAYSIZE(wszDir)-wcslen(wszDir));
  1060. TESTBOOL(hr, SetPrivilege(L"SeRestorePrivilege", TRUE));
  1061. if (FAILED(hr))
  1062. goto done;
  1063. TESTERR(hr, RegLoadKeyW(HKEY_LOCAL_MACHINE, wszTmpName, wszDir));
  1064. if (SUCCEEDED(hr))
  1065. {
  1066. TESTERR(hr, RegOpenKeyExW( HKEY_LOCAL_MACHINE, wszTmpName,
  1067. 0, KEY_WRITE, &hBackupHive ));
  1068. if (SUCCEEDED(hr))
  1069. {
  1070. // create the fault key (if it isn't there) and add this one to the list
  1071. wszRK = ((eet == eetShutdown) ? c_wszTmpRKShut : c_wszTmpRKKrnl);
  1072. TESTERR(hr, RegCreateKeyExW(hBackupHive, wszRK, 0, NULL, 0,
  1073. KEY_WRITE, NULL, &hkey, NULL));
  1074. if (SUCCEEDED(hr))
  1075. {
  1076. DWORD cbData;
  1077. cbData = sizeof(ft);
  1078. TESTERR(hr, RegSetValueExW(hkey, wszDump, 0, REG_BINARY, (LPBYTE)&ft, cbData));
  1079. RegCloseKey(hkey);
  1080. hkey = NULL;
  1081. // create our value in the RunOnce key so that we can report the
  1082. // next time someone logs in.
  1083. TESTERR(hr, RegCreateKeyExW(hBackupHive, c_wszTmpRKRun, 0, NULL, 0,
  1084. KEY_WRITE, NULL, &hkey, NULL));
  1085. if (SUCCEEDED(hr))
  1086. {
  1087. LPCWSTR wszRV = NULL;
  1088. LPCWSTR wszRVD = NULL;
  1089. DWORD cbRVD = NULL;
  1090. if (eet == eetShutdown)
  1091. {
  1092. wszRV = c_wszRVSEC;
  1093. wszRVD = c_wszRVVSEC;
  1094. cbRVD = sizeof(c_wszRVVSEC) - sizeof(WCHAR);
  1095. }
  1096. else
  1097. {
  1098. wszRV = c_wszRVKFC;
  1099. wszRVD = c_wszRVVKFC;
  1100. cbRVD = sizeof(c_wszRVVKFC) - sizeof(WCHAR);
  1101. }
  1102. TESTERR(hr, RegSetValueExW(hkey, wszRV, 0, REG_EXPAND_SZ,
  1103. (LPBYTE)wszRVD, cbRVD));
  1104. RegCloseKey(hkey);
  1105. }
  1106. }
  1107. RegCloseKey(hBackupHive);
  1108. }
  1109. RegUnLoadKeyW(HKEY_LOCAL_MACHINE, wszTmpName);
  1110. }
  1111. TESTBOOL(hr, SetPrivilege(L"SeRestorePrivilege", FALSE));
  1112. }
  1113. #endif // GUI_MODE_SETUP
  1114. frrvRet = frrvOk;
  1115. }
  1116. done:
  1117. return frrvRet;
  1118. }
  1119. // **************************************************************************
  1120. EFaultRepRetVal APIENTRY ReportEREventDW(EEventType eet, LPCWSTR wszDump,
  1121. SEventInfoW *pei)
  1122. {
  1123. USE_TRACING("ReportEREventDW");
  1124. CPFFaultClientCfg oCfg;
  1125. OSVERSIONINFOEXW ovi;
  1126. EFaultRepRetVal frrvRet = frrvErrNoDW;
  1127. SDWManifestBlob dwmb;
  1128. HRESULT hr = NOERROR;
  1129. LPWSTR wszFiles = NULL, pwszExtra = NULL, wszDir = NULL;
  1130. LPWSTR wszManifest = NULL;
  1131. DWORD dw, cch, cchDir, cchSep;
  1132. WCHAR wszBuffer[1025];
  1133. ULONG ulBCCode;
  1134. BOOL fAllowSend = TRUE;
  1135. HKEY hkey = NULL;
  1136. #ifndef _WIN64
  1137. ULONG ulBCP1, ulBCP2, ulBCP3, ulBCP4;
  1138. #else
  1139. ULONG64 ulBCP1, ulBCP2, ulBCP3, ulBCP4;
  1140. #endif
  1141. VALIDATEPARM(hr, ((eet != eetKernelFault && eet != eetShutdown && eet != eetUseEventInfo) ||
  1142. (eet == eetUseEventInfo &&
  1143. (pei == NULL || pei->wszTitle == NULL || pei->wszStage2 == NULL ||
  1144. pei->wszEventName == NULL || pei->cbSEI != sizeof(SEventInfoW))) ||
  1145. ((eet == eetKernelFault || eet == eetShutdown) && wszDump == NULL)));
  1146. if (FAILED(hr))
  1147. {
  1148. frrvRet = frrvErr;
  1149. SetLastError(ERROR_INVALID_PARAMETER);
  1150. goto done;
  1151. }
  1152. switch(eet)
  1153. {
  1154. case eetKernelFault:
  1155. DBG_MSG("eetKernelFault");
  1156. break;
  1157. case eetShutdown:
  1158. DBG_MSG("eetShutdown");
  1159. break;
  1160. case eetUseEventInfo:
  1161. DBG_MSG("eetUseEventInfo");
  1162. break;
  1163. }
  1164. TESTHR(hr, oCfg.Read(eroPolicyRO));
  1165. if (FAILED(hr))
  1166. goto done;
  1167. if (oCfg.get_TextLog() == eedEnabled)
  1168. {
  1169. LPCWSTR wszEvent = NULL;
  1170. if (eet == eetUseEventInfo)
  1171. wszEvent = pei->wszEventName;
  1172. if (wszEvent == NULL)
  1173. wszEvent = c_rgwszEvents[eet];
  1174. if (wcslen(wszEvent) > MAX_PATH)
  1175. wszEvent = c_wszUnknown;
  1176. TextLogOut("(reporting) %ls\r\n", wszEvent);
  1177. }
  1178. if (oCfg.get_ShowUI() == eedDisabled)
  1179. {
  1180. LPCWSTR wszULPath = oCfg.get_DumpPath(NULL, 0);
  1181. // if we're disabled, then don't do anything at all. Still return the
  1182. // frrvErrNoDW so that the calling app can perform whatever default
  1183. // actions it wants to...
  1184. if (oCfg.get_DoReport() == eedDisabled)
  1185. goto done;
  1186. // check and make sure that we have a corporate path specified. If we
  1187. // don't, bail
  1188. if (wszULPath == NULL || *wszULPath == L'\0')
  1189. goto done;
  1190. //
  1191. // When kernel faults are reported by savedump at machine
  1192. // boot time it is possible that the full net infrastructure
  1193. // hasn't quite started by the time savedump calls to report.
  1194. // UNC path references can fail, causing spurious failures
  1195. // when in CER mode. Do a quick retry loop to check for
  1196. // such failures and allow time for the net code to start.
  1197. //
  1198. if (wszULPath[0] == L'\\' && wszULPath[1] == L'\\')
  1199. {
  1200. ULONG ulUncRetry = 60;
  1201. while (ulUncRetry-- > 0)
  1202. {
  1203. // Try to limit the errors for which we'll wait
  1204. // to the minimum set so that a plain bad path
  1205. // won't cause a delay.
  1206. if (GetFileAttributesW(wszULPath) != -1 ||
  1207. (GetLastError() != ERROR_NETWORK_UNREACHABLE &&
  1208. GetLastError() != ERROR_BAD_NETPATH))
  1209. {
  1210. break;
  1211. }
  1212. Sleep(1000);
  1213. }
  1214. // We do not panic and fail here if the path
  1215. // was inaccessible. Instead we let the normal
  1216. // failure path take care of things.
  1217. }
  1218. }
  1219. // if kernel reporting or general reporting is disabled, don't show the
  1220. // send button
  1221. if (oCfg.get_DoReport() == eedDisabled ||
  1222. (eet == eetKernelFault && oCfg.get_IncKernel() == eedDisabled) ||
  1223. (eet == eetShutdown && oCfg.get_IncShutdown() == eedDisabled))
  1224. fAllowSend = FALSE;
  1225. if (CreateTempDirAndFile(NULL, NULL, &wszDir) == 0)
  1226. goto done;
  1227. cchDir = wcslen(wszDir);
  1228. cch = cchDir + sizeofSTRW(c_wszManFileName) + 4;
  1229. __try { wszManifest = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  1230. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1231. {
  1232. wszManifest = NULL;
  1233. }
  1234. if (wszManifest == NULL)
  1235. {
  1236. SetLastError(ERROR_OUTOFMEMORY);
  1237. goto done;
  1238. }
  1239. StringCchCopyW(wszManifest, cch, wszDir);
  1240. wszManifest[cchDir] = L'\\';
  1241. wszManifest[cchDir + 1] = L'\0';
  1242. StringCchCatNW(wszManifest, cch, c_wszManFileName, cch-cchDir-2);
  1243. ZeroMemory(&dwmb, sizeof(dwmb));
  1244. if (eet != eetUseEventInfo)
  1245. {
  1246. ZeroMemory(&ovi, sizeof(ovi));
  1247. ovi.dwOSVersionInfoSize = sizeof(ovi);
  1248. GetVersionExW((LPOSVERSIONINFOW)&ovi);
  1249. cch = 2 * cchDir + wcslen(wszDump) + sizeofSTRW(c_wszEventData) + 4;
  1250. __try { wszFiles = (LPWSTR)_alloca(cch * sizeof(WCHAR)); }
  1251. __except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode() ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  1252. {
  1253. wszFiles = NULL;
  1254. }
  1255. if (wszFiles == NULL)
  1256. {
  1257. SetLastError(ERROR_OUTOFMEMORY);
  1258. goto done;
  1259. }
  1260. StringCchCopyW(wszFiles, cch, wszDump);
  1261. cchSep = wcslen(wszFiles);
  1262. pwszExtra = wszFiles + cchSep + 1;
  1263. StringCchCopyW(pwszExtra, cch - cchSep -1, wszDir);
  1264. pwszExtra[cchDir] = L'\\';
  1265. pwszExtra[cchDir + 1] = L'\0';
  1266. StringCchCatNW(pwszExtra, cch - cchSep - cchDir -2 , c_wszEventData, cch - cchSep - cchDir - 2);
  1267. TESTHR(hr, GetExtraReportInfo(pwszExtra, ovi));
  1268. if (SUCCEEDED(hr))
  1269. wszFiles[cchSep] = L'|';
  1270. // since AndreVa has promised us that savedump will ALWAYS hand us a
  1271. // minidump, we don't have to do any conversions. But this fn will make
  1272. // sure it's a kernel minidump anyway and fail if it isn't
  1273. if (eet == eetKernelFault)
  1274. {
  1275. TESTHR(hr, ExtractBCInfo(wszDump, &ulBCCode, &ulBCP1, &ulBCP2,
  1276. &ulBCP3, &ulBCP4));
  1277. if (FAILED(hr))
  1278. goto done;
  1279. // log an event- don't care if it fails or not.
  1280. TESTHR(hr, LogKrnl(ulBCCode, ulBCP1, ulBCP2, ulBCP3, ulBCP4));
  1281. StringCbPrintfW(wszBuffer, sizeof(wszBuffer), c_wszManKS2,
  1282. ulBCCode, ulBCP1, ulBCP2, ulBCP3,
  1283. ulBCP4, ovi.dwMajorVersion, ovi.dwMinorVersion,
  1284. ovi.dwBuildNumber, ovi.wServicePackMajor,
  1285. ovi.wServicePackMinor, ovi.wSuiteMask, ovi.wProductType);
  1286. dwmb.nidTitle = IDS_KTITLE;
  1287. dwmb.nidErrMsg = IDS_KERRMSG;
  1288. dwmb.nidHdr = IDS_KHDRTXT;
  1289. dwmb.wszStage2 = wszBuffer;
  1290. dwmb.wszBrand = c_wszDWBrand;
  1291. dwmb.wszFileList = wszFiles;
  1292. dwmb.wszCorpPath = c_wszManKCorpPath;
  1293. dwmb.fIsMSApp = TRUE;
  1294. dwmb.dwOptions = emoSupressBucketLogs |
  1295. emoNoDefCabLimit;
  1296. }
  1297. else if (eet == eetShutdown)
  1298. {
  1299. StringCbPrintfW(wszBuffer, sizeof(wszBuffer), c_wszManSS2, ovi.dwMajorVersion,
  1300. ovi.dwMinorVersion, ovi.dwBuildNumber,
  1301. ovi.wServicePackMajor, ovi.wServicePackMinor,
  1302. ovi.wSuiteMask, ovi.wProductType);
  1303. dwmb.nidTitle = IDS_STITLE;
  1304. dwmb.nidErrMsg = IDS_SERRMSG;
  1305. dwmb.nidHdr = IDS_SHDRTXT;
  1306. dwmb.wszStage2 = wszBuffer;
  1307. dwmb.wszBrand = c_wszDWBrand;
  1308. dwmb.wszFileList = wszFiles;
  1309. dwmb.wszCorpPath = c_wszManSCorpPath;
  1310. dwmb.fIsMSApp = TRUE;
  1311. dwmb.dwOptions = emoSupressBucketLogs | emoNoDefCabLimit;
  1312. }
  1313. }
  1314. else
  1315. {
  1316. dwmb.wszTitle = pei->wszTitle;
  1317. dwmb.wszErrMsg = pei->wszErrMsg;
  1318. dwmb.wszHdr = pei->wszHdr;
  1319. dwmb.wszPlea = pei->wszPlea;
  1320. dwmb.fIsMSApp = (pei->fUseLitePlea == FALSE);
  1321. dwmb.wszStage1 = pei->wszStage1;
  1322. dwmb.wszStage2 = pei->wszStage2;
  1323. dwmb.wszCorpPath = pei->wszCorpPath;
  1324. dwmb.wszEventSrc = pei->wszEventSrc;
  1325. dwmb.wszSendBtn = pei->wszSendBtn;
  1326. dwmb.wszNoSendBtn = pei->wszNoSendBtn;
  1327. dwmb.wszFileList = pei->wszFileList;
  1328. dwmb.dwOptions = 0;
  1329. if (pei->fUseIEForURLs)
  1330. dwmb.dwOptions |= emoUseIEforURLs;
  1331. if (pei->fNoBucketLogs)
  1332. dwmb.dwOptions |= emoSupressBucketLogs;
  1333. if (pei->fNoDefCabLimit)
  1334. dwmb.dwOptions |= emoNoDefCabLimit;
  1335. }
  1336. // check and see if the system is shutting down. If so, CreateProcess is
  1337. // gonna pop up some annoying UI that we can't get rid of, so we don't
  1338. // want to call it if we know it's gonna happen.
  1339. if (GetSystemMetrics(SM_SHUTTINGDOWN))
  1340. goto done;
  1341. // we can call DW if the user is an admin, or we are headless...
  1342. if ( oCfg.get_ShowUI() == eedDisabled || NewIsUserAdmin() )
  1343. {
  1344. frrvRet = StartDWManifest(oCfg, dwmb, wszManifest, fAllowSend);
  1345. }
  1346. else
  1347. {
  1348. DBG_MSG("Skipping DW- user is not an admin!");
  1349. }
  1350. #ifdef MANIFEST_DEBUG
  1351. /*
  1352. * This gets turned on in private builds to help people debug
  1353. * their calling parameters for ReportEREvent. Really Useful Feature
  1354. * to have. One day, this should be turned on all the time, and
  1355. * then would be triggered by a registry entry. Of course I don't
  1356. * have that much time right now, as there would be disclosure
  1357. * problems to solve before I could do that.
  1358. * TomFr
  1359. */
  1360. if (wszManifest != NULL)
  1361. {
  1362. WCHAR wszNew[DW_MAX_PATH];
  1363. GetSystemDirectoryW(wszNew, ARRAYSIZE(wszNew));
  1364. wszNew[3] = '\0';
  1365. StringCchCatW(wszNew, DW_MAX_PATH - 4, L"Debug.Manifest.txt");
  1366. CopyFileW(wszManifest, wszNew, FALSE);
  1367. }
  1368. #endif
  1369. done:
  1370. dw = GetLastError();
  1371. // don't clean out if we timed out cuz DW is still not done with the
  1372. // files
  1373. if (frrvRet != frrvErrTimeout)
  1374. {
  1375. if (wszManifest != NULL)
  1376. DeleteFileW(wszManifest);
  1377. if (wszFiles != NULL && pwszExtra != NULL)
  1378. {
  1379. // wszFiles[cchSep] = L'\0';
  1380. DeleteFileW(pwszExtra);
  1381. }
  1382. if (wszDir != NULL)
  1383. {
  1384. DeleteTempDirAndFile(wszDir, FALSE);
  1385. MyFree(wszDir);
  1386. }
  1387. }
  1388. SetLastError(dw);
  1389. return frrvRet;
  1390. }
  1391. // **************************************************************************
  1392. EFaultRepRetVal APIENTRY ReportKernelFaultDWW(LPCWSTR wszDump)
  1393. {
  1394. return ReportEREventDW(eetKernelFault, wszDump, NULL);
  1395. }