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