1
0
mirror of https://github.com/wine-mirror/wine synced 2024-07-03 08:19:41 +00:00

server: Use standard named object functions for registry keys.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2022-07-07 12:32:22 +02:00
parent b79ff648ef
commit 569c27945e
3 changed files with 157 additions and 376 deletions

View File

@ -1009,13 +1009,11 @@ static void test_name_limits(void)
status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %lx\n", str.Length, status );
status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
todo_wine
ok( status == STATUS_INVALID_PARAMETER, "%u: NtOpenKey failed %lx\n", str.Length, status );
str.Length = 2000;
status = pNtCreateKey( &ret, GENERIC_ALL, &attr, 0, NULL, 0, NULL );
ok( status == STATUS_INVALID_PARAMETER, "%u: NtCreateKey failed %lx\n", str.Length, status );
status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
todo_wine
ok( status == STATUS_INVALID_PARAMETER, "%u: NtOpenKey failed %lx\n", str.Length, status );
/* some Windows versions change the error past 2050 chars, others past 4066 chars, some don't */
str.Length = 5000;
@ -1026,7 +1024,6 @@ static void test_name_limits(void)
"%u: NtCreateKey failed %lx\n", str.Length, status );
ret = (HANDLE)0xdeadbeef;
status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
todo_wine
ok( status == STATUS_BUFFER_OVERFLOW ||
status == STATUS_BUFFER_TOO_SMALL ||
status == STATUS_INVALID_PARAMETER,
@ -1042,7 +1039,6 @@ static void test_name_limits(void)
ok( !ret, "handle set %p\n", ret );
ret = (HANDLE)0xdeadbeef;
status = pNtOpenKey( &ret, GENERIC_ALL, &attr );
todo_wine
ok( status == STATUS_OBJECT_NAME_INVALID ||
status == STATUS_BUFFER_OVERFLOW ||
status == STATUS_BUFFER_TOO_SMALL,

View File

@ -382,8 +382,7 @@ static void test_NtOpenKey(void)
InitializeObjectAttributes(&attr, &str, 0, 0, 0);
key = (HANDLE)0xdeadbeef;
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08lx\n", status);
todo_wine
ok(status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey Failed: 0x%08lx\n", status);
ok(!key, "key = %p\n", key);
pRtlFreeUnicodeString( &str );
@ -402,25 +401,21 @@ static void test_NtOpenKey(void)
pRtlCreateUnicodeStringFromAsciiz( &str, "" );
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine
ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine
ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\\\\\" );
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine
ok( status == STATUS_OBJECT_NAME_INVALID, "NtOpenKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\n", status );
pNtClose( key );
pRtlFreeUnicodeString( &str );
@ -433,38 +428,32 @@ static void test_NtOpenKey(void)
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\\\" );
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine
ok( status == STATUS_SUCCESS, "NtOpenKey failed: 0x%08lx\n", status );
pNtClose( key );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine
ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine
ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtOpenKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine
ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtOpenKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
status = pNtOpenKey(&key, KEY_READ, &attr);
todo_wine
ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtOpenKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
@ -608,13 +597,11 @@ static void test_NtCreateKey(void)
pRtlCreateUnicodeStringFromAsciiz( &str, "\\" );
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
todo_wine
ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry" );
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
todo_wine
ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
"NtCreateKey failed: 0x%08lx\n", status );
if (!status) pNtClose( subkey );
@ -629,7 +616,6 @@ static void test_NtCreateKey(void)
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Registry\\\\" );
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
todo_wine
ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
"NtCreateKey failed: 0x%08lx\n", status );
if (!status) pNtClose( subkey );
@ -637,31 +623,26 @@ static void test_NtCreateKey(void)
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar" );
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
todo_wine
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtCreateKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Foobar\\Machine" );
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
todo_wine
ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Machine\\Software\\Classes" );
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
todo_wine
ok( status == STATUS_OBJECT_PATH_NOT_FOUND, "NtCreateKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "Machine\\Software\\Classes" );
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
todo_wine
ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "NtCreateKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
pRtlCreateUnicodeStringFromAsciiz( &str, "\\Device\\Null" );
status = pNtCreateKey( &subkey, am, &attr, 0, 0, 0, 0 );
todo_wine
ok( status == STATUS_OBJECT_TYPE_MISMATCH, "NtCreateKey failed: 0x%08lx\n", status );
pRtlFreeUnicodeString( &str );
@ -1319,16 +1300,8 @@ static void test_symlinks(void)
ok( status == STATUS_OBJECT_NAME_NOT_FOUND, "NtOpenKey wrong status 0x%08lx\n", status );
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
todo_wine ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08lx\n", status );
ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08lx\n", status );
pNtClose( key );
if (status) /* can be removed once todo_wine above is fixed */
{
attr.ObjectName = &target_str;
attr.Attributes = OBJ_OPENLINK;
status = pNtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, 0, 0, 0 );
ok( status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08lx\n", status );
pNtClose( key );
}
attr.ObjectName = &target_str;
attr.Attributes = OBJ_OPENLINK;
@ -1424,7 +1397,6 @@ static void test_symlinks(void)
ok( status == STATUS_SUCCESS, "NtSetValueKey failed: 0x%08lx\n", status );
status = pNtOpenKey( &key, KEY_ALL_ACCESS, &attr );
todo_wine
ok( status == STATUS_NAME_TOO_LONG || status == STATUS_INVALID_PARAMETER /* Win10 1607+ */,
"NtOpenKey failed: 0x%08lx\n", status );

View File

@ -100,6 +100,8 @@ struct key
#define KEY_WOWSHARE 0x0010 /* key is a Wow64 shared key (used for Software\Classes) */
#define KEY_PREDEF 0x0020 /* key is marked as predefined */
#define OBJ_KEY_WOW64 0x100000 /* magic flag added to attributes for WoW64 redirection */
/* a key value */
struct key_value
{
@ -124,7 +126,6 @@ static const timeout_t save_period = 30 * -TICKS_PER_SEC; /* delay between peri
static struct timeout_user *save_timeout_user; /* saving timer */
static enum prefix_type { PREFIX_UNKNOWN, PREFIX_32BIT, PREFIX_64BIT } prefix_type;
static const WCHAR root_name[] = { '\\','R','e','g','i','s','t','r','y','\\' };
static const WCHAR wow6432node[] = {'W','o','w','6','4','3','2','N','o','d','e'};
static const WCHAR symlink_value[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e'};
static const struct unicode_str symlink_str = { symlink_value, sizeof(symlink_value) };
@ -198,6 +199,7 @@ static const struct object_ops key_ops =
static inline int is_wow6432node( const WCHAR *name, unsigned int len )
{
len = get_path_element( name, len );
return (len == sizeof(wow6432node) && !memicmp_strW( name, wow6432node, sizeof( wow6432node )));
}
@ -461,30 +463,14 @@ static struct security_descriptor *key_get_sd( struct object *obj )
static WCHAR *key_get_full_name( struct object *obj, data_size_t *ret_len )
{
static const WCHAR backslash = '\\';
struct key *key = (struct key *) obj;
data_size_t len = sizeof(root_name) - sizeof(WCHAR);
char *ret;
if (key->flags & KEY_DELETED)
{
set_error( STATUS_KEY_DELETED );
return NULL;
}
for (key = (struct key *)obj; key != root_key; key = get_parent( key )) len += key->obj.name->len + sizeof(WCHAR);
if (!(ret = malloc( len ))) return NULL;
*ret_len = len;
key = (struct key *)obj;
for (key = (struct key *)obj; key != root_key; key = get_parent( key ))
{
memcpy( ret + len - key->obj.name->len, key->obj.name->name, key->obj.name->len );
len -= key->obj.name->len + sizeof(WCHAR);
memcpy( ret + len, &backslash, sizeof(WCHAR) );
}
memcpy( ret, root_name, sizeof(root_name) - sizeof(WCHAR) );
return (WCHAR *)ret;
return default_get_full_name( obj, ret_len );
}
static struct object *key_lookup_name( struct object *obj, struct unicode_str *name,
@ -549,6 +535,13 @@ static struct object *key_lookup_name( struct object *obj, struct unicode_str *n
if (name->str[next / sizeof(WCHAR)] != '\\') break;
if (!(found = find_subkey( key, &tmp, &index )))
{
/* try in the 64-bit parent */
if ((key->flags & KEY_WOWSHARE) && (attr & OBJ_KEY_WOW64))
found = find_subkey( get_parent( key ), &tmp, &index );
}
if (!found)
{
if (next < name->len) /* path still has elements */
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
@ -561,6 +554,8 @@ static struct object *key_lookup_name( struct object *obj, struct unicode_str *n
{
name->str += next / sizeof(WCHAR);
name->len -= next;
if ((attr & OBJ_KEY_WOW64) && found->wow6432node && !is_wow6432node( name->str, name->len ))
found = found->wow6432node;
}
else
{
@ -676,77 +671,45 @@ static void key_destroy( struct object *obj )
}
}
/* get the request vararg as registry path */
static inline void get_req_path( struct unicode_str *str, int skip_root )
{
str->str = get_req_data();
str->len = (get_req_data_size() / sizeof(WCHAR)) * sizeof(WCHAR);
if (skip_root && str->len >= sizeof(root_name) && !memicmp_strW( str->str, root_name, sizeof(root_name) ))
{
str->str += ARRAY_SIZE( root_name );
str->len -= sizeof(root_name);
}
}
/* return the next token in a given path */
/* token->str must point inside the path, or be NULL for the first call */
static struct unicode_str *get_path_token( const struct unicode_str *path, struct unicode_str *token )
{
data_size_t i = 0, len = path->len / sizeof(WCHAR);
if (!token->str) /* first time */
{
/* path cannot start with a backslash */
if (len && path->str[0] == '\\')
{
set_error( STATUS_OBJECT_PATH_INVALID );
return NULL;
}
}
else
{
i = token->str - path->str;
i += token->len / sizeof(WCHAR);
while (i < len && path->str[i] == '\\') i++;
}
token->str = path->str + i;
while (i < len && path->str[i] != '\\') i++;
token->len = (path->str + i - token->str) * sizeof(WCHAR);
return token;
}
/* allocate a key object */
static struct key *alloc_key( const struct unicode_str *name, timeout_t modif )
static struct key *create_key_object( struct object *parent, const struct unicode_str *name,
unsigned int attributes, unsigned int options, timeout_t modif,
const struct security_descriptor *sd )
{
struct object_name *name_ptr;
struct key *key;
if (!(name_ptr = mem_alloc( offsetof( struct object_name, name[name->len / sizeof(WCHAR)] ))))
return NULL;
if (!name->len) return open_named_object( parent, &key_ops, name, attributes );
if ((key = alloc_object( &key_ops )))
if ((key = create_named_object( parent, &key_ops, name, attributes, sd )))
{
key->obj.name = name_ptr;
key->class = NULL;
key->classlen = 0;
key->flags = 0;
key->last_subkey = -1;
key->nb_subkeys = 0;
key->subkeys = NULL;
key->wow6432node = NULL;
key->nb_values = 0;
key->last_value = -1;
key->values = NULL;
key->modif = modif;
list_init( &key->notify_list );
if (get_error() != STATUS_OBJECT_NAME_EXISTS)
{
/* initialize it if it didn't already exist */
key->class = NULL;
key->classlen = 0;
key->flags = 0;
key->last_subkey = -1;
key->nb_subkeys = 0;
key->subkeys = NULL;
key->wow6432node = NULL;
key->nb_values = 0;
key->last_value = -1;
key->values = NULL;
key->modif = modif;
list_init( &key->notify_list );
name_ptr->obj = &key->obj;
name_ptr->len = name->len;
name_ptr->parent = NULL;
memcpy( name_ptr->name, name->str, name->len );
if (options & REG_OPTION_CREATE_LINK) key->flags |= KEY_SYMLINK;
if (options & REG_OPTION_VOLATILE) key->flags |= KEY_VOLATILE;
else if (parent && (get_parent( key )->flags & KEY_VOLATILE))
{
set_error( STATUS_CHILD_MUST_BE_VOLATILE );
unlink_named_object( &key->obj );
release_object( key );
return NULL;
}
else key->flags |= KEY_DIRTY;
}
}
else free( name_ptr );
return key;
}
@ -796,223 +759,104 @@ static void touch_key( struct key *key, unsigned int change )
for (key = get_parent( key ); key; key = get_parent( key )) check_notify( key, change, 0 );
}
/* allocate a subkey for a given key, and return its index */
static struct key *alloc_subkey( struct key *parent, const struct unicode_str *name, timeout_t modif )
/* get the wow6432node key if any, grabbing it and releasing the original key */
static struct key *grab_wow6432node( struct key *key )
{
struct key *key;
struct key *ret = key->wow6432node;
if (!(key = alloc_key( name, modif ))) return NULL;
if (key_link_name( &key->obj, key->obj.name, &parent->obj )) return key;
if (!ret) return key;
grab_object( ret );
release_object( key );
return NULL;
}
/* return the wow64 variant of the key, or the key itself if none */
static struct key *find_wow64_subkey( struct key *key, const struct unicode_str *name )
{
if (!key->wow6432node) return key;
if (!is_wow6432node( name->str, name->len )) return key->wow6432node;
return key;
}
/* follow a symlink and return the resolved key */
static struct key *follow_symlink( struct key *key, int iteration )
{
struct unicode_str path, token;
struct key_value *value;
int index;
if (iteration > 16) return NULL;
if (!(key->flags & KEY_SYMLINK)) return key;
if (!(value = find_value( key, &symlink_str, &index ))) return NULL;
path.str = value->data;
path.len = (value->len / sizeof(WCHAR)) * sizeof(WCHAR);
if (path.len <= sizeof(root_name)) return NULL;
if (memicmp_strW( path.str, root_name, sizeof(root_name) )) return NULL;
path.str += ARRAY_SIZE( root_name );
path.len -= sizeof(root_name);
key = root_key;
token.str = NULL;
if (!get_path_token( &path, &token )) return NULL;
while (token.len)
{
if (!(key = find_subkey( key, &token, &index ))) break;
if (!(key = follow_symlink( key, iteration + 1 ))) break;
get_path_token( &path, &token );
}
return key;
}
/* open a key until we find an element that doesn't exist */
/* helper for open_key and create_key */
static struct key *open_key_prefix( struct key *key, const struct unicode_str *name,
unsigned int access, struct unicode_str *token, int *index )
{
token->str = NULL;
if (!get_path_token( name, token )) return NULL;
if (access & KEY_WOW64_32KEY) key = find_wow64_subkey( key, token );
while (token->len)
{
struct key *subkey;
if (!(subkey = find_subkey( key, token, index )))
{
if ((key->flags & KEY_WOWSHARE) && !(access & KEY_WOW64_64KEY))
{
/* try in the 64-bit parent */
key = get_parent( key );
subkey = find_subkey( key, token, index );
}
}
if (!subkey) break;
key = subkey;
get_path_token( name, token );
if (!token->len) break;
if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, token );
if (!(key = follow_symlink( key, 0 )))
{
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
return NULL;
}
}
return key;
return ret;
}
/* open a subkey */
static struct key *open_key( struct key *key, const struct unicode_str *name, unsigned int access,
unsigned int attributes )
static struct key *open_key( struct key *parent, const struct unicode_str *name,
unsigned int access, unsigned int attributes )
{
int index;
struct unicode_str token;
struct key *key;
if (!(key = open_key_prefix( key, name, access, &token, &index ))) return NULL;
if (token.len)
if (name->len >= 65534)
{
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
set_error( STATUS_OBJECT_NAME_INVALID );
return NULL;
}
if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, &token );
if (!(attributes & OBJ_OPENLINK) && !(key = follow_symlink( key, 0 )))
if (parent && (access & KEY_WOW64_32KEY))
{
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
return NULL;
if (parent->wow6432node && !is_wow6432node( name->str, name->len ))
parent = parent->wow6432node;
}
if (!(access & KEY_WOW64_64KEY)) attributes |= OBJ_KEY_WOW64;
if (!(key = open_named_object( &parent->obj, &key_ops, name, attributes ))) return NULL;
if (!(access & KEY_WOW64_64KEY)) key = grab_wow6432node( key );
if (debug_level > 1) dump_operation( key, NULL, "Open" );
if (key->flags & KEY_PREDEF) set_error( STATUS_PREDEFINED_HANDLE );
grab_object( key );
return key;
}
/* create a subkey */
static struct key *create_key( struct key *key, const struct unicode_str *name,
const struct unicode_str *class, unsigned int options,
unsigned int access, unsigned int attributes,
static struct key *create_key( struct key *parent, const struct unicode_str *name,
unsigned int options, unsigned int access, unsigned int attributes,
const struct security_descriptor *sd )
{
int index;
struct unicode_str token, next;
struct key *key;
if (!(key = open_key_prefix( key, name, access, &token, &index ))) return NULL;
if (options & REG_OPTION_CREATE_LINK) attributes = (attributes & ~OBJ_OPENIF) | OBJ_OPENLINK;
if (!token.len) /* the key already exists */
if (parent && (access & KEY_WOW64_32KEY))
{
if (parent->wow6432node && !is_wow6432node( name->str, name->len )) parent = parent->wow6432node;
}
if (!(access & KEY_WOW64_64KEY)) attributes |= OBJ_KEY_WOW64;
if (!(key = create_key_object( &parent->obj, name, attributes, options, current_time, sd )))
return NULL;
if (get_error() == STATUS_OBJECT_NAME_EXISTS)
{
if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, &token );
if (options & REG_OPTION_CREATE_LINK)
{
set_error( STATUS_OBJECT_NAME_COLLISION );
return NULL;
}
if (!(attributes & OBJ_OPENLINK) && !(key = follow_symlink( key, 0 )))
{
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
return NULL;
}
if (debug_level > 1) dump_operation( key, NULL, "Open" );
if (key->flags & KEY_PREDEF) set_error( STATUS_PREDEFINED_HANDLE );
grab_object( key );
set_error( STATUS_OBJECT_NAME_EXISTS );
return key;
if (!(access & KEY_WOW64_64KEY)) key = grab_wow6432node( key );
}
/* token must be the last path component at this point */
next = token;
get_path_token( name, &next );
if (next.len)
else
{
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
return NULL;
if (parent) touch_key( get_parent( key ), REG_NOTIFY_CHANGE_NAME );
if (debug_level > 1) dump_operation( key, NULL, "Create" );
}
if ((key->flags & KEY_VOLATILE) && !(options & REG_OPTION_VOLATILE))
{
set_error( STATUS_CHILD_MUST_BE_VOLATILE );
return NULL;
}
make_dirty( key );
if (!(key = alloc_subkey( key, &token, current_time ))) return NULL;
if (options & REG_OPTION_CREATE_LINK) key->flags |= KEY_SYMLINK;
if (options & REG_OPTION_VOLATILE) key->flags |= KEY_VOLATILE;
else key->flags |= KEY_DIRTY;
if (sd) default_set_sd( &key->obj, sd, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION );
if (debug_level > 1) dump_operation( key, NULL, "Create" );
if (class && class->len)
{
key->classlen = class->len;
free(key->class);
if (!(key->class = memdup( class->str, key->classlen ))) key->classlen = 0;
}
touch_key( get_parent( key ), REG_NOTIFY_CHANGE_NAME );
grab_object( key );
return key;
}
/* recursively create a subkey (for internal use only) */
static struct key *create_key_recursive( struct key *key, const struct unicode_str *name, timeout_t modif )
static struct key *create_key_recursive( struct key *root, const struct unicode_str *name, timeout_t modif )
{
struct key *base;
int index;
struct unicode_str token;
struct key *key, *parent = (struct key *)grab_object( root );
struct unicode_str tmp;
const WCHAR *str = name->str;
data_size_t len = name->len;
token.str = NULL;
if (!get_path_token( name, &token )) return NULL;
while (token.len)
while (len)
{
struct key *subkey;
if (!(subkey = find_subkey( key, &token, &index ))) break;
key = subkey;
if (!(key = follow_symlink( key, 0 )))
{
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
return NULL;
}
get_path_token( name, &token );
}
tmp.str = str;
tmp.len = get_path_element( str, len );
key = create_key_object( &parent->obj, &tmp, OBJ_OPENIF, 0, modif, NULL );
release_object( parent );
if (!key) return NULL;
parent = key;
if (token.len)
{
if (!(key = alloc_subkey( key, &token, modif ))) return NULL;
base = key;
for (;;)
/* skip trailing \\ and move to the next element */
if (tmp.len < len)
{
get_path_token( name, &token );
if (!token.len) break;
if (!(key = alloc_subkey( key, &token, modif )))
{
unlink_named_object( &base->obj );
return NULL;
}
tmp.len += sizeof(WCHAR);
str += tmp.len / sizeof(WCHAR);
len -= tmp.len;
}
else break;
}
grab_object( key );
return key;
return parent;
}
/* query information about a key or a subkey */
@ -1113,46 +957,44 @@ static void enum_key( struct key *key, int index, int info_class, struct enum_ke
}
/* rename a key and its values */
static int rename_key( struct key *key, const struct unicode_str *new_name )
static void rename_key( struct key *key, const struct unicode_str *new_name )
{
struct unicode_str token, name;
struct object_name *new_name_ptr;
struct key *subkey, *parent = get_parent( key );
data_size_t len;
int i, index, cur_index;
token.str = NULL;
/* changing to a path is not allowed */
if (!new_name->len || !get_path_token( new_name, &token ) || token.len != new_name->len)
len = get_path_element( new_name->str, new_name->len );
if (!len || len != new_name->len || len > MAX_NAME_LEN * sizeof(WCHAR))
{
set_error( STATUS_INVALID_PARAMETER );
return -1;
return;
}
/* check for existing subkey with the same name */
if (!parent || (subkey = find_subkey( parent, new_name, &index )))
{
set_error( STATUS_CANNOT_DELETE );
return -1;
return;
}
if (key == parent->wow6432node || is_wow6432node( new_name->str, new_name->len ))
{
set_error( STATUS_INVALID_PARAMETER );
return -1;
return;
}
if (!(new_name_ptr = mem_alloc( offsetof( struct object_name, name[new_name->len / sizeof(WCHAR)] ))))
return -1;
return;
new_name_ptr->obj = &key->obj;
new_name_ptr->len = new_name->len;
new_name_ptr->parent = &parent->obj;
memcpy( new_name_ptr->name, new_name->str, new_name->len );
name.str = key->obj.name->name;
name.len = key->obj.name->len;
find_subkey( parent, &name, &cur_index );
for (cur_index = 0; cur_index <= parent->last_subkey; cur_index++)
if (parent->subkeys[cur_index] == key) break;
if (cur_index < index && (index - cur_index) > 1)
{
@ -1169,9 +1011,7 @@ static int rename_key( struct key *key, const struct unicode_str *new_name )
key->obj.name = new_name_ptr;
if (debug_level > 1) dump_operation( key, NULL, "Rename" );
make_dirty( key );
touch_key( key, REG_NOTIFY_CHANGE_NAME );
return 0;
}
/* delete a key and its values */
@ -1475,13 +1315,6 @@ static struct key *get_hkey_obj( obj_handle_t hkey, unsigned int access )
return key;
}
/* get the registry key corresponding to a parent key handle */
static inline struct key *get_parent_hkey_obj( obj_handle_t hkey )
{
if (!hkey) return (struct key *)grab_object( root_key );
return get_hkey_obj( hkey, 0 );
}
/* read a line from the input file */
static int read_next_line( struct file_load_info *info )
{
@ -1996,6 +1829,7 @@ static void init_supported_machines(void)
/* registry initialisation */
void init_registry(void)
{
static const WCHAR REGISTRY[] = {'\\','R','E','G','I','S','T','R','Y'};
static const WCHAR HKLM[] = { 'M','a','c','h','i','n','e' };
static const WCHAR HKU_default[] = { 'U','s','e','r','\\','.','D','e','f','a','u','l','t' };
static const WCHAR classes_i386[] = {'S','o','f','t','w','a','r','e','\\',
@ -2016,7 +1850,7 @@ 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 struct unicode_str root_name = { NULL, 0 };
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) };
@ -2032,9 +1866,9 @@ void init_registry(void)
if (fchdir( config_dir_fd ) == -1) fatal_error( "chdir to config dir: %s\n", strerror( errno ));
/* create the root key */
root_key = alloc_key( &root_name, current_time );
root_key = create_key_object( NULL, &root_name, OBJ_PERMANENT, 0, current_time, NULL );
assert( root_key );
make_object_permanent( &root_key->obj );
release_object( root_key );
/* load system.reg into Registry\Machine */
@ -2292,9 +2126,10 @@ static int is_wow64_thread( struct thread *thread )
/* create a registry key */
DECL_HANDLER(create_key)
{
struct key *key = NULL, *parent;
struct unicode_str name, class;
struct key *key, *parent = NULL;
unsigned int access = req->access;
const WCHAR *class;
struct unicode_str name;
const struct security_descriptor *sd;
const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
@ -2302,50 +2137,41 @@ DECL_HANDLER(create_key)
if (!is_wow64_thread( current )) access = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY;
class.str = get_req_data_after_objattr( objattr, &class.len );
class.len = (class.len / sizeof(WCHAR)) * sizeof(WCHAR);
if (!objattr->rootdir && name.len >= sizeof(root_name) &&
!memicmp_strW( name.str, root_name, sizeof(root_name) ))
if (objattr->rootdir)
{
name.str += ARRAY_SIZE( root_name );
name.len -= sizeof(root_name);
if (!(parent = get_hkey_obj( objattr->rootdir, 0 ))) return;
}
/* NOTE: no access rights are required from the parent handle to create a key */
if ((parent = get_parent_hkey_obj( objattr->rootdir )))
if ((key = create_key( parent, &name, req->options, access, objattr->attributes, sd )))
{
if ((key = create_key( parent, &name, &class, req->options, access,
objattr->attributes, sd )))
if ((class = get_req_data_after_objattr( objattr, &key->classlen )))
{
reply->hkey = alloc_handle( current->process, key, access, objattr->attributes );
release_object( key );
key->classlen = (key->classlen / sizeof(WCHAR)) * sizeof(WCHAR);
if (!(key->class = memdup( class, key->classlen ))) key->classlen = 0;
}
release_object( parent );
reply->hkey = alloc_handle( current->process, key, access, objattr->attributes );
release_object( key );
}
if (parent) release_object( parent );
}
/* open a registry key */
DECL_HANDLER(open_key)
{
struct key *key, *parent;
struct unicode_str name;
struct key *key, *parent = NULL;
unsigned int access = req->access;
struct unicode_str name = get_req_unicode_str();
if (!is_wow64_thread( current )) access = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY;
reply->hkey = 0;
/* NOTE: no access rights are required to open the parent key, only the child key */
if ((parent = get_parent_hkey_obj( req->parent )))
if (req->parent && !(parent = get_hkey_obj( req->parent, 0 ))) return;
if ((key = open_key( parent, &name, access, req->attributes )))
{
get_req_path( &name, !req->parent );
if ((key = open_key( parent, &name, access, req->attributes )))
{
reply->hkey = alloc_handle( current->process, key, access, req->attributes );
release_object( key );
}
release_object( parent );
reply->hkey = alloc_handle( current->process, key, access, req->attributes );
release_object( key );
}
if (parent) release_object( parent );
}
/* delete a registry key */
@ -2449,7 +2275,7 @@ DECL_HANDLER(delete_key_value)
/* load a registry branch from a file */
DECL_HANDLER(load_registry)
{
struct key *key, *parent;
struct key *key, *parent = NULL;
struct unicode_str name;
const struct security_descriptor *sd;
const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
@ -2461,30 +2287,23 @@ DECL_HANDLER(load_registry)
set_error( STATUS_PRIVILEGE_NOT_HELD );
return;
}
if (!objattr->rootdir && name.len >= sizeof(root_name) &&
!memicmp_strW( name.str, root_name, sizeof(root_name) ))
if (objattr->rootdir)
{
name.str += ARRAY_SIZE( root_name );
name.len -= sizeof(root_name);
if (!(parent = get_hkey_obj( objattr->rootdir, 0 ))) return;
}
if ((parent = get_parent_hkey_obj( objattr->rootdir )))
if ((key = create_key( parent, &name, 0, KEY_WOW64_64KEY, 0, sd )))
{
if ((key = create_key( parent, &name, NULL, 0, KEY_WOW64_64KEY, 0, sd )))
{
load_registry( key, req->file );
release_object( key );
}
release_object( parent );
load_registry( key, req->file );
release_object( key );
}
if (parent) release_object( parent );
}
DECL_HANDLER(unload_registry)
{
struct key *key, *parent;
struct unicode_str name;
unsigned int access = 0;
struct key *key, *parent = NULL;
struct unicode_str name = get_req_unicode_str();
if (!thread_single_check_privilege( current, SeRestorePrivilege ))
{
@ -2492,21 +2311,17 @@ DECL_HANDLER(unload_registry)
return;
}
if (!is_wow64_thread( current )) access = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY;
if (req->parent && !(parent = get_hkey_obj( req->parent, 0 ))) return;
if ((parent = get_parent_hkey_obj( req->parent )))
if ((key = open_key( parent, &name, KEY_WOW64_64KEY, req->attributes )))
{
get_req_path( &name, !req->parent );
if ((key = open_key( parent, &name, access, req->attributes )))
{
if (key->obj.handle_count)
set_error( STATUS_CANNOT_DELETE );
else
delete_key( key, 1 ); /* FIXME */
release_object( key );
}
release_object( parent );
if (key->obj.handle_count)
set_error( STATUS_CANNOT_DELETE );
else
delete_key( key, 1 ); /* FIXME */
release_object( key );
}
if (parent) release_object( parent );
}
/* save a registry branch to a file */
@ -2577,14 +2392,12 @@ DECL_HANDLER(set_registry_notification)
/* rename a registry key */
DECL_HANDLER(rename_key)
{
struct unicode_str name;
struct unicode_str name = get_req_unicode_str();
struct key *key;
key = get_hkey_obj( req->hkey, KEY_WRITE );
if (key)
{
name.str = get_req_data();
name.len = (get_req_data_size() / sizeof(WCHAR)) * sizeof(WCHAR);
rename_key( key, &name );
release_object( key );
}