From: Sven Baars sbaars@codeweavers.com
--- dlls/advapi32/tests/registry.c | 2 +- dlls/kernelbase/registry.c | 97 +++++++++++++++++++++++++++++++++- 2 files changed, 96 insertions(+), 3 deletions(-)
diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c index b4f0398b358..ecc71ec8db8 100644 --- a/dlls/advapi32/tests/registry.c +++ b/dlls/advapi32/tests/registry.c @@ -2778,7 +2778,7 @@ static void test_redirection(void)
/* verify subkey is not present in native mode */ err = RegOpenKeyExA(native, "AWineTest", 0, KEY_ALL_ACCESS, &key); - ok(err == ERROR_FILE_NOT_FOUND, "got %li\n", err); + todo_wine_if(ptr_size == 64) ok(err == ERROR_FILE_NOT_FOUND, "got %li\n", err);
err = pRegDeleteKeyExA(op_key, "AWineTest", opposite, 0); ok(err == ERROR_SUCCESS, "got %li\n", err); diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index b3865eb8467..a4a3f667987 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -117,7 +117,7 @@ static HANDLE open_wow6432node( HANDLE key ) attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; RtlInitUnicodeString( &nameW, L"Wow6432Node" ); - if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) ret = 0; + if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return key; return ret; }
@@ -140,6 +140,67 @@ static HKEY get_perflib_key( HANDLE key ) return key; }
+static BOOL is_shared( HKEY key ) +{ + NTSTATUS status; + DWORD len; + struct { + ULONG Unknown1; + ULONG Unknown2; + ULONG WowShare; + } flags_info; + + status = NtQueryKey( key, KeyFlagsInformation, &flags_info, sizeof(flags_info), &len ); + return (!status && flags_info.WowShare); +} + +static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ); + +static NTSTATUS open_shared_parent( HKEY *subkey, HKEY root, DWORD options, ACCESS_MASK access ) +{ + BOOL is_wow64_key = (access & KEY_WOW64_32KEY) || (is_wow64 && !(access & KEY_WOW64_64KEY)); + ACCESS_MASK access_64 = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY; + KEY_NAME_INFORMATION *info = NULL; + UNICODE_STRING str; + NTSTATUS status; + DWORD len; + + if (is_wow64_key && is_shared( root )) + { + /* Obtain the name of the root key */ + status = NtQueryKey( root, KeyNameInformation, info, 0, &len ); + if (status != STATUS_BUFFER_TOO_SMALL) return status; + + if (!(info = heap_alloc( len ))) + return STATUS_NO_MEMORY; + + /* Open the shared parent only if the key ends in a Wow6432Node */ + status = NtQueryKey( root, KeyNameInformation, info, len, &len ); + if (!status && info->NameLength / sizeof(WCHAR) >= 11) + { + str.Buffer = info->Name + info->NameLength / sizeof(WCHAR) - 11; + str.Length = 11 * sizeof(WCHAR); + if (is_wow6432node( &str )) + { + root = 0; + str.Buffer = info->Name; + str.Length = info->NameLength - 11 * sizeof(WCHAR); + while (!status && str.Length) + { + status = open_subkey( subkey, root, &str, options & ~REG_OPTION_OPEN_LINK, access_64 ); + if (root) NtClose( root ); + root = *subkey; + } + heap_free( info ); + return status; + } + } + heap_free( info ); + } + + return STATUS_OBJECT_NAME_NOT_FOUND; +} + static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ) { BOOL is_wow64_key = (access & KEY_WOW64_32KEY) || (is_wow64 && !(access & KEY_WOW64_64KEY)); @@ -177,6 +238,23 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR }
status = NtOpenKeyEx( (HANDLE *)subkey, access_64, &attr, options ); + if (status == STATUS_OBJECT_NAME_NOT_FOUND && root) + { + HKEY shared_root; + + /* Try to open the shared parent if we can't find the key in the Wow6432Node */ + if (open_shared_parent( &shared_root, root, options, access )) + return STATUS_OBJECT_NAME_NOT_FOUND; + + attr.RootDirectory = (HANDLE)shared_root; + status = NtOpenKeyEx( (HANDLE *)subkey, access_64, &attr, options ); + + if (!status) + NtClose( shared_root ); + else + *subkey = shared_root; + } + if (status == STATUS_PREDEFINED_HANDLE) { *subkey = get_perflib_key( *subkey ); @@ -193,7 +271,7 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR if (is_wow64_key && !is_wow6432node( name )) { HKEY wow6432node = open_wow6432node( *subkey ); - if (wow6432node) + if (wow6432node != *subkey) { NtClose( *subkey ); *subkey = wow6432node; @@ -208,15 +286,30 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR static NTSTATUS unsafe_open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ) { HKEY subkey = 0, subkey_root = root; + BOOL was_wow6432node = TRUE; NTSTATUS status = 0;
+ if (root && is_wow64 && !(access & KEY_WOW64_64KEY) && !is_wow6432node( name ) && is_shared( root )) + subkey_root = open_wow6432node( root ); + while (!status && (name->Length || !subkey)) { + was_wow6432node = is_wow6432node( name ); status = open_subkey( &subkey, subkey_root, name, options, access ); if (subkey && subkey_root && subkey_root != root) NtClose( subkey_root ); if (subkey) subkey_root = subkey; }
+ /* Return the shared parent if we didn't explicitly look for the Wow6432Node */ + if (!status && !was_wow6432node) + { + if (!open_shared_parent( &subkey, subkey_root, options, access )) + { + if (subkey_root && subkey_root != root) NtClose( subkey_root ); + subkey_root = subkey; + } + } + *retkey = subkey_root;
return status;