From: Santino Mazza smazza@codeweavers.com
--- dlls/ntdll/unix/registry.c | 3 +- include/wine/server_protocol.h | 4 ++- include/winnt.h | 1 + server/protocol.def | 1 + server/registry.c | 50 ++++++++++++++++++++++++++++++++-- server/request.h | 5 ++-- server/trace.c | 3 +- 7 files changed, 59 insertions(+), 8 deletions(-)
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index b53ee35f488..a5510af92b0 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -709,7 +709,7 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f
TRACE( "(%p,%p,0x%x,%p,%p,0x%x,%p,%p)\n", attr, file, flags, trustkey, event, access, roothandle, iostatus );
- if (flags) FIXME( "flags %x not handled\n", flags ); + if (flags && (flags & ~REG_LOAD_APP_KEY)) FIXME( "flags %x not handled\n", flags ); if (trustkey) FIXME("trustkey parameter not supported\n"); if (event) FIXME("event parameter not supported\n"); if (iostatus) FIXME("iostatus is not filled\n"); @@ -727,6 +727,7 @@ NTSTATUS WINAPI NtLoadKeyEx( const OBJECT_ATTRIBUTES *attr, OBJECT_ATTRIBUTES *f
SERVER_START_REQ( load_registry ) { + req->flags = flags; req->access = access; wine_server_add_data( req, objattr, len ); wine_server_add_data( req, unix_name, strlen(unix_name) + 1 ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 2aa2dc1880f..0b47e438513 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2360,9 +2360,11 @@ struct delete_key_value_reply struct load_registry_request { struct request_header __header; + unsigned int flags; unsigned int access; /* VARARG(objattr,object_attributes); */ /* VARARG(filename,string); */ + char __pad_20[4]; }; struct load_registry_reply { @@ -6327,7 +6329,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 758 +#define SERVER_PROTOCOL_VERSION 759
/* ### protocol_version end ### */
diff --git a/include/winnt.h b/include/winnt.h index 76aee026d84..ac61da783c9 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| \ diff --git a/server/protocol.def b/server/protocol.def index a5a8105bf06..4e0c4b905db 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1825,6 +1825,7 @@ struct process_info
/* Load a registry branch from a file */ @REQ(load_registry) + unsigned int flags; /* flags */ unsigned int access; /* wanted access rights */ VARARG(objattr,object_attributes); /* object attributes */ VARARG(filename,string); /* file to load name */ diff --git a/server/registry.c b/server/registry.c index 22856e62b5e..ce25b01f7e9 100644 --- a/server/registry.c +++ b/server/registry.c @@ -1753,6 +1753,33 @@ static void load_registry( struct key *key, const char *filename ) else file_set_error(); }
+static void load_app_registry( struct key *key, const char *filename ) +{ + WCHAR applicationhive_fullpath[12] = {'\', 'R', 'E', 'G', 'I', 'S', 'T', 'R', 'Y', '\', 'A'}; + WCHAR *key_fullpath; + data_size_t key_fullpath_size; + + /* check if we are loading in \REGISTRY\A */ + key_fullpath = key_get_full_name( (struct object*)key, &key_fullpath_size ); + if (key_fullpath_size < (sizeof(applicationhive_fullpath) - 1 ) || + memcmp( key_fullpath, applicationhive_fullpath, sizeof(applicationhive_fullpath) - 2 )) + { + set_error( STATUS_PRIVILEGE_NOT_HELD ); + } + free( key_fullpath ); + + if (!get_error()) + load_registry( key, filename ); + + key->file = fopen(filename, "r+"); + if (!key->file) + { + file_set_error(); + return; + } + flockfile(key->file); +} + /* load one of the initial registry files */ static int load_init_registry_from_file( const char *filename, struct key *key ) { @@ -1839,10 +1866,12 @@ 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; @@ -1920,6 +1949,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 );
@@ -2290,7 +2324,7 @@ DECL_HANDLER(load_registry)
if (!objattr) return;
- if (!thread_single_check_privilege( current, SeRestorePrivilege )) + if (!(req->flags & REG_LOAD_APP_KEY) && !thread_single_check_privilege( current, SeRestorePrivilege )) { set_error( STATUS_PRIVILEGE_NOT_HELD ); return; @@ -2302,8 +2336,18 @@ DECL_HANDLER(load_registry)
if ((key = create_key( parent, &name, 0, KEY_WOW64_64KEY, 0, sd ))) { - load_registry( key, filename ); - reply->hkey = alloc_handle( current->process, key, req->access, objattr->attributes ); + if (req->flags & REG_LOAD_APP_KEY) + load_app_registry( key, filename ); + else + load_registry( key, filename ); + + if (!get_error()) + reply->hkey = alloc_handle( current->process, key, req->access, objattr->attributes ); + else + { + reply->hkey = 0; + delete_key( key, 1 ); + } release_object( key ); } if (parent) release_object( parent ); diff --git a/server/request.h b/server/request.h index 10fbddc0852..faf66287b60 100644 --- a/server/request.h +++ b/server/request.h @@ -1230,8 +1230,9 @@ C_ASSERT( FIELD_OFFSET(struct enum_key_value_reply, namelen) == 16 ); 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, access) == 12 ); -C_ASSERT( sizeof(struct load_registry_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct load_registry_request, flags) == 12 ); +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 ); diff --git a/server/trace.c b/server/trace.c index c96b4addffe..97435dc7493 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2406,7 +2406,8 @@ 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, " access=%08x", req->access ); + fprintf( stderr, " flags=%08x", req->flags ); + fprintf( stderr, ", access=%08x", req->access ); dump_varargs_object_attributes( ", objattr=", cur_size ); dump_varargs_string( ", filename=", cur_size ); }