From a9bd3da299079832853884be595fa9b7e08ee95b Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Fri, 23 Jun 2017 21:47:36 +0200 Subject: [PATCH] [APPHELP_APITEST] Add a test for shim database registration CORE-11301 --- .../rostests/apitests/apphelp/CMakeLists.txt | 7 +- .../rostests/apitests/apphelp/register.cpp | 374 ++++++++++++++++++ modules/rostests/apitests/apphelp/testlist.c | 2 + 3 files changed, 381 insertions(+), 2 deletions(-) create mode 100644 modules/rostests/apitests/apphelp/register.cpp diff --git a/modules/rostests/apitests/apphelp/CMakeLists.txt b/modules/rostests/apitests/apphelp/CMakeLists.txt index 06ca2ba83a9..40da34c9054 100644 --- a/modules/rostests/apitests/apphelp/CMakeLists.txt +++ b/modules/rostests/apitests/apphelp/CMakeLists.txt @@ -1,7 +1,9 @@ project(appcompat) -add_definitions(-D__ROS_LONG64__ -DWINETEST_USE_DBGSTR_LONGLONG) +add_definitions(-D__ROS_LONG64__ -DWINETEST_USE_DBGSTR_LONGLONG -DUNICODE -D_UNICODE) +set_cpp(WITH_RUNTIME) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/atl + ${CMAKE_CURRENT_BINARY_DIR}) list(APPEND SOURCE apphelp.c @@ -9,6 +11,7 @@ list(APPEND SOURCE db.cpp env.c layerapi.c + register.cpp testlist.c testdata.rc testdb.xml) diff --git a/modules/rostests/apitests/apphelp/register.cpp b/modules/rostests/apitests/apphelp/register.cpp new file mode 100644 index 00000000000..fb093cc594d --- /dev/null +++ b/modules/rostests/apitests/apphelp/register.cpp @@ -0,0 +1,374 @@ +/* + * PROJECT: apphelp_apitest + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Tests for shim database registration + * COPYRIGHT: Copyright 2017-2019 Mark Jansen (mark.jansen@reactos.org) + */ + +#include +#define WIN32_NO_STATUS +#include +#include +#include +#include +#include "wine/test.h" + +static const unsigned char rawDB[] = +{ + /* Header: Major, Minor, 'sdbf' */ + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x64, 0x62, 0x66, + + /* TAG_DATABASE, Length */ + 0x01, 0x70, 0x22, 0x00, 0x00, 0x00, + /* TAG_NAME, Value */ + 0x01, 0x60, 0x06, 0x00, 0x00, 0x00, + + /* TAG_DATABASE_ID, Length, Value*/ + 0x07, 0x90, 0x10, 0x00, 0x00, 0x00, + /* offset 30 */ + 0xEB, 0x75, 0xDD, 0x79, 0x98, 0xC0, 0x57, 0x47, 0x99, 0x65, 0x9E, 0x83, 0xC4, 0xCA, 0x9D, 0xA4, + + /* TAG_LIBRARY, Length */ + 0x02, 0x70, 0x00, 0x00, 0x00, 0x00, + + /* TAG_STRINGTABLE, Length */ + 0x01, 0x78, 0x0E, 0x00, 0x00, 0x00, + /* TAG_STRINGTABLE_ITEM, Length, Value */ + 0x01, 0x88, 0x08, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x43, 0x00, 0x53, 0x00, 0x00, 0x00 +}; + +static BOOL WriteSdbFile(const WCHAR* FileName, const unsigned char* Data, DWORD Size, const GUID* CustomID) +{ + BOOL Success; + DWORD dwWritten; + HANDLE Handle = CreateFileW(FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (Handle == INVALID_HANDLE_VALUE) + { + skip("Failed to create temp file %ls, error %u\n", FileName, GetLastError()); + return FALSE; + } + Success = WriteFile(Handle, Data, Size, &dwWritten, NULL); + ok(Success == TRUE, "WriteFile failed with %u\n", GetLastError()); + ok(dwWritten == Size, "WriteFile wrote %u bytes instead of %u\n", dwWritten, Size); + if (CustomID) + { + DWORD dwGuidSize; + SetFilePointer(Handle, 30, NULL, FILE_BEGIN); + Success = WriteFile(Handle, CustomID, sizeof(*CustomID), &dwGuidSize, NULL); + ok(dwGuidSize == sizeof(GUID), "WriteFile wrote %u bytes instead of %u\n", dwGuidSize, sizeof(GUID)); + } + CloseHandle(Handle); + return Success && (dwWritten == Size); +} + + + +static const GUID GUID_DATABASE_SHIM = { 0x11111111, 0x1111, 0x1111, { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 } }; +static const GUID GUID_DATABASE_MSI = { 0xd8ff6d16, 0x6a3a, 0x468a, { 0x8b, 0x44, 0x01, 0x71, 0x4d, 0xdc, 0x49, 0xea } }; +static const GUID GUID_DATABASE_DRIVERS = { 0xf9ab2228, 0x3312, 0x4a73, { 0xb6, 0xf9, 0x93, 0x6d, 0x70, 0xe1, 0x12, 0xef } }; +static const GUID TEST_DB_GUID = { 0x79dd75eb, 0xc098, 0x4757, { 0x99, 0x65, 0x9e, 0x83, 0xc4, 0xca, 0x9d, 0xa4 } }; + +#define SDB_DATABASE_MAIN 0x80000000 + +BOOL (WINAPI *pSdbRegisterDatabase)(LPCWSTR pszDatabasePath, DWORD dwDatabaseType); +BOOL (WINAPI *pSdbRegisterDatabaseEx)(LPCWSTR pszDatabasePath, DWORD dwDatabaseType, const PULONGLONG pTimeStamp); +BOOL (WINAPI *pSdbUnregisterDatabase)(REFGUID pguidDB); + + +BOOL IsUserAdmin() +{ + BOOL Result; + SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY }; + PSID AdministratorsGroup; + + Result = AllocateAndInitializeSid(&NtAuthority, 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &AdministratorsGroup); + if (Result) + { + if (!CheckTokenMembership( NULL, AdministratorsGroup, &Result)) + Result = FALSE; + FreeSid(AdministratorsGroup); + } + + return Result; +} + +static DWORD g_QueryFlag = 0xffffffff; +static DWORD QueryFlag(void) +{ + if (g_QueryFlag == 0xffffffff) + { + ULONG_PTR wow64_ptr = 0; + NTSTATUS status = NtQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &wow64_ptr, sizeof(wow64_ptr), NULL); + g_QueryFlag = (NT_SUCCESS(status) && wow64_ptr != 0) ? KEY_WOW64_64KEY : 0; + } + return g_QueryFlag; +} + +static void FileTimeNow(ULARGE_INTEGER& Result) +{ + FILETIME TimeBuffer; + + GetSystemTimeAsFileTime(&TimeBuffer); + Result.HighPart = TimeBuffer.dwHighDateTime; + Result.LowPart = TimeBuffer.dwLowDateTime; +} + +static void ok_keys_(REFGUID Guid, LPCWSTR DisplayName, LPCWSTR Path, DWORD Type, PULONGLONG TimeStamp) +{ + UNICODE_STRING GuidString; + WCHAR StringBuffer[200]; + DWORD ValueBuffer; + ULARGE_INTEGER LargeUIntBuffer; + + CRegKey key; + LSTATUS Status = key.Open(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\InstalledSDB", KEY_READ | QueryFlag()); + winetest_ok(!Status, "Unable to open InstalledSDB key\n"); + if (Status) + return; + + if (!SUCCEEDED(RtlStringFromGUID(Guid, &GuidString))) + { + ok(0, "Unable to format guid\n"); + return; + } + + Status = key.Open(key.m_hKey, GuidString.Buffer, KEY_READ); + winetest_ok(!Status, "Unable to open %s key (0x%x)\n", wine_dbgstr_w(GuidString.Buffer), Status); + RtlFreeUnicodeString(&GuidString); + if (Status) + return; + + ULONG nChars = _countof(StringBuffer); + Status = key.QueryStringValue(L"DatabaseDescription", StringBuffer, &nChars); + winetest_ok(!Status, "Unable to read DatabaseDescription (0x%x)\n", Status); + if (!Status) + winetest_ok(!wcscmp(DisplayName, StringBuffer), "Expected DatabaseDescription to be %s, was %s\n", wine_dbgstr_w(DisplayName), wine_dbgstr_w(StringBuffer)); + + nChars = _countof(StringBuffer); + Status = key.QueryStringValue(L"DatabasePath", StringBuffer, &nChars); + winetest_ok(!Status, "Unable to read DatabasePath (0x%x)\n", Status); + if (!Status) + winetest_ok(!wcscmp(Path, StringBuffer), "Expected DatabasePath to be %s, was %s\n", wine_dbgstr_w(Path), wine_dbgstr_w(StringBuffer)); + + Status = key.QueryDWORDValue(L"DatabaseType", ValueBuffer); + winetest_ok(!Status, "Unable to read DatabaseType (0x%x)\n", Status); + if (!Status) + winetest_ok(ValueBuffer == Type, "Expected DatabaseType to be 0x%x, was 0x%x\n", Type, ValueBuffer); + + Status = key.QueryQWORDValue(L"DatabaseInstallTimeStamp", LargeUIntBuffer.QuadPart); + winetest_ok(!Status, "Unable to read DatabaseInstallTimeStamp (0x%x)\n", Status); + if (!Status) + { + if (TimeStamp) + { + winetest_ok(LargeUIntBuffer.QuadPart == *TimeStamp, "Expected DatabaseInstallTimeStamp to be %s, was %s\n", + wine_dbgstr_longlong(*TimeStamp), wine_dbgstr_longlong(LargeUIntBuffer.QuadPart)); + } + else + { + ULARGE_INTEGER CurrentTime; + FileTimeNow(CurrentTime); + ULONG DiffMS = (ULONG)((CurrentTime.QuadPart - LargeUIntBuffer.QuadPart) / 10000); + winetest_ok(DiffMS < 5000 , "Expected DatabaseInstallTimeStamp to be less than 5 seconds before now (was: %u)\n", DiffMS); + } + } +} + + +#define ok_keys (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : ok_keys_ + + +START_TEST(register) +{ + WCHAR TempPath[MAX_PATH * 2]; + BOOL Success; + HMODULE hdll; + + SetEnvironmentVariableA("SHIM_DEBUG_LEVEL", "4"); + SetEnvironmentVariableA("SHIMENG_DEBUG_LEVEL", "4"); + SetEnvironmentVariableA("DEBUGCHANNEL", "+apphelp"); + + //silence_debug_output(); + hdll = LoadLibraryA("apphelp.dll"); + + *(void**)&pSdbRegisterDatabase = (void*)GetProcAddress(hdll, "SdbRegisterDatabase"); + *(void**)&pSdbRegisterDatabaseEx = (void*)GetProcAddress(hdll, "SdbRegisterDatabaseEx"); + *(void**)&pSdbUnregisterDatabase = (void*)GetProcAddress(hdll, "SdbUnregisterDatabase"); + + if (!pSdbRegisterDatabase || !pSdbRegisterDatabaseEx || !pSdbUnregisterDatabase) + { + skip("Not all functions present: %p, %p, %p\n", pSdbRegisterDatabase, pSdbRegisterDatabaseEx, pSdbUnregisterDatabase); + return; + } + + /* [Err ][SdbUnregisterDatabase] Failed to open key "\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\InstalledSDB\{11111111-1111-1111-1111-111111111111}" Status 0xc0000034 */ + ok_int(pSdbUnregisterDatabase(GUID_DATABASE_SHIM), FALSE); + ok_int(pSdbUnregisterDatabase(GUID_DATABASE_MSI), FALSE); + ok_int(pSdbUnregisterDatabase(GUID_DATABASE_DRIVERS), FALSE); + + + if (!IsUserAdmin()) + { + skip("Not running as admin, unable to install databases!\n"); + return; + } + + GetTempPathW(_countof(TempPath), TempPath); + StringCchCatW(TempPath, _countof(TempPath), L"\\shim_db.sdb"); + if (!WriteSdbFile(TempPath, rawDB, sizeof(rawDB), NULL)) + { + skip("Cannot write %s\n", wine_dbgstr_w(TempPath)); + return; + } + + /* No Type */ + Success = pSdbRegisterDatabase(TempPath, 0); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(TEST_DB_GUID, L"ICS", TempPath, 0, NULL); + Success = pSdbUnregisterDatabase(TEST_DB_GUID); + ok_int(Success, TRUE); + } + + /* Unknown type */ + Success = pSdbRegisterDatabase(TempPath, 1); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(TEST_DB_GUID, L"ICS", TempPath, 1, NULL); + Success = pSdbUnregisterDatabase(TEST_DB_GUID); + ok_int(Success, TRUE); + } + + /* System type */ + Success = pSdbRegisterDatabase(TempPath, SDB_DATABASE_MAIN); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(TEST_DB_GUID, L"ICS", TempPath, SDB_DATABASE_MAIN, NULL); + Success = pSdbUnregisterDatabase(TEST_DB_GUID); + ok_int(Success, TRUE); + } + + /* No type, null time */ + Success = pSdbRegisterDatabaseEx(TempPath, 0, NULL); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(TEST_DB_GUID, L"ICS", TempPath, 0, NULL); + Success = pSdbUnregisterDatabase(TEST_DB_GUID); + ok_int(Success, TRUE); + } + + /* Unknown type, null time */ + Success = pSdbRegisterDatabaseEx(TempPath, 1, NULL); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(TEST_DB_GUID, L"ICS", TempPath, 1, NULL); + Success = pSdbUnregisterDatabase(TEST_DB_GUID); + ok_int(Success, TRUE); + } + + + /* System type, null time */ + Success = pSdbRegisterDatabaseEx(TempPath, SDB_DATABASE_MAIN, NULL); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(TEST_DB_GUID, L"ICS", TempPath, SDB_DATABASE_MAIN, NULL); + Success = pSdbUnregisterDatabase(TEST_DB_GUID); + ok_int(Success, TRUE); + } + + ULARGE_INTEGER Time; + FileTimeNow(Time); + Time.QuadPart ^= 0xffffffffffffffffll; + /* No type, random time */ + Success = pSdbRegisterDatabaseEx(TempPath, 0, &Time.QuadPart); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(TEST_DB_GUID, L"ICS", TempPath, 0, &Time.QuadPart); + Success = pSdbUnregisterDatabase(TEST_DB_GUID); + ok_int(Success, TRUE); + } + + /* Unknown type, random time */ + Success = pSdbRegisterDatabaseEx(TempPath, 1, &Time.QuadPart); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(TEST_DB_GUID, L"ICS", TempPath, 1, &Time.QuadPart); + Success = pSdbUnregisterDatabase(TEST_DB_GUID); + ok_int(Success, TRUE); + } + + /* System type, random time */ + Success = pSdbRegisterDatabaseEx(TempPath, SDB_DATABASE_MAIN, &Time.QuadPart); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(TEST_DB_GUID, L"ICS", TempPath, SDB_DATABASE_MAIN, &Time.QuadPart); + Success = pSdbUnregisterDatabase(TEST_DB_GUID); + ok_int(Success, TRUE); + } + + /* System reserved ID's */ + if (!WriteSdbFile(TempPath, rawDB, sizeof(rawDB), &GUID_DATABASE_SHIM)) + { + skip("Cannot write %s\n", wine_dbgstr_w(TempPath)); + DeleteFileW(TempPath); + return; + } + + Success = pSdbRegisterDatabase(TempPath, 0); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(GUID_DATABASE_SHIM, L"ICS", TempPath, 0, NULL); + Success = pSdbUnregisterDatabase(GUID_DATABASE_SHIM); + ok_int(Success, TRUE); + } + + if (!WriteSdbFile(TempPath, rawDB, sizeof(rawDB), &GUID_DATABASE_MSI)) + { + skip("Cannot write %s\n", wine_dbgstr_w(TempPath)); + DeleteFileW(TempPath); + return; + } + + Success = pSdbRegisterDatabase(TempPath, 0); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(GUID_DATABASE_MSI, L"ICS", TempPath, 0, NULL); + Success = pSdbUnregisterDatabase(GUID_DATABASE_MSI); + ok_int(Success, TRUE); + } + + if (!WriteSdbFile(TempPath, rawDB, sizeof(rawDB), &GUID_DATABASE_DRIVERS)) + { + skip("Cannot write %s\n", wine_dbgstr_w(TempPath)); + DeleteFileW(TempPath); + return; + } + + Success = pSdbRegisterDatabase(TempPath, 0); + ok_int(Success, TRUE); + if (Success) + { + ok_keys(GUID_DATABASE_DRIVERS, L"ICS", TempPath, 0, NULL); + Success = pSdbUnregisterDatabase(GUID_DATABASE_DRIVERS); + ok_int(Success, TRUE); + } + + DeleteFileW(TempPath); +} diff --git a/modules/rostests/apitests/apphelp/testlist.c b/modules/rostests/apitests/apphelp/testlist.c index a90da5fba5d..c27d4e48217 100644 --- a/modules/rostests/apitests/apphelp/testlist.c +++ b/modules/rostests/apitests/apphelp/testlist.c @@ -7,6 +7,7 @@ extern void func_apphelp(void); extern void func_db(void); extern void func_env(void); extern void func_layerapi(void); +extern void func_register(void); const struct test winetest_testlist[] = { @@ -14,5 +15,6 @@ const struct test winetest_testlist[] = { "db", func_db }, { "env", func_env }, { "layerapi", func_layerapi }, + { "register", func_register }, { 0, 0 } }; -- 2.17.1