From: Sven Baars sbaars@codeweavers.com
--- dlls/kernelbase/registry.c | 134 ++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 55 deletions(-)
diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 91462d80e06..135ff48bf7e 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -100,7 +100,7 @@ static inline BOOL is_version_nt(void)
static BOOL is_wow6432node( const UNICODE_STRING *name ) { - return (name->Length == 11 * sizeof(WCHAR) && !wcsnicmp( name->Buffer, L"Wow6432Node", 11 )); + return (name->Length >= 11 * sizeof(WCHAR) && !wcsnicmp( name->Buffer, L"Wow6432Node", 11 )); }
/* open the Wow6432Node subkey of the specified key */ @@ -214,19 +214,77 @@ static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES return status; }
-/* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ -static NTSTATUS open_key( HKEY *retkey, DWORD options, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) +static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access ) { - NTSTATUS status; - BOOL force_wow32 = is_win64 && (access & KEY_WOW64_32KEY); - HANDLE subkey, root = attr->RootDirectory; - WCHAR *buffer = attr->ObjectName->Buffer; - DWORD pos = 0, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); + DWORD i = 0, len = name->Length / sizeof(WCHAR); + WCHAR *buffer = name->Buffer; + OBJECT_ATTRIBUTES attr; UNICODE_STRING str; + NTSTATUS status = 0; + + attr.Length = sizeof(attr); + attr.RootDirectory = (HANDLE)root; + attr.ObjectName = &str; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + if (!root && len > 10 && !wcsnicmp( buffer, L"\Registry\", 10 )) i += 10; + if (i < len && buffer[i] == '\') return STATUS_OBJECT_PATH_INVALID; + while (i < len && buffer[i] != '\') i++; + + str.Buffer = name->Buffer; + str.Length = i * sizeof(WCHAR); + + if (i == len) + { + if (options & REG_OPTION_OPEN_LINK) attr.Attributes |= OBJ_OPENLINK; + status = NtOpenKeyEx( (HANDLE *)subkey, access, &attr, options ); + } + else + { + if (!(options & REG_OPTION_OPEN_LINK)) attr.Attributes &= ~OBJ_OPENLINK; + status = NtOpenKeyEx( (HANDLE *)subkey, access, &attr, options & ~REG_OPTION_OPEN_LINK ); + } + + if (status == STATUS_PREDEFINED_HANDLE) + { + *subkey = get_perflib_key( *subkey ); + status = STATUS_SUCCESS; + } + + if (!status) + { + while (i < len && buffer[i] == '\') i++; + + name->Buffer += i; + name->Length -= i * sizeof(WCHAR); + + if (!is_wow6432node( name )) + { + HKEY wow6432node = open_wow6432node( *subkey ); + if (wow6432node) + { + NtClose( *subkey ); + *subkey = wow6432node; + } + } + } + + return status; +} + + +/* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ +static NTSTATUS open_key( HKEY *retkey, HKEY root, DWORD options, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr ) +{ + HKEY subkey, subkey_root = root; + UNICODE_STRING name; + NTSTATUS status = 0;
*retkey = NULL;
- if (!force_wow32) + if (!(is_win64 && (access & KEY_WOW64_32KEY))) { if (options & REG_OPTION_OPEN_LINK) attr->Attributes |= OBJ_OPENLINK; status = NtOpenKeyEx( (HANDLE *)retkey, access, attr, options ); @@ -238,53 +296,19 @@ static NTSTATUS open_key( HKEY *retkey, DWORD options, ACCESS_MASK access, OBJEC return status; }
- if (len && buffer[0] == '\') return STATUS_OBJECT_PATH_INVALID; - while (i < len && buffer[i] != '\') i++; - attr->ObjectName = &str; + name.Buffer = attr->ObjectName->Buffer; + name.Length = attr->ObjectName->Length;
- for (;;) - { - str.Buffer = buffer + pos; - str.Length = (i - pos) * sizeof(WCHAR); - if (force_wow32 && pos) - { - if (is_wow6432node( &str )) force_wow32 = FALSE; - else if ((subkey = open_wow6432node( attr->RootDirectory ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - force_wow32 = FALSE; - } - } - if (i == len) - { - if (options & REG_OPTION_OPEN_LINK) attr->Attributes |= OBJ_OPENLINK; - status = NtOpenKeyEx( &subkey, access, attr, options ); - } - else - { - if (!(options & REG_OPTION_OPEN_LINK)) attr->Attributes &= ~OBJ_OPENLINK; - status = NtOpenKeyEx( &subkey, access, attr, options & ~REG_OPTION_OPEN_LINK ); - } - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - if (status) return status; - attr->RootDirectory = subkey; - if (i == len) break; - while (i < len && buffer[i] == '\') i++; - pos = i; - while (i < len && buffer[i] != '\') i++; - } - if (force_wow32 && (subkey = open_wow6432node( attr->RootDirectory ))) - { - if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - } - if (status == STATUS_PREDEFINED_HANDLE) + while (!status && name.Length) { - attr->RootDirectory = get_perflib_key( attr->RootDirectory ); - status = STATUS_SUCCESS; + status = open_subkey( &subkey, subkey_root, &name, options, access ); + if (subkey_root && subkey_root != root) NtClose( subkey_root ); + subkey_root = subkey; } - *retkey = attr->RootDirectory; + + if (!status) + *retkey = subkey_root; + return status; }
@@ -538,7 +562,7 @@ LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExW( HKEY hkey, LPCWSTR name, DWORD o attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; RtlInitUnicodeString( &nameW, name ); - return RtlNtStatusToDosError( open_key( retkey, options, access, &attr ) ); + return RtlNtStatusToDosError( open_key( retkey, hkey, options, access, &attr ) ); }
@@ -596,7 +620,7 @@ LSTATUS WINAPI DECLSPEC_HOTPATCH RegOpenKeyExA( HKEY hkey, LPCSTR name, DWORD op if (!(status = RtlAnsiStringToUnicodeString( &NtCurrentTeb()->StaticUnicodeString, &nameA, FALSE ))) { - status = open_key( retkey, options, access, &attr ); + status = open_key( retkey, hkey, options, access, &attr ); } return RtlNtStatusToDosError( status ); }