Reactos
1/*
2 * PROJECT: apphelp_apitest
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Tests for shim database registration
5 * COPYRIGHT: Copyright 2017-2019 Mark Jansen (mark.jansen@reactos.org)
6 */
7
8#include <ntstatus.h>
9#define WIN32_NO_STATUS
10#include <windef.h>
11#include <ntndk.h>
12#include <atlbase.h>
13#include <strsafe.h>
14#include "wine/test.h"
15
16static const unsigned char rawDB[] =
17{
18 /* Header: Major, Minor, 'sdbf' */
19 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x64, 0x62, 0x66,
20
21 /* TAG_DATABASE, Length */
22 0x01, 0x70, 0x22, 0x00, 0x00, 0x00,
23 /* TAG_NAME, Value */
24 0x01, 0x60, 0x06, 0x00, 0x00, 0x00,
25
26 /* TAG_DATABASE_ID, Length, Value*/
27 0x07, 0x90, 0x10, 0x00, 0x00, 0x00,
28 /* offset 30 */
29 0xEB, 0x75, 0xDD, 0x79, 0x98, 0xC0, 0x57, 0x47, 0x99, 0x65, 0x9E, 0x83, 0xC4, 0xCA, 0x9D, 0xA4,
30
31 /* TAG_LIBRARY, Length */
32 0x02, 0x70, 0x00, 0x00, 0x00, 0x00,
33
34 /* TAG_STRINGTABLE, Length */
35 0x01, 0x78, 0x0E, 0x00, 0x00, 0x00,
36 /* TAG_STRINGTABLE_ITEM, Length, Value */
37 0x01, 0x88, 0x08, 0x00, 0x00, 0x00,
38 0x49, 0x00, 0x43, 0x00, 0x53, 0x00, 0x00, 0x00
39};
40
41static BOOL WriteSdbFile(const WCHAR* FileName, const unsigned char* Data, DWORD Size, const GUID* CustomID)
42{
43 BOOL Success;
44 DWORD dwWritten;
45 HANDLE Handle = CreateFileW(FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
46
47 if (Handle == INVALID_HANDLE_VALUE)
48 {
49 skip("Failed to create temp file %ls, error %lu\n", FileName, GetLastError());
50 return FALSE;
51 }
52 Success = WriteFile(Handle, Data, Size, &dwWritten, NULL);
53 ok(Success == TRUE, "WriteFile failed with %lu\n", GetLastError());
54 ok(dwWritten == Size, "WriteFile wrote %lu bytes instead of %lu\n", dwWritten, Size);
55 if (CustomID)
56 {
57 DWORD dwGuidSize;
58 SetFilePointer(Handle, 30, NULL, FILE_BEGIN);
59 Success = WriteFile(Handle, CustomID, sizeof(*CustomID), &dwGuidSize, NULL);
60 ok(dwGuidSize == sizeof(GUID), "WriteFile wrote %lu bytes instead of 0l%u\n", dwGuidSize, sizeof(GUID));
61 }
62 CloseHandle(Handle);
63 return Success && (dwWritten == Size);
64}
65
66
67
68static const GUID GUID_DATABASE_SHIM = { 0x11111111, 0x1111, 0x1111, { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 } };
69static const GUID GUID_DATABASE_MSI = { 0xd8ff6d16, 0x6a3a, 0x468a, { 0x8b, 0x44, 0x01, 0x71, 0x4d, 0xdc, 0x49, 0xea } };
70static const GUID GUID_DATABASE_DRIVERS = { 0xf9ab2228, 0x3312, 0x4a73, { 0xb6, 0xf9, 0x93, 0x6d, 0x70, 0xe1, 0x12, 0xef } };
71static const GUID TEST_DB_GUID = { 0x79dd75eb, 0xc098, 0x4757, { 0x99, 0x65, 0x9e, 0x83, 0xc4, 0xca, 0x9d, 0xa4 } };
72
73#define SDB_DATABASE_MAIN 0x80000000
74
75BOOL (WINAPI *pSdbRegisterDatabase)(LPCWSTR pszDatabasePath, DWORD dwDatabaseType);
76BOOL (WINAPI *pSdbRegisterDatabaseEx)(LPCWSTR pszDatabasePath, DWORD dwDatabaseType, const PULONGLONG pTimeStamp);
77BOOL (WINAPI *pSdbUnregisterDatabase)(REFGUID pguidDB);
78
79
80extern "C"
81BOOL IsUserAdmin(VOID)
82{
83 BOOL Result;
84 SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY };
85 PSID AdministratorsGroup;
86
87 Result = AllocateAndInitializeSid(&NtAuthority, 2,
88 SECURITY_BUILTIN_DOMAIN_RID,
89 DOMAIN_ALIAS_RID_ADMINS,
90 0, 0, 0, 0, 0, 0,
91 &AdministratorsGroup);
92 if (Result)
93 {
94 if (!CheckTokenMembership(NULL, AdministratorsGroup, &Result))
95 Result = FALSE;
96 FreeSid(AdministratorsGroup);
97 }
98
99 return Result;
100}
101
102static DWORD g_QueryFlag = 0xffffffff;
103static DWORD QueryFlag(void)
104{
105 if (g_QueryFlag == 0xffffffff)
106 {
107 ULONG_PTR wow64_ptr = 0;
108 NTSTATUS status = NtQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &wow64_ptr, sizeof(wow64_ptr), NULL);
109 g_QueryFlag = (NT_SUCCESS(status) && wow64_ptr != 0) ? KEY_WOW64_64KEY : 0;
110 }
111 return g_QueryFlag;
112}
113
114static void FileTimeNow(ULARGE_INTEGER& Result)
115{
116 FILETIME TimeBuffer;
117
118 GetSystemTimeAsFileTime(&TimeBuffer);
119 Result.HighPart = TimeBuffer.dwHighDateTime;
120 Result.LowPart = TimeBuffer.dwLowDateTime;
121}
122
123static void ok_keys_(REFGUID Guid, LPCWSTR DisplayName, LPCWSTR Path, DWORD Type, PULONGLONG TimeStamp)
124{
125 UNICODE_STRING GuidString;
126 WCHAR StringBuffer[200];
127 DWORD ValueBuffer;
128 ULARGE_INTEGER LargeUIntBuffer;
129
130 CRegKey key;
131 LSTATUS Status = key.Open(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\InstalledSDB", KEY_READ | QueryFlag());
132 winetest_ok(!Status, "Unable to open InstalledSDB key\n");
133 if (Status)
134 return;
135
136 if (!SUCCEEDED(RtlStringFromGUID(Guid, &GuidString)))
137 {
138 ok(0, "Unable to format guid\n");
139 return;
140 }
141
142 Status = key.Open(key.m_hKey, GuidString.Buffer, KEY_READ);
143 winetest_ok(!Status, "Unable to open %s key (0x%lx)\n", wine_dbgstr_w(GuidString.Buffer), Status);
144 RtlFreeUnicodeString(&GuidString);
145 if (Status)
146 return;
147
148 ULONG nChars = _countof(StringBuffer);
149 Status = key.QueryStringValue(L"DatabaseDescription", StringBuffer, &nChars);
150 winetest_ok(!Status, "Unable to read DatabaseDescription (0x%lx)\n", Status);
151 if (!Status)
152 winetest_ok(!wcscmp(DisplayName, StringBuffer), "Expected DatabaseDescription to be %s, was %s\n", wine_dbgstr_w(DisplayName), wine_dbgstr_w(StringBuffer));
153
154 nChars = _countof(StringBuffer);
155 Status = key.QueryStringValue(L"DatabasePath", StringBuffer, &nChars);
156 winetest_ok(!Status, "Unable to read DatabasePath (0x%lx)\n", Status);
157 if (!Status)
158 winetest_ok(!wcscmp(Path, StringBuffer), "Expected DatabasePath to be %s, was %s\n", wine_dbgstr_w(Path), wine_dbgstr_w(StringBuffer));
159
160 Status = key.QueryDWORDValue(L"DatabaseType", ValueBuffer);
161 winetest_ok(!Status, "Unable to read DatabaseType (0x%lx)\n", Status);
162 if (!Status)
163 winetest_ok(ValueBuffer == Type, "Expected DatabaseType to be 0x%lx, was 0x%lx\n", Type, ValueBuffer);
164
165 Status = key.QueryQWORDValue(L"DatabaseInstallTimeStamp", LargeUIntBuffer.QuadPart);
166 winetest_ok(!Status, "Unable to read DatabaseInstallTimeStamp (0x%lx)\n", Status);
167 if (!Status)
168 {
169 if (TimeStamp)
170 {
171 winetest_ok(LargeUIntBuffer.QuadPart == *TimeStamp, "Expected DatabaseInstallTimeStamp to be %s, was %s\n",
172 wine_dbgstr_longlong(*TimeStamp), wine_dbgstr_longlong(LargeUIntBuffer.QuadPart));
173 }
174 else
175 {
176 ULARGE_INTEGER CurrentTime;
177 FileTimeNow(CurrentTime);
178 ULONG DiffMS = (ULONG)((CurrentTime.QuadPart - LargeUIntBuffer.QuadPart) / 10000);
179 winetest_ok(DiffMS < 5000 , "Expected DatabaseInstallTimeStamp to be less than 5 seconds before now (was: %lu)\n", DiffMS);
180 }
181 }
182}
183
184
185#define ok_keys (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : ok_keys_
186
187
188START_TEST(register)
189{
190 WCHAR TempPath[MAX_PATH * 2];
191 BOOL Success;
192 HMODULE hdll;
193
194 SetEnvironmentVariableA("SHIM_DEBUG_LEVEL", "4");
195 SetEnvironmentVariableA("SHIMENG_DEBUG_LEVEL", "4");
196 SetEnvironmentVariableA("DEBUGCHANNEL", "+apphelp");
197
198 //silence_debug_output();
199 hdll = LoadLibraryA("apphelp.dll");
200
201 *(void**)&pSdbRegisterDatabase = (void*)GetProcAddress(hdll, "SdbRegisterDatabase");
202 *(void**)&pSdbRegisterDatabaseEx = (void*)GetProcAddress(hdll, "SdbRegisterDatabaseEx");
203 *(void**)&pSdbUnregisterDatabase = (void*)GetProcAddress(hdll, "SdbUnregisterDatabase");
204
205 if (!pSdbRegisterDatabase || !pSdbRegisterDatabaseEx || !pSdbUnregisterDatabase)
206 {
207 skip("Not all functions present: %p, %p, %p\n", pSdbRegisterDatabase, pSdbRegisterDatabaseEx, pSdbUnregisterDatabase);
208 return;
209 }
210
211 /* [Err ][SdbUnregisterDatabase] Failed to open key "\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\InstalledSDB\{11111111-1111-1111-1111-111111111111}" Status 0xc0000034 */
212 ok_int(pSdbUnregisterDatabase(GUID_DATABASE_SHIM), FALSE);
213 ok_int(pSdbUnregisterDatabase(GUID_DATABASE_MSI), FALSE);
214 ok_int(pSdbUnregisterDatabase(GUID_DATABASE_DRIVERS), FALSE);
215
216
217 if (!IsUserAdmin())
218 {
219 skip("Not running as admin, unable to install databases!\n");
220 return;
221 }
222
223 GetTempPathW(_countof(TempPath), TempPath);
224 StringCchCatW(TempPath, _countof(TempPath), L"\\shim_db.sdb");
225 if (!WriteSdbFile(TempPath, rawDB, sizeof(rawDB), NULL))
226 {
227 skip("Cannot write %s\n", wine_dbgstr_w(TempPath));
228 return;
229 }
230
231 /* No Type */
232 Success = pSdbRegisterDatabase(TempPath, 0);
233 ok_int(Success, TRUE);
234 if (Success)
235 {
236 ok_keys(TEST_DB_GUID, L"ICS", TempPath, 0, NULL);
237 Success = pSdbUnregisterDatabase(TEST_DB_GUID);
238 ok_int(Success, TRUE);
239 }
240
241 /* Unknown type */
242 Success = pSdbRegisterDatabase(TempPath, 1);
243 ok_int(Success, TRUE);
244 if (Success)
245 {
246 ok_keys(TEST_DB_GUID, L"ICS", TempPath, 1, NULL);
247 Success = pSdbUnregisterDatabase(TEST_DB_GUID);
248 ok_int(Success, TRUE);
249 }
250
251 /* System type */
252 Success = pSdbRegisterDatabase(TempPath, SDB_DATABASE_MAIN);
253 ok_int(Success, TRUE);
254 if (Success)
255 {
256 ok_keys(TEST_DB_GUID, L"ICS", TempPath, SDB_DATABASE_MAIN, NULL);
257 Success = pSdbUnregisterDatabase(TEST_DB_GUID);
258 ok_int(Success, TRUE);
259 }
260
261 /* No type, null time */
262 Success = pSdbRegisterDatabaseEx(TempPath, 0, NULL);
263 ok_int(Success, TRUE);
264 if (Success)
265 {
266 ok_keys(TEST_DB_GUID, L"ICS", TempPath, 0, NULL);
267 Success = pSdbUnregisterDatabase(TEST_DB_GUID);
268 ok_int(Success, TRUE);
269 }
270
271 /* Unknown type, null time */
272 Success = pSdbRegisterDatabaseEx(TempPath, 1, NULL);
273 ok_int(Success, TRUE);
274 if (Success)
275 {
276 ok_keys(TEST_DB_GUID, L"ICS", TempPath, 1, NULL);
277 Success = pSdbUnregisterDatabase(TEST_DB_GUID);
278 ok_int(Success, TRUE);
279 }
280
281
282 /* System type, null time */
283 Success = pSdbRegisterDatabaseEx(TempPath, SDB_DATABASE_MAIN, NULL);
284 ok_int(Success, TRUE);
285 if (Success)
286 {
287 ok_keys(TEST_DB_GUID, L"ICS", TempPath, SDB_DATABASE_MAIN, NULL);
288 Success = pSdbUnregisterDatabase(TEST_DB_GUID);
289 ok_int(Success, TRUE);
290 }
291
292 ULARGE_INTEGER Time;
293 FileTimeNow(Time);
294 Time.QuadPart ^= 0xffffffffffffffffll;
295 /* No type, random time */
296 Success = pSdbRegisterDatabaseEx(TempPath, 0, &Time.QuadPart);
297 ok_int(Success, TRUE);
298 if (Success)
299 {
300 ok_keys(TEST_DB_GUID, L"ICS", TempPath, 0, &Time.QuadPart);
301 Success = pSdbUnregisterDatabase(TEST_DB_GUID);
302 ok_int(Success, TRUE);
303 }
304
305 /* Unknown type, random time */
306 Success = pSdbRegisterDatabaseEx(TempPath, 1, &Time.QuadPart);
307 ok_int(Success, TRUE);
308 if (Success)
309 {
310 ok_keys(TEST_DB_GUID, L"ICS", TempPath, 1, &Time.QuadPart);
311 Success = pSdbUnregisterDatabase(TEST_DB_GUID);
312 ok_int(Success, TRUE);
313 }
314
315 /* System type, random time */
316 Success = pSdbRegisterDatabaseEx(TempPath, SDB_DATABASE_MAIN, &Time.QuadPart);
317 ok_int(Success, TRUE);
318 if (Success)
319 {
320 ok_keys(TEST_DB_GUID, L"ICS", TempPath, SDB_DATABASE_MAIN, &Time.QuadPart);
321 Success = pSdbUnregisterDatabase(TEST_DB_GUID);
322 ok_int(Success, TRUE);
323 }
324
325 /* System reserved ID's */
326 if (!WriteSdbFile(TempPath, rawDB, sizeof(rawDB), &GUID_DATABASE_SHIM))
327 {
328 skip("Cannot write %s\n", wine_dbgstr_w(TempPath));
329 DeleteFileW(TempPath);
330 return;
331 }
332
333 Success = pSdbRegisterDatabase(TempPath, 0);
334 ok_int(Success, TRUE);
335 if (Success)
336 {
337 ok_keys(GUID_DATABASE_SHIM, L"ICS", TempPath, 0, NULL);
338 Success = pSdbUnregisterDatabase(GUID_DATABASE_SHIM);
339 ok_int(Success, TRUE);
340 }
341
342 if (!WriteSdbFile(TempPath, rawDB, sizeof(rawDB), &GUID_DATABASE_MSI))
343 {
344 skip("Cannot write %s\n", wine_dbgstr_w(TempPath));
345 DeleteFileW(TempPath);
346 return;
347 }
348
349 Success = pSdbRegisterDatabase(TempPath, 0);
350 ok_int(Success, TRUE);
351 if (Success)
352 {
353 ok_keys(GUID_DATABASE_MSI, L"ICS", TempPath, 0, NULL);
354 Success = pSdbUnregisterDatabase(GUID_DATABASE_MSI);
355 ok_int(Success, TRUE);
356 }
357
358 if (!WriteSdbFile(TempPath, rawDB, sizeof(rawDB), &GUID_DATABASE_DRIVERS))
359 {
360 skip("Cannot write %s\n", wine_dbgstr_w(TempPath));
361 DeleteFileW(TempPath);
362 return;
363 }
364
365 Success = pSdbRegisterDatabase(TempPath, 0);
366 ok_int(Success, TRUE);
367 if (Success)
368 {
369 ok_keys(GUID_DATABASE_DRIVERS, L"ICS", TempPath, 0, NULL);
370 Success = pSdbUnregisterDatabase(GUID_DATABASE_DRIVERS);
371 ok_int(Success, TRUE);
372 }
373
374 DeleteFileW(TempPath);
375}