1 /*
2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/client/appcache.c
5 * PURPOSE: Application Compatibility Cache
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <k32.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS ********************************************************************/
17
18 ULONG g_ShimsDisabled = -1;
19 static BOOL g_ApphelpInitialized = FALSE;
20 static PVOID g_pApphelpCheckRunAppEx;
21 static PVOID g_pSdbPackAppCompatData;
22
23 typedef BOOL (WINAPI *tApphelpCheckRunAppEx)(HANDLE FileHandle, PVOID Unk1, PVOID Unk2, PWCHAR ApplicationName, PVOID Environment, USHORT ExeType, PULONG Reason,
24 PVOID* SdbQueryAppCompatData, PULONG SdbQueryAppCompatDataSize, PVOID* SxsData, PULONG SxsDataSize,
25 PULONG FusionFlags, PULONG64 SomeFlag1, PULONG SomeFlag2);
26 typedef BOOL (WINAPI *tSdbPackAppCompatData)(PVOID hsdb, PVOID pQueryResult, PVOID* ppData, DWORD *dwSize);
27
28 #define APPHELP_VALID_RESULT 0x10000
29 #define APPHELP_RESULT_NOTFOUND 0x20000
30 #define APPHELP_RESULT_FOUND 0x40000
31
32
33 /* FUNCTIONS ******************************************************************/
34
35 BOOLEAN
36 WINAPI
IsShimInfrastructureDisabled(VOID)37 IsShimInfrastructureDisabled(VOID)
38 {
39 HANDLE KeyHandle;
40 NTSTATUS Status;
41 KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
42 ULONG ResultLength;
43 UNICODE_STRING OptionKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\SafeBoot\\Option");
44 UNICODE_STRING AppCompatKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility");
45 UNICODE_STRING PolicyKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\Software\\Policies\\Microsoft\\Windows\\AppCompat");
46 UNICODE_STRING OptionValue = RTL_CONSTANT_STRING(L"OptionValue");
47 UNICODE_STRING DisableAppCompat = RTL_CONSTANT_STRING(L"DisableAppCompat");
48 UNICODE_STRING DisableEngine = RTL_CONSTANT_STRING(L"DisableEngine");
49 OBJECT_ATTRIBUTES OptionKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&OptionKey, OBJ_CASE_INSENSITIVE);
50 OBJECT_ATTRIBUTES AppCompatKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&AppCompatKey, OBJ_CASE_INSENSITIVE);
51 OBJECT_ATTRIBUTES PolicyKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&PolicyKey, OBJ_CASE_INSENSITIVE);
52
53 /*
54 * This is a TROOLEAN, -1 means we haven't yet figured it out.
55 * 0 means shims are enabled, and 1 means shims are disabled!
56 */
57 if (g_ShimsDisabled == -1)
58 {
59 ULONG DisableShims = FALSE;
60
61 /* Open the safe mode key */
62 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &OptionKeyAttributes);
63 if (NT_SUCCESS(Status))
64 {
65 /* Check if this is safemode */
66 Status = NtQueryValueKey(KeyHandle,
67 &OptionValue,
68 KeyValuePartialInformation,
69 &KeyInfo,
70 sizeof(KeyInfo),
71 &ResultLength);
72 NtClose(KeyHandle);
73 if ((NT_SUCCESS(Status)) &&
74 (KeyInfo.Type == REG_DWORD) &&
75 (KeyInfo.DataLength == sizeof(ULONG)) &&
76 (KeyInfo.Data[0] != FALSE))
77 {
78 /* It is, so disable shims! */
79 DisableShims = TRUE;
80 }
81 }
82
83 if (!DisableShims)
84 {
85 /* Open the app compatibility engine settings key */
86 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &AppCompatKeyAttributes);
87 if (NT_SUCCESS(Status))
88 {
89 /* Check if the app compat engine is turned off */
90 Status = NtQueryValueKey(KeyHandle,
91 &DisableAppCompat,
92 KeyValuePartialInformation,
93 &KeyInfo,
94 sizeof(KeyInfo),
95 &ResultLength);
96 NtClose(KeyHandle);
97 if ((NT_SUCCESS(Status)) &&
98 (KeyInfo.Type == REG_DWORD) &&
99 (KeyInfo.DataLength == sizeof(ULONG)) &&
100 (KeyInfo.Data[0] == TRUE))
101 {
102 /* It is, so disable shims! */
103 DisableShims = TRUE;
104 }
105 }
106 }
107 if (!DisableShims)
108 {
109 /* Finally, open the app compatibility policy key */
110 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &PolicyKeyAttributes);
111 if (NT_SUCCESS(Status))
112 {
113 /* Check if the system policy disables app compat */
114 Status = NtQueryValueKey(KeyHandle,
115 &DisableEngine,
116 KeyValuePartialInformation,
117 &KeyInfo,
118 sizeof(KeyInfo),
119 &ResultLength);
120 NtClose(KeyHandle);
121 if ((NT_SUCCESS(Status)) &&
122 (KeyInfo.Type == REG_DWORD) &&
123 (KeyInfo.DataLength == sizeof(ULONG)) &&
124 (KeyInfo.Data[0] == TRUE))
125 {
126 /* It does, so disable shims! */
127 DisableShims = TRUE;
128 }
129 }
130 }
131 g_ShimsDisabled = DisableShims;
132 }
133
134 /* Return if shims are disabled or not ("Enabled == 1" means disabled!) */
135 return g_ShimsDisabled ? TRUE : FALSE;
136 }
137
138 /*
139 * @unimplemented
140 */
141 BOOL
BasepShimCacheCheckBypass(_In_ PCWSTR ApplicationName,_In_ HANDLE FileHandle,_In_opt_ PCWSTR Environment,_In_ BOOL bUnknown,_Out_opt_ PULONG pdwReason)142 BasepShimCacheCheckBypass(
143 _In_ PCWSTR ApplicationName,
144 _In_ HANDLE FileHandle,
145 _In_opt_ PCWSTR Environment,
146 _In_ BOOL bUnknown,
147 _Out_opt_ PULONG pdwReason)
148 {
149 DPRINT("fixme:(%S, %p, %S, %d, %p)\n", ApplicationName, FileHandle, Environment, bUnknown,
150 pdwReason);
151 return FALSE;
152 }
153
154 /*
155 * @implemented
156 */
157 BOOL
BasepShimCacheSearch(_In_ PCWSTR ApplicationName,_In_ HANDLE FileHandle)158 BasepShimCacheSearch(
159 _In_ PCWSTR ApplicationName,
160 _In_ HANDLE FileHandle)
161 {
162 APPHELP_CACHE_SERVICE_LOOKUP Lookup;
163 RtlInitUnicodeString(&Lookup.ImageName, ApplicationName);
164 Lookup.ImageHandle = FileHandle;
165 return NT_SUCCESS(NtApphelpCacheControl(ApphelpCacheServiceLookup, &Lookup));
166 }
167
168 /*
169 * @unimplemented
170 */
171 BOOL
BasepCheckCacheExcludeList(_In_ PCWSTR ApplicationName)172 BasepCheckCacheExcludeList(
173 _In_ PCWSTR ApplicationName)
174 {
175 return FALSE;
176 }
177
178 /*
179 * @unimplemented
180 */
181 BOOL
BasepCheckCacheExcludeCustom(_In_ PCWSTR ApplicationName)182 BasepCheckCacheExcludeCustom(
183 _In_ PCWSTR ApplicationName)
184 {
185 return FALSE;
186 }
187
188 /*
189 * @implemented
190 */
191 VOID
BasepShimCacheRemoveEntry(_In_ PCWSTR ApplicationName)192 BasepShimCacheRemoveEntry(
193 _In_ PCWSTR ApplicationName)
194 {
195 APPHELP_CACHE_SERVICE_LOOKUP Lookup;
196 RtlInitUnicodeString(&Lookup.ImageName, ApplicationName);
197 Lookup.ImageHandle = INVALID_HANDLE_VALUE;
198 NtApphelpCacheControl(ApphelpCacheServiceRemove, &Lookup);
199 }
200
201 /*
202 * @unimplemented
203 */
204 BOOL
BasepShimCacheLookup(_In_ PCWSTR ApplicationName,_In_ HANDLE FileHandle)205 BasepShimCacheLookup(
206 _In_ PCWSTR ApplicationName,
207 _In_ HANDLE FileHandle)
208 {
209 DPRINT("fixme:(%S, %p)\n", ApplicationName, FileHandle);
210
211 if (!BasepShimCacheSearch(ApplicationName, FileHandle))
212 return FALSE;
213
214 if (!BasepCheckCacheExcludeList(ApplicationName) ||
215 !BasepCheckCacheExcludeCustom(ApplicationName))
216 {
217 BasepShimCacheRemoveEntry(ApplicationName);
218 return FALSE;
219 }
220
221 return TRUE;
222 }
223
224 /*
225 * @implemented
226 */
227 BOOL
228 WINAPI
BaseCheckAppcompatCache(_In_ PCWSTR ApplicationName,_In_ HANDLE FileHandle,_In_opt_ PCWSTR Environment,_Out_opt_ PULONG pdwReason)229 BaseCheckAppcompatCache(
230 _In_ PCWSTR ApplicationName,
231 _In_ HANDLE FileHandle,
232 _In_opt_ PCWSTR Environment,
233 _Out_opt_ PULONG pdwReason)
234 {
235 BOOL ret = FALSE;
236 ULONG dwReason;
237
238 DPRINT("(%S, %p, %S, %p)\n", ApplicationName, FileHandle, Environment, pdwReason);
239
240 dwReason = 0;
241 if (BasepShimCacheCheckBypass(ApplicationName, FileHandle, Environment, TRUE, &dwReason))
242 {
243 dwReason |= 2;
244 }
245 else
246 {
247 ret = BasepShimCacheLookup(ApplicationName, FileHandle);
248 if (!ret)
249 dwReason |= 1;
250 }
251
252 if (pdwReason)
253 *pdwReason = dwReason;
254
255 return ret;
256 }
257
258 static
259 VOID
BaseInitApphelp(VOID)260 BaseInitApphelp(VOID)
261 {
262 WCHAR Buffer[MAX_PATH*2];
263 UNICODE_STRING DllPath = {0};
264 PVOID ApphelpAddress;
265 PVOID pApphelpCheckRunAppEx = NULL, pSdbPackAppCompatData = NULL;
266
267 RtlInitEmptyUnicodeString(&DllPath, Buffer, sizeof(Buffer));
268 RtlCopyUnicodeString(&DllPath, &BaseWindowsDirectory);
269 RtlAppendUnicodeToString(&DllPath, L"\\system32\\apphelp.dll");
270
271 if (NT_SUCCESS(LdrLoadDll(NULL, NULL, &DllPath, &ApphelpAddress)))
272 {
273 ANSI_STRING ProcName;
274
275 RtlInitAnsiString(&ProcName, "ApphelpCheckRunAppEx");
276 if (!NT_SUCCESS(LdrGetProcedureAddress(ApphelpAddress, &ProcName, 0, &pApphelpCheckRunAppEx)))
277 pApphelpCheckRunAppEx = NULL;
278
279 RtlInitAnsiString(&ProcName, "SdbPackAppCompatData");
280 if (!NT_SUCCESS(LdrGetProcedureAddress(ApphelpAddress, &ProcName, 0, &pSdbPackAppCompatData)))
281 pSdbPackAppCompatData = NULL;
282 }
283
284 if (InterlockedCompareExchangePointer(&g_pApphelpCheckRunAppEx, RtlEncodeSystemPointer(pApphelpCheckRunAppEx), NULL) == NULL)
285 {
286 g_pSdbPackAppCompatData = RtlEncodeSystemPointer(pSdbPackAppCompatData);
287 }
288 }
289
290 /*
291 *
292 */
293 BOOL
294 WINAPI
BaseCheckRunApp(IN HANDLE FileHandle,IN PWCHAR ApplicationName,IN PWCHAR Environment,IN USHORT ExeType,IN PULONG pReason,IN PVOID * SdbQueryAppCompatData,IN PULONG SdbQueryAppCompatDataSize,IN PVOID * SxsData,IN PULONG SxsDataSize,OUT PULONG FusionFlags)295 BaseCheckRunApp(IN HANDLE FileHandle,
296 IN PWCHAR ApplicationName,
297 IN PWCHAR Environment,
298 IN USHORT ExeType,
299 IN PULONG pReason,
300 IN PVOID* SdbQueryAppCompatData,
301 IN PULONG SdbQueryAppCompatDataSize,
302 IN PVOID* SxsData,
303 IN PULONG SxsDataSize,
304 OUT PULONG FusionFlags)
305 {
306 ULONG Reason = 0;
307 ULONG64 Flags1 = 0;
308 ULONG Flags2 = 0;
309 BOOL Continue, NeedCleanup = FALSE;
310 tApphelpCheckRunAppEx pApphelpCheckRunAppEx;
311 tSdbPackAppCompatData pSdbPackAppCompatData;
312 PVOID QueryResult = NULL;
313 ULONG QueryResultSize = 0;
314
315 if (!g_ApphelpInitialized)
316 {
317 BaseInitApphelp();
318 g_ApphelpInitialized = TRUE;
319 }
320
321 pApphelpCheckRunAppEx = RtlDecodeSystemPointer(g_pApphelpCheckRunAppEx);
322 pSdbPackAppCompatData = RtlDecodeSystemPointer(g_pSdbPackAppCompatData);
323
324 if (!pApphelpCheckRunAppEx || !pSdbPackAppCompatData)
325 return TRUE;
326
327 if (pReason)
328 Reason = *pReason;
329
330 Continue = pApphelpCheckRunAppEx(FileHandle, NULL, NULL, ApplicationName, Environment, ExeType, &Reason,
331 &QueryResult, &QueryResultSize, SxsData, SxsDataSize, FusionFlags, &Flags1, &Flags2);
332
333 if (pReason)
334 *pReason = Reason;
335
336 if (Continue)
337 {
338 if ((Reason & (APPHELP_VALID_RESULT|APPHELP_RESULT_FOUND)) == (APPHELP_VALID_RESULT|APPHELP_RESULT_FOUND))
339 {
340 if (!pSdbPackAppCompatData(NULL, QueryResult, SdbQueryAppCompatData, SdbQueryAppCompatDataSize))
341 {
342 DPRINT1("SdbPackAppCompatData returned a failure!\n");
343 NeedCleanup = TRUE;
344 }
345 }
346 else
347 {
348 NeedCleanup = TRUE;
349 }
350 }
351
352 if (QueryResult)
353 RtlFreeHeap(RtlGetProcessHeap(), 0, QueryResult);
354
355 if (NeedCleanup)
356 {
357 BasepFreeAppCompatData(*SdbQueryAppCompatData, *SxsData);
358 *SdbQueryAppCompatData = NULL;
359 if (SdbQueryAppCompatDataSize)
360 *SdbQueryAppCompatDataSize = 0;
361 *SxsData = NULL;
362 if (SxsDataSize)
363 *SxsDataSize = 0;
364 }
365
366 return Continue;
367 }
368
369 /*
370 * @implemented
371 */
372 NTSTATUS
373 WINAPI
BasepCheckBadapp(IN HANDLE FileHandle,IN PWCHAR ApplicationName,IN PWCHAR Environment,IN USHORT ExeType,IN PVOID * SdbQueryAppCompatData,IN PULONG SdbQueryAppCompatDataSize,IN PVOID * SxsData,IN PULONG SxsDataSize,OUT PULONG FusionFlags)374 BasepCheckBadapp(IN HANDLE FileHandle,
375 IN PWCHAR ApplicationName,
376 IN PWCHAR Environment,
377 IN USHORT ExeType,
378 IN PVOID* SdbQueryAppCompatData,
379 IN PULONG SdbQueryAppCompatDataSize,
380 IN PVOID* SxsData,
381 IN PULONG SxsDataSize,
382 OUT PULONG FusionFlags)
383 {
384 NTSTATUS Status = STATUS_SUCCESS;
385 ULONG Reason = 0;
386
387 /* Is shimming enabled by group policy? */
388 if (IsShimInfrastructureDisabled())
389 {
390 /* Nothing to worry about */
391 Status = STATUS_SUCCESS;
392 }
393 else
394 {
395 /* It is, check if we know about this app */
396 if (!BaseCheckAppcompatCache(ApplicationName,
397 FileHandle,
398 Environment,
399 &Reason))
400 {
401 if (!BaseCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
402 SdbQueryAppCompatData, SdbQueryAppCompatDataSize, SxsData, SxsDataSize, FusionFlags))
403 {
404 Status = STATUS_ACCESS_DENIED;
405 }
406 }
407 }
408
409 /* Return caller the status */
410 return Status;
411 }
412
413 /*
414 * @implemented
415 */
416 BOOL
417 WINAPI
BaseDumpAppcompatCache(VOID)418 BaseDumpAppcompatCache(VOID)
419 {
420 NTSTATUS Status;
421
422 Status = NtApphelpCacheControl(ApphelpCacheServiceDump, NULL);
423 return NT_SUCCESS(Status);
424 }
425
426 /*
427 * @implemented
428 */
429 BOOL
430 WINAPI
BaseFlushAppcompatCache(VOID)431 BaseFlushAppcompatCache(VOID)
432 {
433 NTSTATUS Status;
434
435 Status = NtApphelpCacheControl(ApphelpCacheServiceFlush, NULL);
436 return NT_SUCCESS(Status);
437 }
438
439 /*
440 * @implemented
441 */
442 VOID
443 WINAPI
BasepFreeAppCompatData(IN PVOID AppCompatData,IN PVOID AppCompatSxsData)444 BasepFreeAppCompatData(IN PVOID AppCompatData,
445 IN PVOID AppCompatSxsData)
446 {
447 /* Free the input pointers if present */
448 if (AppCompatData) RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatData);
449 if (AppCompatSxsData) RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatSxsData);
450 }
451
452 /*
453 * @unimplemented
454 */
455 VOID
456 WINAPI
BaseUpdateAppcompatCache(ULONG Unknown1,ULONG Unknown2,ULONG Unknown3)457 BaseUpdateAppcompatCache(ULONG Unknown1,
458 ULONG Unknown2,
459 ULONG Unknown3)
460 {
461 STUB;
462 }
463
464 /*
465 * @unimplemented
466 */
467 NTSTATUS
468 WINAPI
BaseCleanupAppcompatCache(VOID)469 BaseCleanupAppcompatCache(VOID)
470 {
471 STUB;
472 return STATUS_NOT_IMPLEMENTED;
473 }
474
475 /*
476 * @unimplemented
477 */
478 NTSTATUS
479 WINAPI
BaseCleanupAppcompatCacheSupport(PVOID pUnknown)480 BaseCleanupAppcompatCacheSupport(PVOID pUnknown)
481 {
482 STUB;
483 return STATUS_NOT_IMPLEMENTED;
484 }
485
486 /*
487 * @unimplemented
488 */
489 BOOL
490 WINAPI
BaseInitAppcompatCache(VOID)491 BaseInitAppcompatCache(VOID)
492 {
493 STUB;
494 return FALSE;
495 }
496
497 /*
498 * @unimplemented
499 */
500 BOOL
501 WINAPI
BaseInitAppcompatCacheSupport(VOID)502 BaseInitAppcompatCacheSupport(VOID)
503 {
504 STUB;
505 return FALSE;
506 }
507
508 /*
509 * @unimplemented
510 */
511 PVOID
512 WINAPI
GetComPlusPackageInstallStatus(VOID)513 GetComPlusPackageInstallStatus(VOID)
514 {
515 STUB;
516 return NULL;
517 }
518
519 /*
520 * @implemented
521 */
522 BOOL
523 WINAPI
SetComPlusPackageInstallStatus(IN ULONG ComPlusPackage)524 SetComPlusPackageInstallStatus(IN ULONG ComPlusPackage)
525 {
526 NTSTATUS Status;
527
528 DPRINT("(0x%X)\n", ComPlusPackage);
529
530 if (ComPlusPackage & ~1)
531 {
532 DPRINT1("0x%lX\n", ComPlusPackage);
533 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
534 return FALSE;
535 }
536
537 Status = NtSetSystemInformation(SystemComPlusPackage, &ComPlusPackage, sizeof(ComPlusPackage));
538 if (!NT_SUCCESS(Status))
539 {
540 DPRINT1("0x%lX\n", Status);
541 BaseSetLastNTError(Status);
542 return FALSE;
543 }
544
545 return TRUE;
546 }
547
548 /*
549 * @unimplemented
550 */
551 VOID
552 WINAPI
SetTermsrvAppInstallMode(IN BOOL bInstallMode)553 SetTermsrvAppInstallMode(IN BOOL bInstallMode)
554 {
555 STUB;
556 }
557
558 /*
559 * @unimplemented
560 */
561 BOOL
562 WINAPI
TermsrvAppInstallMode(VOID)563 TermsrvAppInstallMode(VOID)
564 {
565 STUB;
566 return FALSE;
567 }
568