-- v4: server: Create \REGISTRY\A hive. ntdll: Implement roothandle parameter for NtLoadKeyEx. ntdll: Rename key variable and file parameter. ntdll/test: Test for NtRegLoadKey roothandle parameter. winnt.h: Create definition for REG_LOAD_APP_KEY.
From: Santino Mazza smazza@codeweavers.com
Note: This is not the official name for this definition, as I'm aware, I just created it to prevent magic values inside application hives implementation. --- include/winnt.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/winnt.h b/include/winnt.h index c0599a5f757..375c8468cfd 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -5517,6 +5517,7 @@ typedef struct _TAPE_GET_MEDIA_PARAMETERS { #define REG_REFRESH_HIVE 0x00000002 #define REG_NO_LAZY_FLUSH 0x00000004 #define REG_FORCE_RESTORE 0x00000008 +#define REG_LOAD_APP_KEY 0x00000010
#define KEY_READ ((STANDARD_RIGHTS_READ| \ KEY_QUERY_VALUE| \
From: Santino Mazza smazza@codeweavers.com
Windows 7 apparently has a different order or number of parameters, so I had to use broken(). --- dlls/ntdll/tests/reg.c | 97 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+)
diff --git a/dlls/ntdll/tests/reg.c b/dlls/ntdll/tests/reg.c index f3c4eb15da0..3785ce8740a 100644 --- a/dlls/ntdll/tests/reg.c +++ b/dlls/ntdll/tests/reg.c @@ -153,6 +153,7 @@ static NTSTATUS (WINAPI * pNtNotifyChangeKey)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOI static NTSTATUS (WINAPI * pNtNotifyChangeMultipleKeys)(HANDLE,ULONG,OBJECT_ATTRIBUTES*,HANDLE,PIO_APC_ROUTINE, void*,IO_STATUS_BLOCK*,ULONG,BOOLEAN,void*,ULONG,BOOLEAN); static NTSTATUS (WINAPI * pNtWaitForSingleObject)(HANDLE,BOOLEAN,const LARGE_INTEGER*); +static NTSTATUS (WINAPI * pNtLoadKeyEx)(const OBJECT_ATTRIBUTES*,OBJECT_ATTRIBUTES*,ULONG,HANDLE,HANDLE,ACCESS_MASK,HANDLE*,IO_STATUS_BLOCK*);
static HMODULE hntdll = 0; static int CurrentTest = 0; @@ -205,6 +206,7 @@ static BOOL InitFunctionPtrs(void) NTDLL_GET_PROC(RtlpNtQueryValueKey) NTDLL_GET_PROC(RtlOpenCurrentUser) NTDLL_GET_PROC(NtWaitForSingleObject) + NTDLL_GET_PROC(NtLoadKeyEx);
/* optional functions */ pNtQueryLicenseValue = (void *)GetProcAddress(hntdll, "NtQueryLicenseValue"); @@ -2268,6 +2270,100 @@ static void test_NtRenameKey(void) pNtClose(key); }
+static BOOL set_privileges(LPCSTR privilege, BOOL set) +{ + TOKEN_PRIVILEGES tp; + HANDLE hToken; + LUID luid; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) + return FALSE; + + if(!LookupPrivilegeValueA(NULL, privilege, &luid)) + { + CloseHandle(hToken); + return FALSE; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + + if (set) + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + tp.Privileges[0].Attributes = 0; + + AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL); + if (GetLastError() != ERROR_SUCCESS) + { + CloseHandle(hToken); + return FALSE; + } + + CloseHandle(hToken); + return TRUE; +} + +static void test_NtRegLoadKeyEx(void) +{ + NTSTATUS status; + OBJECT_ATTRIBUTES file_attr, key_attr; + WCHAR temp_path[MAX_PATH], hivefile_path[MAX_PATH]; + UNICODE_STRING hivefile_pathW, key_pathW; + HANDLE key = 0; + + GetTempPathW(sizeof(temp_path), temp_path); + GetTempFileNameW(temp_path, L"key", 0, hivefile_path); + DeleteFileW(hivefile_path); + RtlDosPathNameToNtPathName_U(hivefile_path, &hivefile_pathW, NULL, NULL); + + if (!set_privileges(SE_RESTORE_NAME, TRUE) || + !set_privileges(SE_BACKUP_NAME, TRUE)) + { + win_skip("Failed to set SE_RESTORE_NAME and SE_BACKUP_NAME privileges, skipping tests\n"); + RtlFreeUnicodeString(&hivefile_pathW); + return; + } + + /* Generate hive file */ + InitializeObjectAttributes(&key_attr, &winetestpath, 0, NULL, NULL); + status = pNtCreateKey(&key, KEY_ALL_ACCESS, &key_attr, 0, 0, 0, 0); + ok(status == ERROR_SUCCESS, "couldn't create key 0x%lx\n", status); + status = RegSaveKeyW(key, hivefile_path, NULL); + ok(status == ERROR_SUCCESS, "couldn't save key %ld\n", status); + status = pNtDeleteKey(key); + ok(status == ERROR_SUCCESS, "couldn't delete key 0x%lx\n", status); + key = 0; + + /* Test for roothandle parameter with no flags */ + pRtlFormatCurrentUserKeyPath(&key_pathW); + key_pathW.Buffer = pRtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, key_pathW.Buffer, + key_pathW.MaximumLength + sizeof(key_pathW)*sizeof(WCHAR)); + key_pathW.MaximumLength = key_pathW.MaximumLength + sizeof(key_pathW)*sizeof(WCHAR); + pRtlAppendUnicodeToString(&key_pathW, L"TestKey"); + + InitializeObjectAttributes(&file_attr, &hivefile_pathW, 0, NULL, NULL); + key_attr.ObjectName = &key_pathW; + status = pNtLoadKeyEx(&key_attr, &file_attr, 0, NULL, NULL, KEY_READ, &key, NULL); + todo_wine ok(status == STATUS_INVALID_PARAMETER_7 || status == STATUS_INVALID_PARAMETER_6 /* win7 */, "got 0x%lx\n", status); + ok(!key, "key is null\n"); + if (key) pNtClose(key); + RtlFreeUnicodeString(&key_pathW); + + /* Test for roothandle parameter with REG_LOAD_APP_KEY */ + RtlCreateUnicodeString(&key_pathW, L"\REGISTRY\A\TestKey"); + status = pNtLoadKeyEx(&key_attr, &file_attr, REG_LOAD_APP_KEY, NULL, NULL, KEY_READ, &key, NULL); + todo_wine ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_VIOLATION) /* win7 */, "got 0x%lx\n", status); + todo_wine ok(key != NULL || broken(key == NULL) /* win7 */, "key is null\n"); + if (key) pNtClose(key); + RtlFreeUnicodeString(&key_pathW); + + set_privileges(SE_RESTORE_NAME, FALSE); + set_privileges(SE_BACKUP_NAME, FALSE); + RtlFreeUnicodeString(&hivefile_pathW); + DeleteFileW(hivefile_path); +} + START_TEST(reg) { static const WCHAR winetest[] = {'\','W','i','n','e','T','e','s','t',0}; @@ -2298,6 +2394,7 @@ START_TEST(reg) test_symlinks(); test_redirection(); test_NtRenameKey(); + test_NtRegLoadKeyEx();
pRtlFreeUnicodeString(&winetestpath);
From: Santino Mazza smazza@codeweavers.com
--- dlls/ntdll/unix/registry.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index 797e32a5bf1..f61b892875f 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -696,18 +696,18 @@ NTSTATUS WINAPI NtLoadKey2( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *fi /****************************************************************************** * NtLoadKeyEx (NTDLL.@) */ -NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *file, ULONG flags, HANDLE trustkey, +NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *key_attr, OBJECT_ATTRIBUTES *file_attr, ULONG flags, HANDLE trustkey, HANDLE event, ACCESS_MASK access, HANDLE *roothandle, IO_STATUS_BLOCK *iostatus ) { NTSTATUS ret; - HANDLE key; + HANDLE file; data_size_t len; struct object_attributes *objattr; char *unix_name; UNICODE_STRING nt_name; - OBJECT_ATTRIBUTES new_attr = *file; + OBJECT_ATTRIBUTES new_attr = *file_attr;
- TRACE( "(%p,%p,0x%x,%p,%p,0x%x,%p,%p)\n", attr, file, flags, trustkey, event, access, roothandle, iostatus ); + TRACE( "(%p,%p,0x%x,%p,%p,0x%x,%p,%p)\n", key_attr, file_attr, flags, trustkey, event, access, roothandle, iostatus );
if (flags) FIXME( "flags %x not handled\n", flags ); if (trustkey) FIXME("trustkey parameter not supported\n"); @@ -719,7 +719,7 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f get_redirect( &new_attr, &nt_name ); if (!(ret = nt_to_unix_file_name( &new_attr, &unix_name, FILE_OPEN ))) { - ret = open_unix_file( &key, unix_name, GENERIC_READ | SYNCHRONIZE, + ret = open_unix_file( &file, unix_name, GENERIC_READ | SYNCHRONIZE, &new_attr, 0, 0, FILE_OPEN, 0, NULL, 0 ); free( unix_name ); } @@ -727,19 +727,19 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f
if (ret) return ret;
- if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + if ((ret = alloc_object_attributes( key_attr, &objattr, &len ))) return ret; objattr->attributes |= OBJ_OPENIF | OBJ_CASE_INSENSITIVE;
SERVER_START_REQ( load_registry ) { - req->file = wine_server_obj_handle( key ); + req->file = wine_server_obj_handle( file ); wine_server_add_data( req, objattr, len ); ret = wine_server_call( req ); if (ret == STATUS_OBJECT_NAME_EXISTS) ret = STATUS_SUCCESS; } SERVER_END_REQ;
- NtClose( key ); + NtClose( file ); free( objattr ); return ret; }
From: Santino Mazza smazza@codeweavers.com
--- dlls/ntdll/unix/registry.c | 10 +++++++--- include/wine/server_protocol.h | 6 +++++- server/protocol.def | 3 +++ server/registry.c | 1 + server/request.h | 5 ++++- server/trace.c | 8 +++++++- 6 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index f61b892875f..f1e5305cecb 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -700,7 +700,7 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *key_attr, OBJECT_ATTRIBUTE HANDLE event, ACCESS_MASK access, HANDLE *roothandle, IO_STATUS_BLOCK *iostatus ) { NTSTATUS ret; - HANDLE file; + HANDLE file, key; data_size_t len; struct object_attributes *objattr; char *unix_name; @@ -712,10 +712,10 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *key_attr, OBJECT_ATTRIBUTE if (flags) FIXME( "flags %x not handled\n", flags ); if (trustkey) FIXME("trustkey parameter not supported\n"); if (event) FIXME("event parameter not supported\n"); - if (access) FIXME("access parameter not supported\n"); - if (roothandle) FIXME("roothandle is not filled\n"); if (iostatus) FIXME("iostatus is not filled\n");
+ if (roothandle && !(flags & REG_LOAD_APP_KEY)) return STATUS_INVALID_PARAMETER_7; + get_redirect( &new_attr, &nt_name ); if (!(ret = nt_to_unix_file_name( &new_attr, &unix_name, FILE_OPEN ))) { @@ -733,12 +733,16 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *key_attr, OBJECT_ATTRIBUTE SERVER_START_REQ( load_registry ) { req->file = wine_server_obj_handle( file ); + req->access = access; wine_server_add_data( req, objattr, len ); ret = wine_server_call( req ); + key = wine_server_ptr_handle( reply->hkey ); if (ret == STATUS_OBJECT_NAME_EXISTS) ret = STATUS_SUCCESS; } SERVER_END_REQ;
+ if (roothandle) *roothandle = key; + else NtClose( key ); NtClose( file ); free( objattr ); return ret; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index fb3168c4a6a..0fc9cbcafbb 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2361,11 +2361,15 @@ struct load_registry_request { struct request_header __header; obj_handle_t file; + unsigned int access; /* VARARG(objattr,object_attributes); */ + char __pad_20[4]; }; struct load_registry_reply { struct reply_header __header; + obj_handle_t hkey; + char __pad_12[4]; };
@@ -6324,7 +6328,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 755 +#define SERVER_PROTOCOL_VERSION 756
/* ### protocol_version end ### */
diff --git a/server/protocol.def b/server/protocol.def index d828d41d1f7..470242187cd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1826,7 +1826,10 @@ struct process_info /* Load a registry branch from a file */ @REQ(load_registry) obj_handle_t file; /* file to load from */ + unsigned int access; /* wanted access rights */ VARARG(objattr,object_attributes); /* object attributes */ +@REPLY + obj_handle_t hkey; /* handle to root key */ @END
diff --git a/server/registry.c b/server/registry.c index 96ba18a0a5a..2817db327e0 100644 --- a/server/registry.c +++ b/server/registry.c @@ -2298,6 +2298,7 @@ DECL_HANDLER(load_registry) if ((key = create_key( parent, &name, 0, KEY_WOW64_64KEY, 0, sd ))) { load_registry( key, req->file ); + reply->hkey = alloc_handle( current->process, key, req->access, objattr->attributes ); release_object( key ); } if (parent) release_object( parent ); diff --git a/server/request.h b/server/request.h index 9e943cceb3c..edb69ee137d 100644 --- a/server/request.h +++ b/server/request.h @@ -1231,7 +1231,10 @@ C_ASSERT( sizeof(struct enum_key_value_reply) == 24 ); C_ASSERT( FIELD_OFFSET(struct delete_key_value_request, hkey) == 12 ); C_ASSERT( sizeof(struct delete_key_value_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct load_registry_request, file) == 12 ); -C_ASSERT( sizeof(struct load_registry_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct load_registry_request, access) == 16 ); +C_ASSERT( sizeof(struct load_registry_request) == 24 ); +C_ASSERT( FIELD_OFFSET(struct load_registry_reply, hkey) == 8 ); +C_ASSERT( sizeof(struct load_registry_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct unload_registry_request, parent) == 12 ); C_ASSERT( FIELD_OFFSET(struct unload_registry_request, attributes) == 16 ); C_ASSERT( sizeof(struct unload_registry_request) == 24 ); diff --git a/server/trace.c b/server/trace.c index c6a324bb905..329ee3a7b9f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2407,9 +2407,15 @@ static void dump_delete_key_value_request( const struct delete_key_value_request static void dump_load_registry_request( const struct load_registry_request *req ) { fprintf( stderr, " file=%04x", req->file ); + fprintf( stderr, ", access=%08x", req->access ); dump_varargs_object_attributes( ", objattr=", cur_size ); }
+static void dump_load_registry_reply( const struct load_registry_reply *req ) +{ + fprintf( stderr, " hkey=%04x", req->hkey ); +} + static void dump_unload_registry_request( const struct unload_registry_request *req ) { fprintf( stderr, " parent=%04x", req->parent ); @@ -4869,7 +4875,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_key_value_reply, (dump_func)dump_enum_key_value_reply, NULL, - NULL, + (dump_func)dump_load_registry_reply, NULL, NULL, NULL,
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=123494
Your paranoid android.
=== debian11 (32 bit report) ===
ntdll: reg.c:2348: Test succeeded inside todo block: got 0xc00000f5
=== debian11 (32 bit zh:CN report) ===
ntdll: reg.c:2348: Test succeeded inside todo block: got 0xc00000f5
=== debian11 (32 bit WoW report) ===
ntdll: reg.c:2348: Test succeeded inside todo block: got 0xc00000f5
=== debian11 (64 bit WoW report) ===
ntdll: reg.c:2348: Test succeeded inside todo block: got 0xc00000f5
From: Santino Mazza smazza@codeweavers.com
--- dlls/ntdll/tests/reg.c | 6 +++--- server/registry.c | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/reg.c b/dlls/ntdll/tests/reg.c index 3785ce8740a..8f29e2f0903 100644 --- a/dlls/ntdll/tests/reg.c +++ b/dlls/ntdll/tests/reg.c @@ -2345,7 +2345,7 @@ static void test_NtRegLoadKeyEx(void) InitializeObjectAttributes(&file_attr, &hivefile_pathW, 0, NULL, NULL); key_attr.ObjectName = &key_pathW; status = pNtLoadKeyEx(&key_attr, &file_attr, 0, NULL, NULL, KEY_READ, &key, NULL); - todo_wine ok(status == STATUS_INVALID_PARAMETER_7 || status == STATUS_INVALID_PARAMETER_6 /* win7 */, "got 0x%lx\n", status); + ok(status == STATUS_INVALID_PARAMETER_7 || status == STATUS_INVALID_PARAMETER_6 /* win7 */, "got 0x%lx\n", status); ok(!key, "key is null\n"); if (key) pNtClose(key); RtlFreeUnicodeString(&key_pathW); @@ -2353,8 +2353,8 @@ static void test_NtRegLoadKeyEx(void) /* Test for roothandle parameter with REG_LOAD_APP_KEY */ RtlCreateUnicodeString(&key_pathW, L"\REGISTRY\A\TestKey"); status = pNtLoadKeyEx(&key_attr, &file_attr, REG_LOAD_APP_KEY, NULL, NULL, KEY_READ, &key, NULL); - todo_wine ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_VIOLATION) /* win7 */, "got 0x%lx\n", status); - todo_wine ok(key != NULL || broken(key == NULL) /* win7 */, "key is null\n"); + ok(status == STATUS_SUCCESS || broken(status == STATUS_ACCESS_VIOLATION) /* win7 */, "got 0x%lx\n", status); + ok(key != NULL || broken(key == NULL) /* win7 */, "key is null\n"); if (key) pNtClose(key); RtlFreeUnicodeString(&key_pathW);
diff --git a/server/registry.c b/server/registry.c index 2817db327e0..c413d0062b8 100644 --- a/server/registry.c +++ b/server/registry.c @@ -1853,10 +1853,13 @@ void init_registry(void) 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\', 'P','e','r','f','l','i','b','\', '0','0','9'}; + static const WCHAR application[] = {'A'}; + static const struct unicode_str root_name = { REGISTRY, sizeof(REGISTRY) }; static const struct unicode_str HKLM_name = { HKLM, sizeof(HKLM) }; static const struct unicode_str HKU_name = { HKU_default, sizeof(HKU_default) }; static const struct unicode_str perflib_name = { perflib, sizeof(perflib) }; + static const struct unicode_str application_name = { application, sizeof(application) };
WCHAR *current_user_path; struct unicode_str current_user_str; @@ -1934,6 +1937,11 @@ void init_registry(void) release_object( key ); }
+ /* create application hive */ + if (!(key = create_key_recursive( root_key, &application_name, current_time ))) + fatal_error( "could not create \REGISTRY\A registry key\n" ); + release_object(key); + release_object( hklm ); release_object( hkcu );
The commit `server: Create \REGISTRY\A hive.` is required because apparently the roothandle paramter is only valid with the REG_LOAD_APP_KEY flag.