Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

876 lines
23 KiB

  1. /*
  2. Cache handling functions for use in kernel32.dll
  3. VadimB
  4. */
  5. #include "basedll.h"
  6. #include "ahcache.h"
  7. #pragma hdrstop
  8. #ifdef DbgPrint
  9. #undef DbgPrint
  10. #endif
  11. //
  12. //
  13. //
  14. #define DbgPrint 0 && DbgPrint
  15. //
  16. // the define below makes for additional checks
  17. //
  18. // #define DBG_CHK
  19. //
  20. // so that we do not handle exceptions
  21. //
  22. #define NO_EXCEPTION_HANDLING
  23. #if 0 // moved to kernel mode
  24. #define APPCOMPAT_CACHE_KEY_NAME \
  25. L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility"
  26. #define APPCOMPAT_CACHE_VALUE_NAME \
  27. L"AppCompatCache"
  28. #endif
  29. static UNICODE_STRING AppcompatKeyPathLayers =
  30. RTL_CONSTANT_STRING(L"\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
  31. static UNICODE_STRING AppcompatKeyPathCustom =
  32. RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Custom\\");
  33. //
  34. // Reasons for having to call into apphelp.dll
  35. // these flags are also defined in apphelp.h (windows\appcompat\apphelp)
  36. //
  37. #ifndef SHIM_CACHE_NOT_FOUND
  38. #define SHIM_CACHE_NOT_FOUND 0x00000001
  39. #define SHIM_CACHE_BYPASS 0x00000002 // bypass cache (either removable media or temp dir)
  40. #define SHIM_CACHE_LAYER_ENV 0x00000004 // layer env variable set
  41. #define SHIM_CACHE_MEDIA 0x00000008
  42. #define SHIM_CACHE_TEMP 0x00000010
  43. #define SHIM_CACHE_NOTAVAIL 0x00000020
  44. #endif
  45. //
  46. // global strings that we check to see if an exe is running in temp directory
  47. //
  48. UNICODE_STRING gustrWindowsTemp;
  49. UNICODE_STRING gustrSystemdriveTemp;
  50. // this macro aligns a given value on dword boundary, not needed for now
  51. //
  52. // #define ALIGN_DWORD(nSize) (((nSize) + (sizeof(DWORD)-1)) & ~(sizeof(DWORD)-1))
  53. //
  54. // Locally defined functions
  55. //
  56. BOOL
  57. BasepShimCacheInitTempDirs(
  58. VOID
  59. );
  60. BOOL
  61. BasepIsRemovableMedia(
  62. HANDLE FileHandle,
  63. BOOL bCacheNetwork
  64. );
  65. VOID
  66. WINAPI
  67. BaseDumpAppcompatCache(
  68. VOID
  69. );
  70. BOOL
  71. BasepCheckCacheExcludeList(
  72. LPCWSTR pwszPath
  73. );
  74. BOOL
  75. BasepCheckCacheExcludeCustom(
  76. LPCWSTR pwszPath
  77. );
  78. //
  79. // Init support for this user - to be called from WinLogon ONLY
  80. //
  81. BOOL
  82. WINAPI
  83. BaseInitAppcompatCacheSupport(
  84. VOID
  85. )
  86. {
  87. BasepShimCacheInitTempDirs();
  88. return TRUE;
  89. }
  90. BOOL
  91. WINAPI
  92. BaseCleanupAppcompatCacheSupport(
  93. BOOL bWrite
  94. )
  95. {
  96. RtlFreeUnicodeString(&gustrWindowsTemp);
  97. RtlFreeUnicodeString(&gustrSystemdriveTemp);
  98. return TRUE;
  99. }
  100. BOOL
  101. BasepCheckStringPrefixUnicode(
  102. IN PUNICODE_STRING pStrPrefix, // the prefix to check for
  103. IN PUNICODE_STRING pString, // the string
  104. IN BOOL CaseInSensitive
  105. )
  106. /*++
  107. Return: TRUE if the specified string contains pStrPrefix at it's start.
  108. Desc: Verifies if a string is a prefix in another unicode counted string.
  109. It is equivalent to RtlStringPrefix.
  110. --*/
  111. {
  112. PWSTR ps1, ps2;
  113. UINT n;
  114. WCHAR c1, c2;
  115. n = pStrPrefix->Length;
  116. if (pString->Length < n || n == 0) {
  117. return FALSE; // do not prefix with blank strings
  118. }
  119. n /= sizeof(WCHAR); // convert to char count
  120. ps1 = pStrPrefix->Buffer;
  121. ps2 = pString->Buffer;
  122. if (CaseInSensitive) {
  123. while (n--) {
  124. c1 = *ps1++;
  125. c2 = *ps2++;
  126. if (c1 != c2) {
  127. c1 = RtlUpcaseUnicodeChar(c1);
  128. c2 = RtlUpcaseUnicodeChar(c2);
  129. if (c1 != c2) {
  130. return FALSE;
  131. }
  132. }
  133. }
  134. } else {
  135. while (n--) {
  136. if (*ps1++ != *ps2++) {
  137. return FALSE;
  138. }
  139. }
  140. }
  141. return TRUE;
  142. }
  143. BOOL
  144. BasepInitUserTempPath(
  145. PUNICODE_STRING pustrTempPath
  146. )
  147. {
  148. DWORD dwLength;
  149. WCHAR wszBuffer[MAX_PATH];
  150. BOOL TranslationStatus;
  151. BOOL bSuccess = FALSE;
  152. dwLength = BasepGetTempPathW(BASEP_GET_TEMP_PATH_PRESERVE_TEB, sizeof(wszBuffer)/sizeof(wszBuffer[0]), wszBuffer);
  153. if (dwLength && dwLength < sizeof(wszBuffer)/sizeof(wszBuffer[0])) {
  154. TranslationStatus = RtlDosPathNameToNtPathName_U(wszBuffer,
  155. pustrTempPath,
  156. NULL,
  157. NULL);
  158. if (!TranslationStatus) {
  159. DbgPrint("Failed to translate temp directory to nt\n");
  160. }
  161. bSuccess = TranslationStatus;
  162. }
  163. if (!bSuccess) {
  164. DbgPrint("BasepInitUserTempPath: Failed to obtain user's temp path\n");
  165. }
  166. return bSuccess;
  167. }
  168. BOOL
  169. BasepShimCacheInitTempDirs(
  170. VOID
  171. )
  172. {
  173. DWORD dwLength;
  174. WCHAR wszTemp[] = L"\\TEMP";
  175. LPWSTR pwszTemp;
  176. NTSTATUS Status;
  177. UNICODE_STRING ustrSystemDrive;
  178. UNICODE_STRING ustrSystemDriveEnvVarName;
  179. BOOL TranslationStatus;
  180. WCHAR wszBuffer[MAX_PATH];
  181. // next is windows dir
  182. dwLength = GetWindowsDirectoryW(wszBuffer, sizeof(wszBuffer)/sizeof(wszBuffer[0]));
  183. if (dwLength && dwLength < sizeof(wszBuffer)/sizeof(wszBuffer[0])) {
  184. pwszTemp = wszTemp;
  185. if (wszBuffer[dwLength - 1] == L'\\') {
  186. pwszTemp++;
  187. }
  188. wcscpy(&wszBuffer[dwLength], pwszTemp);
  189. TranslationStatus = RtlDosPathNameToNtPathName_U(wszBuffer,
  190. &gustrWindowsTemp,
  191. NULL,
  192. NULL);
  193. if (!TranslationStatus) {
  194. DbgPrint("Failed to translate windows\\temp to nt\n");
  195. }
  196. }
  197. //
  198. // The last one up is Rootdrive\temp for stupid legacy apps.
  199. //
  200. // Especially stupid apps may receive c:\temp as the temp directory
  201. // (what if you don't have drive c, huh?)
  202. //
  203. RtlInitUnicodeString(&ustrSystemDriveEnvVarName, L"SystemDrive");
  204. ustrSystemDrive.Length = 0;
  205. ustrSystemDrive.Buffer = wszBuffer;
  206. ustrSystemDrive.MaximumLength = sizeof(wszBuffer);
  207. Status = RtlQueryEnvironmentVariable_U(NULL,
  208. &ustrSystemDriveEnvVarName,
  209. &ustrSystemDrive);
  210. if (NT_SUCCESS(Status)) {
  211. pwszTemp = wszTemp;
  212. dwLength = ustrSystemDrive.Length / sizeof(WCHAR);
  213. if (wszBuffer[dwLength - 1] == L'\\') {
  214. pwszTemp++;
  215. }
  216. wcscpy(&wszBuffer[dwLength], pwszTemp);
  217. TranslationStatus = RtlDosPathNameToNtPathName_U(wszBuffer,
  218. &gustrSystemdriveTemp,
  219. NULL,
  220. NULL);
  221. if (!TranslationStatus) {
  222. DbgPrint("Failed to translate windows\\temp to nt\n");
  223. }
  224. }
  225. DbgPrint("BasepShimCacheInitTempDirs: Temporary Windows Dir: %S\n", gustrWindowsTemp.Buffer != NULL ? gustrWindowsTemp.Buffer : L"");
  226. DbgPrint("BasepShimCacheInitTempDirs: Temporary SystedDrive: %S\n", gustrSystemdriveTemp.Buffer != NULL ? gustrSystemdriveTemp.Buffer : L"");
  227. return TRUE;
  228. }
  229. BOOL
  230. BasepShimCacheCheckBypass(
  231. IN LPCWSTR pwszPath, // the full path to the EXE to be started
  232. IN HANDLE hFile,
  233. IN WCHAR* pEnvironment, // the environment of the starting EXE
  234. IN BOOL bCheckLayer, // should we check the layer too?
  235. OUT DWORD* pdwReason
  236. )
  237. /*++
  238. Return: TRUE if the cache should be bypassed, FALSE otherwise.
  239. Desc: This function checks if any of the conditions to bypass the cache are met.
  240. --*/
  241. {
  242. UNICODE_STRING ustrPath;
  243. PUNICODE_STRING rgp[3];
  244. int i;
  245. NTSTATUS Status;
  246. UNICODE_STRING ustrCompatLayerVarName;
  247. UNICODE_STRING ustrCompatLayer;
  248. BOOL bBypassCache = FALSE;
  249. DWORD dwReason = 0;
  250. UNICODE_STRING ustrUserTempPath = { 0 };
  251. //
  252. // Is the EXE is running from removable media we need to bypass the cache.
  253. //
  254. if (hFile != INVALID_HANDLE_VALUE && BasepIsRemovableMedia(hFile, TRUE)) {
  255. bBypassCache = TRUE;
  256. dwReason |= SHIM_CACHE_MEDIA;
  257. goto CheckLayer;
  258. }
  259. //
  260. // init user's temp path now and get up-to-date one
  261. //
  262. BasepInitUserTempPath(&ustrUserTempPath);
  263. //
  264. // Check now if the EXE is launched from one of the temp directories.
  265. //
  266. RtlInitUnicodeString(&ustrPath, pwszPath);
  267. rgp[0] = &gustrWindowsTemp;
  268. rgp[1] = &ustrUserTempPath;
  269. rgp[2] = &gustrSystemdriveTemp;
  270. for (i = 0; i < sizeof(rgp) / sizeof(rgp[0]); i++) {
  271. if (rgp[i]->Buffer != NULL && BasepCheckStringPrefixUnicode(rgp[i], &ustrPath, TRUE)) {
  272. DbgPrint("Application \"%ls\" is running in temp directory\n", pwszPath);
  273. bBypassCache = TRUE;
  274. dwReason |= SHIM_CACHE_TEMP;
  275. break;
  276. }
  277. }
  278. RtlFreeUnicodeString(&ustrUserTempPath);
  279. CheckLayer:
  280. if (bCheckLayer) {
  281. //
  282. // Check if the __COMPAT_LAYER environment variable is set
  283. //
  284. RtlInitUnicodeString(&ustrCompatLayerVarName, L"__COMPAT_LAYER");
  285. ustrCompatLayer.Length = 0;
  286. ustrCompatLayer.MaximumLength = 0;
  287. ustrCompatLayer.Buffer = NULL;
  288. Status = RtlQueryEnvironmentVariable_U(pEnvironment,
  289. &ustrCompatLayerVarName,
  290. &ustrCompatLayer);
  291. //
  292. // If the Status is STATUS_BUFFER_TOO_SMALL this means the variable is set.
  293. //
  294. if (Status == STATUS_BUFFER_TOO_SMALL) {
  295. dwReason |= SHIM_CACHE_LAYER_ENV;
  296. bBypassCache = TRUE;
  297. }
  298. }
  299. if (pdwReason != NULL) {
  300. *pdwReason = dwReason;
  301. }
  302. return bBypassCache;
  303. }
  304. BOOL
  305. BasepIsRemovableMedia(
  306. HANDLE FileHandle,
  307. BOOL bCacheNetwork
  308. )
  309. /*++
  310. Return: TRUE if the media from where the app is run is removable,
  311. FALSE otherwise.
  312. Desc: Queries the media for being removable.
  313. --*/
  314. {
  315. NTSTATUS Status;
  316. IO_STATUS_BLOCK IoStatusBlock;
  317. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  318. BOOL bRemovable = FALSE;
  319. Status = NtQueryVolumeInformationFile(FileHandle,
  320. &IoStatusBlock,
  321. &DeviceInfo,
  322. sizeof(DeviceInfo),
  323. FileFsDeviceInformation);
  324. if (!NT_SUCCESS(Status)) {
  325. /*
  326. DBGPRINT((sdlError,
  327. "IsRemovableMedia",
  328. "NtQueryVolumeInformationFile Failed 0x%x\n",
  329. Status));
  330. */
  331. DbgPrint("BasepIsRemovableMedia: NtQueryVolumeInformationFile failed 0x%lx\n", Status);
  332. return TRUE;
  333. }
  334. //
  335. // We look at the characteristics of this particular device.
  336. // If the media is cdrom then we DO NOT need to convert to local time
  337. //
  338. bRemovable = (DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA);
  339. if (!bCacheNetwork) {
  340. bRemovable |= (DeviceInfo.Characteristics & FILE_REMOTE_DEVICE);
  341. }
  342. if (!bRemovable) {
  343. //
  344. // Check the device type now.
  345. //
  346. switch (DeviceInfo.DeviceType) {
  347. case FILE_DEVICE_CD_ROM:
  348. case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
  349. bRemovable = TRUE;
  350. break;
  351. case FILE_DEVICE_NETWORK:
  352. case FILE_DEVICE_NETWORK_FILE_SYSTEM:
  353. if (!bCacheNetwork) {
  354. bRemovable = TRUE;
  355. }
  356. break;
  357. }
  358. }
  359. if (bRemovable) {
  360. DbgPrint("BasepIsRemovableMedia: Host device is removable, Shim cache deactivated\n");
  361. /*
  362. DBGPRINT((sdlInfo,
  363. "IsRemovableMedia",
  364. "The host device is removable. Shim cache deactivated for this file\n"));
  365. */
  366. }
  367. return bRemovable;
  368. }
  369. BOOL
  370. BasepShimCacheSearch(
  371. IN LPCWSTR pwszPath,
  372. IN HANDLE FileHandle
  373. )
  374. /*++
  375. Return: TRUE if we have a cache hit, FALSE otherwise.
  376. Desc: Search the cache, return TRUE if we have a cache hit
  377. pIndex will receive an index into the rgIndex array that contains
  378. the entry which has been hit
  379. So that if entry 5 contains the hit, and rgIndexes[3] == 5 then
  380. *pIndex == 3
  381. --*/
  382. {
  383. int nIndex, nEntry;
  384. WCHAR* pCachePath;
  385. BOOL bSuccess;
  386. UNICODE_STRING FileName;
  387. NTSTATUS Status;
  388. AHCACHESERVICEDATA Data;
  389. RtlInitUnicodeString(&Data.FileName, pwszPath);
  390. Data.FileHandle = FileHandle;
  391. Status = NtApphelpCacheControl(ApphelpCacheServiceLookup,
  392. &Data);
  393. return NT_SUCCESS(Status);
  394. }
  395. BOOL
  396. BasepShimCacheRemoveEntry(
  397. IN LPCWSTR pwszPath
  398. )
  399. /*++
  400. Return: TRUE.
  401. Desc: Remove the entry from the cache.
  402. We remove the entry by placing it as the last lru entry
  403. and emptying the path. This routine assumes that the index
  404. passed in is valid.
  405. --*/
  406. {
  407. AHCACHESERVICEDATA Data;
  408. NTSTATUS Status;
  409. RtlInitUnicodeString(&Data.FileName, pwszPath);
  410. Data.FileHandle = INVALID_HANDLE_VALUE;
  411. Status = NtApphelpCacheControl(ApphelpCacheServiceRemove,
  412. &Data);
  413. return NT_SUCCESS(Status);
  414. }
  415. //
  416. // This function is called to search the cache and update the
  417. // entry if found. It will not check for the removable media -- but
  418. // it does check other conditions (update file for instance)
  419. //
  420. BOOL
  421. BasepShimCacheLookup(
  422. LPCWSTR pwszPath,
  423. HANDLE hFile
  424. )
  425. {
  426. NTSTATUS Status;
  427. if (!BasepShimCacheSearch(pwszPath, hFile)) {
  428. return FALSE; // not found, sorry
  429. }
  430. //
  431. // check if this entry has been disallowed
  432. //
  433. if (!BasepCheckCacheExcludeList(pwszPath) || !BasepCheckCacheExcludeCustom(pwszPath)) {
  434. DbgPrint("BasepShimCacheLookup: Entry for %ls was disallowed yet found in cache, cleaning up\n", pwszPath);
  435. BasepShimCacheRemoveEntry(pwszPath);
  436. return FALSE;
  437. }
  438. return TRUE;
  439. }
  440. /*++
  441. Callable functions, with protection, etc
  442. BasepCheckAppcompatCache returns true if an app has been found in cache, no fixes are needed
  443. if BasepCheckAppcompatCache returns false - we will have to call into apphelp.dll to check further
  444. apphelp.dll will then call BasepUpdateAppcompatCache if an app has no fixes to be applied to it
  445. --*/
  446. BOOL
  447. WINAPI
  448. BaseCheckAppcompatCache(
  449. LPCWSTR pwszPath,
  450. HANDLE hFile,
  451. PVOID pEnvironment,
  452. DWORD* pdwReason
  453. )
  454. {
  455. BOOL bFoundInCache = FALSE;
  456. BOOL bLayer = FALSE;
  457. DWORD dwReason = 0;
  458. if (BasepShimCacheCheckBypass(pwszPath, hFile, pEnvironment, TRUE, &dwReason)) {
  459. //
  460. // cache bypass was needed
  461. //
  462. dwReason |= SHIM_CACHE_BYPASS;
  463. DbgPrint("Application \"%S\" Cache bypassed reason 0x%lx\n", pwszPath, dwReason);
  464. goto Exit;
  465. }
  466. bFoundInCache = BasepShimCacheLookup(pwszPath, hFile);
  467. if (!bFoundInCache) {
  468. dwReason |= SHIM_CACHE_NOT_FOUND;
  469. }
  470. if (bFoundInCache) {
  471. DbgPrint("Application \"%S\" found in cache\n", pwszPath);
  472. } else {
  473. DbgPrint("Application \"%S\" not found in cache\n", pwszPath);
  474. }
  475. Exit:
  476. if (pdwReason != NULL) {
  477. *pdwReason = dwReason;
  478. }
  479. return bFoundInCache;
  480. }
  481. //
  482. // returns TRUE if cache is allowed
  483. //
  484. BOOL
  485. BasepCheckCacheExcludeList(
  486. LPCWSTR pwszPath
  487. )
  488. {
  489. NTSTATUS Status;
  490. ULONG ResultLength;
  491. OBJECT_ATTRIBUTES ObjectAttributes;
  492. UNICODE_STRING KeyPathUser = { 0 }; // path to hkcu
  493. UNICODE_STRING ExePathNt; // temp holder
  494. KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  495. RTL_UNICODE_STRING_BUFFER ExePathBuffer; // buffer to store exe path
  496. RTL_UNICODE_STRING_BUFFER KeyNameBuffer;
  497. UCHAR BufferKey[MAX_PATH * 2];
  498. UCHAR BufferPath[MAX_PATH * 2];
  499. HANDLE KeyHandle = NULL;
  500. BOOL bCacheAllowed = FALSE;
  501. RtlInitUnicodeStringBuffer(&ExePathBuffer, BufferPath, sizeof(BufferPath));
  502. RtlInitUnicodeStringBuffer(&KeyNameBuffer, BufferKey, sizeof(BufferKey));
  503. Status = RtlFormatCurrentUserKeyPath(&KeyPathUser);
  504. if (!NT_SUCCESS(Status)) {
  505. DbgPrint("BasepCheckCacheExcludeList: failed to format user key path 0x%lx\n", Status);
  506. goto Cleanup;
  507. }
  508. //
  509. // allocate a buffer that'd be large enough -- or use a local buffer
  510. //
  511. Status = RtlAssignUnicodeStringBuffer(&KeyNameBuffer, &KeyPathUser);
  512. if (!NT_SUCCESS(Status)) {
  513. DbgPrint("BasepCheckCacheExcludeList: failed to copy hkcu path status 0x%lx\n", Status);
  514. goto Cleanup;
  515. }
  516. Status = RtlAppendUnicodeStringBuffer(&KeyNameBuffer, &AppcompatKeyPathLayers);
  517. if (!NT_SUCCESS(Status)) {
  518. DbgPrint("BasepCheckCacheExcludeList: failed to copy layers path status 0x%lx\n", Status);
  519. goto Cleanup;
  520. }
  521. // we have a string for the key path
  522. InitializeObjectAttributes(&ObjectAttributes,
  523. &KeyNameBuffer.String,
  524. OBJ_CASE_INSENSITIVE,
  525. NULL,
  526. NULL);
  527. Status = NtOpenKey(&KeyHandle,
  528. KEY_READ|KEY_WOW64_64KEY, // note - read access only
  529. &ObjectAttributes);
  530. if (!NT_SUCCESS(Status)) {
  531. bCacheAllowed = (STATUS_OBJECT_NAME_NOT_FOUND == Status);
  532. goto Cleanup;
  533. }
  534. //
  535. // now create value name
  536. //
  537. RtlInitUnicodeString(&ExePathNt, pwszPath);
  538. Status = RtlAssignUnicodeStringBuffer(&ExePathBuffer, &ExePathNt);
  539. if (!NT_SUCCESS(Status)) {
  540. DbgPrint("BasepCheckCacheExcludeList: failed to acquire sufficient buffer size for path %ls status 0x%lx\n", pwszPath, Status);
  541. goto Cleanup;
  542. }
  543. Status = RtlNtPathNameToDosPathName(0, &ExePathBuffer, NULL, NULL);
  544. if (!NT_SUCCESS(Status)) {
  545. DbgPrint("BasepCheckCacheExcludeList: failed to convert nt path name %ls to dos path name status 0x%lx\n", pwszPath, Status);
  546. goto Cleanup;
  547. }
  548. // now we shall query the value
  549. Status = NtQueryValueKey(KeyHandle,
  550. &ExePathBuffer.String,
  551. KeyValuePartialInformation,
  552. &KeyValueInformation,
  553. sizeof(KeyValueInformation),
  554. &ResultLength);
  555. bCacheAllowed = (Status == STATUS_OBJECT_NAME_NOT_FOUND); // does not exist is more like it
  556. Cleanup:
  557. if (KeyHandle) {
  558. NtClose(KeyHandle);
  559. }
  560. RtlFreeUnicodeString(&KeyPathUser);
  561. RtlFreeUnicodeStringBuffer(&ExePathBuffer);
  562. RtlFreeUnicodeStringBuffer(&KeyNameBuffer);
  563. if (!bCacheAllowed) {
  564. DbgPrint("BasepCheckCacheExcludeList: Cache not allowed for %ls\n", pwszPath);
  565. }
  566. return bCacheAllowed;
  567. }
  568. BOOL
  569. BasepCheckCacheExcludeCustom(
  570. LPCWSTR pwszPath
  571. )
  572. {
  573. LPCWSTR pwszFileName;
  574. RTL_UNICODE_STRING_BUFFER KeyPath; // buffer to store exe path
  575. UCHAR BufferKeyPath[MAX_PATH * 2];
  576. NTSTATUS Status;
  577. UNICODE_STRING ustrPath;
  578. UNICODE_STRING ustrPathSeparators = RTL_CONSTANT_STRING(L"\\/");
  579. USHORT uPrefix;
  580. OBJECT_ATTRIBUTES ObjectAttributes;
  581. HANDLE KeyHandle = NULL;
  582. BOOL bCacheAllowed = FALSE;
  583. RtlInitUnicodeString(&ustrPath, pwszPath);
  584. Status = RtlFindCharInUnicodeString(RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END,
  585. &ustrPath,
  586. &ustrPathSeparators,
  587. &uPrefix);
  588. if (NT_SUCCESS(Status) && (uPrefix + sizeof(WCHAR)) < ustrPath.Length) {
  589. //
  590. // uPrefix is number of character preceding the one we found not including it
  591. //
  592. ustrPath.Buffer += uPrefix / sizeof(WCHAR) + 1;
  593. ustrPath.Length -= (uPrefix + sizeof(WCHAR));
  594. ustrPath.MaximumLength -= (uPrefix + sizeof(WCHAR));
  595. }
  596. //
  597. // construct path for custom sdb lookup
  598. //
  599. RtlInitUnicodeStringBuffer(&KeyPath, BufferKeyPath, sizeof(BufferKeyPath));
  600. Status = RtlAssignUnicodeStringBuffer(&KeyPath, &AppcompatKeyPathCustom);
  601. if (!NT_SUCCESS(Status)) {
  602. DbgPrint("BasepCheckCacheExcludeCustom: failed to copy appcompat custom path status 0x%lx\n", Status);
  603. goto Cleanup;
  604. }
  605. Status = RtlAppendUnicodeStringBuffer(&KeyPath, &ustrPath);
  606. if (!NT_SUCCESS(Status)) {
  607. DbgPrint("BasepCheckCacheExcludeCustom: failed to append %ls status 0x%lx\n", ustrPath.Buffer, Status);
  608. goto Cleanup;
  609. }
  610. // we have built the key, try open
  611. InitializeObjectAttributes(&ObjectAttributes,
  612. &KeyPath.String,
  613. OBJ_CASE_INSENSITIVE,
  614. NULL,
  615. NULL);
  616. Status = NtOpenKey(&KeyHandle,
  617. KEY_READ|KEY_WOW64_64KEY, // note - read access only
  618. &ObjectAttributes);
  619. if (!NT_SUCCESS(Status)) {
  620. bCacheAllowed = (STATUS_OBJECT_NAME_NOT_FOUND == Status);
  621. }
  622. Cleanup:
  623. if (KeyHandle) {
  624. NtClose(KeyHandle);
  625. }
  626. RtlFreeUnicodeStringBuffer(&KeyPath);
  627. if (!bCacheAllowed) {
  628. DbgPrint("BasepCheckCacheExcludeList: Cache not allowed for %ls\n", pwszPath);
  629. }
  630. return bCacheAllowed;
  631. }
  632. VOID
  633. WINAPI
  634. BaseDumpAppcompatCache(
  635. VOID
  636. )
  637. {
  638. NtApphelpCacheControl(ApphelpCacheServiceDump,
  639. NULL);
  640. }
  641. BOOL
  642. WINAPI
  643. BaseFlushAppcompatCache(
  644. VOID
  645. )
  646. {
  647. NTSTATUS Status;
  648. Status = NtApphelpCacheControl(ApphelpCacheServiceFlush,
  649. NULL);
  650. return NT_SUCCESS(Status);
  651. }
  652. VOID
  653. BasepFreeAppCompatData(
  654. PVOID pAppCompatData,
  655. SIZE_T cbAppCompatData,
  656. PVOID pSxsData,
  657. SIZE_T cbSxsData
  658. )
  659. {
  660. if (pAppCompatData) {
  661. NtFreeVirtualMemory(NtCurrentProcess(),
  662. &pAppCompatData,
  663. &cbAppCompatData,
  664. MEM_RELEASE);
  665. }
  666. if (pSxsData) {
  667. NtFreeVirtualMemory(NtCurrentProcess(),
  668. &pSxsData,
  669. &cbSxsData,
  670. MEM_RELEASE);
  671. }
  672. }
  673. BOOL
  674. WINAPI
  675. BaseUpdateAppcompatCache(
  676. LPCWSTR pwszPath,
  677. HANDLE hFile,
  678. BOOL bRemove
  679. )
  680. {
  681. if (bRemove) {
  682. return BasepShimCacheRemoveEntry(pwszPath);
  683. }
  684. return FALSE;
  685. }