xref: /reactos/dll/win32/kernel32/client/appcache.c (revision 0c2cdcae)
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
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
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
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
172 BasepCheckCacheExcludeList(
173     _In_ PCWSTR ApplicationName)
174 {
175     return FALSE;
176 }
177 
178 /*
179  * @unimplemented
180  */
181 BOOL
182 BasepCheckCacheExcludeCustom(
183     _In_ PCWSTR ApplicationName)
184 {
185     return FALSE;
186 }
187 
188 /*
189  * @implemented
190  */
191 VOID
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
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
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
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
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
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
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
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
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
457 BaseUpdateAppcompatCache(ULONG Unknown1,
458                          ULONG Unknown2,
459                          ULONG Unknown3)
460 {
461     STUB;
462 }
463 
464 /*
465  * @unimplemented
466  */
467 NTSTATUS
468 WINAPI
469 BaseCleanupAppcompatCache(VOID)
470 {
471     STUB;
472     return STATUS_NOT_IMPLEMENTED;
473 }
474 
475 /*
476  * @unimplemented
477  */
478 NTSTATUS
479 WINAPI
480 BaseCleanupAppcompatCacheSupport(PVOID pUnknown)
481 {
482     STUB;
483     return STATUS_NOT_IMPLEMENTED;
484 }
485 
486 /*
487  * @unimplemented
488  */
489 BOOL
490 WINAPI
491 BaseInitAppcompatCache(VOID)
492 {
493     STUB;
494     return FALSE;
495 }
496 
497 /*
498  * @unimplemented
499  */
500 BOOL
501 WINAPI
502 BaseInitAppcompatCacheSupport(VOID)
503 {
504     STUB;
505     return FALSE;
506 }
507 
508 /*
509  * @unimplemented
510  */
511 PVOID
512 WINAPI
513 GetComPlusPackageInstallStatus(VOID)
514 {
515     STUB;
516     return NULL;
517 }
518 
519 /*
520  * @implemented
521  */
522 BOOL
523 WINAPI
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
553 SetTermsrvAppInstallMode(IN BOOL bInstallMode)
554 {
555     STUB;
556 }
557 
558 /*
559  * @unimplemented
560  */
561 BOOL
562 WINAPI
563 TermsrvAppInstallMode(VOID)
564 {
565     STUB;
566     return FALSE;
567 }
568