Commit 63c6b893 authored by Sven Baars's avatar Sven Baars Committed by Alexandre Julliard

kernelbase: Add support for shared registry keys.

parent 3bbd37d0
...@@ -104,11 +104,59 @@ static BOOL is_wow6432node( const UNICODE_STRING *name ) ...@@ -104,11 +104,59 @@ static BOOL is_wow6432node( const UNICODE_STRING *name )
return (len >= 11 && !wcsnicmp( name->Buffer, L"Wow6432Node\\", min( len, 12 ) )); return (len >= 11 && !wcsnicmp( name->Buffer, L"Wow6432Node\\", min( len, 12 ) ));
} }
/* open the Wow6432Node subkey of the specified key */ static BOOL is_classes_root( const UNICODE_STRING *name )
{
static const WCHAR classes_root[] = L"\\Registry\\Machine\\Software\\Classes\\";
DWORD classes_root_len = ARRAY_SIZE( classes_root ) - 1;
DWORD len = name->Length / sizeof(WCHAR);
return (len >= classes_root_len - 1 && !wcsnicmp( name->Buffer, classes_root, min( len, classes_root_len ) ));
}
static BOOL is_classes_wow6432node( HKEY key )
{
char buffer[256], *buf_ptr = buffer;
KEY_NAME_INFORMATION *info = (KEY_NAME_INFORMATION *)buffer;
DWORD len = sizeof(buffer);
UNICODE_STRING name;
NTSTATUS status;
BOOL ret = FALSE;
/* Obtain the name of the root key */
status = NtQueryKey( key, KeyNameInformation, info, len, &len );
if (status && status != STATUS_BUFFER_OVERFLOW) return FALSE;
/* Retry with a dynamically allocated buffer */
while (status == STATUS_BUFFER_OVERFLOW)
{
if (buf_ptr != buffer) heap_free( buf_ptr );
if (!(buf_ptr = heap_alloc( len ))) return FALSE;
info = (KEY_NAME_INFORMATION *)buf_ptr;
status = NtQueryKey( key, KeyNameInformation, info, len, &len );
}
/* Check if the key ends in Wow6432Node and if the root is the Classes key*/
if (!status && info->NameLength / sizeof(WCHAR) >= 11)
{
name.Buffer = info->Name + info->NameLength / sizeof(WCHAR) - 11;
name.Length = 11 * sizeof(WCHAR);
if (is_wow6432node( &name ))
{
name.Buffer = info->Name;
name.Length = info->NameLength;
ret = is_classes_root( &name );
}
}
if (buf_ptr != buffer) heap_free( buf_ptr );
return ret;
}
/* Open the Wow6432Node subkey of the specified key */
static HANDLE open_wow6432node( HANDLE key ) static HANDLE open_wow6432node( HANDLE key )
{ {
OBJECT_ATTRIBUTES attr;
UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"Wow6432Node" ); UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"Wow6432Node" );
OBJECT_ATTRIBUTES attr;
HANDLE ret; HANDLE ret;
attr.Length = sizeof(attr); attr.Length = sizeof(attr);
...@@ -117,7 +165,25 @@ static HANDLE open_wow6432node( HANDLE key ) ...@@ -117,7 +165,25 @@ static HANDLE open_wow6432node( HANDLE key )
attr.Attributes = 0; attr.Attributes = 0;
attr.SecurityDescriptor = NULL; attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL; attr.SecurityQualityOfService = NULL;
if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) ret = 0; if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return key;
return ret;
}
/* Open HKCR, which should already exist because it's used when we're in its Wow6432Node child */
static HANDLE open_classes_root( void )
{
OBJECT_ATTRIBUTES attr;
UNICODE_STRING nameW;
HANDLE ret = 0;
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.ObjectName = &nameW;
attr.Attributes = 0;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
RtlInitUnicodeString( &nameW, root_key_names[0] );
NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 );
return ret; return ret;
} }
...@@ -162,6 +228,21 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR ...@@ -162,6 +228,21 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR
options &= ~REG_OPTION_OPEN_LINK; options &= ~REG_OPTION_OPEN_LINK;
status = open_key( subkey, root, &str, options, access_64, FALSE ); status = open_key( subkey, root, &str, options, access_64, FALSE );
if (status == STATUS_OBJECT_NAME_NOT_FOUND && root && is_wow64_key)
{
/* Try to open the shared parent if we can't find the key in the Wow6432Node */
if (!is_classes_wow6432node( root ))
return STATUS_OBJECT_NAME_NOT_FOUND;
root = open_classes_root();
status = open_key( subkey, root, &str, options, access_64, FALSE );
if (!status)
NtClose( root );
else
*subkey = root;
}
if (!status) if (!status)
{ {
while (i < len && buffer[i] == '\\') i++; while (i < len && buffer[i] == '\\') i++;
...@@ -172,7 +253,7 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR ...@@ -172,7 +253,7 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR
if (is_wow64_key && !is_wow6432node( name )) if (is_wow64_key && !is_wow6432node( name ))
{ {
HKEY wow6432node = open_wow6432node( *subkey ); HKEY wow6432node = open_wow6432node( *subkey );
if (wow6432node) if (wow6432node != *subkey)
{ {
NtClose( *subkey ); NtClose( *subkey );
*subkey = wow6432node; *subkey = wow6432node;
...@@ -186,8 +267,10 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR ...@@ -186,8 +267,10 @@ static NTSTATUS open_subkey( HKEY *subkey, HKEY root, UNICODE_STRING *name, DWOR
/* wrapper for NtOpenKeyEx to handle Wow6432 nodes */ /* wrapper for NtOpenKeyEx to handle Wow6432 nodes */
static NTSTATUS open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access, BOOL create ) static NTSTATUS open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD options, ACCESS_MASK access, BOOL create )
{ {
BOOL is_wow64_key = (is_win64 && (access & KEY_WOW64_32KEY)) || (is_wow64 && !(access & KEY_WOW64_64KEY));
HKEY subkey = 0, subkey_root = root; HKEY subkey = 0, subkey_root = root;
NTSTATUS status = 0; NTSTATUS status = STATUS_SUCCESS;
BOOL was_wow6432node = TRUE;
*retkey = NULL; *retkey = NULL;
...@@ -212,13 +295,31 @@ static NTSTATUS open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD o ...@@ -212,13 +295,31 @@ static NTSTATUS open_key( HKEY *retkey, HKEY root, UNICODE_STRING *name, DWORD o
return status; return status;
} }
if (root && is_wow64 && !(access & KEY_WOW64_64KEY) && !is_wow6432node( name ))
{
subkey_root = open_wow6432node( root );
if (!is_classes_wow6432node( subkey_root ) && subkey_root != root)
{
NtClose( subkey_root );
subkey_root = root;
}
}
while (!status && (name->Length || !subkey)) while (!status && (name->Length || !subkey))
{ {
was_wow6432node = is_wow6432node( name );
status = open_subkey( &subkey, subkey_root, name, options, access ); status = open_subkey( &subkey, subkey_root, name, options, access );
if (subkey && subkey_root && subkey_root != root) NtClose( subkey_root ); if (subkey && subkey_root && subkey_root != root) NtClose( subkey_root );
if (subkey) subkey_root = subkey; if (subkey) subkey_root = subkey;
} }
/* Return the shared parent if we didn't explicitly look for the Wow6432Node */
if (!status && !was_wow6432node && is_wow64_key && is_classes_wow6432node( subkey_root ))
{
if (subkey_root && subkey_root != root) NtClose( subkey_root );
subkey_root = open_classes_root();
}
if (!status || (status == STATUS_OBJECT_NAME_NOT_FOUND && create)) if (!status || (status == STATUS_OBJECT_NAME_NOT_FOUND && create))
*retkey = subkey_root; *retkey = subkey_root;
else if (subkey_root && subkey_root != root) else if (subkey_root && subkey_root != root)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment