xref: /reactos/dll/win32/kernel32/client/appcache.c (revision 6b700c6a)
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 WINAPI
143 BaseCheckAppcompatCache(IN PWCHAR ApplicationName,
144                         IN HANDLE FileHandle,
145                         IN PWCHAR Environment,
146                         OUT PULONG Reason)
147 {
148     DPRINT("BaseCheckAppcompatCache is UNIMPLEMENTED\n");
149 
150     if (Reason) *Reason = 0;
151 
152     // We don't know this app.
153     return FALSE;
154 }
155 
156 static
157 VOID
158 BaseInitApphelp(VOID)
159 {
160     WCHAR Buffer[MAX_PATH*2];
161     UNICODE_STRING DllPath = {0};
162     PVOID ApphelpAddress;
163     PVOID pApphelpCheckRunAppEx = NULL, pSdbPackAppCompatData = NULL;
164 
165     RtlInitEmptyUnicodeString(&DllPath, Buffer, sizeof(Buffer));
166     RtlCopyUnicodeString(&DllPath, &BaseWindowsDirectory);
167     RtlAppendUnicodeToString(&DllPath, L"\\system32\\apphelp.dll");
168 
169     if (NT_SUCCESS(LdrLoadDll(NULL, NULL, &DllPath, &ApphelpAddress)))
170     {
171         ANSI_STRING ProcName;
172 
173         RtlInitAnsiString(&ProcName, "ApphelpCheckRunAppEx");
174         if (!NT_SUCCESS(LdrGetProcedureAddress(ApphelpAddress, &ProcName, 0, &pApphelpCheckRunAppEx)))
175             pApphelpCheckRunAppEx = NULL;
176 
177         RtlInitAnsiString(&ProcName, "SdbPackAppCompatData");
178         if (!NT_SUCCESS(LdrGetProcedureAddress(ApphelpAddress, &ProcName, 0, &pSdbPackAppCompatData)))
179             pSdbPackAppCompatData = NULL;
180     }
181 
182     if (InterlockedCompareExchangePointer(&g_pApphelpCheckRunAppEx, RtlEncodeSystemPointer(pApphelpCheckRunAppEx), NULL) == NULL)
183     {
184         g_pSdbPackAppCompatData = RtlEncodeSystemPointer(pSdbPackAppCompatData);
185     }
186 }
187 
188 /*
189  *
190  */
191 BOOL
192 WINAPI
193 BaseCheckRunApp(IN HANDLE FileHandle,
194                  IN PWCHAR ApplicationName,
195                  IN PWCHAR Environment,
196                  IN USHORT ExeType,
197                  IN PULONG pReason,
198                  IN PVOID* SdbQueryAppCompatData,
199                  IN PULONG SdbQueryAppCompatDataSize,
200                  IN PVOID* SxsData,
201                  IN PULONG SxsDataSize,
202                  OUT PULONG FusionFlags)
203 {
204     ULONG Reason = 0;
205     ULONG64 Flags1 = 0;
206     ULONG Flags2 = 0;
207     BOOL Continue, NeedCleanup = FALSE;
208     tApphelpCheckRunAppEx pApphelpCheckRunAppEx;
209     tSdbPackAppCompatData pSdbPackAppCompatData;
210     PVOID QueryResult = NULL;
211     ULONG QueryResultSize = 0;
212 
213     if (!g_ApphelpInitialized)
214     {
215         BaseInitApphelp();
216         g_ApphelpInitialized = TRUE;
217     }
218 
219     pApphelpCheckRunAppEx = RtlDecodeSystemPointer(g_pApphelpCheckRunAppEx);
220     pSdbPackAppCompatData = RtlDecodeSystemPointer(g_pSdbPackAppCompatData);
221 
222     if (!pApphelpCheckRunAppEx || !pSdbPackAppCompatData)
223         return TRUE;
224 
225     if (pReason)
226         Reason = *pReason;
227 
228     Continue = pApphelpCheckRunAppEx(FileHandle, NULL, NULL, ApplicationName, Environment, ExeType, &Reason,
229         &QueryResult, &QueryResultSize, SxsData, SxsDataSize, FusionFlags, &Flags1, &Flags2);
230 
231     if (pReason)
232         *pReason = Reason;
233 
234     if (Continue)
235     {
236         if ((Reason & (APPHELP_VALID_RESULT|APPHELP_RESULT_FOUND)) == (APPHELP_VALID_RESULT|APPHELP_RESULT_FOUND))
237         {
238             if (!pSdbPackAppCompatData(NULL, QueryResult, SdbQueryAppCompatData, SdbQueryAppCompatDataSize))
239             {
240                 DPRINT1("SdbPackAppCompatData returned a failure!\n");
241                 NeedCleanup = TRUE;
242             }
243         }
244         else
245         {
246             NeedCleanup = TRUE;
247         }
248     }
249 
250     if (QueryResult)
251         RtlFreeHeap(RtlGetProcessHeap(), 0, QueryResult);
252 
253     if (NeedCleanup)
254     {
255         BasepFreeAppCompatData(*SdbQueryAppCompatData, *SxsData);
256         *SdbQueryAppCompatData = NULL;
257         if (SdbQueryAppCompatDataSize)
258             *SdbQueryAppCompatDataSize = 0;
259         *SxsData = NULL;
260         if (SxsDataSize)
261             *SxsDataSize = 0;
262     }
263 
264     return Continue;
265 }
266 
267 /*
268  * @implemented
269  */
270 NTSTATUS
271 WINAPI
272 BasepCheckBadapp(IN HANDLE FileHandle,
273                  IN PWCHAR ApplicationName,
274                  IN PWCHAR Environment,
275                  IN USHORT ExeType,
276                  IN PVOID* SdbQueryAppCompatData,
277                  IN PULONG SdbQueryAppCompatDataSize,
278                  IN PVOID* SxsData,
279                  IN PULONG SxsDataSize,
280                  OUT PULONG FusionFlags)
281 {
282     NTSTATUS Status = STATUS_SUCCESS;
283     ULONG Reason = 0;
284 
285     /* Is shimming enabled by group policy? */
286     if (IsShimInfrastructureDisabled())
287     {
288         /* Nothing to worry about */
289         Status = STATUS_SUCCESS;
290     }
291     else
292     {
293         /* It is, check if we know about this app */
294         if (!BaseCheckAppcompatCache(ApplicationName,
295                                      FileHandle,
296                                      Environment,
297                                      &Reason))
298         {
299             if (!BaseCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
300                                 SdbQueryAppCompatData, SdbQueryAppCompatDataSize, SxsData, SxsDataSize, FusionFlags))
301             {
302                 Status = STATUS_ACCESS_DENIED;
303             }
304         }
305     }
306 
307     /* Return caller the status */
308     return Status;
309 }
310 
311 /*
312  * @implemented
313  */
314 BOOL
315 WINAPI
316 BaseDumpAppcompatCache(VOID)
317 {
318     NTSTATUS Status;
319 
320     Status = NtApphelpCacheControl(ApphelpCacheServiceDump, NULL);
321     return NT_SUCCESS(Status);
322 }
323 
324 /*
325  * @implemented
326  */
327 BOOL
328 WINAPI
329 BaseFlushAppcompatCache(VOID)
330 {
331     NTSTATUS Status;
332 
333     Status = NtApphelpCacheControl(ApphelpCacheServiceFlush, NULL);
334     return NT_SUCCESS(Status);
335 }
336 
337 /*
338  * @implemented
339  */
340 VOID
341 WINAPI
342 BasepFreeAppCompatData(IN PVOID AppCompatData,
343                        IN PVOID AppCompatSxsData)
344 {
345     /* Free the input pointers if present */
346     if (AppCompatData) RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatData);
347     if (AppCompatSxsData) RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatSxsData);
348 }
349 
350 /*
351  * @unimplemented
352  */
353 VOID
354 WINAPI
355 BaseUpdateAppcompatCache(ULONG Unknown1,
356                          ULONG Unknown2,
357                          ULONG Unknown3)
358 {
359     STUB;
360 }
361 
362 /*
363  * @unimplemented
364  */
365 NTSTATUS
366 WINAPI
367 BaseCleanupAppcompatCache(VOID)
368 {
369     STUB;
370     return STATUS_NOT_IMPLEMENTED;
371 }
372 
373 /*
374  * @unimplemented
375  */
376 NTSTATUS
377 WINAPI
378 BaseCleanupAppcompatCacheSupport(PVOID pUnknown)
379 {
380     STUB;
381     return STATUS_NOT_IMPLEMENTED;
382 }
383 
384 /*
385  * @unimplemented
386  */
387 BOOL
388 WINAPI
389 BaseInitAppcompatCache(VOID)
390 {
391     STUB;
392     return FALSE;
393 }
394 
395 /*
396  * @unimplemented
397  */
398 BOOL
399 WINAPI
400 BaseInitAppcompatCacheSupport(VOID)
401 {
402     STUB;
403     return FALSE;
404 }
405 
406 /*
407  * @unimplemented
408  */
409 PVOID
410 WINAPI
411 GetComPlusPackageInstallStatus(VOID)
412 {
413     STUB;
414     return NULL;
415 }
416 
417 /*
418  * @unimplemented
419  */
420 BOOL
421 WINAPI
422 SetComPlusPackageInstallStatus(LPVOID lpInfo)
423 {
424    STUB;
425    return FALSE;
426 }
427 
428 /*
429  * @unimplemented
430  */
431 VOID
432 WINAPI
433 SetTermsrvAppInstallMode(IN BOOL bInstallMode)
434 {
435     STUB;
436 }
437 
438 /*
439  * @unimplemented
440  */
441 BOOL
442 WINAPI
443 TermsrvAppInstallMode(VOID)
444 {
445     STUB;
446     return FALSE;
447 }
448