Reactos
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
18ULONG g_ShimsDisabled = -1;
19static BOOL g_ApphelpInitialized = FALSE;
20static PVOID g_pApphelpCheckRunAppEx;
21static PVOID g_pSdbPackAppCompatData;
22
23typedef 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);
26typedef 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
35BOOLEAN
36WINAPI
37IsShimInfrastructureDisabled(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 */
141BOOL
142BasepShimCacheCheckBypass(
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 */
157BOOL
158BasepShimCacheSearch(
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 */
171BOOL
172BasepCheckCacheExcludeList(
173 _In_ PCWSTR ApplicationName)
174{
175 return FALSE;
176}
177
178/*
179 * @unimplemented
180 */
181BOOL
182BasepCheckCacheExcludeCustom(
183 _In_ PCWSTR ApplicationName)
184{
185 return FALSE;
186}
187
188/*
189 * @implemented
190 */
191VOID
192BasepShimCacheRemoveEntry(
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 */
204BOOL
205BasepShimCacheLookup(
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 */
227BOOL
228WINAPI
229BaseCheckAppcompatCache(
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
258static
259VOID
260BaseInitApphelp(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 */
293BOOL
294WINAPI
295BaseCheckRunApp(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 */
372NTSTATUS
373WINAPI
374BasepCheckBadapp(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 */
416BOOL
417WINAPI
418BaseDumpAppcompatCache(VOID)
419{
420 NTSTATUS Status;
421
422 Status = NtApphelpCacheControl(ApphelpCacheServiceDump, NULL);
423 return NT_SUCCESS(Status);
424}
425
426/*
427 * @implemented
428 */
429BOOL
430WINAPI
431BaseFlushAppcompatCache(VOID)
432{
433 NTSTATUS Status;
434
435 Status = NtApphelpCacheControl(ApphelpCacheServiceFlush, NULL);
436 return NT_SUCCESS(Status);
437}
438
439/*
440 * @implemented
441 */
442VOID
443WINAPI
444BasepFreeAppCompatData(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 */
455VOID
456WINAPI
457BaseUpdateAppcompatCache(ULONG Unknown1,
458 ULONG Unknown2,
459 ULONG Unknown3)
460{
461 STUB;
462}
463
464/*
465 * @unimplemented
466 */
467NTSTATUS
468WINAPI
469BaseCleanupAppcompatCache(VOID)
470{
471 STUB;
472 return STATUS_NOT_IMPLEMENTED;
473}
474
475/*
476 * @unimplemented
477 */
478NTSTATUS
479WINAPI
480BaseCleanupAppcompatCacheSupport(PVOID pUnknown)
481{
482 STUB;
483 return STATUS_NOT_IMPLEMENTED;
484}
485
486/*
487 * @unimplemented
488 */
489BOOL
490WINAPI
491BaseInitAppcompatCache(VOID)
492{
493 STUB;
494 return FALSE;
495}
496
497/*
498 * @unimplemented
499 */
500BOOL
501WINAPI
502BaseInitAppcompatCacheSupport(VOID)
503{
504 STUB;
505 return FALSE;
506}
507
508/*
509 * @unimplemented
510 */
511PVOID
512WINAPI
513GetComPlusPackageInstallStatus(VOID)
514{
515 STUB;
516 return NULL;
517}
518
519/*
520 * @implemented
521 */
522BOOL
523WINAPI
524SetComPlusPackageInstallStatus(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 */
551VOID
552WINAPI
553SetTermsrvAppInstallMode(IN BOOL bInstallMode)
554{
555 STUB;
556}
557
558/*
559 * @unimplemented
560 */
561BOOL
562WINAPI
563TermsrvAppInstallMode(VOID)
564{
565 STUB;
566 return FALSE;
567}