Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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