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.

4314 lines
124 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. ntbaseplus.c
  5. Abstract:
  6. This module implements low level primitives. They should never be
  7. called by anything other than this module.
  8. Author:
  9. dmunsil created sometime in 1999
  10. Revision History:
  11. several people contributed (vadimb, clupu, ...)
  12. kinshu - 01/10/2002 - Fixed a bug in the circular linked list
  13. insertion and deletion routines(InsertLookup,
  14. RemoveLookup)
  15. --*/
  16. #include "sdbp.h"
  17. extern const UNICODE_STRING g_ustrDatabasePath = RTL_CONSTANT_STRING(L"DatabasePath");
  18. extern const UNICODE_STRING g_ustrDatabaseType = RTL_CONSTANT_STRING(L"DatabaseType");
  19. extern const UNICODE_STRING g_ustrDatabaseDescription = RTL_CONSTANT_STRING(L"DatabaseDescription");
  20. extern const UNICODE_STRING g_ustrInstallTimeStamp = RTL_CONSTANT_STRING(L"DatabaseInstallTimeStamp");
  21. extern const UNICODE_STRING g_ustrShimDbgLevelVar = RTL_CONSTANT_STRING(L"SHIM_DEBUG_LEVEL");
  22. extern const TCHAR g_szCompatLayer[];
  23. void
  24. SdbpRtlInitUnicodeStringBuffer(
  25. RTL_UNICODE_STRING_BUFFER* pBuff,
  26. UCHAR* StatBuff,
  27. SIZE_T StatSize
  28. );
  29. //
  30. // Global flag for wow64. On Win2k we zero this flag out
  31. //
  32. DWORD volatile g_dwWow64Key = (DWORD)-1;
  33. typedef NTSTATUS
  34. (SDBAPI* PFNEnsureBufferSize)(
  35. IN ULONG Flags,
  36. IN OUT PRTL_BUFFER Buffer,
  37. IN SIZE_T Size);
  38. PFNEnsureBufferSize volatile g_pfnEnsureBufferSize = NULL;
  39. NTSTATUS
  40. SDBAPI
  41. SdbEnsureBufferSizeFunction(
  42. IN ULONG Flags,
  43. IN OUT PRTL_BUFFER Buffer,
  44. IN SIZE_T Size);
  45. //
  46. // to work on win2k, we have to modify default buffer-manipulation macro
  47. //
  48. #undef RtlEnsureBufferSize
  49. #define RtlEnsureBufferSize(Flags, Buff, NewSizeBytes) \
  50. ( ((Buff) != NULL && (NewSizeBytes) <= (Buff)->Size) \
  51. ? STATUS_SUCCESS \
  52. : SdbEnsureBufferSizeFunction((Flags), (Buff), (NewSizeBytes)) \
  53. )
  54. //
  55. // This routine was stolen from buffer.c in ntdll so that we can support downlevel platforms
  56. //
  57. NTSTATUS
  58. SDBAPI
  59. SdbpEnsureBufferSize(
  60. IN ULONG Flags,
  61. IN OUT PRTL_BUFFER Buffer,
  62. IN SIZE_T Size
  63. )
  64. {
  65. NTSTATUS Status = STATUS_SUCCESS;
  66. PUCHAR Temp = NULL;
  67. if ((Flags & ~(RTL_ENSURE_BUFFER_SIZE_NO_COPY)) != 0) {
  68. Status = STATUS_INVALID_PARAMETER;
  69. goto Exit;
  70. }
  71. if (Buffer == NULL) {
  72. Status = STATUS_INVALID_PARAMETER;
  73. goto Exit;
  74. }
  75. if (Size <= Buffer->Size) {
  76. Status = STATUS_SUCCESS;
  77. goto Exit;
  78. }
  79. //
  80. // Size <= Buffer->StaticSize does not imply static allocation, it
  81. // could be heap allocation that the client poked smaller.
  82. //
  83. if (Buffer->Buffer == Buffer->StaticBuffer && Size <= Buffer->StaticSize) {
  84. Buffer->Size = Size;
  85. Status = STATUS_SUCCESS;
  86. goto Exit;
  87. }
  88. //
  89. // The realloc case was messed up in Whistler, and got removed.
  90. // Put it back in Blackcomb.
  91. //
  92. Temp = (PUCHAR)RtlAllocateHeap(RtlProcessHeap(), 0, (Size));
  93. if (Temp == NULL) {
  94. Status = STATUS_NO_MEMORY;
  95. goto Exit;
  96. }
  97. if ((Flags & RTL_ENSURE_BUFFER_SIZE_NO_COPY) == 0) {
  98. RtlCopyMemory(Temp, Buffer->Buffer, Buffer->Size);
  99. }
  100. if (RTLP_BUFFER_IS_HEAP_ALLOCATED(Buffer)) {
  101. RtlFreeHeap(RtlProcessHeap(), 0, Buffer->Buffer);
  102. Buffer->Buffer = NULL;
  103. }
  104. ASSERT(Temp != NULL);
  105. Buffer->Buffer = Temp;
  106. Buffer->Size = Size;
  107. Status = STATUS_SUCCESS;
  108. Exit:
  109. return Status;
  110. }
  111. #define KEY_MACHINE TEXT("\\Registry\\Machine")
  112. BOOL
  113. SdbpBuildMachineKeyPath(
  114. IN LPCWSTR pwszPath,
  115. OUT PUNICODE_STRING pmachineKeyPath
  116. )
  117. /*++
  118. Return: TRUE on success, FALSE otherwise.
  119. Desc: Given a path to the key it builds it up for HKEY_LOCAL_MACHINE
  120. registry. The buffer used by pmachineKeyPath will have to be freed
  121. using SdbFree!
  122. --*/
  123. {
  124. BOOL bReturn = FALSE;
  125. UNICODE_STRING machineKey = {0};
  126. RtlInitUnicodeString(&machineKey, KEY_MACHINE);
  127. pmachineKeyPath->Length = 0;
  128. pmachineKeyPath->MaximumLength = (USHORT)(wcslen(pwszPath) * sizeof(*pwszPath) +
  129. machineKey.Length +
  130. sizeof(UNICODE_NULL));
  131. pmachineKeyPath->Buffer = SdbAlloc(pmachineKeyPath->MaximumLength);
  132. if (pmachineKeyPath->Buffer == NULL) {
  133. DBGPRINT((sdlError,
  134. "SdbpBuildUserKeyPath",
  135. "Failed to allocate %d bytes for user key buffer.\n",
  136. pmachineKeyPath->MaximumLength));
  137. goto out;
  138. }
  139. RtlAppendUnicodeStringToString(pmachineKeyPath, &machineKey);
  140. RtlAppendUnicodeToString(pmachineKeyPath, pwszPath);
  141. bReturn = TRUE;
  142. out:
  143. return bReturn;
  144. }
  145. BOOL
  146. SdbpBuildUserKeyPath(
  147. IN LPCWSTR pwszPath,
  148. OUT PUNICODE_STRING puserKeyPath
  149. )
  150. /*++
  151. Return: TRUE on success, FALSE otherwise.
  152. Desc: Given a path to the key it builds it up for HKEY_CURRENT_USER
  153. registry. The buffer used by puserKeyPath will have to be freed
  154. using SdbFree!
  155. --*/
  156. {
  157. BOOL bReturn = FALSE;
  158. NTSTATUS Status;
  159. UNICODE_STRING userKey = {0};
  160. Status = RtlFormatCurrentUserKeyPath(&userKey);
  161. if (!NT_SUCCESS(Status)) {
  162. DBGPRINT((sdlError,
  163. "SdbpBuildUserKeyPath",
  164. "Failed to format current user key path 0x%x\n",
  165. Status));
  166. goto out;
  167. }
  168. puserKeyPath->Length = 0;
  169. puserKeyPath->MaximumLength = (USHORT)(wcslen(pwszPath) * sizeof(*pwszPath) +
  170. userKey.Length +
  171. sizeof(UNICODE_NULL));
  172. puserKeyPath->Buffer = SdbAlloc(puserKeyPath->MaximumLength);
  173. if (puserKeyPath->Buffer == NULL) {
  174. DBGPRINT((sdlError,
  175. "SdbpBuildUserKeyPath",
  176. "Failed to allocate %d bytes for user key buffer.\n",
  177. puserKeyPath->MaximumLength));
  178. goto out;
  179. }
  180. RtlAppendUnicodeStringToString(puserKeyPath, &userKey);
  181. RtlAppendUnicodeToString(puserKeyPath, pwszPath);
  182. bReturn = TRUE;
  183. out:
  184. RtlFreeUnicodeString(&userKey);
  185. return bReturn;
  186. }
  187. /////////////////////////////////////////////////////////////////////////////////////////
  188. //
  189. // Custom SDB cache code
  190. //
  191. PUSERSDBLOOKUP
  192. SdbpFindSDBLookupEntry(
  193. IN PSDBCONTEXT pSdbContext, // sdb context for searches
  194. IN LPCWSTR pwszItemName, // item name foo.exe for instance
  195. IN BOOL bLayer // true if Layer
  196. )
  197. {
  198. PUSERSDBLOOKUP pLookup = pSdbContext->pLookupHead;
  199. if (pLookup == NULL) {
  200. return NULL;
  201. }
  202. do {
  203. if (!_wcsicmp(pLookup->pwszItemName, pwszItemName) && pLookup->bLayer == bLayer) {
  204. return pLookup;
  205. }
  206. pLookup = pLookup->pNext;
  207. } while (pLookup != pSdbContext->pLookupHead);
  208. return NULL;
  209. }
  210. void
  211. RemoveLookup(
  212. PSDBCONTEXT pSdbContext,
  213. PUSERSDBLOOKUP pLookup
  214. )
  215. {
  216. assert(pLookup);
  217. if (pLookup->pPrev == pLookup) {
  218. //
  219. // There is only one element
  220. //
  221. pSdbContext->pLookupHead = NULL;
  222. SdbFree(pLookup);
  223. return;
  224. }
  225. if (pSdbContext->pLookupHead == pLookup) {
  226. //
  227. // We are deleting the first element
  228. //
  229. pSdbContext->pLookupHead = pLookup->pNext;
  230. }
  231. pLookup->pPrev->pNext = pLookup->pNext;
  232. pLookup->pNext->pPrev = pLookup->pPrev;
  233. SdbFree(pLookup);
  234. }
  235. void
  236. InsertLookup(
  237. PSDBCONTEXT pSdbContext,
  238. PUSERSDBLOOKUP pLookup
  239. )
  240. {
  241. assert(pLookup);
  242. if (pSdbContext->pLookupHead == NULL) {
  243. pSdbContext->pLookupHead = pLookup;
  244. pLookup->pPrev = pLookup;
  245. pLookup->pNext = pLookup;
  246. return;
  247. }
  248. pLookup->pNext = pSdbContext->pLookupHead;
  249. pLookup->pPrev = pSdbContext->pLookupHead->pPrev;
  250. //
  251. // The pNext of the last element (pSdbContext->pLookupHead->pPrev) should point to the
  252. // new element
  253. //
  254. pSdbContext->pLookupHead->pPrev->pNext = pLookup;
  255. pSdbContext->pLookupHead->pPrev = pLookup;
  256. pSdbContext->pLookupHead = pLookup;
  257. }
  258. PUSERSDBLOOKUP
  259. SdbpCreateSDBLookupEntry(
  260. IN PSDBCONTEXT pSdbContext,
  261. IN DWORD dwCount,
  262. IN LPCWSTR pwszItemName,
  263. IN BOOL bLayer
  264. )
  265. {
  266. int nLen;
  267. DWORD dwSize;
  268. PUSERSDBLOOKUP pLookup;
  269. pLookup = SdbpFindSDBLookupEntry(pSdbContext, pwszItemName, bLayer);
  270. if (pLookup != NULL) {
  271. //
  272. // cornel: If we already have it shouldn't we just return here ?
  273. //
  274. assert(pLookup->dwCount == dwCount);
  275. RemoveLookup(pSdbContext, pLookup);
  276. }
  277. //
  278. // One entry is already included. See the structure definition.
  279. //
  280. // The memory layout is:
  281. //
  282. // USERSDBLOOKUP
  283. // (dwCount - 1) USERSDBLOOKUPENTRY structures
  284. // the string that pLookup->pwszItemName points to
  285. //
  286. nLen = (int)wcslen(pwszItemName) + 1;
  287. dwSize = (DWORD)(sizeof(USERSDBLOOKUP) + nLen * sizeof(WCHAR) +
  288. (dwCount - 1) * sizeof(USERSDBLOOKUPENTRY)); // one is already included
  289. pLookup = (PUSERSDBLOOKUP)SdbAlloc(dwSize);
  290. if (pLookup == NULL) {
  291. DBGPRINT((sdlError,
  292. "SdbpCreateSDBLookupEntry",
  293. "Failed to allocate 0x%lx bytes for sdb lookup buffer\n",
  294. dwSize));
  295. return NULL;
  296. }
  297. pLookup->pwszItemName = (LPWSTR)((PBYTE)(pLookup + 1) +
  298. (dwCount - 1) * sizeof(USERSDBLOOKUPENTRY));
  299. pLookup->bLayer = bLayer;
  300. pLookup->dwCount = dwCount;
  301. StringCchCopy(pLookup->pwszItemName, nLen, pwszItemName);
  302. InsertLookup(pSdbContext, pLookup);
  303. return pLookup;
  304. }
  305. void
  306. SdbpCleanupUserSDBCache(
  307. IN PSDBCONTEXT pSdbContext
  308. )
  309. {
  310. while (pSdbContext->pLookupHead) {
  311. RemoveLookup(pSdbContext, pSdbContext->pLookupHead);
  312. }
  313. }
  314. //
  315. // We built the array of these in accordance with ValueName's corresponding to a
  316. // list of custom databases we have -- and query existing values for this particular entry
  317. // ValueBuffer shall be allocated to be of a maximum length considering the number
  318. // of the entries that we have
  319. //
  320. typedef int (__cdecl* PFNQSORTCOMPARE)(const void* pElem1, const void* pElem2);
  321. int __cdecl
  322. SdbpUserSDBLookupCompareEntries(
  323. LPCVOID pEntry1,
  324. LPCVOID pEntry2
  325. )
  326. {
  327. //
  328. // last-installed goes first
  329. //
  330. PUSERSDBLOOKUPENTRY pLookupEntry1 = (PUSERSDBLOOKUPENTRY)pEntry1;
  331. PUSERSDBLOOKUPENTRY pLookupEntry2 = (PUSERSDBLOOKUPENTRY)pEntry2;
  332. if (pLookupEntry1->liTimeStamp.QuadPart < pLookupEntry2->liTimeStamp.QuadPart) {
  333. return 1;
  334. }
  335. if (pLookupEntry1->liTimeStamp.QuadPart == pLookupEntry2->liTimeStamp.QuadPart) {
  336. return 0;
  337. }
  338. return -1;
  339. }
  340. NTSTATUS
  341. SDBAPI
  342. SdbpFindCharInUnicodeString(
  343. ULONG Flags,
  344. PCUNICODE_STRING StringToSearch,
  345. PCUNICODE_STRING CharSet,
  346. USHORT* NonInclusivePrefixLength
  347. )
  348. {
  349. LPCWSTR pch;
  350. //
  351. // Implement only the case when we move backwards
  352. //
  353. if (Flags != RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END) {
  354. return STATUS_NOT_IMPLEMENTED;
  355. }
  356. pch = StringToSearch->Buffer + StringToSearch->Length / sizeof(WCHAR);
  357. while (pch >= StringToSearch->Buffer) {
  358. if (_tcschr(CharSet->Buffer, *pch)) {
  359. //
  360. // Got the char
  361. //
  362. if (NonInclusivePrefixLength) {
  363. *NonInclusivePrefixLength = (USHORT)(pch - StringToSearch->Buffer) * sizeof(WCHAR);
  364. }
  365. return STATUS_SUCCESS;
  366. }
  367. pch--;
  368. }
  369. //
  370. // We haven't found it. Return failure.
  371. //
  372. return STATUS_NOT_FOUND;
  373. }
  374. BOOL
  375. SdbpEnumUserSdb(
  376. IN PSDBCONTEXT pSdbContext,
  377. IN LPCWSTR wszItemName, // file name of an exe or the layer name
  378. IN BOOL bLayer,
  379. OUT PUSERSDBLOOKUP* ppSdbLookup
  380. )
  381. {
  382. //
  383. // This is how we figure:
  384. // path + \\layers\\ + MAX_PATH (for name)
  385. //
  386. WCHAR FullKeyBuffer[sizeof(APPCOMPAT_KEY_PATH_MACHINE_CUSTOM)/sizeof(WCHAR) + 8 + MAX_PATH];
  387. OBJECT_ATTRIBUTES ObjectAttributes;
  388. struct {
  389. KEY_FULL_INFORMATION KeyFullInformation;
  390. WCHAR Buffer[MAX_PATH];
  391. } KeyInformationBuffer;
  392. PKEY_FULL_INFORMATION pFullInfo = &KeyInformationBuffer.KeyFullInformation;
  393. struct {
  394. KEY_VALUE_FULL_INFORMATION KeyValueFullInformation;
  395. BYTE Buffer[MAX_PATH * 2 * sizeof(WCHAR)];
  396. } KeyValueInformationBuffer;
  397. PKEY_VALUE_FULL_INFORMATION pValue = &KeyValueInformationBuffer.KeyValueFullInformation;
  398. PBYTE pData;
  399. PUSERSDBLOOKUPENTRY pEntry;
  400. ULONG ResultLength;
  401. ULONG KeyValueLength;
  402. DWORD dwIndexValue = 0;
  403. DWORD dwIndexEntries = 0;
  404. NTSTATUS Status;
  405. HANDLE KeyHandle = NULL;
  406. UNICODE_STRING ustrDbGuid;
  407. USHORT uPrefix = 0;
  408. UNICODE_STRING ustrFullKey;
  409. UNICODE_STRING ustrValue;
  410. UNICODE_STRING ustrCharDot = RTL_CONSTANT_STRING(L".");
  411. GUID guidDB;
  412. PUSERSDBLOOKUP pLookup = NULL;
  413. BOOL bSuccess = FALSE;
  414. ULARGE_INTEGER liTimeStamp = {0};
  415. ustrFullKey.Length = 0;
  416. ustrFullKey.Buffer = FullKeyBuffer;
  417. ustrFullKey.MaximumLength = sizeof(FullKeyBuffer);
  418. RtlAppendUnicodeToString(&ustrFullKey, APPCOMPAT_KEY_PATH_MACHINE_CUSTOM);
  419. if (bLayer) {
  420. RtlAppendUnicodeToString(&ustrFullKey, L"\\Layers\\");
  421. } else {
  422. RtlAppendUnicodeToString(&ustrFullKey, L"\\");
  423. }
  424. RtlAppendUnicodeToString(&ustrFullKey, wszItemName);
  425. InitializeObjectAttributes(&ObjectAttributes,
  426. &ustrFullKey,
  427. OBJ_CASE_INSENSITIVE,
  428. NULL,
  429. NULL);
  430. Status = NtOpenKey(&KeyHandle, GENERIC_READ|SdbpGetWow64Flag(), &ObjectAttributes);
  431. if (!NT_SUCCESS(Status)) {
  432. DBGPRINT((sdlWarning,
  433. "SdbpEnumUserSdb",
  434. "Failed to open key \"%s\" Status 0x%lx\n",
  435. ustrFullKey.Buffer,
  436. Status));
  437. goto cleanup;
  438. }
  439. Status = NtQueryKey(KeyHandle,
  440. KeyFullInformation,
  441. &KeyInformationBuffer,
  442. sizeof(KeyInformationBuffer),
  443. &ResultLength);
  444. if (!NT_SUCCESS(Status)) {
  445. DBGPRINT((sdlWarning,
  446. "SdbpEnumUserSdb",
  447. "Failed to query key \"%s\" Status 0x%lx\n",
  448. ustrFullKey.Buffer,
  449. Status));
  450. goto cleanup;
  451. }
  452. if (pFullInfo->Values == 0) {
  453. goto cleanup; // nothing to look at
  454. }
  455. //
  456. // Create new lookup item
  457. //
  458. pLookup = SdbpCreateSDBLookupEntry(pSdbContext, pFullInfo->Values, wszItemName, bLayer);
  459. if (pLookup == NULL) {
  460. //
  461. // Oops, can't have an entry -- can't do lookups
  462. //
  463. goto cleanup;
  464. }
  465. //
  466. // Load all the values
  467. //
  468. for (dwIndexValue = 0; dwIndexValue < pFullInfo->Values; dwIndexValue++) {
  469. Status = NtEnumerateValueKey(KeyHandle,
  470. dwIndexValue,
  471. KeyValueFullInformation,
  472. &KeyValueInformationBuffer,
  473. sizeof(KeyValueInformationBuffer),
  474. &KeyValueLength);
  475. if (!NT_SUCCESS(Status)) {
  476. DBGPRINT((sdlWarning,
  477. "SdbpEnumUserSdb",
  478. "Failed to enum value index 0x%lx Status 0x%lx\n",
  479. dwIndexValue,
  480. Status));
  481. continue;
  482. }
  483. //
  484. // Extract database guid
  485. //
  486. ustrDbGuid.Buffer = &pValue->Name[0];
  487. ustrDbGuid.MaximumLength =
  488. ustrDbGuid.Length = (USHORT)pValue->NameLength;
  489. Status = SdbpFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
  490. &ustrDbGuid,
  491. &ustrCharDot,
  492. &uPrefix);
  493. if (NT_SUCCESS(Status)) {
  494. ustrDbGuid.Length = uPrefix;
  495. ustrDbGuid.Buffer[uPrefix / sizeof(WCHAR)] = 0;
  496. }
  497. //
  498. // Convert to guid
  499. //
  500. if (!SdbGUIDFromStringN(ustrDbGuid.Buffer, ustrDbGuid.Length, &guidDB)) {
  501. DBGPRINT((sdlWarning, "SdbpEnumUserSdb",
  502. "Failed to convert db name \"%s\" to guid Status 0x%lx\n",
  503. ustrDbGuid.Buffer, Status));
  504. continue; // We have failed to convert, skip and do the next
  505. }
  506. //
  507. // Data may not be aligned, we store here timestamp
  508. //
  509. pData = (PBYTE)pValue + pValue->DataOffset;
  510. //
  511. // Check out value type
  512. //
  513. switch (pValue->Type) {
  514. case REG_BINARY:
  515. //
  516. // The value is likely a timestamp
  517. //
  518. if (pValue->DataLength < sizeof(liTimeStamp.QuadPart)) {
  519. DBGPRINT((sdlError,
  520. "SdbpEnumUserSdb",
  521. "Data length (0x%lx) does not match timestamp length for index 0x%lx\n",
  522. pValue->DataLength,
  523. dwIndexValue));
  524. liTimeStamp.QuadPart = 0;
  525. } else {
  526. RtlCopyMemory(&liTimeStamp.QuadPart, (LPCVOID)pData, sizeof(liTimeStamp.QuadPart));
  527. }
  528. break;
  529. case REG_QWORD:
  530. //
  531. // Naturally supported type, not aligned though
  532. //
  533. liTimeStamp.QuadPart = *(PULONGLONG UNALIGNED)pData;
  534. break;
  535. case REG_SZ:
  536. //
  537. // Hack: in case we need to enforce a particular order on some odd entry -- we
  538. // use this hack
  539. //
  540. liTimeStamp.QuadPart = 0;
  541. if (pValue->DataLength > 0) {
  542. ustrValue.Buffer = (WCHAR*)pData;
  543. ustrValue.Length = (USHORT)pValue->DataLength - sizeof(UNICODE_NULL);
  544. ustrValue.MaximumLength = (USHORT)pValue->DataLength;
  545. Status = RtlUnicodeStringToInteger(&ustrValue, 0, &liTimeStamp.LowPart);
  546. if (!NT_SUCCESS(Status)) {
  547. DBGPRINT((sdlWarning,
  548. "SdbpEnumUserSdb",
  549. "Bad value for \"%s\" -> \"%s\" for index 0x%lx\n",
  550. pValue->Name,
  551. (LPCWSTR)pData,
  552. dwIndexValue));
  553. }
  554. }
  555. break;
  556. default:
  557. //
  558. // Error case
  559. //
  560. DBGPRINT((sdlError,
  561. "SdbpEnumUserSdb",
  562. "Bad value type 0x%lx for index 0x%lx\n",
  563. pValue->Type,
  564. dwIndexValue));
  565. Status = STATUS_INVALID_PARAMETER; // bugbug
  566. break;
  567. }
  568. //
  569. // Check the status
  570. //
  571. if (!NT_SUCCESS(Status)) {
  572. continue;
  573. }
  574. //
  575. // Fill-in this entry
  576. //
  577. pEntry = &pLookup->rgEntries[dwIndexEntries];
  578. ++dwIndexEntries;
  579. RtlCopyMemory(&pEntry->guidDB, &guidDB, sizeof(GUID));
  580. pEntry->liTimeStamp.QuadPart = liTimeStamp.QuadPart;
  581. }
  582. //
  583. // After this, we are basically ready to lookup entries in sdbs
  584. //
  585. pLookup->dwCount = dwIndexEntries; // adjust count based on actually filled-in entries
  586. if (dwIndexEntries > 1) {
  587. //
  588. // Optimization: only sort if more than one entry.
  589. //
  590. qsort((void*)&pLookup->rgEntries[0],
  591. (size_t)pLookup->dwCount,
  592. (size_t)sizeof(USERSDBLOOKUPENTRY),
  593. (PFNQSORTCOMPARE)SdbpUserSDBLookupCompareEntries);
  594. }
  595. if (ppSdbLookup) {
  596. *ppSdbLookup = pLookup;
  597. }
  598. bSuccess = TRUE;
  599. cleanup:
  600. if (KeyHandle) {
  601. NtClose(KeyHandle);
  602. }
  603. if (!bSuccess && pLookup != NULL) {
  604. RemoveLookup(pSdbContext, pLookup);
  605. }
  606. return bSuccess;
  607. }
  608. BOOL
  609. SdbGetNthUserSdb(
  610. IN HSDB hSDB,
  611. IN LPCWSTR wszItemName, // item name (foo.exe or layer name)
  612. IN BOOL bLayer,
  613. IN OUT LPDWORD pdwIndex, // (0-based)
  614. OUT GUID* pGuidDB
  615. )
  616. {
  617. PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
  618. PUSERSDBLOOKUP pLookup = NULL;
  619. BOOL bSuccess = FALSE;
  620. DWORD nIndex = *pdwIndex;
  621. //
  622. // Context already may have a user sdb cache -- do not touch it
  623. //
  624. if (nIndex == 0) {
  625. //
  626. // The first call, we have to init our system
  627. //
  628. if (!SdbpEnumUserSdb(pSdbContext, wszItemName, bLayer, &pLookup)) {
  629. goto cleanup; // no custom sdb will be accessible
  630. }
  631. } else {
  632. pLookup = SdbpFindSDBLookupEntry(pSdbContext, wszItemName, bLayer);
  633. }
  634. if (pLookup == NULL || nIndex >= pLookup->dwCount) {
  635. return FALSE;
  636. }
  637. RtlCopyMemory(pGuidDB, &pLookup->rgEntries[nIndex].guidDB, sizeof(*pGuidDB));
  638. ++nIndex;
  639. bSuccess = TRUE;
  640. *pdwIndex = nIndex;
  641. cleanup:
  642. return bSuccess;
  643. }
  644. #ifndef WIN32U_MODE
  645. BOOL
  646. SDBAPI
  647. SdbpGetLongPathName(
  648. IN LPCWSTR pwszPath,
  649. OUT PRTL_UNICODE_STRING_BUFFER pBuffer
  650. )
  651. {
  652. DWORD dwBufferSize;
  653. NTSTATUS Status;
  654. RtlSyncStringToBuffer(pBuffer);
  655. dwBufferSize = GetLongPathNameW(pwszPath,
  656. pBuffer->String.Buffer,
  657. RTL_STRING_GET_MAX_LENGTH_CHARS(&pBuffer->String));
  658. if (!dwBufferSize) {
  659. DBGPRINT((sdlError,
  660. "SdbpGetLongPathName",
  661. "Failed to convert short path to long path error 0x%lx\n",
  662. GetLastError()));
  663. return FALSE;
  664. }
  665. if (dwBufferSize < RTL_STRING_GET_MAX_LENGTH_CHARS(&pBuffer->String)) {
  666. goto Done;
  667. }
  668. Status = RtlEnsureUnicodeStringBufferSizeChars(pBuffer, dwBufferSize);
  669. if (!NT_SUCCESS(Status)) {
  670. DBGPRINT((sdlError,
  671. "SdbpGetLongPathName",
  672. "Failed to obtain sufficient buffer for long path (0x%lx chars) status 0x%lx\n",
  673. dwBufferSize,
  674. Status));
  675. return FALSE;
  676. }
  677. dwBufferSize = GetLongPathNameW(pwszPath,
  678. pBuffer->String.Buffer,
  679. RTL_STRING_GET_MAX_LENGTH_CHARS(&pBuffer->String));
  680. if (!dwBufferSize || dwBufferSize > RTL_STRING_GET_MAX_LENGTH_CHARS(&pBuffer->String)) {
  681. DBGPRINT((sdlError,
  682. "SdbpGetLongPathName",
  683. "Failed to convert short path to long path (0x%lx chars) error 0x%lx\n",
  684. dwBufferSize,
  685. GetLastError()));
  686. return FALSE;
  687. }
  688. Done:
  689. pBuffer->String.Length = (USHORT)dwBufferSize;
  690. return TRUE;
  691. }
  692. void
  693. SdbpGetPermLayersInternal(
  694. IN PUNICODE_STRING pstrExePath,
  695. OUT LPWSTR wszLayers, // output receives layers string if success
  696. IN OUT LPDWORD pdwBytes, // pointer to the size of wszLayers buffer
  697. IN BOOL bMachine
  698. )
  699. {
  700. UNICODE_STRING strKeyPath = { 0 };
  701. OBJECT_ATTRIBUTES ObjectAttributes;
  702. HANDLE KeyHandle;
  703. ULONG KeyValueBuffer[256];
  704. ULONG KeyValueLength;
  705. NTSTATUS Status;
  706. DWORD dwBytes = *pdwBytes;
  707. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  708. *pdwBytes = 0;
  709. if (bMachine) {
  710. //
  711. // Build the machine path
  712. //
  713. if (!SdbpBuildMachineKeyPath(APPCOMPAT_PERM_LAYER_PATH, &strKeyPath)) {
  714. DBGPRINT((sdlError,
  715. "SdbpGetPermLayersInternal",
  716. "Failed to format machine key path for \"%S\"\n",
  717. APPCOMPAT_PERM_LAYER_PATH));
  718. goto out;
  719. }
  720. } else {
  721. if (!SdbpBuildUserKeyPath(APPCOMPAT_PERM_LAYER_PATH, &strKeyPath)) {
  722. DBGPRINT((sdlError,
  723. "SdbpGetPermLayersInternal",
  724. "Failed to format user key path for \"%S\"\n",
  725. APPCOMPAT_PERM_LAYER_PATH));
  726. goto out;
  727. }
  728. }
  729. InitializeObjectAttributes(&ObjectAttributes,
  730. &strKeyPath,
  731. OBJ_CASE_INSENSITIVE,
  732. NULL,
  733. NULL);
  734. Status = NtOpenKey(&KeyHandle, GENERIC_READ|SdbpGetWow64Flag(), &ObjectAttributes);
  735. if (!NT_SUCCESS(Status)) {
  736. DBGPRINT((sdlInfo,
  737. "SdbpGetPermLayersInternal",
  738. "Failed to open Key \"%S\" Status 0x%x\n",
  739. strKeyPath.Buffer,
  740. Status));
  741. goto out;
  742. }
  743. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
  744. Status = NtQueryValueKey(KeyHandle,
  745. pstrExePath,
  746. KeyValuePartialInformation,
  747. KeyValueInformation,
  748. sizeof(KeyValueBuffer),
  749. &KeyValueLength);
  750. NtClose(KeyHandle);
  751. if (!NT_SUCCESS(Status)) {
  752. DBGPRINT((sdlInfo,
  753. "SdbpGetPermLayersInternal",
  754. "Failed to read value info from Key \"%S\" Status 0x%x\n",
  755. strKeyPath.Buffer,
  756. Status));
  757. goto out;
  758. }
  759. //
  760. // Check for the value type.
  761. //
  762. if (KeyValueInformation->Type != REG_SZ) {
  763. DBGPRINT((sdlError,
  764. "SdbpGetPermLayersInternal",
  765. "Unexpected value type 0x%x for Key \"%S\".\n",
  766. KeyValueInformation->Type,
  767. strKeyPath.Buffer));
  768. goto out;
  769. }
  770. if (wszLayers == NULL || KeyValueInformation->DataLength > dwBytes) {
  771. DBGPRINT((sdlError,
  772. "SdbpGetPermLayersInternal",
  773. "Value length %d too long for key \"%S\".\n",
  774. KeyValueInformation->DataLength,
  775. strKeyPath.Buffer));
  776. *pdwBytes = KeyValueInformation->DataLength;
  777. goto out;
  778. }
  779. RtlMoveMemory(wszLayers, KeyValueInformation->Data, KeyValueInformation->DataLength);
  780. *pdwBytes = KeyValueInformation->DataLength;
  781. out:
  782. if (strKeyPath.Buffer != NULL) {
  783. SdbFree(strKeyPath.Buffer);
  784. }
  785. }
  786. BOOL
  787. SdbGetPermLayerKeys(
  788. IN LPCWSTR pwszPath, // exe path
  789. OUT LPWSTR pwszLayers, // output receives layers string if success
  790. IN LPDWORD pdwBytes, // pointer to the size of wszLayers buffer
  791. IN DWORD dwFlags // per machine, per user flags
  792. )
  793. /*++
  794. Return: TRUE on success, FALSE otherwise.
  795. Desc: Retrieves layers string associated with a given exe.
  796. wszLayers may be NULL. In that case pdwBytes will receive necessary
  797. size if the size provided in pdwBytes is not sufficient. The function
  798. will return TRUE and pdwBytes will contain the necessary size.
  799. --*/
  800. {
  801. UNICODE_STRING ustrPath;
  802. BOOL bRet = FALSE;
  803. WCHAR wszSignPath[MAX_PATH];
  804. LPCWSTR pwszNewPath;
  805. UCHAR PathBuffer[MAX_PATH * 2];
  806. DWORD dwBytesMachine, dwBytesUser;
  807. RTL_UNICODE_STRING_BUFFER LongPath;
  808. SdbpRtlInitUnicodeStringBuffer(&LongPath, PathBuffer, sizeof(PathBuffer));
  809. if (!pwszPath || !pdwBytes) {
  810. DBGPRINT((sdlError,
  811. "SdbGetPermLayerKeys",
  812. "NULL parameter passed for wszPath or pdwBytes.\n"));
  813. goto out;
  814. }
  815. if (!SdbpGetLongPathName(pwszPath, &LongPath)) {
  816. goto out;
  817. }
  818. pwszPath = LongPath.String.Buffer;
  819. if (SdbpIsPathOnCdRom(pwszPath)) {
  820. SdbpBuildSignature(pwszPath, wszSignPath, CHARCOUNT(wszSignPath));
  821. pwszNewPath = wszSignPath;
  822. } else {
  823. pwszNewPath = pwszPath;
  824. }
  825. RtlInitUnicodeString(&ustrPath, pwszNewPath);
  826. dwBytesMachine = 0;
  827. dwBytesUser = 0;
  828. if (dwFlags & GPLK_MACHINE) {
  829. dwBytesMachine = *pdwBytes;
  830. SdbpGetPermLayersInternal(&ustrPath, pwszLayers, &dwBytesMachine, TRUE);
  831. }
  832. if (dwFlags & GPLK_USER) {
  833. if (dwBytesMachine != 0) {
  834. if (pwszLayers != NULL) {
  835. pwszLayers += (dwBytesMachine / sizeof(TCHAR) - 1);
  836. *pwszLayers++ = TEXT(' ');
  837. }
  838. dwBytesMachine += sizeof(TCHAR);
  839. }
  840. if (pwszLayers != NULL) {
  841. dwBytesUser = *pdwBytes - dwBytesMachine;
  842. }
  843. SdbpGetPermLayersInternal(&ustrPath, pwszLayers, &dwBytesUser, FALSE);
  844. if (dwBytesUser == 0 && dwBytesMachine != 0) {
  845. dwBytesMachine -= sizeof(TCHAR);
  846. if (pwszLayers != NULL) {
  847. *(--pwszLayers) = 0;
  848. }
  849. }
  850. }
  851. if (pwszLayers != NULL) {
  852. if (*pdwBytes >= dwBytesMachine + dwBytesUser) {
  853. bRet = TRUE;
  854. }
  855. } else {
  856. bRet = TRUE;
  857. }
  858. *pdwBytes = dwBytesMachine + dwBytesUser;
  859. if (*pdwBytes == 0) {
  860. bRet = FALSE;
  861. }
  862. out:
  863. RtlFreeUnicodeStringBuffer(&LongPath);
  864. return bRet;
  865. }
  866. #else // WIN32U_MODE case, stub the perm layer api
  867. BOOL
  868. SdbGetPermLayerKeys(
  869. IN LPCTSTR szPath,
  870. OUT LPTSTR szLayers,
  871. IN LPDWORD pdwBytes,
  872. IN DWORD dwFlags
  873. )
  874. {
  875. UNREFERENCED_PARAMETER(szPath);
  876. UNREFERENCED_PARAMETER(szLayers);
  877. UNREFERENCED_PARAMETER(pdwBytes);
  878. UNREFERENCED_PARAMETER(dwFlags);
  879. return FALSE;
  880. }
  881. #endif // WIN32U_MODE
  882. HANDLE
  883. SdbpCreateKeyPath(
  884. LPCWSTR pwszPath,
  885. BOOL bMachine
  886. )
  887. /*++
  888. Return: The handle to the registry key created.
  889. Desc: Given a path to the key relative to HKEY_CURRENT_USER open/create
  890. the key returns the handle to the key or NULL on failure.
  891. --*/
  892. {
  893. UNICODE_STRING strKeyPath = { 0 };
  894. HANDLE KeyHandle = NULL;
  895. NTSTATUS Status;
  896. OBJECT_ATTRIBUTES ObjectAttributes;
  897. ULONG CreateDisposition;
  898. if (bMachine) {
  899. if (!SdbpBuildMachineKeyPath(pwszPath, &strKeyPath)) {
  900. DBGPRINT((sdlError,
  901. "SdbCreateKeyPath",
  902. "Failed to format machine key path for \"%s\"\n",
  903. pwszPath));
  904. goto out;
  905. }
  906. } else {
  907. if (!SdbpBuildUserKeyPath(pwszPath, &strKeyPath)) {
  908. DBGPRINT((sdlError,
  909. "SdbCreateKeyPath",
  910. "Failed to format user key path for \"%s\"\n",
  911. pwszPath));
  912. goto out;
  913. }
  914. }
  915. InitializeObjectAttributes(&ObjectAttributes,
  916. &strKeyPath,
  917. OBJ_CASE_INSENSITIVE,
  918. NULL,
  919. NULL);
  920. Status = NtCreateKey(&KeyHandle,
  921. STANDARD_RIGHTS_WRITE |
  922. KEY_QUERY_VALUE |
  923. KEY_ENUMERATE_SUB_KEYS |
  924. KEY_SET_VALUE |
  925. KEY_CREATE_SUB_KEY|
  926. SdbpGetWow64Flag(),
  927. &ObjectAttributes,
  928. 0,
  929. NULL,
  930. REG_OPTION_NON_VOLATILE,
  931. &CreateDisposition);
  932. if (!NT_SUCCESS(Status)) {
  933. DBGPRINT((sdlError,
  934. "SdbCreateKeyPath",
  935. "NtCreateKey failed for \"%s\" Status 0x%x\n",
  936. pwszPath,
  937. Status));
  938. KeyHandle = NULL;
  939. goto out;
  940. }
  941. out:
  942. if (strKeyPath.Buffer != NULL) {
  943. SdbFree(strKeyPath.Buffer);
  944. }
  945. return KeyHandle;
  946. }
  947. #ifndef WIN32U_MODE
  948. BOOL
  949. SdbSetPermLayerKeys(
  950. IN LPCWSTR wszPath, // application path
  951. IN LPCWSTR wszLayers, // layers to associate with this application
  952. IN BOOL bMachine // TRUE if the layers should be set per machine
  953. )
  954. /*++
  955. Return: TRUE on success, FALSE otherwise.
  956. Desc: Associates wszLayers string with application wszPath.
  957. --*/
  958. {
  959. UNICODE_STRING ustrPath;
  960. NTSTATUS Status;
  961. HANDLE KeyHandle;
  962. BOOL bRet = FALSE;
  963. WCHAR wszSignPath[MAX_PATH];
  964. LPCWSTR pwszPath;
  965. RTL_UNICODE_STRING_BUFFER LongPath;
  966. UCHAR PathBuffer[MAX_PATH * 2];
  967. if (!wszLayers || !wszLayers[0]) {
  968. //
  969. // They passed in an empty string -- delete the layer keys
  970. //
  971. return SdbDeletePermLayerKeys(wszPath, bMachine);
  972. }
  973. SdbpRtlInitUnicodeStringBuffer(&LongPath, PathBuffer, sizeof(PathBuffer));
  974. if (!SdbpGetLongPathName(wszPath, &LongPath)) {
  975. goto out;
  976. }
  977. wszPath = LongPath.String.Buffer;
  978. if (SdbpIsPathOnCdRom(wszPath)) {
  979. SdbpBuildSignature(wszPath, wszSignPath, CHARCOUNT(wszSignPath));
  980. pwszPath = wszSignPath;
  981. } else {
  982. pwszPath = wszPath;
  983. }
  984. RtlInitUnicodeString(&ustrPath, pwszPath);
  985. KeyHandle = SdbpCreateKeyPath(APPCOMPAT_KEY_PATH_NT, bMachine);
  986. if (KeyHandle == NULL) {
  987. DBGPRINT((sdlError,
  988. "SdbSetPermLayerKeys",
  989. "Failed to create user key path for \"%s\"\n",
  990. APPCOMPAT_KEY_PATH_NT));
  991. goto out;
  992. }
  993. NtClose(KeyHandle);
  994. KeyHandle = SdbpCreateKeyPath(APPCOMPAT_PERM_LAYER_PATH, bMachine);
  995. if (KeyHandle == NULL) {
  996. DBGPRINT((sdlError,
  997. "SdbSetPermLayerKeys",
  998. "Failed to create user key path \"%s\"\n",
  999. APPCOMPAT_PERM_LAYER_PATH));
  1000. goto out;
  1001. }
  1002. Status = NtSetValueKey(KeyHandle,
  1003. &ustrPath,
  1004. 0,
  1005. REG_SZ,
  1006. (PVOID)wszLayers,
  1007. (ULONG)(wcslen(wszLayers) + 1) * sizeof(WCHAR));
  1008. NtClose(KeyHandle);
  1009. if (!NT_SUCCESS(Status)) {
  1010. DBGPRINT((sdlError,
  1011. "SdbSetPermLayerKeys",
  1012. "Failed NtSetValueKey status 0x%x\n",
  1013. Status));
  1014. goto out;
  1015. }
  1016. bRet = TRUE;
  1017. out:
  1018. RtlFreeUnicodeStringBuffer(&LongPath);
  1019. return bRet;
  1020. }
  1021. BOOL
  1022. SdbDeletePermLayerKeys(
  1023. IN LPCWSTR wszPath,
  1024. IN BOOL bMachine
  1025. )
  1026. /*++
  1027. Return: TRUE if success
  1028. Desc: This function is used to disable permanent layer storage entry
  1029. for the application.
  1030. --*/
  1031. {
  1032. UNICODE_STRING strKeyPath = { 0 };
  1033. UNICODE_STRING ustrPath;
  1034. NTSTATUS Status;
  1035. OBJECT_ATTRIBUTES ObjectAttributes;
  1036. HANDLE KeyHandle;
  1037. BOOL bRet = FALSE;
  1038. WCHAR wszSignPath[MAX_PATH];
  1039. LPCWSTR pwszPath;
  1040. RTL_UNICODE_STRING_BUFFER LongPath;
  1041. UCHAR PathBuffer[MAX_PATH * 2];
  1042. SdbpRtlInitUnicodeStringBuffer(&LongPath, PathBuffer, sizeof(PathBuffer));
  1043. if (!SdbpGetLongPathName(wszPath, &LongPath)) {
  1044. goto out;
  1045. }
  1046. wszPath = LongPath.String.Buffer;
  1047. if (SdbpIsPathOnCdRom(wszPath)) {
  1048. SdbpBuildSignature(wszPath, wszSignPath, CHARCOUNT(wszSignPath));
  1049. pwszPath = wszSignPath;
  1050. } else {
  1051. pwszPath = wszPath;
  1052. }
  1053. RtlInitUnicodeString(&ustrPath, pwszPath);
  1054. if (bMachine) {
  1055. if (!SdbpBuildMachineKeyPath(APPCOMPAT_PERM_LAYER_PATH, &strKeyPath)) {
  1056. DBGPRINT((sdlError,
  1057. "SdbDeletePermLayerKeys",
  1058. "Failed to format machine key path for \"%S\"\n",
  1059. APPCOMPAT_PERM_LAYER_PATH));
  1060. goto out;
  1061. }
  1062. } else {
  1063. if (!SdbpBuildUserKeyPath(APPCOMPAT_PERM_LAYER_PATH, &strKeyPath)) {
  1064. DBGPRINT((sdlError,
  1065. "SdbDeletePermLayerKeys",
  1066. "Failed to format user key path for \"%S\"\n",
  1067. APPCOMPAT_PERM_LAYER_PATH));
  1068. goto out;
  1069. }
  1070. }
  1071. InitializeObjectAttributes(&ObjectAttributes,
  1072. &strKeyPath,
  1073. OBJ_CASE_INSENSITIVE,
  1074. NULL,
  1075. NULL);
  1076. Status = NtOpenKey(&KeyHandle,
  1077. KEY_WRITE|SdbpGetWow64Flag(),
  1078. &ObjectAttributes);
  1079. if (!NT_SUCCESS(Status)) {
  1080. DBGPRINT((sdlInfo,
  1081. "SdbDeletePermLayerKeys",
  1082. "Failed to open Key for \"%S\" Status 0x%x\n",
  1083. strKeyPath.Buffer,
  1084. Status));
  1085. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1086. bRet = TRUE;
  1087. }
  1088. goto out;
  1089. }
  1090. Status = NtDeleteValueKey(KeyHandle,
  1091. &ustrPath);
  1092. NtClose(KeyHandle);
  1093. if (!NT_SUCCESS(Status)) {
  1094. DBGPRINT((sdlInfo,
  1095. "SdbDeletePermLayerKeys",
  1096. "Failed to delete value from Key \"%S\" Status 0x%x\n",
  1097. strKeyPath.Buffer,
  1098. Status));
  1099. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1100. bRet = TRUE;
  1101. }
  1102. goto out;
  1103. }
  1104. bRet = TRUE;
  1105. out:
  1106. if (strKeyPath.Buffer != NULL) {
  1107. SdbFree(strKeyPath.Buffer);
  1108. }
  1109. RtlFreeUnicodeStringBuffer(&LongPath);
  1110. return bRet;
  1111. }
  1112. #endif // WIN32U_MODE
  1113. BOOL
  1114. SdbSetEntryFlags(
  1115. IN GUID* pGuidID,
  1116. IN DWORD dwFlags
  1117. )
  1118. /*++
  1119. Return: TRUE if success
  1120. Desc: This function is used to disable apphelp or shim entries.
  1121. --*/
  1122. {
  1123. UNICODE_STRING ustrExeID = { 0 };
  1124. NTSTATUS Status;
  1125. HANDLE KeyHandle;
  1126. BOOL bReturn = FALSE;
  1127. Status = GUID_TO_UNICODE_STRING(pGuidID, &ustrExeID);
  1128. if (!NT_SUCCESS(Status)) {
  1129. DBGPRINT((sdlError,
  1130. "SdbSetEntryFlags",
  1131. "Failed to convert GUID to string 0x%x\n",
  1132. Status));
  1133. goto out;
  1134. }
  1135. KeyHandle = SdbpCreateKeyPath(APPCOMPAT_KEY_PATH_NT, FALSE);
  1136. if (KeyHandle == NULL) {
  1137. DBGPRINT((sdlError,
  1138. "SdbSetEntryFlags",
  1139. "Failed to create user key path for \"%s\"\n",
  1140. APPCOMPAT_KEY_PATH_NT));
  1141. goto out;
  1142. }
  1143. Status = NtSetValueKey(KeyHandle,
  1144. &ustrExeID,
  1145. 0,
  1146. REG_DWORD,
  1147. &dwFlags,
  1148. sizeof(DWORD));
  1149. NtClose(KeyHandle);
  1150. if (!NT_SUCCESS(Status)) {
  1151. DBGPRINT((sdlError,
  1152. "SdbSetEntryFlags",
  1153. "Failed NtSetValueKey status 0x%x\n",
  1154. Status));
  1155. goto out;
  1156. }
  1157. bReturn = TRUE;
  1158. out:
  1159. FREE_GUID_STRING(&ustrExeID);
  1160. return bReturn;
  1161. }
  1162. BOOL
  1163. SdbpGetLongFileName(
  1164. IN LPCWSTR szFullPath, // a full UNC or DOS path & filename, "c:\foo\mylong~1.ext"
  1165. OUT LPWSTR szLongFileName, // the long filename portion "mylongfilename.ext",
  1166. IN DWORD cchSize // size (in characters) of szLongFileName
  1167. )
  1168. /*++
  1169. Return: TRUE if successful, FALSE otherwise.
  1170. Desc: Retrieves the long filename (without the path) of a potentially
  1171. short full-path filename.
  1172. --*/
  1173. {
  1174. NTSTATUS status;
  1175. BOOL bSuccess = FALSE;
  1176. UNICODE_STRING FileName;
  1177. UNICODE_STRING PathName;
  1178. OBJECT_ATTRIBUTES ObjPathName;
  1179. IO_STATUS_BLOCK IoStatusBlock;
  1180. HANDLE hDirectoryHandle = NULL;
  1181. PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
  1182. struct SEARCH_BUFFER {
  1183. FILE_BOTH_DIR_INFORMATION DirInfo;
  1184. WCHAR Names[MAX_PATH-1];
  1185. } Buffer;
  1186. PathName.Buffer = NULL;
  1187. if (!RtlDosPathNameToNtPathName_U(szFullPath,
  1188. &PathName,
  1189. &FileName.Buffer,
  1190. NULL)) {
  1191. PathName.Buffer = NULL;
  1192. DBGPRINT((sdlError,
  1193. "SdbpGetLongFileName",
  1194. "Failed to get NT path name for \"%s\"\n",
  1195. szFullPath));
  1196. goto out;
  1197. }
  1198. if (FileName.Buffer == NULL) {
  1199. DBGPRINT((sdlError,
  1200. "SdbpGetLongFileName",
  1201. "Filename buffer is NULL for \"%s\"\n",
  1202. szFullPath));
  1203. goto out;
  1204. }
  1205. FileName.Length = PathName.Length -
  1206. (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)PathName.Buffer);
  1207. FileName.MaximumLength = FileName.Length;
  1208. PathName.Length = (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)PathName.Buffer);
  1209. PathName.MaximumLength = PathName.Length;
  1210. InitializeObjectAttributes(&ObjPathName,
  1211. &PathName,
  1212. OBJ_CASE_INSENSITIVE,
  1213. NULL,
  1214. NULL);
  1215. status = NtOpenFile(&hDirectoryHandle,
  1216. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  1217. &ObjPathName,
  1218. &IoStatusBlock,
  1219. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1220. FILE_DIRECTORY_FILE |
  1221. FILE_SYNCHRONOUS_IO_NONALERT |
  1222. FILE_OPEN_FOR_BACKUP_INTENT);
  1223. if (STATUS_SUCCESS != status) {
  1224. DBGPRINT((sdlError,
  1225. "SdbpGetLongFileName",
  1226. "Failed to open directory file. Status 0x%x\n",
  1227. status));
  1228. goto out;
  1229. }
  1230. DirectoryInfo = &(Buffer.DirInfo);
  1231. status = NtQueryDirectoryFile(hDirectoryHandle,
  1232. NULL,
  1233. NULL,
  1234. NULL,
  1235. &IoStatusBlock,
  1236. DirectoryInfo,
  1237. sizeof(Buffer),
  1238. FileBothDirectoryInformation,
  1239. TRUE,
  1240. &FileName,
  1241. FALSE);
  1242. if (STATUS_SUCCESS != status) {
  1243. DBGPRINT((sdlError,
  1244. "SdbpGetLongFileName",
  1245. "NtQueryDirectoryFile Failed 0x%x\n",
  1246. status));
  1247. goto out;
  1248. }
  1249. if (DirectoryInfo->FileNameLength > MAX_PATH - 2) {
  1250. DBGPRINT((sdlError,
  1251. "SdbpGetLongFileName",
  1252. "File name longer than MAX_PATH - 2\n"));
  1253. goto out;
  1254. }
  1255. StringCchCopyN(szLongFileName,
  1256. cchSize,
  1257. DirectoryInfo->FileName,
  1258. DirectoryInfo->FileNameLength / sizeof(WCHAR));
  1259. bSuccess = TRUE;
  1260. out:
  1261. if (PathName.Buffer) {
  1262. RtlFreeHeap(RtlProcessHeap(), 0, PathName.Buffer);
  1263. }
  1264. if (hDirectoryHandle) {
  1265. NtClose(hDirectoryHandle);
  1266. }
  1267. return bSuccess;
  1268. }
  1269. void
  1270. SdbpGetWinDir(
  1271. OUT LPWSTR pwszDir,
  1272. IN DWORD cchSize
  1273. )
  1274. /*++
  1275. Return: void.
  1276. Desc: Retrieves the system windows directory.
  1277. --*/
  1278. {
  1279. StringCchCopy(pwszDir, cchSize, USER_SHARED_DATA->NtSystemRoot);
  1280. }
  1281. void
  1282. SdbpGetAppPatchDir(
  1283. IN HSDB hSDB,
  1284. OUT LPWSTR szAppPatchPath,
  1285. IN DWORD cchSize
  1286. )
  1287. /*++
  1288. Return: void.
  1289. Desc: Retrieves the %windir%\AppPatch directory.
  1290. --*/
  1291. {
  1292. PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
  1293. int nLen;
  1294. StringCchCopy(szAppPatchPath, cchSize, USER_SHARED_DATA->NtSystemRoot);
  1295. nLen = (int)wcslen(szAppPatchPath);
  1296. if (nLen > 0 && L'\\' == szAppPatchPath[nLen-1]) {
  1297. szAppPatchPath[nLen-1] = L'\0';
  1298. }
  1299. if (pContext != NULL && pContext->uExeType == IMAGE_FILE_MACHINE_IA64) {
  1300. StringCchCat(szAppPatchPath, cchSize, L"\\AppPatch\\IA64");
  1301. } else {
  1302. StringCchCat(szAppPatchPath, cchSize, L"\\AppPatch");
  1303. }
  1304. }
  1305. void
  1306. SdbpGetCurrentTime(
  1307. OUT LPSYSTEMTIME lpTime
  1308. )
  1309. /*++
  1310. Return: void.
  1311. Desc: Retrieves the current local time.
  1312. --*/
  1313. {
  1314. LARGE_INTEGER LocalTime;
  1315. LARGE_INTEGER SystemTime;
  1316. LARGE_INTEGER Bias;
  1317. TIME_FIELDS TimeFields;
  1318. volatile KSYSTEM_TIME* pRealBias = &(USER_SHARED_DATA->TimeZoneBias);
  1319. //
  1320. // Read system time from shared region.
  1321. //
  1322. do {
  1323. SystemTime.HighPart = USER_SHARED_DATA->SystemTime.High1Time;
  1324. SystemTime.LowPart = USER_SHARED_DATA->SystemTime.LowPart;
  1325. } while (SystemTime.HighPart != USER_SHARED_DATA->SystemTime.High2Time);
  1326. //
  1327. // Read time zone bias from shared region.
  1328. // If it's terminal server session use client bias.
  1329. //
  1330. do {
  1331. Bias.HighPart = pRealBias->High1Time;
  1332. Bias.LowPart = pRealBias->LowPart;
  1333. } while (Bias.HighPart != pRealBias->High2Time);
  1334. LocalTime.QuadPart = SystemTime.QuadPart - Bias.QuadPart;
  1335. RtlTimeToTimeFields(&LocalTime, &TimeFields);
  1336. lpTime->wYear = TimeFields.Year;
  1337. lpTime->wMonth = TimeFields.Month;
  1338. lpTime->wDayOfWeek = TimeFields.Weekday;
  1339. lpTime->wDay = TimeFields.Day;
  1340. lpTime->wHour = TimeFields.Hour;
  1341. lpTime->wMinute = TimeFields.Minute;
  1342. lpTime->wSecond = TimeFields.Second;
  1343. lpTime->wMilliseconds = TimeFields.Milliseconds;
  1344. }
  1345. NTSTATUS
  1346. SdbpGetEnvVar(
  1347. IN LPCWSTR pEnvironment,
  1348. IN LPCWSTR pszVariableName,
  1349. OUT LPWSTR pszVariableValue,
  1350. OUT LPDWORD pdwBufferSize
  1351. )
  1352. /*++
  1353. Return:
  1354. Desc: Retrieves the value of the specified environment variable.
  1355. --*/
  1356. {
  1357. NTSTATUS Status = STATUS_VARIABLE_NOT_FOUND;
  1358. UNICODE_STRING ustrVariableName;
  1359. UNICODE_STRING ustrVariableValue;
  1360. DWORD dwBufferSize = 0;
  1361. if (pdwBufferSize && pszVariableValue) {
  1362. dwBufferSize = *pdwBufferSize;
  1363. }
  1364. RtlInitUnicodeString(&ustrVariableName, pszVariableName);
  1365. ustrVariableValue.Length = 0;
  1366. ustrVariableValue.MaximumLength = (USHORT)dwBufferSize * sizeof(WCHAR);
  1367. ustrVariableValue.Buffer = (WCHAR*)pszVariableValue;
  1368. Status = RtlQueryEnvironmentVariable_U((LPVOID)pEnvironment,
  1369. &ustrVariableName,
  1370. &ustrVariableValue);
  1371. if (pdwBufferSize) {
  1372. *pdwBufferSize = (DWORD)ustrVariableValue.Length / sizeof(WCHAR);
  1373. }
  1374. return Status;
  1375. }
  1376. BOOL
  1377. SdbpMapFile(
  1378. IN HANDLE hFile, // handle to the open file (this is done previously)
  1379. OUT PIMAGEFILEDATA pImageData
  1380. )
  1381. /*++
  1382. Return: TRUE on success, FALSE otherwise.
  1383. Desc: Maps a file into memory.
  1384. --*/
  1385. {
  1386. NTSTATUS Status;
  1387. HANDLE hSection = NULL;
  1388. SIZE_T ViewSize = 0;
  1389. PVOID pBase = NULL;
  1390. IO_STATUS_BLOCK IoStatusBlock;
  1391. FILE_STANDARD_INFORMATION StandardInfo;
  1392. if (hFile == INVALID_HANDLE_VALUE) {
  1393. DBGPRINT((sdlError, "SdbpMapFile", "Invalid argument\n"));
  1394. return FALSE;
  1395. }
  1396. //
  1397. // Query the file's size.
  1398. //
  1399. Status = NtQueryInformationFile(hFile,
  1400. &IoStatusBlock,
  1401. &StandardInfo,
  1402. sizeof(StandardInfo),
  1403. FileStandardInformation);
  1404. if (!NT_SUCCESS(Status)) {
  1405. DBGPRINT((sdlError,
  1406. "SdbpMapFile",
  1407. "NtQueryInformationFile (EOF) failed Status = 0x%x\n",
  1408. Status));
  1409. return FALSE;
  1410. }
  1411. //
  1412. // Create a view of the file.
  1413. //
  1414. Status = NtCreateSection(&hSection,
  1415. SECTION_MAP_READ,
  1416. NULL,
  1417. 0,
  1418. PAGE_READONLY,
  1419. SEC_COMMIT,
  1420. hFile);
  1421. if (!NT_SUCCESS(Status)) {
  1422. DBGPRINT((sdlError,
  1423. "SdbpMapFile",
  1424. "NtCreateSection failed Status 0x%x\n",
  1425. Status));
  1426. //
  1427. // Can't create section, thus no way to map the file.
  1428. //
  1429. return FALSE;
  1430. }
  1431. Status = NtMapViewOfSection(hSection,
  1432. NtCurrentProcess(),
  1433. &pBase,
  1434. 0,
  1435. 0,
  1436. NULL,
  1437. &ViewSize,
  1438. ViewUnmap,
  1439. 0,
  1440. PAGE_READONLY);
  1441. if (!NT_SUCCESS(Status)) {
  1442. NtClose(hSection);
  1443. DBGPRINT((sdlError,
  1444. "SdbpMapFile",
  1445. "NtMapViewOfSection failed Status 0x%x\n",
  1446. Status));
  1447. return FALSE;
  1448. }
  1449. //
  1450. // We have made it. The file is mapped.
  1451. //
  1452. pImageData->hFile = hFile;
  1453. pImageData->hSection = hSection;
  1454. pImageData->pBase = pBase;
  1455. pImageData->ViewSize = ViewSize;
  1456. pImageData->FileSize = StandardInfo.EndOfFile.QuadPart;
  1457. return TRUE;
  1458. }
  1459. BOOL
  1460. SdbpUnmapFile(
  1461. IN PIMAGEFILEDATA pImageData
  1462. )
  1463. /*++
  1464. Return: TRUE on success, FALSE otherwise.
  1465. Desc: Unmaps a file from memory.
  1466. --*/
  1467. {
  1468. NTSTATUS Status;
  1469. BOOL bReturn = TRUE;
  1470. if (pImageData->pBase != NULL) {
  1471. Status = NtUnmapViewOfSection(NtCurrentProcess(), pImageData->pBase);
  1472. if (!NT_SUCCESS(Status)) {
  1473. DBGPRINT((sdlError,
  1474. "SdbpUnmapFile",
  1475. "NtUnmapViewOfSection failed Status 0x%x\n",
  1476. Status));
  1477. bReturn = FALSE;
  1478. }
  1479. pImageData->pBase = NULL;
  1480. }
  1481. if (pImageData->hSection) {
  1482. NtClose(pImageData->hSection);
  1483. pImageData->hSection = NULL;
  1484. }
  1485. pImageData->hFile = INVALID_HANDLE_VALUE; // hFile is not owned by us
  1486. return bReturn;
  1487. }
  1488. #ifndef _WIN64
  1489. void
  1490. SdbResetStackOverflow(
  1491. void
  1492. )
  1493. /*++
  1494. Return: void.
  1495. Desc: This function sets the guard page to its position before the
  1496. stack overflow.
  1497. This is a copy of the following CRT routine:
  1498. void _resetstkoflw(void) - Recovers from Stack Overflow
  1499. --*/
  1500. {
  1501. LPBYTE pStack, pGuard, pStackBase, pCommitBase;
  1502. MEMORY_BASIC_INFORMATION mbi;
  1503. SYSTEM_BASIC_INFORMATION BasicInfo;
  1504. DWORD PageSize;
  1505. NTSTATUS Status;
  1506. SIZE_T ReturnLength;
  1507. DWORD OldProtect;
  1508. SIZE_T RegionSize;
  1509. //
  1510. // Use alloca() to get the current stack pointer
  1511. // the call below DOES NOT fail
  1512. //
  1513. __try {
  1514. pStack = _alloca(1);
  1515. } __except(GetExceptionCode() == EXCEPTION_STACK_OVERFLOW ?
  1516. EXCEPTION_EXECUTE_HANDLER:EXCEPTION_CONTINUE_SEARCH) {
  1517. pStack = (LPBYTE)&pStack; // hack: we just grab the address of our internal variable
  1518. }
  1519. //
  1520. // Find the base of the stack.
  1521. //
  1522. Status = NtQueryVirtualMemory(NtCurrentProcess(),
  1523. pStack,
  1524. MemoryBasicInformation,
  1525. &mbi,
  1526. sizeof(mbi),
  1527. &ReturnLength);
  1528. if (!NT_SUCCESS(Status)) {
  1529. DBGPRINT((sdlError,
  1530. "SdbpResetStackOverflow",
  1531. "NtQueryVirtualMemory failed on stack 0x%x Status 0x%x\n",
  1532. pStack,
  1533. Status));
  1534. return;
  1535. }
  1536. pStackBase = mbi.AllocationBase;
  1537. Status = NtQueryVirtualMemory(NtCurrentProcess(),
  1538. pStackBase,
  1539. MemoryBasicInformation,
  1540. &mbi,
  1541. sizeof(mbi),
  1542. &ReturnLength);
  1543. if (!NT_SUCCESS(Status)) {
  1544. DBGPRINT((sdlError,
  1545. "SdbpResetStackOverflow",
  1546. "NtQueryVirtualMemory failed on stack base 0x%x Status 0x%x\n",
  1547. pStackBase,
  1548. Status));
  1549. return;
  1550. }
  1551. if (mbi.State & MEM_RESERVE) {
  1552. pCommitBase = (LPBYTE)mbi.AllocationBase + mbi.RegionSize;
  1553. Status = NtQueryVirtualMemory(NtCurrentProcess(),
  1554. pCommitBase,
  1555. MemoryBasicInformation,
  1556. &mbi,
  1557. sizeof(mbi),
  1558. &ReturnLength);
  1559. if (!NT_SUCCESS(Status)) {
  1560. DBGPRINT((sdlError,
  1561. "SdbpResetStackOverflow",
  1562. "NtQueryVirtualMemory failed on stack commit base 0x%x Status 0x%x\n",
  1563. pCommitBase,
  1564. Status));
  1565. return;
  1566. }
  1567. } else {
  1568. pCommitBase = pStackBase;
  1569. }
  1570. //
  1571. // Find the page size.
  1572. //
  1573. Status = NtQuerySystemInformation(SystemBasicInformation,
  1574. &BasicInfo,
  1575. sizeof(BasicInfo),
  1576. NULL);
  1577. if (!NT_SUCCESS(Status)) {
  1578. DBGPRINT((sdlError,
  1579. "SdbpResetStackOverflow",
  1580. "NtQuerySystemInformation failed Status 0x%x\n",
  1581. Status));
  1582. return;
  1583. }
  1584. PageSize = BasicInfo.PageSize;
  1585. //
  1586. // Find the page just below where stack pointer currently points.
  1587. //
  1588. pGuard = (LPBYTE)(((DWORD_PTR)pStack & ~(DWORD_PTR)(PageSize -1)) - PageSize);
  1589. if (pGuard < pStackBase) {
  1590. //
  1591. // We can't save this.
  1592. //
  1593. DBGPRINT((sdlError,
  1594. "SdbpResetStackOverflow",
  1595. "Bad guard page 0x%x base 0x%x\n",
  1596. pGuard,
  1597. pStackBase));
  1598. return;
  1599. }
  1600. if (pGuard > pStackBase) {
  1601. RegionSize = pGuard - pStackBase;
  1602. Status = NtFreeVirtualMemory(NtCurrentProcess(),
  1603. &pStackBase,
  1604. &RegionSize,
  1605. MEM_DECOMMIT);
  1606. if (!NT_SUCCESS(Status)) {
  1607. DBGPRINT((sdlError,
  1608. "SdbpResetStackOverflow",
  1609. "NtFreeVirtualMemory on 0x%x failed Status 0x%x\n",
  1610. pStackBase,
  1611. Status));
  1612. }
  1613. }
  1614. Status = NtAllocateVirtualMemory(NtCurrentProcess(),
  1615. &pGuard,
  1616. 0,
  1617. &PageSize,
  1618. MEM_COMMIT,
  1619. PAGE_READWRITE);
  1620. if (!NT_SUCCESS(Status)) {
  1621. DBGPRINT((sdlError,
  1622. "SdbpResetStackOverflow",
  1623. "NtAllocateVirtualMemory on 0x%x failed Status 0x%x\n",
  1624. pGuard,
  1625. Status));
  1626. return;
  1627. }
  1628. Status = NtProtectVirtualMemory(NtCurrentProcess(),
  1629. &pGuard,
  1630. &PageSize,
  1631. PAGE_READWRITE|PAGE_GUARD,
  1632. &OldProtect);
  1633. if (!NT_SUCCESS(Status)) {
  1634. DBGPRINT((sdlError,
  1635. "SdbpResetStackOverflow",
  1636. "NtProtectVirtualMemory on 0x%x failed Status 0x%x\n",
  1637. pGuard,
  1638. Status));
  1639. }
  1640. }
  1641. #endif // _WIN64
  1642. BOOL
  1643. SdbpQueryFileDirectoryAttributes(
  1644. LPCWSTR FilePath,
  1645. PFILEDIRECTORYATTRIBUTES pFileDirectoryAttributes
  1646. )
  1647. /*++
  1648. Return: BUGBUG: ?
  1649. Desc: BUGBUG: ?
  1650. --*/
  1651. {
  1652. OBJECT_ATTRIBUTES DirObjectAttributes;
  1653. UNICODE_STRING FileName; // filename part
  1654. IO_STATUS_BLOCK IoStatusBlock;
  1655. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  1656. UNICODE_STRING Path = { 0 }; // nt path name
  1657. struct tagDirectoryInformationBuffer { // directory information (see ntioapi)
  1658. FILE_DIRECTORY_INFORMATION DirInfo;
  1659. WCHAR name[MAX_PATH];
  1660. } DirectoryInformationBuf;
  1661. PFILE_DIRECTORY_INFORMATION pDirInfo = &DirectoryInformationBuf.DirInfo;
  1662. USHORT nPathLength;
  1663. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  1664. BOOL bTranslationStatus;
  1665. RtlZeroMemory(pFileDirectoryAttributes, sizeof(*pFileDirectoryAttributes));
  1666. bTranslationStatus = RtlDosPathNameToNtPathName_U(FilePath,
  1667. &Path,
  1668. &FileName.Buffer,
  1669. NULL);
  1670. if (!bTranslationStatus) {
  1671. DBGPRINT((sdlError,
  1672. "SdbpGetFileDirectoryAttributes",
  1673. "RtlDosPathNameToNtPathName_U failed for \"%s\"\n",
  1674. FilePath));
  1675. assert(FALSE);
  1676. goto Fail;
  1677. }
  1678. if (FileName.Buffer == NULL) {
  1679. DBGPRINT((sdlError,
  1680. "SdbpGetFileDirectoryAttributes",
  1681. "RtlDosPathNameToNtPathName_U returned no filename for \"%s\"",
  1682. FilePath));
  1683. Status = STATUS_INVALID_PARAMETER;
  1684. goto Fail;
  1685. }
  1686. nPathLength = (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)Path.Buffer);
  1687. FileName.Length = Path.Length - nPathLength;
  1688. FileName.MaximumLength = FileName.Length;
  1689. //
  1690. // path length, adjust please -- chopping off trailing backslash
  1691. //
  1692. // BUGBUG: what am I suppose to understand from the above comment ?
  1693. //
  1694. Path.Length = nPathLength;
  1695. if (nPathLength > 2 * sizeof(WCHAR)) {
  1696. if (*(Path.Buffer + (nPathLength/sizeof(WCHAR)) - 2) != L':' &&
  1697. *(Path.Buffer + (nPathLength/sizeof(WCHAR)) - 1) == L'\\') {
  1698. Path.Length -= sizeof(WCHAR);
  1699. }
  1700. }
  1701. Path.MaximumLength = Path.Length;
  1702. InitializeObjectAttributes(&DirObjectAttributes,
  1703. &Path,
  1704. OBJ_CASE_INSENSITIVE,
  1705. NULL,
  1706. NULL);
  1707. Status = NtOpenFile(&FileHandle,
  1708. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  1709. &DirObjectAttributes,
  1710. &IoStatusBlock,
  1711. FILE_SHARE_READ|FILE_SHARE_WRITE,
  1712. FILE_DIRECTORY_FILE|
  1713. FILE_SYNCHRONOUS_IO_NONALERT |
  1714. FILE_OPEN_FOR_BACKUP_INTENT);
  1715. if (!NT_SUCCESS(Status)) {
  1716. DBGPRINT((sdlError,
  1717. "SdbpGetFileDirectoryAttributes",
  1718. "NtOpenFile Failed to open \"%s\", status 0x%x\n",
  1719. (int)Path.Length,
  1720. Path.Buffer,
  1721. Status));
  1722. goto Fail;
  1723. }
  1724. Status = NtQueryDirectoryFile(FileHandle,
  1725. NULL,
  1726. NULL,
  1727. NULL,
  1728. &IoStatusBlock,
  1729. pDirInfo,
  1730. sizeof(DirectoryInformationBuf),
  1731. FileDirectoryInformation,
  1732. TRUE,
  1733. &FileName,
  1734. FALSE);
  1735. if (!NT_SUCCESS(Status)) {
  1736. DBGPRINT((sdlError,
  1737. "SdbpGetFileDirectoryAttributes",
  1738. "NtQueryDirectoryFile Failed to query \"%s\" for \"%s\" status 0x%x\n",
  1739. (int)Path.Length,
  1740. Path.Buffer,
  1741. (int)FileName.Length,
  1742. FileName.Buffer,
  1743. Status));
  1744. goto Fail;
  1745. }
  1746. pFileDirectoryAttributes->dwFlags |= FDA_FILESIZE;
  1747. pFileDirectoryAttributes->dwFileSizeHigh = pDirInfo->EndOfFile.HighPart;
  1748. pFileDirectoryAttributes->dwFileSizeLow = pDirInfo->EndOfFile.LowPart;
  1749. Fail:
  1750. if (Path.Buffer) {
  1751. RtlFreeHeap(RtlProcessHeap(), 0, Path.Buffer);
  1752. }
  1753. if (FileHandle != INVALID_HANDLE_VALUE) {
  1754. NtClose(FileHandle);
  1755. }
  1756. return NT_SUCCESS(Status);
  1757. }
  1758. LPWSTR
  1759. StringToUnicodeString(
  1760. IN LPCSTR pszSrc // pointer to the ANSI string to be converted
  1761. )
  1762. /*++
  1763. Return: A pointer to an allocated UNICODE string.
  1764. Desc: Converts an ANSI string to UNICODE.
  1765. --*/
  1766. {
  1767. NTSTATUS Status;
  1768. ANSI_STRING AnsiSrc;
  1769. UNICODE_STRING UnicodeDest = { 0 };
  1770. LPWSTR pwszUnicodeDest = NULL;
  1771. ULONG Length;
  1772. RtlInitString(&AnsiSrc, pszSrc);
  1773. Length = RtlAnsiStringToUnicodeSize(&AnsiSrc);
  1774. if (Length > MAXUSHORT) {
  1775. DBGPRINT((sdlWarning, "StringToUnicodeString", "String too long.\n"));
  1776. return pwszUnicodeDest;
  1777. }
  1778. pwszUnicodeDest = (LPWSTR)SdbAlloc(Length); // already contains the NULL
  1779. if (pwszUnicodeDest == NULL) {
  1780. DBGPRINT((sdlWarning, "StringToUnicodeString", "Failed to allocate %d bytes.\n", Length));
  1781. return pwszUnicodeDest;
  1782. }
  1783. UnicodeDest.MaximumLength = (USHORT)Length;
  1784. UnicodeDest.Length = UnicodeDest.MaximumLength - sizeof(UNICODE_NULL);
  1785. UnicodeDest.Buffer = pwszUnicodeDest;
  1786. Status = RtlAnsiStringToUnicodeString(&UnicodeDest, &AnsiSrc, FALSE);
  1787. if (!NT_SUCCESS(Status)) {
  1788. SdbFree(pwszUnicodeDest);
  1789. pwszUnicodeDest = NULL;
  1790. DBGPRINT((sdlWarning,
  1791. "StringToUnicodeString",
  1792. "Failed to convert \"%s\" to UNICODE. Status 0x%x\n",
  1793. pszSrc,
  1794. Status));
  1795. }
  1796. return pwszUnicodeDest;
  1797. }
  1798. BOOL
  1799. SdbpGet16BitDescription(
  1800. OUT LPWSTR* ppszDescription,
  1801. IN PIMAGEFILEDATA pImageData
  1802. )
  1803. /*++
  1804. Return: TRUE on success, FALSE otherwise
  1805. Desc: This function retrieves 16-bit description from the
  1806. module identified by pImageData
  1807. --*/
  1808. {
  1809. BOOL bSuccess;
  1810. char szBuffer[256];
  1811. LPWSTR pwszDescription = NULL;
  1812. bSuccess = SdbpQuery16BitDescription(szBuffer, pImageData);
  1813. if (bSuccess) {
  1814. pwszDescription = StringToUnicodeString(szBuffer);
  1815. *ppszDescription = pwszDescription;
  1816. }
  1817. return (pwszDescription != NULL);
  1818. }
  1819. BOOL
  1820. SdbpGet16BitModuleName(
  1821. OUT LPWSTR* ppszModuleName,
  1822. IN PIMAGEFILEDATA pImageData
  1823. )
  1824. /*++
  1825. Return: TRUE on success, FALSE otherwise
  1826. Desc: Retrieves 16-bit module name from the image
  1827. identified by pImageData, then converts it to UNICODE
  1828. --*/
  1829. {
  1830. BOOL bSuccess;
  1831. char szBuffer[256]; // max possible length of a string is 256 (1-byte worth of length)
  1832. LPWSTR pwszModuleName = NULL;
  1833. bSuccess = SdbpQuery16BitModuleName(szBuffer, pImageData);
  1834. if (bSuccess) {
  1835. pwszModuleName = StringToUnicodeString(szBuffer);
  1836. *ppszModuleName = pwszModuleName;
  1837. }
  1838. return (pwszModuleName != NULL);
  1839. }
  1840. PVOID
  1841. SdbGetFileInfo(
  1842. IN HSDB hSDB,
  1843. IN LPCWSTR pwszFilePath,
  1844. IN HANDLE hFile, // OPTIONAL HANDLE to the file, not used here
  1845. IN LPVOID pImageBase,
  1846. IN DWORD dwImageSize, // ignored
  1847. IN BOOL bNoCache
  1848. )
  1849. /*++
  1850. Return: BUGBUG: ?
  1851. Desc: Create and link a new entry in a file attribute cache.
  1852. --*/
  1853. {
  1854. PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
  1855. WCHAR* FullPath = NULL;
  1856. PFILEINFO pFileInfo = NULL;
  1857. ULONG nBufferLength;
  1858. ULONG cch;
  1859. UNICODE_STRING FullPathU;
  1860. BOOL bFreeFullPath;
  1861. //
  1862. // Check hFile and/or pImageBase -- if these are supplied --
  1863. // we presume that the file exists and we do not touch it
  1864. //
  1865. if (hFile != INVALID_HANDLE_VALUE || pImageBase != NULL) {
  1866. FullPath = (LPWSTR)pwszFilePath; // we do not have to free it
  1867. cch = (ULONG)wcslen(FullPath) * sizeof(WCHAR);
  1868. nBufferLength = cch + sizeof(UNICODE_NULL);
  1869. bFreeFullPath = FALSE;
  1870. goto CreateFileInfo;
  1871. }
  1872. //
  1873. // See if we have info on this file. First we get the full path.
  1874. //
  1875. cch = RtlGetFullPathName_U(pwszFilePath,
  1876. 0,
  1877. NULL,
  1878. NULL);
  1879. if (cch == 0) {
  1880. DBGPRINT((sdlError,
  1881. "SdbGetFileInfo",
  1882. "RtlGetFullPathName_U failed for \"%s\"\n",
  1883. pwszFilePath));
  1884. return pFileInfo;
  1885. }
  1886. //
  1887. // Now allocate that much.
  1888. //
  1889. nBufferLength = cch + sizeof(UNICODE_NULL);
  1890. STACK_ALLOC(FullPath, nBufferLength);
  1891. if (FullPath == NULL) {
  1892. DBGPRINT((sdlError,
  1893. "SdbGetFileInfo",
  1894. "Failed to allocate %d bytes for full path\n",
  1895. nBufferLength));
  1896. return pFileInfo;
  1897. }
  1898. bFreeFullPath = TRUE;
  1899. cch = RtlGetFullPathName_U(pwszFilePath,
  1900. nBufferLength,
  1901. FullPath,
  1902. NULL);
  1903. assert(cch <= nBufferLength);
  1904. if (cch > nBufferLength || cch == 0) {
  1905. DBGPRINT((sdlError,
  1906. "SdbGetFileInfo",
  1907. "RtlGetFullPathName_U failed for \"%s\"\n",
  1908. pwszFilePath));
  1909. goto Done;
  1910. }
  1911. CreateFileInfo:
  1912. if (!bNoCache) {
  1913. pFileInfo = FindFileInfo(pContext, FullPath);
  1914. }
  1915. if (pFileInfo == NULL) {
  1916. if (hFile != INVALID_HANDLE_VALUE || pImageBase != NULL ||
  1917. RtlDoesFileExists_U(FullPath)) {
  1918. //
  1919. // The path does exist. Create a record of this file path.
  1920. //
  1921. FullPathU.Buffer = FullPath;
  1922. FullPathU.Length = (USHORT)cch;
  1923. FullPathU.MaximumLength = (USHORT)nBufferLength;
  1924. pFileInfo = CreateFileInfo(pContext,
  1925. FullPathU.Buffer,
  1926. FullPathU.Length / sizeof(WCHAR),
  1927. hFile,
  1928. pImageBase,
  1929. dwImageSize,
  1930. bNoCache);
  1931. }
  1932. }
  1933. Done:
  1934. if (FullPath != NULL && bFreeFullPath) {
  1935. STACK_FREE(FullPath);
  1936. }
  1937. return (PVOID)pFileInfo;
  1938. }
  1939. int
  1940. GetShimDbgLevel(
  1941. void
  1942. )
  1943. /*++
  1944. Return: The current debug level.
  1945. Desc: Checks the environment variable that controls the amount of
  1946. debug output.
  1947. --*/
  1948. {
  1949. UNICODE_STRING ShimDbgLevel;
  1950. INT iShimDebugLevel = 0;
  1951. NTSTATUS Status;
  1952. WCHAR Buffer[MAX_PATH];
  1953. ULONG ulValue;
  1954. ShimDbgLevel.Buffer = (PWCHAR)Buffer;
  1955. ShimDbgLevel.Length = 0;
  1956. ShimDbgLevel.MaximumLength = sizeof(Buffer);
  1957. Status = RtlQueryEnvironmentVariable_U(NULL,
  1958. &g_ustrShimDbgLevelVar,
  1959. &ShimDbgLevel);
  1960. if (NT_SUCCESS(Status)) {
  1961. //
  1962. // We have the debug level variable present. Parse it to see what
  1963. // is the value of this variable.
  1964. //
  1965. Status = RtlUnicodeStringToInteger(&ShimDbgLevel, 0, (PULONG)&ulValue);
  1966. if (NT_SUCCESS(Status)) {
  1967. iShimDebugLevel = (int)ulValue;
  1968. }
  1969. }
  1970. return iShimDebugLevel;
  1971. }
  1972. //
  1973. // Functions that deal with APPCOMPAT_EXE_DATA
  1974. //
  1975. //
  1976. // These two functions should be used when passing APPCOMPAT_EXE_DATA structure
  1977. // across the boundaries of CreateProcess. Before passing the struct it should
  1978. // be "denormalized"; after -- normalized.
  1979. //
  1980. #define APPCOMPAT_EXE_DATA_MAGIC 0xAC0DEDAB
  1981. BOOL
  1982. SdbPackAppCompatData(
  1983. IN HSDB hSDB,
  1984. IN PSDBQUERYRESULT pSdbQuery,
  1985. OUT PVOID* ppData, // app compat data package
  1986. OUT LPDWORD pdwSize // data size
  1987. )
  1988. /*++
  1989. Return: TRUE on success, FALSE otherwise.
  1990. Desc: Packs the APPCOMPAT_EXE_DATA to be sent to the kernel in the context
  1991. of the process about to be started (and shimmed).
  1992. --*/
  1993. {
  1994. DWORD cbData;
  1995. PAPPCOMPAT_EXE_DATA pData = NULL;
  1996. assert(ppData != NULL);
  1997. assert(pdwSize != NULL);
  1998. if (pSdbQuery->atrExes[0] == TAGREF_NULL && pSdbQuery->atrLayers[0] == TAGREF_NULL) {
  1999. DBGPRINT((sdlError, "SdbPackAppCompatData", "Invalid arguments.\n"));
  2000. return FALSE;
  2001. }
  2002. cbData = sizeof(APPCOMPAT_EXE_DATA);
  2003. //
  2004. // Allocate memory. Use this form of allocation so we know that
  2005. // we can free it from CreateProcess.
  2006. //
  2007. pData = (PAPPCOMPAT_EXE_DATA)RtlAllocateHeap(RtlProcessHeap(),
  2008. HEAP_ZERO_MEMORY,
  2009. cbData);
  2010. if (pData == NULL) {
  2011. DBGPRINT((sdlError,
  2012. "SdbPackAppCompatData",
  2013. "Failed to allocate %d bytes.\n",
  2014. cbData));
  2015. return FALSE;
  2016. }
  2017. pData->cbSize = cbData;
  2018. pData->dwMagic = APPCOMPAT_EXE_DATA_MAGIC;
  2019. pData->dwFlags = pSdbQuery->dwFlags;
  2020. pData->trAppHelp = pSdbQuery->trAppHelp;
  2021. pData->dwLayerFlags = pSdbQuery->dwLayerFlags;
  2022. RtlCopyMemory(&pData->atrExes[0],
  2023. &pSdbQuery->atrExes[0],
  2024. sizeof(pSdbQuery->atrExes));
  2025. RtlCopyMemory(&pData->atrLayers[0],
  2026. &pSdbQuery->atrLayers[0],
  2027. sizeof(pSdbQuery->atrLayers));
  2028. StringCchCopy(pData->szShimEngine, CHARCOUNT(pData->szShimEngine), L"ShimEng.dll");
  2029. //
  2030. // Store custom sdbs
  2031. //
  2032. pData->dwDatabaseMap = pSdbQuery->dwCustomSDBMap;
  2033. if (pData->dwDatabaseMap) {
  2034. RtlCopyMemory(&pData->rgGuidDB[0],
  2035. &pSdbQuery->rgGuidDB[0],
  2036. sizeof(pData->rgGuidDB));
  2037. }
  2038. DBGPRINT((sdlInfo|sdlLogShimViewer,
  2039. "SdbPackAppCompatData",
  2040. "\n\tdwFlags 0x%X\n"
  2041. "\tdwMagic 0x%X\n"
  2042. "\ttrExe 0x%X\n"
  2043. "\ttrLayer 0x%X\n",
  2044. hSDB,
  2045. pData->dwFlags,
  2046. pData->dwMagic,
  2047. pData->atrExes[0],
  2048. pData->atrLayers[0]));
  2049. //
  2050. // Dump all the relevant entries
  2051. //
  2052. if (SDBCONTEXT_IS_INSTRUMENTED(hSDB)) {
  2053. DWORD dwMask;
  2054. DWORD dwIndex;
  2055. WCHAR szGuid[64];
  2056. PDB pdb;
  2057. LPCWSTR pszDescription;
  2058. SDBDATABASEINFO DbInfo;
  2059. if (pSdbQuery->dwCustomSDBMap) {
  2060. DBGPRINT((sdlInfo|sdlLogShimViewer, "SdbPackAppcompatData", "Database List\n", hSDB));
  2061. for (dwIndex = 0; dwIndex < ARRAYSIZE(pSdbQuery->rgGuidDB); ++dwIndex) {
  2062. dwMask = (1UL << dwIndex);
  2063. if (!(pSdbQuery->dwCustomSDBMap & dwMask)) {
  2064. continue;
  2065. }
  2066. //
  2067. // Dump the guid
  2068. //
  2069. pszDescription = NULL;
  2070. pdb = SdbGetPDBFromGUID(hSDB, &pSdbQuery->rgGuidDB[dwIndex]);
  2071. if (pdb != NULL && SdbGetDatabaseInformation(pdb, &DbInfo)) {
  2072. pszDescription = DbInfo.pszDescription;
  2073. }
  2074. if (!SdbGUIDToString(&pSdbQuery->rgGuidDB[dwIndex],
  2075. szGuid,
  2076. CHARCOUNT(szGuid))) {
  2077. DBGPRINT((sdlError,
  2078. "SdbPackAppcompatData",
  2079. "Failed to convert GUID to string\n"));
  2080. }
  2081. DBGPRINT((sdlInfo|sdlLogShimViewer,
  2082. "SdbPackAppcompatData",
  2083. "0x%lx %s %s\n",
  2084. hSDB,
  2085. SDB_INDEX_TO_MASK(dwIndex),
  2086. szGuid,
  2087. (pszDescription ? pszDescription : L"")));
  2088. }
  2089. }
  2090. //
  2091. // Now dump all the matches
  2092. //
  2093. for (dwIndex = 0; dwIndex < ARRAYSIZE(pSdbQuery->atrExes); ++dwIndex) {
  2094. if (pSdbQuery->atrExes[dwIndex] == TAGREF_NULL) {
  2095. continue;
  2096. }
  2097. DBGPRINT((sdlInfo|sdlLogShimViewer,
  2098. "SdbPackAppcompatData",
  2099. "Exe 0x%.8lx\n",
  2100. hSDB,
  2101. pSdbQuery->atrExes[dwIndex]));
  2102. }
  2103. for (dwIndex = 0; dwIndex < ARRAYSIZE(pSdbQuery->atrLayers); ++dwIndex) {
  2104. if (pSdbQuery->atrLayers[dwIndex] == TAGREF_NULL) {
  2105. continue;
  2106. }
  2107. DBGPRINT((sdlInfo|sdlLogShimViewer,
  2108. "SdbPackAppcompatData",
  2109. "Layer 0x%.8lx\n",
  2110. hSDB,
  2111. pSdbQuery->atrLayers[dwIndex]));
  2112. }
  2113. }
  2114. *ppData = (PVOID)pData;
  2115. *pdwSize = cbData;
  2116. return TRUE;
  2117. }
  2118. BOOL
  2119. SdbUnpackAppCompatData(
  2120. IN HSDB hSDB,
  2121. IN LPCWSTR pwszExeName,
  2122. IN PVOID pAppCompatData,
  2123. OUT PSDBQUERYRESULT pSdbQuery
  2124. )
  2125. /*++
  2126. Return: TRUE on success, FALSE otherwise.
  2127. Desc: Unpacks the APPCOMPAT_EXE_DATA to extract the TAGREFs to be used
  2128. for the EXE that just started. This function is called from
  2129. LdrpInitializeProcess (in ntdll).
  2130. --*/
  2131. {
  2132. PAPPCOMPAT_EXE_DATA pData = (PAPPCOMPAT_EXE_DATA)pAppCompatData;
  2133. PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
  2134. if (pData == NULL) {
  2135. DBGPRINT((sdlError, "SdbUnpackAppCompatData", "Invalid parameter\n"));
  2136. return FALSE;
  2137. }
  2138. if (pData->dwMagic != APPCOMPAT_EXE_DATA_MAGIC) {
  2139. DbgPrint("[SdbUnpackAppCompatData] Invalid magic 0x%x. Expected 0x%x\n",
  2140. pData->dwMagic,
  2141. APPCOMPAT_EXE_DATA_MAGIC);
  2142. return FALSE;
  2143. }
  2144. DBGPRINT((sdlInfo,
  2145. "SdbUnpackAppCompatData",
  2146. "Appcompat Data for \"%s\":\n"
  2147. "\tdwFlags 0x%X\n"
  2148. "\tdwMagic 0x%X\n"
  2149. "\ttrExe 0x%X\n"
  2150. "\ttrLayer 0x%X\n",
  2151. pwszExeName,
  2152. pData->dwFlags,
  2153. pData->dwMagic,
  2154. pData->atrExes[0],
  2155. pData->atrLayers[0]));
  2156. //
  2157. // We have no use for dwFlags so far.
  2158. //
  2159. //
  2160. // We should get rid of all the local sdbs in this context
  2161. //
  2162. if (pSdbContext->pdbLocal != NULL) {
  2163. SdbCloseLocalDatabase(hSDB);
  2164. }
  2165. RtlCopyMemory(&pSdbQuery->atrExes[0],
  2166. &pData->atrExes[0],
  2167. sizeof(pData->atrExes));
  2168. RtlCopyMemory(&pSdbQuery->atrLayers[0],
  2169. &pData->atrLayers[0],
  2170. sizeof(pData->atrLayers));
  2171. pSdbQuery->dwFlags = pData->dwFlags;
  2172. pSdbQuery->trAppHelp = pData->trAppHelp;
  2173. pSdbQuery->dwLayerFlags = pData->dwLayerFlags;
  2174. //
  2175. // See if we need to open local db
  2176. //
  2177. // We might need to be able to use local dbs --
  2178. // actual open on a local db will be performed by a tagref translation layer
  2179. //
  2180. if (pData->dwDatabaseMap) {
  2181. DWORD dwMask;
  2182. DWORD dwIndex;
  2183. PSDBENTRY pEntry;
  2184. DWORD dwCount = 2;
  2185. SdbpCleanupLocalDatabaseSupport(hSDB);
  2186. //
  2187. // Now introduce entries, one by one
  2188. //
  2189. for (dwIndex = 2; dwIndex < ARRAYSIZE(pSdbContext->rgSDB); ++dwIndex) {
  2190. dwMask = (1UL << dwIndex);
  2191. if (pData->dwDatabaseMap & dwMask) {
  2192. pEntry = SDBGETENTRY(hSDB, dwIndex);
  2193. pEntry->dwFlags = SDBENTRY_VALID_GUID;
  2194. pEntry->guidDB = pData->rgGuidDB[dwIndex];
  2195. dwCount = dwIndex;
  2196. }
  2197. }
  2198. pSdbContext->dwDatabaseMask |= (pData->dwDatabaseMap & SDB_CUSTOM_MASK);
  2199. }
  2200. return TRUE;
  2201. }
  2202. DWORD
  2203. SdbGetAppCompatDataSize(
  2204. IN PVOID pAppCompatData
  2205. )
  2206. /*++
  2207. Return: The size of the appcompat data.
  2208. Desc: Self explanatory.
  2209. --*/
  2210. {
  2211. PAPPCOMPAT_EXE_DATA pData = (PAPPCOMPAT_EXE_DATA)pAppCompatData;
  2212. if (pData == NULL) {
  2213. DBGPRINT((sdlError, "SdbGetAppCompatDataSize", "Invalid parameter\n"));
  2214. return 0;
  2215. }
  2216. if (pData->dwMagic != APPCOMPAT_EXE_DATA_MAGIC) {
  2217. DBGPRINT((sdlError,
  2218. "SdbGetAppCompatDataSize",
  2219. "Invalid magic 0x%x. Expected 0x%x\n",
  2220. pData->dwMagic,
  2221. APPCOMPAT_EXE_DATA_MAGIC));
  2222. return 0;
  2223. }
  2224. return pData->cbSize;
  2225. }
  2226. BOOL
  2227. SdbpWriteBitsToFile(
  2228. IN LPCTSTR pszFile,
  2229. IN PBYTE pBuffer,
  2230. IN DWORD dwSize
  2231. )
  2232. /*++
  2233. Return: TRUE on success, FALSE otherwise.
  2234. Desc: Self explanatory.
  2235. --*/
  2236. {
  2237. LPCWSTR pszFileU = (LPCWSTR)pszFile;
  2238. UNICODE_STRING strFilePath;
  2239. OBJECT_ATTRIBUTES ObjectAttributes;
  2240. NTSTATUS status = STATUS_UNSUCCESSFUL;
  2241. HANDLE hFile = NULL;
  2242. IO_STATUS_BLOCK IoStatusBlock;
  2243. LARGE_INTEGER liOffset;
  2244. //
  2245. // Create the file.
  2246. //
  2247. RtlInitUnicodeString(&strFilePath, pszFileU);
  2248. if (!RtlDosPathNameToNtPathName_U(strFilePath.Buffer,
  2249. &strFilePath,
  2250. NULL,
  2251. NULL)) {
  2252. DBGPRINT((sdlError,
  2253. "SdbpWriteBitsToFile",
  2254. "Failed to convert file name \"%s\" to NT path.\n",
  2255. pszFileU));
  2256. goto cleanup;
  2257. }
  2258. InitializeObjectAttributes(&ObjectAttributes,
  2259. &strFilePath,
  2260. OBJ_CASE_INSENSITIVE,
  2261. NULL,
  2262. NULL);
  2263. status = NtCreateFile(&hFile,
  2264. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  2265. &ObjectAttributes,
  2266. &IoStatusBlock,
  2267. 0,
  2268. FILE_ATTRIBUTE_NORMAL,
  2269. 0,
  2270. FILE_OVERWRITE_IF,
  2271. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  2272. NULL,
  2273. 0);
  2274. //
  2275. // RtlDosPathNameToNtPathName_U allocates memory for the
  2276. // unicode string. This is where we dump it.
  2277. //
  2278. RtlFreeUnicodeString(&strFilePath);
  2279. if (!NT_SUCCESS(status)) {
  2280. DBGPRINT((sdlError,
  2281. "SdbpWriteBitsToFile",
  2282. "Failed to create file \"%s\".\n",
  2283. pszFileU));
  2284. goto cleanup;
  2285. }
  2286. //
  2287. // ...and write the bits to disk
  2288. //
  2289. liOffset.LowPart = 0;
  2290. liOffset.HighPart = 0;
  2291. status = NtWriteFile(hFile,
  2292. NULL,
  2293. NULL,
  2294. NULL,
  2295. &IoStatusBlock,
  2296. (PVOID)pBuffer,
  2297. dwSize,
  2298. &liOffset,
  2299. NULL);
  2300. if (!NT_SUCCESS(status)) {
  2301. DBGPRINT((sdlError,
  2302. "SdbpWriteBitsToFile",
  2303. "Failed 0x%x to write file \"%s\" to disk.\n",
  2304. status,
  2305. pszFileU));
  2306. goto cleanup;
  2307. }
  2308. status = STATUS_SUCCESS;
  2309. cleanup:
  2310. if (hFile != NULL) {
  2311. NtClose(hFile);
  2312. }
  2313. return (status == STATUS_SUCCESS);
  2314. }
  2315. DWORD
  2316. SdbExpandEnvironmentStrings(
  2317. IN LPCWSTR lpSrc,
  2318. OUT LPWSTR lpDst,
  2319. IN DWORD nSize
  2320. )
  2321. {
  2322. NTSTATUS Status;
  2323. UNICODE_STRING Source;
  2324. UNICODE_STRING Destination;
  2325. ULONG Length;
  2326. DWORD iSize;
  2327. if (nSize > (MAXUSHORT >> 1) - 2) {
  2328. iSize = (MAXUSHORT >> 1) - 2;
  2329. } else {
  2330. iSize = nSize;
  2331. }
  2332. RtlInitUnicodeString(&Source, lpSrc);
  2333. Destination.Buffer = lpDst;
  2334. Destination.Length = 0;
  2335. Destination.MaximumLength = (USHORT)(iSize * sizeof( WCHAR ));
  2336. Length = 0;
  2337. Status = RtlExpandEnvironmentStrings_U(NULL,
  2338. &Source,
  2339. &Destination,
  2340. &Length);
  2341. if (NT_SUCCESS( Status ) || Status == STATUS_BUFFER_TOO_SMALL) {
  2342. return (Length / sizeof(WCHAR));
  2343. }
  2344. return 0;
  2345. }
  2346. BOOL
  2347. SDBAPI
  2348. SdbRegisterDatabaseEx(
  2349. IN LPCWSTR pszDatabasePath,
  2350. IN DWORD dwDatabaseType,
  2351. IN PULONGLONG pTimeStamp OPTIONAL
  2352. )
  2353. /*++
  2354. Registers any given database so that it is "known" to our database lookup apis
  2355. --*/
  2356. {
  2357. PSDBDATABASEINFO pDbInfo = NULL;
  2358. BOOL bReturn = FALSE;
  2359. UNICODE_STRING ustrPath;
  2360. UNICODE_STRING ustrFullPath = { 0 };
  2361. BOOL bFreeFullPath = FALSE;
  2362. BOOL bExpandSZ = FALSE;
  2363. UNICODE_STRING ustrKey;
  2364. UNICODE_STRING ustrFullKey;
  2365. UNICODE_STRING ustrDatabaseID = { 0 };
  2366. WCHAR wszFullKey[MAX_PATH];
  2367. NTSTATUS Status;
  2368. HANDLE KeyHandleAppcompat = NULL;
  2369. HANDLE KeyHandle = NULL;
  2370. ULONG CreateDisposition;
  2371. ULONG PathLength = 0;
  2372. OBJECT_ATTRIBUTES ObjectAttributes;
  2373. FILETIME TimeStamp;
  2374. LARGE_INTEGER liTimeStamp;
  2375. KEY_WRITE_TIME_INFORMATION KeyWriteTimeInfo;
  2376. //
  2377. // See if we need to expand some strings...
  2378. //
  2379. if (_tcschr(pszDatabasePath, TEXT('%')) != NULL) {
  2380. bExpandSZ = TRUE;
  2381. RtlInitUnicodeString(&ustrPath, pszDatabasePath);
  2382. Status = RtlExpandEnvironmentStrings_U(NULL,
  2383. &ustrPath,
  2384. &ustrFullPath,
  2385. &PathLength);
  2386. if (Status != STATUS_BUFFER_TOO_SMALL) {
  2387. DBGPRINT((sdlError,
  2388. "SdbRegisterDatabase",
  2389. "Failed to expand environment strings for \"%s\" Status 0x%lx\n",
  2390. pszDatabasePath,
  2391. Status));
  2392. return FALSE;
  2393. }
  2394. //
  2395. // Allocate the length we need
  2396. //
  2397. ustrFullPath.Buffer = (WCHAR*)SdbAlloc(PathLength);
  2398. if (ustrFullPath.Buffer == NULL) {
  2399. DBGPRINT((sdlError,
  2400. "SdbRegisterDatabase",
  2401. "Failed to allocate 0x%lx bytes for the path buffer \"%s\"\n",
  2402. PathLength,
  2403. pszDatabasePath));
  2404. return FALSE;
  2405. }
  2406. ustrFullPath.MaximumLength = (USHORT)PathLength;
  2407. ustrFullPath.Length = 0;
  2408. bFreeFullPath = TRUE;
  2409. Status = RtlExpandEnvironmentStrings_U(NULL,
  2410. &ustrPath,
  2411. &ustrFullPath,
  2412. &PathLength);
  2413. if (!NT_SUCCESS(Status)) {
  2414. DBGPRINT((sdlError,
  2415. "SdbRegisterDatabase",
  2416. "Failed to expand environment strings for \"%s\" Status 0x%lx\n",
  2417. pszDatabasePath,
  2418. Status));
  2419. goto HandleError;
  2420. }
  2421. } else {
  2422. RtlInitUnicodeString(&ustrFullPath, pszDatabasePath);
  2423. }
  2424. if (!SdbGetDatabaseInformationByName(ustrFullPath.Buffer, &pDbInfo)) {
  2425. DBGPRINT((sdlError,
  2426. "SdbRegisterDatabase",
  2427. "Cannot obtain database information for \"%s\"\n",
  2428. pszDatabasePath));
  2429. goto HandleError;
  2430. }
  2431. if (!(pDbInfo->dwFlags & DBINFO_GUID_VALID)) {
  2432. DBGPRINT((sdlError,
  2433. "SdbRegisterDatabase",
  2434. "Cannot register database with no id \"%s\"\n",
  2435. pszDatabasePath));
  2436. goto HandleError;
  2437. }
  2438. Status = GUID_TO_UNICODE_STRING(&pDbInfo->guidDB, &ustrDatabaseID);
  2439. if (!NT_SUCCESS(Status)) {
  2440. DBGPRINT((sdlError,
  2441. "SdbRegisterDatabase",
  2442. "Cannot convert guid to unicode string status 0x%lx\n",
  2443. Status));
  2444. goto HandleError;
  2445. }
  2446. //
  2447. // Now that we have database information - create entry
  2448. //
  2449. ustrFullKey.Length = 0;
  2450. ustrFullKey.MaximumLength = sizeof(wszFullKey);
  2451. ustrFullKey.Buffer = wszFullKey;
  2452. RtlAppendUnicodeToString(&ustrFullKey, APPCOMPAT_KEY_PATH_MACHINE_INSTALLEDSDB);
  2453. RtlAppendUnicodeToString(&ustrFullKey, L"\\");
  2454. RtlAppendUnicodeStringToString(&ustrFullKey, &ustrDatabaseID);
  2455. FREE_GUID_STRING(&ustrDatabaseID);
  2456. //
  2457. // All done, now create key - first make sure that appcompat key path machine exists...
  2458. //
  2459. RtlInitUnicodeString(&ustrKey, APPCOMPAT_KEY_PATH_MACHINE_INSTALLEDSDB);
  2460. InitializeObjectAttributes(&ObjectAttributes,
  2461. &ustrKey,
  2462. OBJ_CASE_INSENSITIVE,
  2463. NULL,
  2464. NULL);
  2465. Status = NtCreateKey(&KeyHandleAppcompat,
  2466. STANDARD_RIGHTS_WRITE |
  2467. KEY_QUERY_VALUE |
  2468. KEY_ENUMERATE_SUB_KEYS |
  2469. KEY_SET_VALUE |
  2470. KEY_CREATE_SUB_KEY|
  2471. SdbpGetWow64Flag(),
  2472. &ObjectAttributes,
  2473. 0,
  2474. NULL,
  2475. REG_OPTION_NON_VOLATILE,
  2476. &CreateDisposition);
  2477. if (!NT_SUCCESS(Status)) {
  2478. DBGPRINT((sdlError,
  2479. "SdbRegisterDatabase",
  2480. "Failed to create key \"%s\" status = 0x%lx\n",
  2481. ustrKey.Buffer,
  2482. Status));
  2483. goto HandleError;
  2484. }
  2485. InitializeObjectAttributes(&ObjectAttributes,
  2486. &ustrFullKey,
  2487. OBJ_CASE_INSENSITIVE,
  2488. NULL,
  2489. NULL);
  2490. Status = NtCreateKey(&KeyHandle,
  2491. STANDARD_RIGHTS_WRITE |
  2492. KEY_QUERY_VALUE |
  2493. KEY_ENUMERATE_SUB_KEYS |
  2494. KEY_SET_VALUE |
  2495. KEY_CREATE_SUB_KEY|
  2496. SdbpGetWow64Flag(),
  2497. &ObjectAttributes,
  2498. 0,
  2499. NULL,
  2500. REG_OPTION_NON_VOLATILE,
  2501. &CreateDisposition);
  2502. if (!NT_SUCCESS(Status)) {
  2503. DBGPRINT((sdlError,
  2504. "SdbRegisterDatabase",
  2505. "Failed to create key \"%s\" Status 0x%x\n",
  2506. ustrFullKey.Buffer,
  2507. Status));
  2508. goto HandleError;
  2509. }
  2510. //
  2511. // We have an open key, we shall set these values:
  2512. //
  2513. Status = NtSetValueKey(KeyHandle,
  2514. (PUNICODE_STRING)&g_ustrDatabasePath,
  2515. 0,
  2516. bExpandSZ ? REG_EXPAND_SZ : REG_SZ,
  2517. (PVOID)pszDatabasePath,
  2518. (ULONG)(_tcslen(pszDatabasePath) + 1) * sizeof(*pszDatabasePath));
  2519. if (!NT_SUCCESS(Status)) {
  2520. DBGPRINT((sdlError,
  2521. "SdbRegisterDatabase",
  2522. "Failed to set value \"%s\" to \"%s\" Status 0x%lx\n",
  2523. g_ustrDatabasePath.Buffer,
  2524. pszDatabasePath,
  2525. Status));
  2526. goto HandleError;
  2527. }
  2528. Status = NtSetValueKey(KeyHandle,
  2529. (PUNICODE_STRING)&g_ustrDatabaseType,
  2530. 0,
  2531. REG_DWORD,
  2532. (PVOID)&dwDatabaseType,
  2533. sizeof(dwDatabaseType));
  2534. if (!NT_SUCCESS(Status)) {
  2535. DBGPRINT((sdlError,
  2536. "SdbRegisterDatabase",
  2537. "Failed to set value \"%s\" to 0x%lx Status 0x%lx\n",
  2538. g_ustrDatabaseType.Buffer,
  2539. dwDatabaseType, Status));
  2540. goto HandleError;
  2541. }
  2542. if (pDbInfo->pszDescription != NULL) {
  2543. Status = NtSetValueKey(KeyHandle,
  2544. (PUNICODE_STRING)&g_ustrDatabaseDescription,
  2545. 0,
  2546. REG_SZ,
  2547. (PVOID)pDbInfo->pszDescription,
  2548. (ULONG)(_tcslen(pDbInfo->pszDescription) + 1) * sizeof(WCHAR));
  2549. if (!NT_SUCCESS(Status)) {
  2550. DBGPRINT((sdlError,
  2551. "SdbRegisterDatabase",
  2552. "Failed to set value \"%s\" to 0x%lx Status 0x%lx\n",
  2553. g_ustrDatabaseDescription.Buffer,
  2554. pDbInfo->pszDescription,
  2555. Status));
  2556. goto HandleError;
  2557. }
  2558. }
  2559. //
  2560. // Finally, set the date/time stamp explicitly as a value
  2561. //
  2562. if (pTimeStamp == NULL) {
  2563. GetSystemTimeAsFileTime(&TimeStamp);
  2564. liTimeStamp.LowPart = TimeStamp.dwLowDateTime;
  2565. liTimeStamp.HighPart = TimeStamp.dwHighDateTime;
  2566. } else {
  2567. liTimeStamp.QuadPart = *pTimeStamp;
  2568. }
  2569. Status = NtSetValueKey(KeyHandle,
  2570. (PUNICODE_STRING)&g_ustrInstallTimeStamp,
  2571. 0,
  2572. REG_QWORD,
  2573. (PVOID)&liTimeStamp.QuadPart,
  2574. sizeof(liTimeStamp.QuadPart));
  2575. if (!NT_SUCCESS(Status)) {
  2576. DBGPRINT((sdlError,
  2577. "SdbRegisterDatabase",
  2578. "Failed to set value \"%s\" Status 0x%lx\n",
  2579. g_ustrInstallTimeStamp.Buffer,
  2580. Status));
  2581. goto HandleError;
  2582. }
  2583. //
  2584. // Make the value we set into the timestamp MATCH the last write date/time stamp
  2585. // on the key itself (just to be consistent)
  2586. //
  2587. KeyWriteTimeInfo.LastWriteTime.QuadPart = liTimeStamp.QuadPart;
  2588. Status = NtSetInformationKey(KeyHandle,
  2589. KeyWriteTimeInformation,
  2590. &KeyWriteTimeInfo,
  2591. sizeof(KeyWriteTimeInfo));
  2592. if (!NT_SUCCESS(Status)) {
  2593. DBGPRINT((sdlError,
  2594. "SdbRegisterDatabase",
  2595. "Failed to set last write time on key Status 0x%lx\n",
  2596. Status));
  2597. goto HandleError;
  2598. }
  2599. bReturn = TRUE;
  2600. HandleError:
  2601. if (pDbInfo != NULL) {
  2602. SdbFreeDatabaseInformation(pDbInfo);
  2603. }
  2604. if (bFreeFullPath && ustrFullPath.Buffer != NULL) {
  2605. SdbFree(ustrFullPath.Buffer);
  2606. }
  2607. if (KeyHandle != NULL) {
  2608. NtClose(KeyHandle);
  2609. }
  2610. if (KeyHandleAppcompat != NULL) {
  2611. NtClose(KeyHandleAppcompat);
  2612. }
  2613. return bReturn;
  2614. }
  2615. BOOL
  2616. SDBAPI
  2617. SdbRegisterDatabase(
  2618. IN LPCWSTR pszDatabasePath,
  2619. IN DWORD dwDatabaseType
  2620. )
  2621. {
  2622. return SdbRegisterDatabaseEx(pszDatabasePath, dwDatabaseType, NULL);
  2623. }
  2624. BOOL
  2625. SDBAPI
  2626. SdbUnregisterDatabase(
  2627. IN GUID* pguidDB
  2628. )
  2629. /*++
  2630. Unregisters a database so it's no longer available.
  2631. --*/
  2632. {
  2633. BOOL bReturn = FALSE;
  2634. UNICODE_STRING ustrFullKey;
  2635. UNICODE_STRING ustrDatabaseID = { 0 };
  2636. WCHAR wszFullKey[MAX_PATH];
  2637. NTSTATUS Status;
  2638. HANDLE KeyHandle = NULL;
  2639. OBJECT_ATTRIBUTES ObjectAttributes;
  2640. Status = GUID_TO_UNICODE_STRING(pguidDB, &ustrDatabaseID);
  2641. if (!NT_SUCCESS(Status)) {
  2642. DBGPRINT((sdlError,
  2643. "SdbUnregisterDatabase",
  2644. "Cannot convert guid to unicode string status 0x%lx\n",
  2645. Status));
  2646. goto HandleError;
  2647. }
  2648. //
  2649. // Now that we have database information - remove entry
  2650. //
  2651. ustrFullKey.Length = 0;
  2652. ustrFullKey.MaximumLength = sizeof(wszFullKey);
  2653. ustrFullKey.Buffer = wszFullKey;
  2654. RtlAppendUnicodeToString(&ustrFullKey, APPCOMPAT_KEY_PATH_MACHINE_INSTALLEDSDB);
  2655. RtlAppendUnicodeToString(&ustrFullKey, L"\\");
  2656. RtlAppendUnicodeStringToString(&ustrFullKey, &ustrDatabaseID);
  2657. FREE_GUID_STRING(&ustrDatabaseID);
  2658. //
  2659. // All done, now delete key
  2660. //
  2661. InitializeObjectAttributes(&ObjectAttributes,
  2662. &ustrFullKey,
  2663. OBJ_CASE_INSENSITIVE,
  2664. NULL,
  2665. NULL);
  2666. Status = NtOpenKey(&KeyHandle, DELETE|SdbpGetWow64Flag(), &ObjectAttributes);
  2667. if (!NT_SUCCESS(Status)) {
  2668. DBGPRINT((sdlError,
  2669. "SdbUnregisterDatabase",
  2670. "Failed to open key \"%s\" Status 0x%x\n",
  2671. ustrFullKey.Buffer,
  2672. Status));
  2673. goto HandleError;
  2674. }
  2675. //
  2676. // We have an open key, now delete it
  2677. //
  2678. Status = NtDeleteKey(KeyHandle);
  2679. if (!NT_SUCCESS(Status)) {
  2680. DBGPRINT((sdlError,
  2681. "SdbUnregisterDatabase",
  2682. "Failed to delete key \"%s\" Status 0x%x\n",
  2683. ustrFullKey.Buffer,
  2684. Status));
  2685. goto HandleError;
  2686. }
  2687. bReturn = TRUE;
  2688. HandleError:
  2689. if (KeyHandle != NULL) {
  2690. NtClose(KeyHandle);
  2691. }
  2692. return bReturn;
  2693. }
  2694. BOOL
  2695. SdbpDoesFileExistNTPath(
  2696. LPCWSTR lpwszFileName
  2697. )
  2698. {
  2699. OBJECT_ATTRIBUTES Obja;
  2700. UNICODE_STRING NtFileName;
  2701. NTSTATUS Status;
  2702. BOOL ReturnValue = FALSE;
  2703. FILE_BASIC_INFORMATION BasicInfo;
  2704. RtlInitUnicodeString(&NtFileName, lpwszFileName);
  2705. InitializeObjectAttributes(&Obja,
  2706. &NtFileName,
  2707. OBJ_CASE_INSENSITIVE,
  2708. NULL,
  2709. NULL);
  2710. //
  2711. // Query the file's attributes. Note that the file cannot simply be opened
  2712. // to determine whether or not it exists, as the NT LanMan redirector lies
  2713. // on NtOpenFile to a Lan Manager server because it does not actually open
  2714. // the file until an operation is performed on it. We don't care since net is not
  2715. // even involved -- we always check for LOCAL files
  2716. //
  2717. Status = NtQueryAttributesFile(&Obja, &BasicInfo);
  2718. if (!NT_SUCCESS(Status)) {
  2719. if (Status == STATUS_SHARING_VIOLATION || Status == STATUS_ACCESS_DENIED) {
  2720. ReturnValue = TRUE;
  2721. } else {
  2722. ReturnValue = FALSE;
  2723. }
  2724. } else {
  2725. ReturnValue = TRUE;
  2726. }
  2727. return ReturnValue;
  2728. }
  2729. BOOL
  2730. SDBAPI
  2731. SdbGetStandardDatabaseGUID(
  2732. IN DWORD dwDatabaseType,
  2733. OUT GUID* pGuidDB
  2734. )
  2735. {
  2736. GUID const * pguid = NULL;
  2737. if (!(dwDatabaseType & SDB_DATABASE_MAIN)) {
  2738. DBGPRINT((sdlError,
  2739. "SdbGetStandardDatabaseGUID",
  2740. "Cannot obtain database guid for databases other than main\n"));
  2741. return FALSE;
  2742. }
  2743. switch (dwDatabaseType & SDB_DATABASE_TYPE_MASK) {
  2744. case SDB_DATABASE_MAIN_DRIVERS:
  2745. pguid = &GUID_DRVMAIN_SDB;
  2746. break;
  2747. case SDB_DATABASE_MAIN_DETAILS:
  2748. pguid = &GUID_APPHELP_SDB;
  2749. break;
  2750. case SDB_DATABASE_MAIN_MSI:
  2751. pguid = &GUID_MSIMAIN_SDB;
  2752. break;
  2753. case SDB_DATABASE_MAIN_SHIM:
  2754. pguid = &GUID_SYSMAIN_SDB;
  2755. break;
  2756. }
  2757. if (pguid != NULL) {
  2758. if (pGuidDB != NULL) {
  2759. RtlCopyMemory(pGuidDB, pguid, sizeof(*pGuidDB));
  2760. }
  2761. return TRUE;
  2762. }
  2763. return FALSE;
  2764. }
  2765. DWORD
  2766. SdbpGetStandardDatabasePath(
  2767. IN HSDB hSDB,
  2768. IN DWORD dwDatabaseType,
  2769. IN DWORD dwFlags, // specify HID_DOS_PATHS for dos paths
  2770. OUT LPTSTR pszDatabasePath,
  2771. IN DWORD dwBufferSize // in tchars
  2772. )
  2773. {
  2774. PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
  2775. TCHAR szAppPatch[MAX_PATH];
  2776. LPCTSTR pszDatabase = NULL;
  2777. LPCTSTR pszDir = NULL;
  2778. LCID lcid;
  2779. int nLen;
  2780. size_t cchRemaining;
  2781. if (dwFlags & HID_DOS_PATHS) {
  2782. SdbpGetAppPatchDir(hSDB, szAppPatch, CHARCOUNT(szAppPatch));
  2783. } else {
  2784. if (pContext && pContext->uExeType == IMAGE_FILE_MACHINE_IA64) {
  2785. StringCchCopy(szAppPatch,
  2786. CHARCOUNT(szAppPatch),
  2787. TEXT("\\SystemRoot\\AppPatch\\IA64"));
  2788. } else {
  2789. StringCchCopy(szAppPatch,
  2790. CHARCOUNT(szAppPatch),
  2791. TEXT("\\SystemRoot\\AppPatch"));
  2792. }
  2793. }
  2794. if (!(dwDatabaseType & SDB_DATABASE_MAIN)) { // cannot get it for non-main d
  2795. return 0;
  2796. }
  2797. pszDir = szAppPatch;
  2798. switch (dwDatabaseType & SDB_DATABASE_TYPE_MASK) {
  2799. case SDB_DATABASE_MAIN_DRIVERS:
  2800. pszDatabase = TEXT("drvmain.sdb");
  2801. break;
  2802. case SDB_DATABASE_MAIN_MSI:
  2803. pszDatabase = TEXT("msimain.sdb");
  2804. break;
  2805. case SDB_DATABASE_MAIN_SHIM:
  2806. pszDatabase = TEXT("sysmain.sdb");
  2807. break;
  2808. case SDB_DATABASE_MAIN_TEST:
  2809. pszDatabase = TEXT("systest.sdb");
  2810. break;
  2811. case SDB_DATABASE_MAIN_DETAILS:
  2812. //
  2813. // The code below is not operational on nt4 yet. It would prevent sdbapiu from
  2814. // working properly as GetUserDefaultUILanguage does not exist.
  2815. //
  2816. #ifndef WIN32U_MODE
  2817. lcid = GetUserDefaultUILanguage();
  2818. if (lcid != MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)) {
  2819. BOOL bFoundDB = FALSE;
  2820. TCHAR szTemp[MAX_PATH];
  2821. //
  2822. // When doing this, always remember which apppatch we are putting up here
  2823. // we need to form our own private apppatch
  2824. //
  2825. StringCchPrintfEx(szTemp,
  2826. CHARCOUNT(szTemp),
  2827. NULL,
  2828. &cchRemaining,
  2829. 0,
  2830. TEXT("%s\\MUI\\%04x\\apphelp.sdb"),
  2831. szAppPatch,
  2832. lcid);
  2833. nLen = CHARCOUNT(szTemp) - (int)cchRemaining;
  2834. if (nLen > 0) {
  2835. if (dwFlags & HID_DOS_PATHS) {
  2836. bFoundDB = RtlDoesFileExists_U(szTemp);
  2837. } else {
  2838. bFoundDB = SdbpDoesFileExistNTPath(szTemp);
  2839. }
  2840. }
  2841. if (bFoundDB) {
  2842. StringCchPrintf(szTemp, CHARCOUNT(szTemp), TEXT("MUI\\%04x\\apphelp.sdb"), lcid);
  2843. pszDatabase = szTemp;
  2844. }
  2845. }
  2846. #else
  2847. UNREFERENCED_PARAMETER(lcid);
  2848. #endif
  2849. if (pszDatabase == NULL) {
  2850. //
  2851. // Standard case
  2852. //
  2853. pszDatabase = TEXT("apphelp.sdb");
  2854. }
  2855. break;
  2856. }
  2857. if (pszDatabase == NULL) {
  2858. DBGPRINT((sdlError,
  2859. "SdbpGetStandardDatabasePath",
  2860. "Cannot get the path for database type 0x%lx\n",
  2861. dwDatabaseType));
  2862. return 0;
  2863. }
  2864. if (pszDatabasePath != NULL) {
  2865. StringCchPrintfEx(pszDatabasePath,
  2866. (int)dwBufferSize,
  2867. NULL,
  2868. &cchRemaining,
  2869. 0,
  2870. TEXT("%s\\%s"),
  2871. pszDir,
  2872. pszDatabase);
  2873. nLen = (int)dwBufferSize - (int)cchRemaining;
  2874. } else {
  2875. nLen = -1;
  2876. }
  2877. if (nLen < 0) {
  2878. if (pszDatabasePath != NULL) {
  2879. DBGPRINT((sdlError, "SdbpGetStandardDatabasePath", "Path is too long\n"));
  2880. }
  2881. //
  2882. // Calc expected length. One for term null char and one for "\\" ...
  2883. //
  2884. nLen = (pszDir == NULL ? 0 : (int)_tclen(pszDir)) + (int)_tcslen(pszDatabase) + 1 + 1;
  2885. }
  2886. return (DWORD)nLen;
  2887. }
  2888. DWORD
  2889. SDBAPI
  2890. SdbResolveDatabase(
  2891. IN HSDB hSDB,
  2892. IN GUID* pguidDB, // pointer to the database guid to resolve
  2893. OUT LPDWORD lpdwDatabaseType, // optional pointer to the database type
  2894. OUT LPTSTR pszDatabasePath, // optional pointer to the database path
  2895. IN DWORD dwBufferSize // size of the buffer pszDatabasePath
  2896. )
  2897. {
  2898. WCHAR wszFullKey[MAX_PATH];
  2899. UNICODE_STRING ustrFullKey;
  2900. UNICODE_STRING ustrKey;
  2901. UNICODE_STRING ustrPath;
  2902. NTSTATUS Status;
  2903. OBJECT_ATTRIBUTES ObjectAttributes;
  2904. HANDLE KeyHandle = NULL;
  2905. ULONG KeyValueBuffer[MAX_PATH];
  2906. ULONG KeyValueLength = 0;
  2907. ULONG PathValueLength = 0; // this is return result
  2908. DWORD dwDatabaseType = 0;
  2909. int i;
  2910. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  2911. static struct tagSTDGUIDSDB {
  2912. const GUID* pGuid;
  2913. DWORD dwDatabaseType;
  2914. } guidStd[] = {
  2915. { &GUID_SYSMAIN_SDB, SDB_DATABASE_MAIN_SHIM },
  2916. { &GUID_MSIMAIN_SDB, SDB_DATABASE_MAIN_MSI },
  2917. { &GUID_DRVMAIN_SDB, SDB_DATABASE_MAIN_DRIVERS },
  2918. { &GUID_APPHELP_SDB, SDB_DATABASE_MAIN_DETAILS },
  2919. { &GUID_SYSTEST_SDB, SDB_DATABASE_MAIN_TEST }
  2920. };
  2921. for (i = 0; i < ARRAYSIZE(guidStd); ++i) {
  2922. if (!memcmp(guidStd[i].pGuid, pguidDB, sizeof(GUID))) {
  2923. dwDatabaseType = guidStd[i].dwDatabaseType;
  2924. break;
  2925. }
  2926. }
  2927. if (i < ARRAYSIZE(guidStd)) {
  2928. DWORD dwLen;
  2929. dwLen = SdbpGetStandardDatabasePath(hSDB,
  2930. dwDatabaseType,
  2931. HID_DOS_PATHS,
  2932. pszDatabasePath,
  2933. dwBufferSize);
  2934. if (lpdwDatabaseType != NULL) {
  2935. *lpdwDatabaseType = dwDatabaseType;
  2936. }
  2937. return dwLen;
  2938. }
  2939. ustrFullKey.Buffer = wszFullKey;
  2940. ustrFullKey.MaximumLength = sizeof(wszFullKey);
  2941. ustrFullKey.Length = 0;
  2942. RtlAppendUnicodeToString(&ustrFullKey, APPCOMPAT_KEY_PATH_MACHINE_INSTALLEDSDB);
  2943. RtlAppendUnicodeToString(&ustrFullKey, L"\\");
  2944. Status = GUID_TO_UNICODE_STRING(pguidDB, &ustrKey);
  2945. if (!NT_SUCCESS(Status)) {
  2946. DBGPRINT((sdlError,
  2947. "SdbResolveDatabase",
  2948. "Failed to convert guid to string status 0x%lx\n",
  2949. Status));
  2950. goto HandleError; // 0 means error
  2951. }
  2952. RtlAppendUnicodeStringToString(&ustrFullKey, &ustrKey);
  2953. FREE_GUID_STRING(&ustrKey);
  2954. InitializeObjectAttributes(&ObjectAttributes,
  2955. &ustrFullKey,
  2956. OBJ_CASE_INSENSITIVE,
  2957. NULL,
  2958. NULL);
  2959. Status = NtOpenKey(&KeyHandle, GENERIC_READ|SdbpGetWow64Flag(), &ObjectAttributes);
  2960. if (!NT_SUCCESS(Status)) {
  2961. DBGPRINT((sdlError,
  2962. "SdbResolveDatabase",
  2963. "Failed to open Key \"%s\" Status 0x%lx\n",
  2964. ustrFullKey.Buffer,
  2965. Status));
  2966. goto HandleError;
  2967. }
  2968. //
  2969. // Now since we were able to open the key -- database was found, recover path and type
  2970. //
  2971. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
  2972. Status = NtQueryValueKey(KeyHandle,
  2973. (PUNICODE_STRING)&g_ustrDatabasePath,
  2974. KeyValuePartialInformation,
  2975. KeyValueInformation,
  2976. sizeof(KeyValueBuffer),
  2977. &KeyValueLength);
  2978. if (!NT_SUCCESS(Status)) {
  2979. DBGPRINT((sdlError,
  2980. "SdbResolveDatabase",
  2981. "Failed trying to query value \"%s\" Status 0x%lx\n",
  2982. g_ustrDatabasePath.Buffer,
  2983. Status));
  2984. goto HandleError;
  2985. }
  2986. switch (KeyValueInformation->Type) {
  2987. case REG_SZ:
  2988. PathValueLength = KeyValueInformation->DataLength;
  2989. if (pszDatabasePath == NULL || dwBufferSize * sizeof(WCHAR) < PathValueLength) {
  2990. DBGPRINT((sdlWarning,
  2991. "SdbResolveDatabase",
  2992. "Insufficient buffer for the database path\n"));
  2993. goto HandleError;
  2994. }
  2995. RtlMoveMemory(pszDatabasePath, KeyValueInformation->Data, PathValueLength);
  2996. break;
  2997. case REG_EXPAND_SZ:
  2998. ustrKey.Buffer = (PWSTR)&KeyValueInformation->Data;
  2999. ustrKey.Length = (USHORT)(KeyValueInformation->DataLength - sizeof(UNICODE_NULL));
  3000. ustrKey.MaximumLength = (USHORT)KeyValueInformation->DataLength;
  3001. ustrPath.Buffer = pszDatabasePath;
  3002. ustrPath.Length = 0;
  3003. ustrPath.MaximumLength = (USHORT)(dwBufferSize * sizeof(WCHAR));
  3004. Status = RtlExpandEnvironmentStrings_U(NULL, &ustrKey, &ustrPath, &PathValueLength);
  3005. if (Status == STATUS_BUFFER_TOO_SMALL) {
  3006. DBGPRINT((sdlWarning, "SdbResolveDatabase", "Insufficient buffer to expand path\n"));
  3007. goto HandleError;
  3008. }
  3009. if (!NT_SUCCESS(Status)) {
  3010. PathValueLength = 0;
  3011. }
  3012. break;
  3013. default:
  3014. DBGPRINT((sdlError,
  3015. "SdbResolveDatabase",
  3016. "Wrong key type 0x%lx\n",
  3017. KeyValueInformation->Type));
  3018. PathValueLength = 0;
  3019. goto HandleError;
  3020. break;
  3021. }
  3022. if (lpdwDatabaseType != NULL) {
  3023. //
  3024. // Query for the database type
  3025. //
  3026. Status = NtQueryValueKey(KeyHandle,
  3027. (PUNICODE_STRING)&g_ustrDatabaseType,
  3028. KeyValuePartialInformation,
  3029. KeyValueInformation,
  3030. sizeof(KeyValueBuffer),
  3031. &KeyValueLength);
  3032. if (NT_SUCCESS(Status)) {
  3033. if (KeyValueInformation->Type != REG_DWORD) {
  3034. //
  3035. // bummer, get out -- wrong type
  3036. //
  3037. DBGPRINT((sdlError,
  3038. "SdbResolveDatabase",
  3039. "Wrong database type - value type 0x%lx\n",
  3040. KeyValueInformation->Type));
  3041. PathValueLength = 0;
  3042. goto HandleError;
  3043. }
  3044. //
  3045. // Else, we get the value
  3046. //
  3047. RtlMoveMemory(lpdwDatabaseType, &KeyValueInformation->Data, sizeof(*lpdwDatabaseType));
  3048. } else {
  3049. *lpdwDatabaseType = 0; // we do not have any value then
  3050. }
  3051. }
  3052. HandleError:
  3053. if (KeyHandle != NULL) {
  3054. NtClose(KeyHandle);
  3055. }
  3056. return PathValueLength / sizeof(WCHAR);
  3057. }
  3058. LPTSTR
  3059. SDBAPI
  3060. SdbGetLayerName(
  3061. IN HSDB hSDB,
  3062. IN TAGREF trLayer
  3063. )
  3064. /*++
  3065. Return: BUGBUG
  3066. Desc: BUGBUG
  3067. --*/
  3068. {
  3069. PDB pdb;
  3070. TAGID tiLayer, tiName;
  3071. LPTSTR pwszName;
  3072. if (!SdbTagRefToTagID(hSDB, trLayer, &pdb, &tiLayer)) {
  3073. DBGPRINT((sdlError,
  3074. "SdbGetLayerName",
  3075. "Failed to get tag id from tag ref 0x%lx\n",
  3076. trLayer));
  3077. return NULL;
  3078. }
  3079. tiName = SdbFindFirstTag(pdb, tiLayer, TAG_NAME);
  3080. if (tiName == TAGID_NULL) {
  3081. DBGPRINT((sdlError,
  3082. "SdbGetLayerName",
  3083. "Failed to get the name tag id for 0x%lx\n",
  3084. tiName));
  3085. return NULL;
  3086. }
  3087. pwszName = SdbGetStringTagPtr(pdb, tiName);
  3088. if (pwszName == NULL) {
  3089. DBGPRINT((sdlError,
  3090. "SdbGetLayerName",
  3091. "Cannot read the name of the layer tag id 0x%lx\n",
  3092. tiName));
  3093. }
  3094. return pwszName;
  3095. }
  3096. /*++
  3097. SdbBuildComapatEnvVar
  3098. This function builds the environment variable necessary for
  3099. Compat Layer propagation
  3100. --*/
  3101. DWORD
  3102. SDBAPI
  3103. SdbBuildCompatEnvVariables(
  3104. IN HSDB hSDB,
  3105. IN SDBQUERYRESULT* psdbQuery,
  3106. IN DWORD dwFlags,
  3107. IN LPCWSTR pwszParentEnv OPTIONAL, // environment which contains vars
  3108. // that we shall inherit from
  3109. OUT LPWSTR pBuffer,
  3110. IN DWORD cchSize, // size of the buffer in tchars
  3111. OUT LPDWORD lpdwShimsCount OPTIONAL
  3112. )
  3113. {
  3114. int i;
  3115. TCHAR szFullEnvVar[MAX_PATH];
  3116. TAGREF trShimRef;
  3117. INT nCountLayers = 0;
  3118. DWORD dwSizeRequired;
  3119. size_t cchRemaining;
  3120. //
  3121. // Count the DLLs that trLayer uses, and put together the environment variable
  3122. //
  3123. szFullEnvVar[0] = TEXT('\0');
  3124. //
  3125. // Make sure to propagate the flags.
  3126. //
  3127. if (!(dwFlags & SBCE_ADDITIVE)) {
  3128. StringCchCat(szFullEnvVar, CHARCOUNT(szFullEnvVar), TEXT("!"));
  3129. }
  3130. if (dwFlags & SBCE_INCLUDESYSTEMEXES) {
  3131. StringCchCat(szFullEnvVar, CHARCOUNT(szFullEnvVar), TEXT("#"));
  3132. }
  3133. for (i = 0; i < SDB_MAX_LAYERS && psdbQuery->atrLayers[i] != TAGREF_NULL; ++i) {
  3134. WCHAR* pszEnvVar;
  3135. //
  3136. // Get the environment var and tack it onto the full string
  3137. //
  3138. pszEnvVar = SdbGetLayerName(hSDB, psdbQuery->atrLayers[i]);
  3139. if (pszEnvVar) {
  3140. if (nCountLayers) {
  3141. StringCchCat(szFullEnvVar, CHARCOUNT(szFullEnvVar), TEXT(" "));
  3142. }
  3143. ++nCountLayers;
  3144. StringCchCat(szFullEnvVar, CHARCOUNT(szFullEnvVar), pszEnvVar);
  3145. }
  3146. if (lpdwShimsCount != NULL) {
  3147. //
  3148. // Keep counting the dlls.
  3149. //
  3150. trShimRef = SdbFindFirstTagRef(hSDB, psdbQuery->atrLayers[i], TAG_SHIM_REF);
  3151. while (trShimRef != TAGREF_NULL) {
  3152. (*lpdwShimsCount)++;
  3153. trShimRef = SdbFindNextTagRef(hSDB, psdbQuery->atrLayers[i], trShimRef);
  3154. }
  3155. }
  3156. }
  3157. dwSizeRequired = (DWORD)(_tcslen(szFullEnvVar) + _tcslen(g_szCompatLayer) + 3);
  3158. if (cchSize < dwSizeRequired || pBuffer == NULL) {
  3159. //
  3160. // need g_szCompatLayer + '=' + \0 + szFullEnvVar space in the buffer
  3161. //
  3162. return dwSizeRequired;
  3163. }
  3164. StringCchPrintfEx(pBuffer,
  3165. cchSize,
  3166. NULL,
  3167. &cchRemaining,
  3168. 0,
  3169. TEXT("%s=%s%c"),
  3170. g_szCompatLayer,
  3171. szFullEnvVar,
  3172. TEXT('\0'));
  3173. return (DWORD)cchSize - (int)cchRemaining;
  3174. UNREFERENCED_PARAMETER(pwszParentEnv);
  3175. }
  3176. DWORD
  3177. SdbpGetProcessorArchitecture(
  3178. IN USHORT uExeType // executable's image type
  3179. )
  3180. {
  3181. static DWORD dwProcessorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
  3182. SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
  3183. NTSTATUS Status;
  3184. if (dwProcessorArchitecture == PROCESSOR_ARCHITECTURE_UNKNOWN) {
  3185. Status = NtQuerySystemInformation(SystemProcessorInformation,
  3186. &ProcessorInfo,
  3187. sizeof(ProcessorInfo),
  3188. NULL);
  3189. if (!NT_SUCCESS(Status)) {
  3190. DBGPRINT((sdlError,
  3191. "SdbpGetProcessorArchitecture",
  3192. "Failed to obtain system processor information 0x%lx\n",
  3193. Status));
  3194. goto Cleanup;
  3195. }
  3196. dwProcessorArchitecture = ProcessorInfo.ProcessorArchitecture;
  3197. }
  3198. //
  3199. // if we are running under WOW64 we would have right now
  3200. // PROCESSOR_ARCHITECTURE_INTEL
  3201. // if we are running 64-bit code we'd have now PROCESSOR_ARCHITECTURE_*
  3202. // as a result to determine further course of actions, we need to consider
  3203. // dynamically finding out whether we are running native code or not
  3204. // if we have an image type that we're checking -- there is no problem since
  3205. // we just check the image type and we're done, MSI case however is different
  3206. //
  3207. if (dwProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 ||
  3208. dwProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
  3209. dwProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA64) {
  3210. if (uExeType == IMAGE_FILE_MACHINE_I386) {
  3211. return PROCESSOR_ARCHITECTURE_IA32_ON_WIN64;
  3212. }
  3213. } else if (dwProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL && uExeType == IMAGE_FILE_MSI) {
  3214. //
  3215. // determine dynamically what kind of code we're running
  3216. //
  3217. PVOID Wow64Info = NULL;
  3218. Status = NtQueryInformationProcess(NtCurrentProcess(),
  3219. ProcessWow64Information,
  3220. &Wow64Info,
  3221. sizeof(Wow64Info),
  3222. NULL);
  3223. if (NT_SUCCESS(Status) && Wow64Info != NULL) {
  3224. return PROCESSOR_ARCHITECTURE_IA32_ON_WIN64;
  3225. }
  3226. }
  3227. Cleanup:
  3228. return dwProcessorArchitecture;
  3229. }
  3230. #define FULL_TABLETPC_KEY_PATH KEY_MACHINE TEXT("\\") TABLETPC_KEY_PATH
  3231. #define FULL_EHOME_KEY_PATH KEY_MACHINE TEXT("\\") EHOME_KEY_PATH
  3232. BOOL
  3233. SdbpIsOs(
  3234. DWORD dwOSSKU
  3235. )
  3236. {
  3237. BOOL bRet = FALSE;
  3238. UNICODE_STRING ustrKeyPath = {0};
  3239. UNICODE_STRING ustrValue;
  3240. NTSTATUS status;
  3241. OBJECT_ATTRIBUTES ObjectAttributes;
  3242. HANDLE KeyHandle;
  3243. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  3244. ULONG KeyValueBuffer[64];
  3245. ULONG KeyValueLength;
  3246. if (dwOSSKU == OS_SKU_TAB) {
  3247. RtlInitUnicodeString(&ustrKeyPath, FULL_TABLETPC_KEY_PATH);
  3248. } else if (dwOSSKU == OS_SKU_MED) {
  3249. RtlInitUnicodeString(&ustrKeyPath, FULL_EHOME_KEY_PATH);
  3250. } else {
  3251. DBGPRINT((sdlWarning,
  3252. "SdbpIsOs",
  3253. "Specified unknown OS type 0x%lx",
  3254. dwOSSKU));
  3255. return FALSE;
  3256. }
  3257. InitializeObjectAttributes(
  3258. &ObjectAttributes,
  3259. &ustrKeyPath,
  3260. OBJ_CASE_INSENSITIVE,
  3261. NULL,
  3262. NULL);
  3263. status = NtOpenKey(
  3264. &KeyHandle,
  3265. KEY_QUERY_VALUE | SdbpGetWow64Flag(),
  3266. &ObjectAttributes);
  3267. if (!NT_SUCCESS(status)) {
  3268. DBGPRINT((sdlWarning,
  3269. "SdbpIsOs",
  3270. "Failed to open Key %s Status 0x%lx",
  3271. ustrKeyPath.Buffer,
  3272. status));
  3273. goto out;
  3274. }
  3275. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyValueBuffer;
  3276. RtlInitUnicodeString(&ustrValue, IS_OS_INSTALL_VALUE);
  3277. status = NtQueryValueKey(
  3278. KeyHandle,
  3279. &ustrValue,
  3280. KeyValuePartialInformation,
  3281. KeyValueInformation,
  3282. sizeof(KeyValueBuffer),
  3283. &KeyValueLength);
  3284. NtClose(KeyHandle);
  3285. if (!NT_SUCCESS(status)) {
  3286. DBGPRINT((sdlWarning,
  3287. "SdbpIsOs",
  3288. "Failed to read value info for value %s for key %s Status 0x%lx",
  3289. IS_OS_INSTALL_VALUE,
  3290. ustrKeyPath.Buffer,
  3291. status));
  3292. goto out;
  3293. }
  3294. if (KeyValueInformation->Type != REG_DWORD) {
  3295. DBGPRINT((sdlWarning,
  3296. "SdbpIsOs",
  3297. "Unexpected value type 0x%x for value %s under key %s",
  3298. KeyValueInformation->Type,
  3299. IS_OS_INSTALL_VALUE,
  3300. ustrKeyPath.Buffer));
  3301. goto out;
  3302. }
  3303. if (*(DWORD*)(&KeyValueInformation->Data[0]) != 0) {
  3304. bRet = TRUE;
  3305. }
  3306. DBGPRINT((sdlInfo|sdlLogShimViewer,
  3307. "SdbpIsOs",
  3308. "%s %s installed",
  3309. 0,
  3310. (dwOSSKU == OS_SKU_TAB ? TEXT("TabletPC") : TEXT("eHome")),
  3311. (bRet ? TEXT("is") : TEXT("is not"))));
  3312. out:
  3313. return bRet;
  3314. }
  3315. void
  3316. SdbpGetOSSKU(
  3317. LPDWORD lpdwSKU,
  3318. LPDWORD lpdwSP
  3319. )
  3320. {
  3321. WORD wServicePackMajor;
  3322. WORD wSuiteMask;
  3323. WORD wProductType;
  3324. PPEB Peb = NtCurrentPeb();
  3325. wServicePackMajor = (Peb->OSCSDVersion >> 8) & 0xFF;
  3326. wSuiteMask = (USHORT)(USER_SHARED_DATA->SuiteMask & 0xffff);
  3327. *lpdwSP = 1 << wServicePackMajor;
  3328. wSuiteMask = wSuiteMask;
  3329. wProductType = USER_SHARED_DATA->NtProductType;
  3330. if (wProductType == VER_NT_WORKSTATION) {
  3331. if (wSuiteMask & VER_SUITE_PERSONAL) {
  3332. *lpdwSKU = OS_SKU_PER;
  3333. } else {
  3334. #if (_WIN32_WINNT >= 0x0501)
  3335. if (SdbpIsOs(OS_SKU_TAB)) {
  3336. *lpdwSKU = OS_SKU_TAB;
  3337. } else if (SdbpIsOs(OS_SKU_MED)) {
  3338. *lpdwSKU = OS_SKU_MED;
  3339. } else {
  3340. *lpdwSKU = OS_SKU_PRO;
  3341. }
  3342. #else
  3343. *lpdwSKU = OS_SKU_PRO;
  3344. #endif
  3345. }
  3346. return;
  3347. }
  3348. if (wSuiteMask & VER_SUITE_DATACENTER) {
  3349. *lpdwSKU = OS_SKU_DTC;
  3350. return;
  3351. }
  3352. if (wSuiteMask & VER_SUITE_ENTERPRISE) {
  3353. *lpdwSKU = OS_SKU_ADS;
  3354. return;
  3355. }
  3356. if (wSuiteMask & VER_SUITE_BLADE) {
  3357. *lpdwSKU = OS_SKU_BLA;
  3358. return;
  3359. }
  3360. if (wSuiteMask & VER_SUITE_SMALLBUSINESS) {
  3361. *lpdwSKU = OS_SKU_SBS;
  3362. return;
  3363. }
  3364. *lpdwSKU = OS_SKU_SRV;
  3365. }
  3366. DWORD
  3367. SdbpGetWow64Flag(
  3368. VOID
  3369. )
  3370. {
  3371. if (g_dwWow64Key == (DWORD)-1) {
  3372. OSVERSIONINFOEXW osvi;
  3373. BOOL bSuccess;
  3374. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
  3375. #ifdef WIN32U_MODE
  3376. bSuccess = GetVersionExW((POSVERSIONINFOW)&osvi);
  3377. #else
  3378. bSuccess = NT_SUCCESS(RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi));
  3379. #endif
  3380. if (bSuccess) {
  3381. //
  3382. // Straight win2k
  3383. //
  3384. if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
  3385. g_dwWow64Key = 0; // no flag since there is no wow64 on win2k
  3386. } else {
  3387. g_dwWow64Key = KEY_WOW64_64KEY;
  3388. }
  3389. } else {
  3390. DBGPRINT((sdlError, "SdbGetWow64Flag", "RtlGetVersion failed\n"));
  3391. //
  3392. // XP or higher.
  3393. //
  3394. g_dwWow64Key = KEY_WOW64_64KEY;
  3395. }
  3396. }
  3397. return g_dwWow64Key;
  3398. }
  3399. NTSTATUS
  3400. SDBAPI
  3401. SdbEnsureBufferSizeFunction(
  3402. IN ULONG Flags,
  3403. IN OUT PRTL_BUFFER Buffer,
  3404. IN SIZE_T Size
  3405. )
  3406. {
  3407. HANDLE ModuleHandle;
  3408. UNICODE_STRING ModuleName = RTL_CONSTANT_STRING(L"ntdll.dll");
  3409. STRING ProcedureName = RTL_CONSTANT_STRING("RtlpEnsureBufferSize");
  3410. NTSTATUS Status;
  3411. ULONG DllCharacteristics = IMAGE_FILE_SYSTEM;
  3412. if (g_pfnEnsureBufferSize == NULL) {
  3413. Status = LdrGetDllHandle(NULL,
  3414. &DllCharacteristics,
  3415. &ModuleName,
  3416. (PVOID)&ModuleHandle);
  3417. if (!NT_SUCCESS(Status)) {
  3418. DBGPRINT((sdlError,
  3419. "SdbEnsureBufferSizeFunction",
  3420. "Failed to retrieve ntdll.dll module handle, Error 0x%lx\n",
  3421. Status));
  3422. return Status;
  3423. }
  3424. Status = LdrGetProcedureAddress(ModuleHandle,
  3425. &ProcedureName,
  3426. 0,
  3427. (PVOID*)&g_pfnEnsureBufferSize);
  3428. if (!NT_SUCCESS(Status)) {
  3429. DBGPRINT((sdlError,
  3430. "SdbEnsureBufferSizeFunction",
  3431. "RtlpEnsureBufferSize is not available, reverting to sdbapi\n"));
  3432. g_pfnEnsureBufferSize = SdbpEnsureBufferSize;
  3433. }
  3434. }
  3435. return g_pfnEnsureBufferSize(Flags, Buffer, Size);
  3436. }
  3437. BOOL
  3438. SdbpWriteToShimViewer(
  3439. HSDB hSDB,
  3440. LPCSTR pszBuffer
  3441. )
  3442. {
  3443. ANSI_STRING strMessage;
  3444. UNICODE_STRING ustrMessage;
  3445. WCHAR pwszFullMessageBuffer[SHIMVIEWER_DATA_SIZE];
  3446. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  3447. PCHAR pchStart;
  3448. PCHAR pch;
  3449. PWCHAR pwch;
  3450. UNREFERENCED_PARAMETER(hSDB);
  3451. if (g_eShimViewerOption != SHIMVIEWER_OPTION_YES || pszBuffer == NULL) {
  3452. return FALSE;
  3453. }
  3454. StringCchCopy(pwszFullMessageBuffer, SHIMVIEWER_DATA_SIZE, SHIMVIEWER_DATA_PREFIX);
  3455. //
  3456. // Preprocess the string to eliminate any \t \r \n
  3457. //
  3458. pchStart = (PCHAR)pszBuffer;
  3459. while (pchStart != NULL && *pchStart) {
  3460. //
  3461. // Skip over white space and any empty lines
  3462. //
  3463. pchStart += strspn(pchStart, " \t\r\n");
  3464. pch = strpbrk(pchStart, "\r\n");
  3465. if (pch == NULL) {
  3466. RtlInitAnsiString(&strMessage, pchStart);
  3467. pchStart = NULL;
  3468. } else {
  3469. //
  3470. // if it's a tab, nuke it by replacing it with ' '
  3471. //
  3472. strMessage.Buffer = pchStart;
  3473. strMessage.MaximumLength =
  3474. strMessage.Length = (USHORT)((DWORD_PTR)pch - (DWORD_PTR)pchStart); // size in bytes
  3475. //
  3476. // now adjust the pointer past \r\n
  3477. //
  3478. pchStart = pch + strspn(pch, "\r\n");
  3479. }
  3480. if (strMessage.Length == 0) {
  3481. continue;
  3482. }
  3483. Status = RtlAnsiStringToUnicodeString(&ustrMessage, &strMessage, TRUE);
  3484. if (!NT_SUCCESS(Status)) {
  3485. DBGPRINT((sdlWarning,
  3486. "SdbpWriteToShimViewer",
  3487. "Failed to convert string to unicode status 0x%lx\n",
  3488. Status));
  3489. goto cleanup;
  3490. }
  3491. //
  3492. // Second line of defense against rogue chars in shimviewer.
  3493. // Search and replace all instances of '\t' with ' '
  3494. //
  3495. pwch = ustrMessage.Buffer;
  3496. while (pwch != NULL && *pwch) {
  3497. pwch = wcschr(pwch, L'\t');
  3498. if (pwch != NULL) {
  3499. *pwch++ = L' ';
  3500. }
  3501. }
  3502. //
  3503. // Send the spew to shimviewer.
  3504. //
  3505. pwszFullMessageBuffer[SHIMVIEWER_DATA_PREFIX_LEN] = 0;
  3506. StringCchCat(pwszFullMessageBuffer, SHIMVIEWER_DATA_SIZE, ustrMessage.Buffer);
  3507. RtlFreeUnicodeString(&ustrMessage);
  3508. OutputDebugStringW(pwszFullMessageBuffer);
  3509. }
  3510. cleanup:
  3511. return NT_SUCCESS(Status);
  3512. }
  3513. #pragma warning(disable:4101) // we do this to cover up for a bug in RtlInitUnicodeStringBuffer
  3514. void
  3515. SdbpRtlInitUnicodeStringBuffer(
  3516. RTL_UNICODE_STRING_BUFFER* pBuff,
  3517. UCHAR* StatBuff,
  3518. SIZE_T StatSize
  3519. )
  3520. {
  3521. RtlInitUnicodeStringBuffer(pBuff, StatBuff, StatSize);
  3522. }
  3523. #pragma warning(default:4101)