diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index ebe39931048..ddbdce0281c 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -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, diff --git a/dlls/ntdll/tests/reg.c b/dlls/ntdll/tests/reg.c index 5e141b1370d..d76f511f97d 100644 --- a/dlls/ntdll/tests/reg.c +++ b/dlls/ntdll/tests/reg.c @@ -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 ); diff --git a/server/registry.c b/server/registry.c index f800bcd842c..f9a9f75a974 100644 --- a/server/registry.c +++ b/server/registry.c @@ -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 ); }