From: Sven Baars sbaars@codeweavers.com
--- dlls/kernelbase/registry.c | 56 +++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 22 deletions(-)
diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c index 3c2352a3a16..757ced4f00a 100644 --- a/dlls/kernelbase/registry.c +++ b/dlls/kernelbase/registry.c @@ -142,6 +142,8 @@ static HKEY get_perflib_key( HANDLE key )
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)); + ACCESS_MASK access_64 = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY; DWORD i = 0, len = name->Length / sizeof(WCHAR); WCHAR *buffer = name->Buffer; OBJECT_ATTRIBUTES attr; @@ -155,7 +157,8 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL;
- if (buffer[0] == '\') return STATUS_OBJECT_PATH_INVALID; + 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; @@ -171,7 +174,7 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR options &= ~REG_OPTION_OPEN_LINK; }
- status = NtOpenKeyEx( (HANDLE *)subkey, access, &attr, options ); + status = NtOpenKeyEx( (HANDLE *)subkey, access_64, &attr, options ); if (status == STATUS_PREDEFINED_HANDLE) { *subkey = get_perflib_key( *subkey ); @@ -185,7 +188,7 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR name->Buffer += i; name->Length -= i * sizeof(WCHAR);
- if (!is_wow6432node( name )) + if (is_wow64_key && !is_wow6432node( name )) { HKEY wow6432node = open_wow6432node( *subkey ); if (wow6432node) @@ -241,7 +244,8 @@ static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES const UNICODE_STRING *class, ULONG options, PULONG dispos ) { NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; - HANDLE subkey, root = attr->RootDirectory; + HKEY subkey, root = attr->RootDirectory, subkey_root = root; + UNICODE_STRING name;
if (!(is_win64 && (access & KEY_WOW64_32KEY))) { @@ -257,10 +261,31 @@ static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES return status; }
+ name.Buffer = attr->ObjectName->Buffer; + name.Length = attr->ObjectName->Length; + + while (name.Length) + { + status = open_subkey( &subkey, subkey_root, &name, options & REG_OPTION_OPEN_LINK, access ); + if (status) break; + if (subkey_root && subkey_root != root) NtClose( subkey_root ); + subkey_root = subkey; + } + attr->RootDirectory = subkey_root; + + if (!status && (options & REG_OPTION_CREATE_LINK)) + { + NtClose( subkey_root ); + status = STATUS_OBJECT_NAME_COLLISION; + } + + if (!status) + if (dispos) *dispos = REG_OPENED_EXISTING_KEY; + if (status == STATUS_OBJECT_NAME_NOT_FOUND) { - WCHAR *buffer = attr->ObjectName->Buffer; - DWORD attrs, i = 0, len = attr->ObjectName->Length / sizeof(WCHAR); + WCHAR *buffer = name.Buffer; + DWORD attrs, i = 0, len = name.Length / sizeof(WCHAR); UNICODE_STRING str;
attrs = attr->Attributes; @@ -269,9 +294,7 @@ static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES while (len) { i = 0; - - /* don't try to create registry root */ - if (!attr->RootDirectory && len > 10 && !wcsnicmp( buffer, L"\Registry\", 10 )) i += 10; + if (buffer[0] == '\') return STATUS_OBJECT_PATH_INVALID; while (i < len && buffer[i] != '\') i++;
str.Buffer = buffer; @@ -280,12 +303,12 @@ static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES if (i == len) { attr->Attributes = attrs; - status = NtCreateKey( &subkey, access, attr, 0, class, options, dispos ); + status = NtCreateKey( (HANDLE *)&subkey, access, attr, 0, class, options, dispos ); } else { attr->Attributes = attrs & ~OBJ_OPENLINK; - status = NtCreateKey( &subkey, access, attr, 0, class, + status = NtCreateKey( (HANDLE *)&subkey, access, attr, 0, class, options & ~REG_OPTION_CREATE_LINK, dispos ); } if (attr->RootDirectory != root) NtClose( attr->RootDirectory ); @@ -294,17 +317,6 @@ static NTSTATUS create_key( HKEY *retkey, ACCESS_MASK access, OBJECT_ATTRIBUTES while (i < len && buffer[i] == '\') i++; buffer += i; len -= i; - - str.Buffer = buffer; - str.Length = len * sizeof(WCHAR); - if (!is_wow6432node( &str )) - { - if ((subkey = open_wow6432node( attr->RootDirectory ))) - { - NtClose( attr->RootDirectory ); - attr->RootDirectory = subkey; - } - } } } if (status == STATUS_PREDEFINED_HANDLE)