Reactos
at master 567 lines 15 kB view raw
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}