mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-19 17:06:04 -07:00
Merge branch 'reg_shared_hkcu' into 'master'
server, kernelbase: Force WoW sharing on HKCU/Software key. See merge request wine/wine!6072
This commit is contained in:
commit
786b3e4812
4 changed files with 203 additions and 24 deletions
|
@ -3375,6 +3375,78 @@ static void test_redirection(void)
|
|||
|
||||
RegDeleteKeyA( key32, "" );
|
||||
RegCloseKey( key32 );
|
||||
|
||||
/* HKCU\\Software is shared. */
|
||||
err = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Wow6432Node\\tmp", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &key, NULL );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
RegDeleteKeyA( key, "" );
|
||||
RegCloseKey( key );
|
||||
|
||||
err = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\TestKey", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &root64, NULL );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
err = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\Wow6432Node\\TestKey", 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &root32 );
|
||||
ok ( err == ERROR_FILE_NOT_FOUND, "got %#lx.\n", err );
|
||||
|
||||
err = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Wow6432Node\\TestKey", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &root32, NULL );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
|
||||
dw = 1;
|
||||
err = RegSetKeyValueA( root64, NULL, "val", REG_DWORD, &dw, sizeof(dw) );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
|
||||
dw = 2;
|
||||
err = RegSetKeyValueA( root32, NULL, "val", REG_DWORD, &dw, sizeof(dw) );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
|
||||
err = RegCreateKeyExA( root64, "subkey", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &key64, NULL );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
dw = 1;
|
||||
err = RegSetKeyValueA( key64, NULL, "val", REG_DWORD, &dw, sizeof(dw) );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
|
||||
err = RegCreateKeyExA( root32, "subkey", 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &key32, NULL );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
dw = 2;
|
||||
err = RegSetKeyValueA( key32, NULL, "val", REG_DWORD, &dw, sizeof(dw) );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
|
||||
err = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\TestKey", 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &key );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
len = sizeof(dw);
|
||||
err = RegQueryValueExA( key, "val", NULL, NULL, (BYTE *)&dw, &len );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
ok( dw == 1, "got %lu.\n", dw );
|
||||
RegCloseKey( key );
|
||||
err = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\TestKey", 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, &key );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
len = sizeof(dw);
|
||||
err = RegQueryValueExA( key, "val", NULL, NULL, (BYTE *)&dw, &len );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
ok( dw == 1, "got %lu.\n", dw );
|
||||
RegCloseKey( key );
|
||||
err = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\TestKey\\subkey", 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &key );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
len = sizeof(dw);
|
||||
err = RegQueryValueExA( key, "val", NULL, NULL, (BYTE *)&dw, &len );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
ok( dw == 1, "got %lu.\n", dw );
|
||||
RegCloseKey( key );
|
||||
err = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\TestKey\\subkey", 0, KEY_ALL_ACCESS | KEY_WOW64_32KEY, &key );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
len = sizeof(dw);
|
||||
err = RegQueryValueExA( key, "val", NULL, NULL, (BYTE *)&dw, &len );
|
||||
ok( !err, "got %#lx.\n", err );
|
||||
ok( dw == 1, "got %lu.\n", dw );
|
||||
RegCloseKey( key );
|
||||
|
||||
RegDeleteKeyA( key64, "" );
|
||||
RegCloseKey( key64 );
|
||||
RegDeleteKeyA( key32, "" );
|
||||
RegCloseKey( key32 );
|
||||
RegDeleteKeyA( root32, "" );
|
||||
RegCloseKey( root32 );
|
||||
RegDeleteKeyA( root64, "" );
|
||||
RegCloseKey( root64 );
|
||||
}
|
||||
|
||||
static void test_classesroot(void)
|
||||
|
|
|
@ -112,20 +112,15 @@ static BOOL is_classes_root( const UNICODE_STRING *name )
|
|||
return (len >= classes_root_len - 1 && !wcsnicmp( name->Buffer, classes_root, min( len, classes_root_len ) ));
|
||||
}
|
||||
|
||||
static BOOL is_classes_wow6432node( HKEY key )
|
||||
static KEY_NAME_INFORMATION *get_key_name( HKEY key, char *buffer, DWORD len )
|
||||
{
|
||||
char buffer[256], *buf_ptr = buffer;
|
||||
char *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;
|
||||
status = NtQueryKey( key, KeyNameInformation, buf_ptr, len, &len );
|
||||
if (status && status != STATUS_BUFFER_OVERFLOW) return NULL;
|
||||
|
||||
/* Retry with a dynamically allocated buffer */
|
||||
while (status == STATUS_BUFFER_OVERFLOW)
|
||||
{
|
||||
if (buf_ptr != buffer) heap_free( buf_ptr );
|
||||
|
@ -133,9 +128,22 @@ static BOOL is_classes_wow6432node( HKEY key )
|
|||
info = (KEY_NAME_INFORMATION *)buf_ptr;
|
||||
status = NtQueryKey( key, KeyNameInformation, info, len, &len );
|
||||
}
|
||||
if (!status) return (KEY_NAME_INFORMATION *)buf_ptr;
|
||||
if (buf_ptr != buffer) heap_free( buf_ptr );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL is_classes_wow6432node( HKEY key )
|
||||
{
|
||||
KEY_NAME_INFORMATION *info;
|
||||
char buffer[256];
|
||||
UNICODE_STRING name;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (!(info = get_key_name( key, buffer, sizeof(buffer) ))) return FALSE;
|
||||
|
||||
/* Check if the key ends in Wow6432Node and if the root is the Classes key*/
|
||||
if (!status && info->NameLength / sizeof(WCHAR) >= 11)
|
||||
if (info->NameLength / sizeof(WCHAR) >= 11)
|
||||
{
|
||||
name.Buffer = info->Name + info->NameLength / sizeof(WCHAR) - 11;
|
||||
name.Length = 11 * sizeof(WCHAR);
|
||||
|
@ -146,9 +154,39 @@ static BOOL is_classes_wow6432node( HKEY key )
|
|||
ret = is_classes_root( &name );
|
||||
}
|
||||
}
|
||||
if ((char *)info != buffer) heap_free( info );
|
||||
|
||||
if (buf_ptr != buffer) heap_free( buf_ptr );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL is_wow6432_shared( HANDLE key )
|
||||
{
|
||||
static const WCHAR users_root[] = L"\\Registry\\User\\";
|
||||
const DWORD users_root_len = ARRAY_SIZE( users_root ) - 1;
|
||||
static const WCHAR software[] = L"\\Software";
|
||||
const DWORD software_len = ARRAY_SIZE( software ) - 1;
|
||||
KEY_NAME_INFORMATION *info;
|
||||
char buffer[256];
|
||||
BOOL ret = FALSE;
|
||||
WCHAR *name;
|
||||
DWORD len;
|
||||
|
||||
if (!(info = get_key_name( key, buffer, sizeof(buffer) ))) return FALSE;
|
||||
len = info->NameLength / sizeof(WCHAR);
|
||||
if (len <= users_root_len) goto done;
|
||||
name = info->Name;
|
||||
if (wcsnicmp( name, users_root, users_root_len )) goto done;
|
||||
name += users_root_len;
|
||||
len -= users_root_len;
|
||||
while (len && *name != '\\')
|
||||
{
|
||||
++name;
|
||||
--len;
|
||||
}
|
||||
if (len != software_len) goto done;
|
||||
ret = !wcsnicmp( name, software, software_len );
|
||||
done:
|
||||
if ((char *)info != buffer) heap_free( info );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -166,6 +204,11 @@ static HANDLE open_wow6432node( HANDLE key )
|
|||
attr.SecurityDescriptor = NULL;
|
||||
attr.SecurityQualityOfService = NULL;
|
||||
if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED | KEY_WOW64_64KEY, &attr, 0 )) return key;
|
||||
if (is_wow6432_shared( key ))
|
||||
{
|
||||
NtClose( ret );
|
||||
return key;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1454,7 +1454,7 @@ static void test_redirection(void)
|
|||
KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
|
||||
KEY_FULL_INFORMATION *full_info = (KEY_FULL_INFORMATION *)buffer;
|
||||
DWORD dw, len;
|
||||
HANDLE key, key32, key64, root, root32, root64;
|
||||
HANDLE key, key32, key64, root, root32, root64, hkcu;
|
||||
int subkeys64, subkeys32;
|
||||
|
||||
if (ptr_size != 64)
|
||||
|
@ -2012,6 +2012,62 @@ static void test_redirection(void)
|
|||
|
||||
pNtDeleteKey( key32 );
|
||||
pNtClose( key32 );
|
||||
|
||||
/* HKCU\\Software is shared. */
|
||||
pRtlOpenCurrentUser( KEY_ALL_ACCESS, (HANDLE *)&hkcu );
|
||||
attr.RootDirectory = hkcu;
|
||||
pRtlInitUnicodeString( &str, L"Software\\Wow6432Node\\tmp" );
|
||||
status = pNtCreateKey( &key, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
pNtDeleteKey( key );
|
||||
pNtClose( key );
|
||||
|
||||
pRtlInitUnicodeString( &str, L"Software\\TestKey" );
|
||||
status = pNtCreateKey( &root64, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
|
||||
pRtlInitUnicodeString( &str, L"Software\\Wow6432Node\\TestKey" );
|
||||
status = pNtOpenKey( &root32, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr );
|
||||
ok ( status == STATUS_OBJECT_NAME_NOT_FOUND, "got %#lx.\n", status );
|
||||
status = pNtCreateKey( &root32, KEY_WOW64_32KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
|
||||
dw = 1;
|
||||
status = pNtSetValueKey( root64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
dw = 2;
|
||||
status = pNtSetValueKey( root32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
|
||||
attr.RootDirectory = root64;
|
||||
pRtlInitUnicodeString( &str, L"subkey" );
|
||||
status = pNtCreateKey( &key64, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
dw = 1;
|
||||
status = pNtSetValueKey( key64, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
|
||||
attr.RootDirectory = root32;
|
||||
status = pNtCreateKey( &key32, KEY_WOW64_64KEY | KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
dw = 2;
|
||||
status = pNtSetValueKey( key32, &value_str, 0, REG_DWORD, &dw, sizeof(dw) );
|
||||
ok( !status, "got %#lx.\n", status );
|
||||
|
||||
check_key_value( hkcu, "Software\\TestKey", KEY_WOW64_64KEY, 1 );
|
||||
check_key_value( hkcu, "Software\\TestKey", KEY_WOW64_32KEY, 1 );
|
||||
check_key_value( hkcu, "Software\\TestKey\\subkey", KEY_WOW64_64KEY, 1 );
|
||||
check_key_value( hkcu, "Software\\TestKey\\subkey", KEY_WOW64_32KEY, 1 );
|
||||
|
||||
pNtDeleteKey( key64 );
|
||||
pNtClose( key64 );
|
||||
pNtDeleteKey( key32 );
|
||||
pNtClose( key32 );
|
||||
pNtDeleteKey( root32 );
|
||||
pNtClose( root32 );
|
||||
pNtDeleteKey( root64 );
|
||||
pNtClose( root64 );
|
||||
pNtClose( hkcu );
|
||||
}
|
||||
|
||||
static void test_long_value_name(void)
|
||||
|
|
|
@ -97,8 +97,9 @@ struct key
|
|||
#define KEY_DELETED 0x0002 /* key has been deleted */
|
||||
#define KEY_DIRTY 0x0004 /* key has been modified */
|
||||
#define KEY_SYMLINK 0x0008 /* key is a symbolic link */
|
||||
#define KEY_WOWSHARE 0x0010 /* key is a Wow64 shared key (used for Software\Classes) */
|
||||
#define KEY_WOWREFLECT 0x0010 /* key is a Wow64 shared and reflected key (used for Software\Classes) */
|
||||
#define KEY_PREDEF 0x0020 /* key is marked as predefined */
|
||||
#define KEY_WOWSHARE 0x0040 /* key is Wow64 shared */
|
||||
|
||||
#define OBJ_KEY_WOW64 0x100000 /* magic flag added to attributes for WoW64 redirection */
|
||||
|
||||
|
@ -518,7 +519,7 @@ static struct object *key_lookup_name( struct object *obj, struct unicode_str *n
|
|||
}
|
||||
|
||||
key = (struct key *)obj;
|
||||
if (key && (key->flags & KEY_WOWSHARE) && (attr & OBJ_KEY_WOW64) && !name->str)
|
||||
if (key && (key->flags & KEY_WOWREFLECT) && (attr & OBJ_KEY_WOW64) && !name->str)
|
||||
{
|
||||
key = get_parent( key );
|
||||
release_object( obj );
|
||||
|
@ -545,7 +546,7 @@ static struct object *key_lookup_name( struct object *obj, struct unicode_str *n
|
|||
|
||||
if (!(found = find_subkey( key, &tmp, &index )))
|
||||
{
|
||||
if ((key->flags & KEY_WOWSHARE) && (attr & OBJ_KEY_WOW64))
|
||||
if ((key->flags & KEY_WOWREFLECT) && (attr & OBJ_KEY_WOW64))
|
||||
{
|
||||
/* try in the 64-bit parent */
|
||||
key = get_parent( key );
|
||||
|
@ -604,7 +605,7 @@ static int key_link_name( struct object *obj, struct object_name *name, struct o
|
|||
for (i = ++parent_key->last_subkey; i > index; i--)
|
||||
parent_key->subkeys[i] = parent_key->subkeys[i - 1];
|
||||
parent_key->subkeys[index] = (struct key *)grab_object( key );
|
||||
if (is_wow6432node( name->name, name->len ) &&
|
||||
if (!(parent_key->flags & KEY_WOWSHARE) && is_wow6432node( name->name, name->len ) &&
|
||||
!is_wow6432node( parent_key->obj.name->name, parent_key->obj.name->len ))
|
||||
parent_key->wow6432node = key;
|
||||
name->parent = parent;
|
||||
|
@ -777,7 +778,7 @@ static struct key *grab_wow6432node( struct key *key )
|
|||
struct key *ret = key->wow6432node;
|
||||
|
||||
if (!ret) return key;
|
||||
if (ret->flags & KEY_WOWSHARE) return key;
|
||||
if (ret->flags & KEY_WOWREFLECT) return key;
|
||||
grab_object( ret );
|
||||
release_object( key );
|
||||
return ret;
|
||||
|
@ -823,7 +824,7 @@ static struct key *open_key( struct key *parent, const struct unicode_str *name,
|
|||
if (parent && !(access & KEY_WOW64_64KEY) && !is_wow6432node( name->str, name->len ))
|
||||
{
|
||||
key = get_wow6432node( parent );
|
||||
if (key && ((access & KEY_WOW64_32KEY) || (key->flags & KEY_WOWSHARE)))
|
||||
if (key && ((access & KEY_WOW64_32KEY) || (key->flags & KEY_WOWREFLECT)))
|
||||
parent = key;
|
||||
}
|
||||
|
||||
|
@ -849,7 +850,7 @@ static struct key *create_key( struct key *parent, const struct unicode_str *nam
|
|||
if (parent && !(access & KEY_WOW64_64KEY) && !is_wow6432node( name->str, name->len ))
|
||||
{
|
||||
key = get_wow6432node( parent );
|
||||
if (key && ((access & KEY_WOW64_32KEY) || (key->flags & KEY_WOWSHARE)))
|
||||
if (key && ((access & KEY_WOW64_32KEY) || (key->flags & KEY_WOWREFLECT)))
|
||||
parent = key;
|
||||
}
|
||||
|
||||
|
@ -1886,13 +1887,14 @@ 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 software[] = {'S','o','f','t','w','a','r','e',};
|
||||
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) };
|
||||
|
||||
WCHAR *current_user_path;
|
||||
struct unicode_str current_user_str;
|
||||
struct unicode_str current_user_str, name;
|
||||
struct key *key, *hklm, *hkcu;
|
||||
unsigned int i;
|
||||
char *p;
|
||||
|
@ -1944,8 +1946,6 @@ void init_registry(void)
|
|||
/* set the shared flag on Software\Classes\Wow6432Node for all platforms */
|
||||
for (i = 1; i < supported_machines_count; i++)
|
||||
{
|
||||
struct unicode_str name;
|
||||
|
||||
switch (supported_machines[i])
|
||||
{
|
||||
case IMAGE_FILE_MACHINE_I386: name.str = classes_i386; name.len = sizeof(classes_i386); break;
|
||||
|
@ -1954,10 +1954,18 @@ void init_registry(void)
|
|||
}
|
||||
if ((key = create_key_recursive( hklm, &name, current_time )))
|
||||
{
|
||||
key->flags |= KEY_WOWSHARE;
|
||||
key->flags |= KEY_WOWREFLECT;
|
||||
release_object( key );
|
||||
}
|
||||
/* FIXME: handle HKCU too */
|
||||
}
|
||||
|
||||
name.str = software;
|
||||
name.len = sizeof(software);
|
||||
if ((key = create_key_recursive( hkcu, &name, current_time )))
|
||||
{
|
||||
key->flags |= KEY_WOWSHARE;
|
||||
key->wow6432node = NULL;
|
||||
release_object( key );
|
||||
}
|
||||
|
||||
if ((key = create_key_recursive( hklm, &perflib_name, current_time )))
|
||||
|
|
Loading…
Reference in a new issue