registry.c 65.2 KB
Newer Older
1 2 3 4
/*
 * Server-side registry management
 *
 * Copyright (C) 1999 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21 22 23 24
 */

/* To do:
 * - symbolic links
 */

25 26 27
#include "config.h"
#include "wine/port.h"

28
#include <assert.h>
29
#include <ctype.h>
30 31
#include <errno.h>
#include <fcntl.h>
32 33
#include <limits.h>
#include <stdio.h>
34
#include <stdarg.h>
35
#include <string.h>
36
#include <stdlib.h>
37
#include <sys/stat.h>
38
#include <unistd.h>
39

40 41
#include "ntstatus.h"
#define WIN32_NO_STATUS
42
#include "object.h"
43
#include "file.h"
44 45
#include "handle.h"
#include "request.h"
46
#include "process.h"
47
#include "unicode.h"
48
#include "security.h"
49

50
#include "winternl.h"
51
#include "wine/library.h"
52

53 54
struct notify
{
55
    struct list       entry;    /* entry in list of notifications */
56 57 58 59
    struct event     *event;    /* event to set when changing this key */
    int               subtree;  /* true if subtree notification */
    unsigned int      filter;   /* which events to notify on */
    obj_handle_t      hkey;     /* hkey associated with this notification */
60
    struct process   *process;  /* process in which the hkey is valid */
61 62
};

63 64 65 66 67 68
/* a registry key */
struct key
{
    struct object     obj;         /* object header */
    WCHAR            *name;        /* key name */
    WCHAR            *class;       /* key class */
69 70
    unsigned short    namelen;     /* length of key name */
    unsigned short    classlen;    /* length of class name */
71 72 73 74 75 76 77
    struct key       *parent;      /* parent key */
    int               last_subkey; /* last in use subkey */
    int               nb_subkeys;  /* count of allocated subkeys */
    struct key      **subkeys;     /* subkeys array */
    int               last_value;  /* last in use value */
    int               nb_values;   /* count of allocated values in array */
    struct key_value *values;      /* values array */
78
    unsigned int      flags;       /* flags */
79
    timeout_t         modif;       /* last modification time */
80
    struct list       notify_list; /* list of notifications */
81 82 83 84 85
};

/* key flags */
#define KEY_VOLATILE 0x0001  /* key is volatile (not saved to disk) */
#define KEY_DELETED  0x0002  /* key has been deleted */
86
#define KEY_DIRTY    0x0004  /* key has been modified */
87
#define KEY_SYMLINK  0x0008  /* key is a symbolic link */
88
#define KEY_WOW64    0x0010  /* key contains a Wow6432Node subkey */
89
#define KEY_WOWSHARE 0x0020  /* key is a Wow64 shared key (used for Software\Classes) */
90 91 92 93 94

/* a key value */
struct key_value
{
    WCHAR            *name;    /* value name */
95 96
    unsigned short    namelen; /* length of value name */
    unsigned short    type;    /* value type */
97
    data_size_t       len;     /* value data length in bytes */
98 99 100 101 102 103
    void             *data;    /* pointer to value data */
};

#define MIN_SUBKEYS  8   /* min. number of allocated subkeys per key */
#define MIN_VALUES   8   /* min. number of allocated values per key */

104 105
#define MAX_NAME_LEN  255    /* max. length of a key name */
#define MAX_VALUE_LEN 16383  /* max. length of a value name */
106

107
/* the root of the registry tree */
108 109
static struct key *root_key;

110
static const timeout_t ticks_1601_to_1970 = (timeout_t)86400 * (369 * 365 + 89) * TICKS_PER_SEC;
111
static const timeout_t save_period = 30 * -TICKS_PER_SEC;  /* delay between periodic saves */
112
static struct timeout_user *save_timeout_user;  /* saving timer */
113
static enum prefix_type { PREFIX_UNKNOWN, PREFIX_32BIT, PREFIX_64BIT } prefix_type;
114

115
static const WCHAR root_name[] = { '\\','R','e','g','i','s','t','r','y','\\' };
116
static const WCHAR wow6432node[] = {'W','o','w','6','4','3','2','N','o','d','e'};
117 118 119
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) };

120
static void set_periodic_save_timer(void);
121
static struct key_value *find_value( const struct key *key, const struct unicode_str *name, int *index );
122

123 124 125 126
/* information about where to save a registry branch */
struct save_branch_info
{
    struct key  *key;
127
    const char  *path;
128 129
};

130
#define MAX_SAVE_BRANCH_INFO 3
131 132 133
static int save_branch_count;
static struct save_branch_info save_branch_info[MAX_SAVE_BRANCH_INFO];

134

135 136 137
/* information about a file being loaded */
struct file_load_info
{
138 139 140 141 142 143 144
    const char *filename; /* input file name */
    FILE       *file;     /* input file */
    char       *buffer;   /* line buffer */
    int         len;      /* buffer length */
    int         line;     /* current input line */
    WCHAR      *tmp;      /* temp buffer to use while parsing input */
    size_t      tmplen;   /* length of temp buffer */
145 146 147
};


148
static void key_dump( struct object *obj, int verbose );
149
static unsigned int key_map_access( struct object *obj, unsigned int access );
150
static int key_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
151 152 153 154
static void key_destroy( struct object *obj );

static const struct object_ops key_ops =
{
155 156
    sizeof(struct key),      /* size */
    key_dump,                /* dump */
157
    no_get_type,             /* get_type */
158 159 160 161
    no_add_queue,            /* add_queue */
    NULL,                    /* remove_queue */
    NULL,                    /* signaled */
    NULL,                    /* satisfied */
162
    no_signal,               /* signal */
163
    no_get_fd,               /* get_fd */
164
    key_map_access,          /* map_access */
165 166
    default_get_sd,          /* get_sd */
    default_set_sd,          /* set_sd */
167
    no_lookup_name,          /* lookup_name */
168
    no_open_file,            /* open_file */
169
    key_close_handle,        /* close_handle */
170
    key_destroy              /* destroy */
171 172 173
};


174 175 176 177 178 179
static inline int is_wow6432node( const WCHAR *name, unsigned int len )
{
    return (len == sizeof(wow6432node) &&
            !memicmpW( name, wow6432node, sizeof(wow6432node)/sizeof(WCHAR) ));
}

180 181 182 183 184 185 186 187 188 189
/*
 * The registry text file format v2 used by this code is similar to the one
 * used by REGEDIT import/export functionality, with the following differences:
 * - strings and key names can contain \x escapes for Unicode
 * - key names use escapes too in order to support Unicode
 * - the modification time optionally follows the key name
 * - REG_EXPAND_SZ and REG_MULTI_SZ are saved as strings instead of hex
 */

/* dump the full path of a key */
190
static void dump_path( const struct key *key, const struct key *base, FILE *f )
191
{
192
    if (key->parent && key->parent != base)
193
    {
194
        dump_path( key->parent, base, f );
195 196
        fprintf( f, "\\\\" );
    }
197
    dump_strW( key->name, key->namelen / sizeof(WCHAR), f, "[]" );
198 199 200
}

/* dump a value to a text file */
201
static void dump_value( const struct key_value *value, FILE *f )
202
{
203
    unsigned int i, dw;
204
    int count;
205

206
    if (value->namelen)
207 208
    {
        fputc( '\"', f );
209
        count = 1 + dump_strW( value->name, value->namelen / sizeof(WCHAR), f, "\"\"" );
210 211 212 213 214 215 216 217 218
        count += fprintf( f, "\"=" );
    }
    else count = fprintf( f, "@=" );

    switch(value->type)
    {
    case REG_SZ:
    case REG_EXPAND_SZ:
    case REG_MULTI_SZ:
219 220 221 222 223
        /* only output properly terminated strings in string format */
        if (value->len < sizeof(WCHAR)) break;
        if (value->len % sizeof(WCHAR)) break;
        if (((WCHAR *)value->data)[value->len / sizeof(WCHAR) - 1]) break;
        if (value->type != REG_SZ) fprintf( f, "str(%x):", value->type );
224
        fputc( '\"', f );
225
        dump_strW( (WCHAR *)value->data, value->len / sizeof(WCHAR), f, "\"\"" );
226 227 228
        fprintf( f, "\"\n" );
        return;

229
    case REG_DWORD:
230 231 232 233 234 235 236 237 238 239 240 241
        if (value->len != sizeof(dw)) break;
        memcpy( &dw, value->data, sizeof(dw) );
        fprintf( f, "dword:%08x\n", dw );
        return;
    }

    if (value->type == REG_BINARY) count += fprintf( f, "hex:" );
    else count += fprintf( f, "hex(%x):", value->type );
    for (i = 0; i < value->len; i++)
    {
        count += fprintf( f, "%02x", *((unsigned char *)value->data + i) );
        if (i < value->len-1)
242
        {
243 244
            fputc( ',', f );
            if (++count > 76)
245
            {
246 247
                fprintf( f, "\\\n  " );
                count = 2;
248 249 250 251 252 253 254
            }
        }
    }
    fputc( '\n', f );
}

/* save a registry and all its subkeys to a text file */
255
static void save_subkeys( const struct key *key, const struct key *base, FILE *f )
256 257 258 259
{
    int i;

    if (key->flags & KEY_VOLATILE) return;
260
    /* save key if it has either some values or no subkeys, or needs special options */
261
    /* keys with no values but subkeys are saved implicitly by saving the subkeys */
262
    if ((key->last_value >= 0) || (key->last_subkey == -1) || key->class || (key->flags & KEY_SYMLINK))
263 264
    {
        fprintf( f, "\n[" );
265
        if (key != base) dump_path( key, base, f );
266
        fprintf( f, "] %u\n", (unsigned int)((key->modif - ticks_1601_to_1970) / TICKS_PER_SEC) );
267 268 269 270 271 272
        if (key->class)
        {
            fprintf( f, "#class=\"" );
            dump_strW( key->class, key->classlen / sizeof(WCHAR), f, "\"\"" );
            fprintf( f, "\"\n" );
        }
273
        if (key->flags & KEY_SYMLINK) fputs( "#link\n", f );
274 275
        for (i = 0; i <= key->last_value; i++) dump_value( &key->values[i], f );
    }
276
    for (i = 0; i <= key->last_subkey; i++) save_subkeys( key->subkeys[i], base, f );
277 278
}

279
static void dump_operation( const struct key *key, const struct key_value *value, const char *op )
280 281
{
    fprintf( stderr, "%s key ", op );
282
    if (key) dump_path( key, NULL, stderr );
283 284 285 286 287 288 289 290 291 292 293 294 295 296
    else fprintf( stderr, "ERROR" );
    if (value)
    {
        fprintf( stderr, " value ");
        dump_value( value, stderr );
    }
    else fprintf( stderr, "\n" );
}

static void key_dump( struct object *obj, int verbose )
{
    struct key *key = (struct key *)obj;
    assert( obj->ops == &key_ops );
    fprintf( stderr, "Key flags=%x ", key->flags );
297
    dump_path( key, NULL, stderr );
298 299 300
    fprintf( stderr, "\n" );
}

301 302 303
/* notify waiter and maybe delete the notification */
static void do_notification( struct key *key, struct notify *notify, int del )
{
304
    if (notify->event)
305 306 307 308 309
    {
        set_event( notify->event );
        release_object( notify->event );
        notify->event = NULL;
    }
310 311 312 313 314
    if (del)
    {
        list_remove( &notify->entry );
        free( notify );
    }
315 316
}

317
static inline struct notify *find_notify( struct key *key, struct process *process, obj_handle_t hkey )
318
{
319
    struct notify *notify;
320

321 322
    LIST_FOR_EACH_ENTRY( notify, &key->notify_list, struct notify, entry )
    {
323
        if (notify->process == process && notify->hkey == hkey) return notify;
324 325
    }
    return NULL;
326 327
}

328 329 330 331 332 333
static unsigned int key_map_access( struct object *obj, unsigned int access )
{
    if (access & GENERIC_READ)    access |= KEY_READ;
    if (access & GENERIC_WRITE)   access |= KEY_WRITE;
    if (access & GENERIC_EXECUTE) access |= KEY_EXECUTE;
    if (access & GENERIC_ALL)     access |= KEY_ALL_ACCESS;
334 335 336
    /* filter the WOW64 masks, as they aren't real access bits */
    return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL |
                      KEY_WOW64_64KEY | KEY_WOW64_32KEY);
337 338
}

339
/* close the notification associated with a handle */
340
static int key_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
341 342
{
    struct key * key = (struct key *) obj;
343
    struct notify *notify = find_notify( key, process, handle );
344 345
    if (notify) do_notification( key, notify, 1 );
    return 1;  /* ok to close */
346 347
}

348 349 350
static void key_destroy( struct object *obj )
{
    int i;
351
    struct list *ptr;
352 353 354
    struct key *key = (struct key *)obj;
    assert( obj->ops == &key_ops );

355 356
    free( key->name );
    free( key->class );
357 358
    for (i = 0; i <= key->last_value; i++)
    {
359 360
        free( key->values[i].name );
        free( key->values[i].data );
361
    }
362
    free( key->values );
363 364 365 366 367
    for (i = 0; i <= key->last_subkey; i++)
    {
        key->subkeys[i]->parent = NULL;
        release_object( key->subkeys[i] );
    }
368
    free( key->subkeys );
369
    /* unconditionally notify everything waiting on this key */
370 371 372 373 374
    while ((ptr = list_head( &key->notify_list )))
    {
        struct notify *notify = LIST_ENTRY( ptr, struct notify, entry );
        do_notification( key, notify, 1 );
    }
375 376
}

377
/* get the request vararg as registry path */
378
static inline void get_req_path( struct unicode_str *str, int skip_root )
379
{
380 381
    str->str = get_req_data();
    str->len = (get_req_data_size() / sizeof(WCHAR)) * sizeof(WCHAR);
382

383 384
    if (skip_root && str->len >= sizeof(root_name) &&
        !memicmpW( str->str, root_name, sizeof(root_name)/sizeof(WCHAR) ))
385
    {
386 387
        str->str += sizeof(root_name)/sizeof(WCHAR);
        str->len -= sizeof(root_name);
388 389 390
    }
}

391
/* return the next token in a given path */
392 393
/* 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 )
394
{
395
    data_size_t i = 0, len = path->len / sizeof(WCHAR);
396

397
    if (!token->str)  /* first time */
398
    {
399
        /* path cannot start with a backslash */
400
        if (len && path->str[0] == '\\')
401 402 403 404
        {
            set_error( STATUS_OBJECT_PATH_INVALID );
            return NULL;
        }
405
    }
406
    else
407
    {
408 409 410
        i = token->str - path->str;
        i += token->len / sizeof(WCHAR);
        while (i < len && path->str[i] == '\\') i++;
411
    }
412 413 414 415
    token->str = path->str + i;
    while (i < len && path->str[i] != '\\') i++;
    token->len = (path->str + i - token->str) * sizeof(WCHAR);
    return token;
416 417 418
}

/* allocate a key object */
419
static struct key *alloc_key( const struct unicode_str *name, timeout_t modif )
420 421
{
    struct key *key;
422
    if ((key = alloc_object( &key_ops )))
423
    {
424
        key->name        = NULL;
425
        key->class       = NULL;
426 427
        key->namelen     = name->len;
        key->classlen    = 0;
428 429 430 431 432 433 434 435 436
        key->flags       = 0;
        key->last_subkey = -1;
        key->nb_subkeys  = 0;
        key->subkeys     = NULL;
        key->nb_values   = 0;
        key->last_value  = -1;
        key->values      = NULL;
        key->modif       = modif;
        key->parent      = NULL;
437
        list_init( &key->notify_list );
438
        if (name->len && !(key->name = memdup( name->str, name->len )))
439 440 441 442 443 444 445 446
        {
            release_object( key );
            key = NULL;
        }
    }
    return key;
}

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
/* mark a key and all its parents as dirty (modified) */
static void make_dirty( struct key *key )
{
    while (key)
    {
        if (key->flags & (KEY_DIRTY|KEY_VOLATILE)) return;  /* nothing to do */
        key->flags |= KEY_DIRTY;
        key = key->parent;
    }
}

/* mark a key and all its subkeys as clean (not modified) */
static void make_clean( struct key *key )
{
    int i;

    if (key->flags & KEY_VOLATILE) return;
    if (!(key->flags & KEY_DIRTY)) return;
    key->flags &= ~KEY_DIRTY;
    for (i = 0; i <= key->last_subkey; i++) make_clean( key->subkeys[i] );
}

469
/* go through all the notifications and send them if necessary */
470
static void check_notify( struct key *key, unsigned int change, int not_subtree )
471
{
472 473 474
    struct list *ptr, *next;

    LIST_FOR_EACH_SAFE( ptr, next, &key->notify_list )
475
    {
476
        struct notify *n = LIST_ENTRY( ptr, struct notify, entry );
477 478 479 480 481
        if ( ( not_subtree || n->subtree ) && ( change & n->filter ) )
            do_notification( key, n, 0 );
    }
}

482
/* update key modification time */
483
static void touch_key( struct key *key, unsigned int change )
484
{
485 486
    struct key *k;

487
    key->modif = current_time;
488
    make_dirty( key );
489 490 491 492 493

    /* do notifications */
    check_notify( key, change, 1 );
    for ( k = key->parent; k; k = k->parent )
        check_notify( k, change & ~REG_NOTIFY_CHANGE_LAST_SET, 0 );
494 495 496 497 498 499 500 501 502 503 504 505 506
}

/* try to grow the array of subkeys; return 1 if OK, 0 on error */
static int grow_subkeys( struct key *key )
{
    struct key **new_subkeys;
    int nb_subkeys;

    if (key->nb_subkeys)
    {
        nb_subkeys = key->nb_subkeys + (key->nb_subkeys / 2);  /* grow by 50% */
        if (!(new_subkeys = realloc( key->subkeys, nb_subkeys * sizeof(*new_subkeys) )))
        {
507
            set_error( STATUS_NO_MEMORY );
508 509 510 511 512 513 514 515 516 517 518 519 520 521
            return 0;
        }
    }
    else
    {
        nb_subkeys = MIN_VALUES;
        if (!(new_subkeys = mem_alloc( nb_subkeys * sizeof(*new_subkeys) ))) return 0;
    }
    key->subkeys    = new_subkeys;
    key->nb_subkeys = nb_subkeys;
    return 1;
}

/* allocate a subkey for a given key, and return its index */
522
static struct key *alloc_subkey( struct key *parent, const struct unicode_str *name,
523
                                 int index, timeout_t modif )
524 525 526 527
{
    struct key *key;
    int i;

528 529 530 531 532
    if (name->len > MAX_NAME_LEN * sizeof(WCHAR))
    {
        set_error( STATUS_NAME_TOO_LONG );
        return NULL;
    }
533 534 535 536 537 538 539 540 541 542 543
    if (parent->last_subkey + 1 == parent->nb_subkeys)
    {
        /* need to grow the array */
        if (!grow_subkeys( parent )) return NULL;
    }
    if ((key = alloc_key( name, modif )) != NULL)
    {
        key->parent = parent;
        for (i = ++parent->last_subkey; i > index; i--)
            parent->subkeys[i] = parent->subkeys[i-1];
        parent->subkeys[index] = key;
544 545
        if (is_wow6432node( key->name, key->namelen ) && !is_wow6432node( parent->name, parent->namelen ))
            parent->flags |= KEY_WOW64;
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
    }
    return key;
}

/* free a subkey of a given key */
static void free_subkey( struct key *parent, int index )
{
    struct key *key;
    int i, nb_subkeys;

    assert( index >= 0 );
    assert( index <= parent->last_subkey );

    key = parent->subkeys[index];
    for (i = index; i < parent->last_subkey; i++) parent->subkeys[i] = parent->subkeys[i + 1];
    parent->last_subkey--;
    key->flags |= KEY_DELETED;
    key->parent = NULL;
564
    if (is_wow6432node( key->name, key->namelen )) parent->flags &= ~KEY_WOW64;
565
    release_object( key );
566

567
    /* try to shrink the array */
568 569
    nb_subkeys = parent->nb_subkeys;
    if (nb_subkeys > MIN_SUBKEYS && parent->last_subkey < nb_subkeys / 2)
570 571 572 573
    {
        struct key **new_subkeys;
        nb_subkeys -= nb_subkeys / 3;  /* shrink by 33% */
        if (nb_subkeys < MIN_SUBKEYS) nb_subkeys = MIN_SUBKEYS;
574 575 576
        if (!(new_subkeys = realloc( parent->subkeys, nb_subkeys * sizeof(*new_subkeys) ))) return;
        parent->subkeys = new_subkeys;
        parent->nb_subkeys = nb_subkeys;
577 578 579 580
    }
}

/* find the named child of a given key and return its index */
581
static struct key *find_subkey( const struct key *key, const struct unicode_str *name, int *index )
582 583
{
    int i, min, max, res;
584
    data_size_t len;
585 586 587 588 589 590

    min = 0;
    max = key->last_subkey;
    while (min <= max)
    {
        i = (min + max) / 2;
591 592 593 594
        len = min( key->subkeys[i]->namelen, name->len );
        res = memicmpW( key->subkeys[i]->name, name->str, len / sizeof(WCHAR) );
        if (!res) res = key->subkeys[i]->namelen - name->len;
        if (!res)
595 596 597 598 599 600 601 602 603 604 605
        {
            *index = i;
            return key->subkeys[i];
        }
        if (res > 0) max = i - 1;
        else min = i + 1;
    }
    *index = min;  /* this is where we should insert it */
    return NULL;
}

606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
/* 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 )
{
    static const struct unicode_str wow6432node_str = { wow6432node, sizeof(wow6432node) };
    int index;

    if (!(key->flags & KEY_WOW64)) return key;
    if (!is_wow6432node( name->str, name->len ))
    {
        key = find_subkey( key, &wow6432node_str, &index );
        assert( key );  /* if KEY_WOW64 is set we must find it */
    }
    return key;
}


622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
/* 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 (memicmpW( path.str, root_name, sizeof(root_name)/sizeof(WCHAR) )) return NULL;
    path.str += sizeof(root_name) / sizeof(WCHAR);
    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;
}

652 653 654 655
/* 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 )
656
{
657 658 659 660
    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)
661
    {
662
        struct key *subkey;
663 664 665 666 667 668 669 670 671 672
        if (!(subkey = find_subkey( key, token, index )))
        {
            if ((key->flags & KEY_WOWSHARE) && !(access & KEY_WOW64_64KEY))
            {
                /* try in the 64-bit parent */
                key = key->parent;
                subkey = find_subkey( key, token, index );
            }
        }
        if (!subkey) break;
673 674 675 676
        key = subkey;
        get_path_token( name, token );
        if (!token->len) break;
        if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, token );
677 678 679 680 681
        if (!(key = follow_symlink( key, 0 )))
        {
            set_error( STATUS_OBJECT_NAME_NOT_FOUND );
            return NULL;
        }
682
    }
683 684
    return key;
}
685

686 687 688 689 690 691 692 693 694 695 696 697 698 699
/* open a subkey */
static struct key *open_key( struct key *key, const struct unicode_str *name, unsigned int access,
                             unsigned int attributes )
{
    int index;
    struct unicode_str token;

    if (!(key = open_key_prefix( key, name, access, &token, &index ))) return NULL;

    if (token.len)
    {
        set_error( STATUS_OBJECT_NAME_NOT_FOUND );
        return NULL;
    }
700
    if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, &token );
701 702 703 704 705
    if (!(attributes & OBJ_OPENLINK) && !(key = follow_symlink( key, 0 )))
    {
        set_error( STATUS_OBJECT_NAME_NOT_FOUND );
        return NULL;
    }
706
    if (debug_level > 1) dump_operation( key, NULL, "Open" );
707
    grab_object( key );
708 709 710 711
    return key;
}

/* create a subkey */
712
static struct key *create_key( struct key *key, const struct unicode_str *name,
713
                               const struct unicode_str *class, unsigned int options,
714
                               unsigned int access, unsigned int attributes, int *created )
715
{
716
    int index;
717
    struct unicode_str token, next;
718 719

    *created = 0;
720
    if (!(key = open_key_prefix( key, name, access, &token, &index ))) return NULL;
721

722
    if (!token.len)  /* the key already exists */
723
    {
724
        if (!(access & KEY_WOW64_64KEY)) key = find_wow64_subkey( key, &token );
725 726 727 728 729 730 731 732 733 734
        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;
        }
735 736 737 738 739 740 741 742 743 744 745 746
        if (debug_level > 1) dump_operation( key, NULL, "Open" );
        grab_object( key );
        return key;
    }

    /* token must be the last path component at this point */
    next = token;
    get_path_token( name, &next );
    if (next.len)
    {
        set_error( STATUS_OBJECT_NAME_NOT_FOUND );
        return NULL;
747
    }
748

749
    if ((key->flags & KEY_VOLATILE) && !(options & REG_OPTION_VOLATILE))
750 751 752 753
    {
        set_error( STATUS_CHILD_MUST_BE_VOLATILE );
        return NULL;
    }
754
    *created = 1;
755 756
    make_dirty( key );
    if (!(key = alloc_subkey( key, &token, index, current_time ))) return NULL;
757

758
    if (options & REG_OPTION_CREATE_LINK) key->flags |= KEY_SYMLINK;
759 760
    if (options & REG_OPTION_VOLATILE) key->flags |= KEY_VOLATILE;
    else key->flags |= KEY_DIRTY;
761 762

    if (debug_level > 1) dump_operation( key, NULL, "Create" );
763 764 765
    if (class && class->len)
    {
        key->classlen = class->len;
766
        free(key->class);
767 768
        if (!(key->class = memdup( class->str, key->classlen ))) key->classlen = 0;
    }
769 770 771 772
    grab_object( key );
    return key;
}

773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
/* 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 )
{
    struct key *base;
    int index;
    struct unicode_str token;

    token.str = NULL;
    if (!get_path_token( name, &token )) return NULL;
    while (token.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 );
    }

    if (token.len)
    {
        if (!(key = alloc_subkey( key, &token, index, modif ))) return NULL;
        base = key;
        for (;;)
        {
            get_path_token( name, &token );
            if (!token.len) break;
            /* we know the index is always 0 in a new key */
            if (!(key = alloc_subkey( key, &token, 0, modif )))
            {
                free_subkey( base, index );
                return NULL;
            }
        }
    }

    grab_object( key );
    return key;
}

816
/* query information about a key or a subkey */
817 818
static void enum_key( const struct key *key, int index, int info_class,
                      struct enum_key_reply *reply )
819
{
820
    int i;
821
    data_size_t len, namelen, classlen;
822 823
    data_size_t max_subkey = 0, max_class = 0;
    data_size_t max_value = 0, max_data = 0;
824
    char *data;
825

826 827 828 829 830
    if (index != -1)  /* -1 means use the specified key directly */
    {
        if ((index < 0) || (index > key->last_subkey))
        {
            set_error( STATUS_NO_MORE_ENTRIES );
831
            return;
832 833 834 835
        }
        key = key->subkeys[index];
    }

836 837
    namelen = key->namelen;
    classlen = key->classlen;
838 839

    switch(info_class)
840
    {
841 842 843 844 845 846 847 848 849 850
    case KeyBasicInformation:
        classlen = 0; /* only return the name */
        /* fall through */
    case KeyNodeInformation:
        reply->max_subkey = 0;
        reply->max_class  = 0;
        reply->max_value  = 0;
        reply->max_data   = 0;
        break;
    case KeyFullInformation:
851 852 853
        for (i = 0; i <= key->last_subkey; i++)
        {
            struct key *subkey = key->subkeys[i];
854
            len = subkey->namelen / sizeof(WCHAR);
855
            if (len > max_subkey) max_subkey = len;
856
            len = subkey->classlen / sizeof(WCHAR);
857 858 859 860
            if (len > max_class) max_class = len;
        }
        for (i = 0; i <= key->last_value; i++)
        {
861
            len = key->values[i].namelen / sizeof(WCHAR);
862 863 864 865
            if (len > max_value) max_value = len;
            len = key->values[i].len;
            if (len > max_data) max_data = len;
        }
866 867 868 869 870 871 872 873 874
        reply->max_subkey = max_subkey;
        reply->max_class  = max_class;
        reply->max_value  = max_value;
        reply->max_data   = max_data;
        namelen = 0;  /* only return the class */
        break;
    default:
        set_error( STATUS_INVALID_PARAMETER );
        return;
875
    }
876 877 878 879
    reply->subkeys = key->last_subkey + 1;
    reply->values  = key->last_value + 1;
    reply->modif   = key->modif;
    reply->total   = namelen + classlen;
880

881 882
    len = min( reply->total, get_reply_max_size() );
    if (len && (data = set_reply_data_size( len )))
883
    {
884 885 886 887
        if (len > namelen)
        {
            reply->namelen = namelen;
            memcpy( data, key->name, namelen );
888
            memcpy( data + namelen, key->class, len - namelen );
889 890 891 892 893 894
        }
        else
        {
            reply->namelen = len;
            memcpy( data, key->name, len );
        }
895 896
    }
    if (debug_level > 1) dump_operation( key, NULL, "Enum" );
897 898 899
}

/* delete a key and its values */
900
static int delete_key( struct key *key, int recurse )
901 902
{
    int index;
903
    struct key *parent = key->parent;
904

905
    /* must find parent and index */
906
    if (key == root_key)
907
    {
908
        set_error( STATUS_ACCESS_DENIED );
909
        return -1;
910
    }
911
    assert( parent );
912 913

    while (recurse && (key->last_subkey>=0))
914
        if (0 > delete_key(key->subkeys[key->last_subkey], 1))
915 916
            return -1;

917 918 919
    for (index = 0; index <= parent->last_subkey; index++)
        if (parent->subkeys[index] == key) break;
    assert( index <= parent->last_subkey );
920

921 922
    /* we can only delete a key that has no subkeys */
    if (key->last_subkey >= 0)
923
    {
924
        set_error( STATUS_ACCESS_DENIED );
925
        return -1;
926
    }
927

928 929
    if (debug_level > 1) dump_operation( key, NULL, "Delete" );
    free_subkey( parent, index );
930
    touch_key( parent, REG_NOTIFY_CHANGE_NAME );
931
    return 0;
932 933 934 935 936 937 938 939 940 941 942 943 944
}

/* try to grow the array of values; return 1 if OK, 0 on error */
static int grow_values( struct key *key )
{
    struct key_value *new_val;
    int nb_values;

    if (key->nb_values)
    {
        nb_values = key->nb_values + (key->nb_values / 2);  /* grow by 50% */
        if (!(new_val = realloc( key->values, nb_values * sizeof(*new_val) )))
        {
945
            set_error( STATUS_NO_MEMORY );
946 947 948 949 950 951 952 953 954 955 956 957 958 959
            return 0;
        }
    }
    else
    {
        nb_values = MIN_VALUES;
        if (!(new_val = mem_alloc( nb_values * sizeof(*new_val) ))) return 0;
    }
    key->values = new_val;
    key->nb_values = nb_values;
    return 1;
}

/* find the named value of a given key and return its index in the array */
960
static struct key_value *find_value( const struct key *key, const struct unicode_str *name, int *index )
961 962
{
    int i, min, max, res;
963
    data_size_t len;
964 965 966 967 968 969

    min = 0;
    max = key->last_value;
    while (min <= max)
    {
        i = (min + max) / 2;
970 971 972 973
        len = min( key->values[i].namelen, name->len );
        res = memicmpW( key->values[i].name, name->str, len / sizeof(WCHAR) );
        if (!res) res = key->values[i].namelen - name->len;
        if (!res)
974 975 976 977 978 979 980 981 982 983 984
        {
            *index = i;
            return &key->values[i];
        }
        if (res > 0) max = i - 1;
        else min = i + 1;
    }
    *index = min;  /* this is where we should insert it */
    return NULL;
}

985
/* insert a new value; the index must have been returned by find_value */
986
static struct key_value *insert_value( struct key *key, const struct unicode_str *name, int index )
987 988
{
    struct key_value *value;
989
    WCHAR *new_name = NULL;
990
    int i;
991

992 993 994 995 996
    if (name->len > MAX_VALUE_LEN * sizeof(WCHAR))
    {
        set_error( STATUS_NAME_TOO_LONG );
        return NULL;
    }
997
    if (key->last_value + 1 == key->nb_values)
998
    {
999
        if (!grow_values( key )) return NULL;
1000
    }
1001
    if (name->len && !(new_name = memdup( name->str, name->len ))) return NULL;
1002 1003
    for (i = ++key->last_value; i > index; i--) key->values[i] = key->values[i - 1];
    value = &key->values[index];
1004 1005 1006 1007
    value->name    = new_name;
    value->namelen = name->len;
    value->len     = 0;
    value->data    = NULL;
1008 1009 1010 1011
    return value;
}

/* set a key value */
1012
static void set_value( struct key *key, const struct unicode_str *name,
1013
                       int type, const void *data, data_size_t len )
1014 1015 1016
{
    struct key_value *value;
    void *ptr = NULL;
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
    int index;

    if ((value = find_value( key, name, &index )))
    {
        /* check if the new value is identical to the existing one */
        if (value->type == type && value->len == len &&
            value->data && !memcmp( value->data, data, len ))
        {
            if (debug_level > 1) dump_operation( key, value, "Skip setting" );
            return;
        }
    }
1029

1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
    if (key->flags & KEY_SYMLINK)
    {
        if (type != REG_LINK || name->len != symlink_str.len ||
            memicmpW( name->str, symlink_str.str, name->len / sizeof(WCHAR) ))
        {
            set_error( STATUS_ACCESS_DENIED );
            return;
        }
    }

1040
    if (len && !(ptr = memdup( data, len ))) return;
1041

1042
    if (!value)
1043
    {
1044 1045
        if (!(value = insert_value( key, name, index )))
        {
1046
            free( ptr );
1047 1048
            return;
        }
1049
    }
1050
    else free( value->data ); /* already existing, free previous data */
1051

1052
    value->type  = type;
1053
    value->len   = len;
1054
    value->data  = ptr;
1055
    touch_key( key, REG_NOTIFY_CHANGE_LAST_SET );
1056 1057 1058 1059
    if (debug_level > 1) dump_operation( key, value, "Set" );
}

/* get a key value */
1060
static void get_value( struct key *key, const struct unicode_str *name, int *type, data_size_t *len )
1061 1062 1063 1064 1065 1066 1067 1068
{
    struct key_value *value;
    int index;

    if ((value = find_value( key, name, &index )))
    {
        *type = value->type;
        *len  = value->len;
1069
        if (value->data) set_reply_data( value->data, min( value->len, get_reply_max_size() ));
1070 1071 1072 1073 1074
        if (debug_level > 1) dump_operation( key, value, "Get" );
    }
    else
    {
        *type = -1;
1075
        set_error( STATUS_OBJECT_NAME_NOT_FOUND );
1076 1077 1078 1079
    }
}

/* enumerate a key value */
1080
static void enum_value( struct key *key, int i, int info_class, struct enum_key_value_reply *reply )
1081 1082 1083
{
    struct key_value *value;

1084
    if (i < 0 || i > key->last_value) set_error( STATUS_NO_MORE_ENTRIES );
1085 1086
    else
    {
1087
        void *data;
1088
        data_size_t namelen, maxlen;
1089

1090
        value = &key->values[i];
1091
        reply->type = value->type;
1092
        namelen = value->namelen;
1093

1094
        switch(info_class)
1095
        {
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
        case KeyValueBasicInformation:
            reply->total = namelen;
            break;
        case KeyValueFullInformation:
            reply->total = namelen + value->len;
            break;
        case KeyValuePartialInformation:
            reply->total = value->len;
            namelen = 0;
            break;
        default:
            set_error( STATUS_INVALID_PARAMETER );
            return;
        }

        maxlen = min( reply->total, get_reply_max_size() );
        if (maxlen && ((data = set_reply_data_size( maxlen ))))
        {
            if (maxlen > namelen)
1115
            {
1116 1117 1118
                reply->namelen = namelen;
                memcpy( data, value->name, namelen );
                memcpy( (char *)data + namelen, value->data, maxlen - namelen );
1119
            }
1120
            else
1121
            {
1122 1123
                reply->namelen = maxlen;
                memcpy( data, value->name, maxlen );
1124
            }
1125
        }
1126 1127 1128 1129 1130
        if (debug_level > 1) dump_operation( key, value, "Enum" );
    }
}

/* delete a value */
1131
static void delete_value( struct key *key, const struct unicode_str *name )
1132 1133 1134 1135 1136 1137
{
    struct key_value *value;
    int i, index, nb_values;

    if (!(value = find_value( key, name, &index )))
    {
1138
        set_error( STATUS_OBJECT_NAME_NOT_FOUND );
1139 1140 1141
        return;
    }
    if (debug_level > 1) dump_operation( key, value, "Delete" );
1142 1143
    free( value->name );
    free( value->data );
1144 1145
    for (i = index; i < key->last_value; i++) key->values[i] = key->values[i + 1];
    key->last_value--;
1146
    touch_key( key, REG_NOTIFY_CHANGE_LAST_SET );
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158

    /* try to shrink the array */
    nb_values = key->nb_values;
    if (nb_values > MIN_VALUES && key->last_value < nb_values / 2)
    {
        struct key_value *new_val;
        nb_values -= nb_values / 3;  /* shrink by 33% */
        if (nb_values < MIN_VALUES) nb_values = MIN_VALUES;
        if (!(new_val = realloc( key->values, nb_values * sizeof(*new_val) ))) return;
        key->values = new_val;
        key->nb_values = nb_values;
    }
1159
}
1160 1161

/* get the registry key corresponding to an hkey handle */
1162
static struct key *get_hkey_obj( obj_handle_t hkey, unsigned int access )
1163
{
1164 1165 1166 1167 1168 1169 1170 1171 1172
    struct key *key = (struct key *)get_handle_obj( current->process, hkey, access, &key_ops );

    if (key && key->flags & KEY_DELETED)
    {
        set_error( STATUS_KEY_DELETED );
        release_object( key );
        key = NULL;
    }
    return key;
1173 1174
}

1175 1176 1177 1178
/* 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 );
1179
    return get_hkey_obj( hkey, 0 );
1180 1181
}

1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
/* read a line from the input file */
static int read_next_line( struct file_load_info *info )
{
    char *newbuf;
    int newlen, pos = 0;

    info->line++;
    for (;;)
    {
        if (!fgets( info->buffer + pos, info->len - pos, info->file ))
            return (pos != 0);  /* EOF */
        pos = strlen(info->buffer);
        if (info->buffer[pos-1] == '\n')
        {
            /* got a full line */
            info->buffer[--pos] = 0;
            if (pos > 0 && info->buffer[pos-1] == '\r') info->buffer[pos-1] = 0;
            return 1;
        }
        if (pos < info->len - 1) return 1;  /* EOF but something was read */

        /* need to enlarge the buffer */
        newlen = info->len + info->len / 2;
        if (!(newbuf = realloc( info->buffer, newlen )))
        {
1207
            set_error( STATUS_NO_MEMORY );
1208 1209 1210 1211 1212 1213 1214 1215
            return -1;
        }
        info->buffer = newbuf;
        info->len = newlen;
    }
}

/* make sure the temp buffer holds enough space */
1216
static int get_file_tmp_space( struct file_load_info *info, size_t size )
1217
{
1218
    WCHAR *tmp;
1219 1220 1221
    if (info->tmplen >= size) return 1;
    if (!(tmp = realloc( info->tmp, size )))
    {
1222
        set_error( STATUS_NO_MEMORY );
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
        return 0;
    }
    info->tmp = tmp;
    info->tmplen = size;
    return 1;
}

/* report an error while loading an input file */
static void file_read_error( const char *err, struct file_load_info *info )
{
1233 1234 1235 1236
    if (info->filename)
        fprintf( stderr, "%s:%d: %s '%s'\n", info->filename, info->line, err, info->buffer );
    else
        fprintf( stderr, "<fd>:%d: %s '%s'\n", info->line, err, info->buffer );
1237 1238 1239 1240 1241 1242 1243
}

/* convert a data type tag to a value type */
static int get_data_type( const char *buffer, int *type, int *parse_type )
{
    struct data_type { const char *tag; int len; int type; int parse_type; };

1244
    static const struct data_type data_types[] =
1245 1246 1247 1248 1249 1250 1251 1252
    {                   /* actual type */  /* type to assume for parsing */
        { "\"",        1,   REG_SZ,              REG_SZ },
        { "str:\"",    5,   REG_SZ,              REG_SZ },
        { "str(2):\"", 8,   REG_EXPAND_SZ,       REG_SZ },
        { "str(7):\"", 8,   REG_MULTI_SZ,        REG_SZ },
        { "hex:",      4,   REG_BINARY,          REG_BINARY },
        { "dword:",    6,   REG_DWORD,           REG_DWORD },
        { "hex(",      4,   -1,                  REG_BINARY },
1253
        { NULL,        0,    0,                  0 }
1254 1255 1256 1257 1258 1259 1260
    };

    const struct data_type *ptr;
    char *end;

    for (ptr = data_types; ptr->tag; ptr++)
    {
1261
        if (strncmp( ptr->tag, buffer, ptr->len )) continue;
1262 1263 1264 1265
        *parse_type = ptr->parse_type;
        if ((*type = ptr->type) != -1) return ptr->len;
        /* "hex(xx):" is special */
        *type = (int)strtoul( buffer + 4, &end, 16 );
1266
        if ((end <= buffer) || strncmp( end, "):", 2 )) return 0;
1267 1268 1269 1270 1271 1272
        return end + 2 - buffer;
    }
    return 0;
}

/* load and create a key from the input file */
1273
static struct key *load_key( struct key *base, const char *buffer,
1274
                             int prefix_len, struct file_load_info *info )
1275
{
1276 1277
    WCHAR *p;
    struct unicode_str name;
1278 1279 1280
    int res;
    unsigned int mod;
    timeout_t modif = current_time;
1281
    data_size_t len;
1282

1283
    if (!get_file_tmp_space( info, strlen(buffer) * sizeof(WCHAR) )) return NULL;
1284

1285
    len = info->tmplen;
1286
    if ((res = parse_strW( info->tmp, &len, buffer, ']' )) == -1)
1287 1288 1289 1290
    {
        file_read_error( "Malformed key", info );
        return NULL;
    }
1291 1292
    if (sscanf( buffer + res, " %u", &mod ) == 1)
        modif = (timeout_t)mod * TICKS_PER_SEC + ticks_1601_to_1970;
1293

1294
    p = info->tmp;
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
    while (prefix_len && *p) { if (*p++ == '\\') prefix_len--; }

    if (!*p)
    {
        if (prefix_len > 1)
        {
            file_read_error( "Malformed key", info );
            return NULL;
        }
        /* empty key name, return base key */
        return (struct key *)grab_object( base );
    }
1307 1308
    name.str = p;
    name.len = len - (p - info->tmp + 1) * sizeof(WCHAR);
1309
    return create_key_recursive( base, &name, modif );
1310 1311
}

1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
/* load a global option from the input file */
static int load_global_option( const char *buffer, struct file_load_info *info )
{
    const char *p;

    if (!strncmp( buffer, "#arch=", 6 ))
    {
        enum prefix_type type;
        p = buffer + 6;
        if (!strcmp( p, "win32" )) type = PREFIX_32BIT;
        else if (!strcmp( p, "win64" )) type = PREFIX_64BIT;
        else
        {
            file_read_error( "Unknown architecture", info );
            set_error( STATUS_NOT_REGISTRY_FILE );
            return 0;
        }
        if (prefix_type == PREFIX_UNKNOWN) prefix_type = type;
        else if (type != prefix_type)
        {
            file_read_error( "Mismatched architecture", info );
            set_error( STATUS_NOT_REGISTRY_FILE );
            return 0;
        }
    }
    /* ignore unknown options */
    return 1;
}

1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
/* load a key option from the input file */
static int load_key_option( struct key *key, const char *buffer, struct file_load_info *info )
{
    const char *p;
    data_size_t len;

    if (!strncmp( buffer, "#class=", 7 ))
    {
        p = buffer + 7;
        if (*p++ != '"') return 0;
        if (!get_file_tmp_space( info, strlen(p) * sizeof(WCHAR) )) return 0;
        len = info->tmplen;
        if (parse_strW( info->tmp, &len, p, '\"' ) == -1) return 0;
        free( key->class );
        if (!(key->class = memdup( info->tmp, len ))) len = 0;
        key->classlen = len;
    }
1358
    if (!strncmp( buffer, "#link", 5 )) key->flags |= KEY_SYMLINK;
1359 1360 1361 1362
    /* ignore unknown options */
    return 1;
}

1363
/* parse a comma-separated list of hex digits */
1364
static int parse_hex( unsigned char *dest, data_size_t *len, const char *buffer )
1365 1366
{
    const char *p = buffer;
1367
    data_size_t count = 0;
1368 1369
    char *end;

1370 1371
    while (isxdigit(*p))
    {
1372 1373
        unsigned int val = strtoul( p, &end, 16 );
        if (end == p || val > 0xff) return -1;
1374
        if (count++ >= *len) return -1;  /* dest buffer overflow */
1375 1376 1377
        *dest++ = val;
        p = end;
        while (isspace(*p)) p++;
1378
        if (*p == ',') p++;
1379
        while (isspace(*p)) p++;
1380 1381 1382 1383 1384 1385
    }
    *len = count;
    return p - buffer;
}

/* parse a value name and create the corresponding value */
1386
static struct key_value *parse_value_name( struct key *key, const char *buffer, data_size_t *len,
1387 1388
                                           struct file_load_info *info )
{
1389
    struct key_value *value;
1390 1391
    struct unicode_str name;
    int index;
1392

1393
    if (!get_file_tmp_space( info, strlen(buffer) * sizeof(WCHAR) )) return NULL;
1394
    name.str = info->tmp;
1395
    name.len = info->tmplen;
1396 1397
    if (buffer[0] == '@')
    {
1398
        name.len = 0;
1399 1400 1401 1402
        *len = 1;
    }
    else
    {
1403
        int r = parse_strW( info->tmp, &name.len, buffer + 1, '\"' );
1404 1405
        if (r == -1) goto error;
        *len = r + 1; /* for initial quote */
1406
        name.len -= sizeof(WCHAR);  /* terminating null */
1407
    }
1408
    while (isspace(buffer[*len])) (*len)++;
1409 1410
    if (buffer[*len] != '=') goto error;
    (*len)++;
1411
    while (isspace(buffer[*len])) (*len)++;
1412
    if (!(value = find_value( key, &name, &index ))) value = insert_value( key, &name, index );
1413
    return value;
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424

 error:
    file_read_error( "Malformed value name", info );
    return NULL;
}

/* load a value from the input file */
static int load_value( struct key *key, const char *buffer, struct file_load_info *info )
{
    DWORD dw;
    void *ptr, *newptr;
1425
    int res, type, parse_type;
1426
    data_size_t maxlen, len;
1427 1428 1429 1430 1431 1432 1433 1434 1435
    struct key_value *value;

    if (!(value = parse_value_name( key, buffer, &len, info ))) return 0;
    if (!(res = get_data_type( buffer + len, &type, &parse_type ))) goto error;
    buffer += len + res;

    switch(parse_type)
    {
    case REG_SZ:
1436 1437
        if (!get_file_tmp_space( info, strlen(buffer) * sizeof(WCHAR) )) return 0;
        len = info->tmplen;
1438
        if ((res = parse_strW( info->tmp, &len, buffer, '\"' )) == -1) goto error;
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
        ptr = info->tmp;
        break;
    case REG_DWORD:
        dw = strtoul( buffer, NULL, 16 );
        ptr = &dw;
        len = sizeof(dw);
        break;
    case REG_BINARY:  /* hex digits */
        len = 0;
        for (;;)
        {
1450
            maxlen = 1 + strlen(buffer) / 2;  /* at least 2 chars for one hex byte */
1451
            if (!get_file_tmp_space( info, len + maxlen )) return 0;
1452
            if ((res = parse_hex( (unsigned char *)info->tmp + len, &maxlen, buffer )) == -1) goto error;
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472
            len += maxlen;
            buffer += res;
            while (isspace(*buffer)) buffer++;
            if (!*buffer) break;
            if (*buffer != '\\') goto error;
            if (read_next_line( info) != 1) goto error;
            buffer = info->buffer;
            while (isspace(*buffer)) buffer++;
        }
        ptr = info->tmp;
        break;
    default:
        assert(0);
        ptr = NULL;  /* keep compiler quiet */
        break;
    }

    if (!len) newptr = NULL;
    else if (!(newptr = memdup( ptr, len ))) return 0;

1473
    free( value->data );
1474 1475 1476 1477 1478 1479 1480
    value->data = newptr;
    value->len  = len;
    value->type = type;
    return 1;

 error:
    file_read_error( "Malformed value", info );
1481 1482 1483 1484
    free( value->data );
    value->data = NULL;
    value->len  = 0;
    value->type = REG_NONE;
1485 1486 1487
    return 0;
}

1488 1489 1490 1491 1492 1493
/* return the length (in path elements) of name that is part of the key name */
/* for instance if key is USER\foo\bar and name is foo\bar\baz, return 2 */
static int get_prefix_len( struct key *key, const char *name, struct file_load_info *info )
{
    WCHAR *p;
    int res;
1494
    data_size_t len;
1495

1496
    if (!get_file_tmp_space( info, strlen(name) * sizeof(WCHAR) )) return 0;
1497

1498
    len = info->tmplen;
1499
    if ((res = parse_strW( info->tmp, &len, name, ']' )) == -1)
1500 1501
    {
        file_read_error( "Malformed key", info );
1502
        return 0;
1503
    }
1504
    for (p = info->tmp; *p; p++) if (*p == '\\') break;
1505
    len = (p - info->tmp) * sizeof(WCHAR);
1506
    for (res = 1; key != root_key; res++)
1507
    {
1508
        if (len == key->namelen && !memicmpW( info->tmp, key->name, len / sizeof(WCHAR) )) break;
1509 1510
        key = key->parent;
    }
1511
    if (key == root_key) res = 0;  /* no matching name */
1512 1513 1514
    return res;
}

1515
/* load all the keys from the input file */
1516
/* prefix_len is the number of key name prefixes to skip, or -1 for autodetection */
1517
static void load_keys( struct key *key, const char *filename, FILE *f, int prefix_len )
1518 1519 1520 1521
{
    struct key *subkey = NULL;
    struct file_load_info info;
    char *p;
1522

1523
    info.filename = filename;
1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537
    info.file   = f;
    info.len    = 4;
    info.tmplen = 4;
    info.line   = 0;
    if (!(info.buffer = mem_alloc( info.len ))) return;
    if (!(info.tmp = mem_alloc( info.tmplen )))
    {
        free( info.buffer );
        return;
    }

    if ((read_next_line( &info ) != 1) ||
        strcmp( info.buffer, "WINE REGISTRY Version 2" ))
    {
1538
        set_error( STATUS_NOT_REGISTRY_FILE );
1539 1540 1541 1542 1543
        goto done;
    }

    while (read_next_line( &info ) == 1)
    {
1544 1545
        p = info.buffer;
        while (*p && isspace(*p)) p++;
1546 1547 1548 1549
        switch(*p)
        {
        case '[':   /* new key */
            if (subkey) release_object( subkey );
1550
            if (prefix_len == -1) prefix_len = get_prefix_len( key, p + 1, &info );
1551
            if (!(subkey = load_key( key, p + 1, prefix_len, &info )))
1552
                file_read_error( "Error creating key", &info );
1553 1554 1555 1556 1557 1558
            break;
        case '@':   /* default value */
        case '\"':  /* value */
            if (subkey) load_value( subkey, p, &info );
            else file_read_error( "Value without key", &info );
            break;
1559 1560
        case '#':   /* option */
            if (subkey) load_key_option( subkey, p, &info );
1561
            else if (!load_global_option( p, &info )) goto done;
1562
            break;
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578
        case ';':   /* comment */
        case 0:     /* empty line */
            break;
        default:
            file_read_error( "Unrecognized input", &info );
            break;
        }
    }

 done:
    if (subkey) release_object( subkey );
    free( info.buffer );
    free( info.tmp );
}

/* load a part of the registry from a file */
1579
static void load_registry( struct key *key, obj_handle_t handle )
1580
{
1581
    struct file *file;
1582 1583
    int fd;

1584
    if (!(file = get_file_obj( current->process, handle, FILE_READ_DATA ))) return;
1585 1586
    fd = dup( get_file_unix_fd( file ) );
    release_object( file );
1587 1588 1589 1590 1591
    if (fd != -1)
    {
        FILE *f = fdopen( fd, "r" );
        if (f)
        {
1592
            load_keys( key, NULL, f, -1 );
1593 1594 1595 1596 1597 1598
            fclose( f );
        }
        else file_set_error();
    }
}

1599
/* load one of the initial registry files */
1600
static int load_init_registry_from_file( const char *filename, struct key *key )
1601 1602 1603
{
    FILE *f;

1604 1605
    if ((f = fopen( filename, "r" )))
    {
1606
        load_keys( key, filename, f, 0 );
1607 1608
        fclose( f );
        if (get_error() == STATUS_NOT_REGISTRY_FILE)
1609 1610
        {
            fprintf( stderr, "%s is not a valid registry file\n", filename );
1611
            return 1;
1612
        }
1613
    }
1614

1615
    assert( save_branch_count < MAX_SAVE_BRANCH_INFO );
1616

1617 1618 1619
    save_branch_info[save_branch_count].path = filename;
    save_branch_info[save_branch_count++].key = (struct key *)grab_object( key );
    make_object_static( &key->obj );
1620
    return (f != NULL);
1621 1622
}

1623
static WCHAR *format_user_registry_path( const SID *sid, struct unicode_str *path )
1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
{
    static const WCHAR prefixW[] = {'U','s','e','r','\\','S',0};
    static const WCHAR formatW[] = {'-','%','u',0};
    WCHAR buffer[7 + 10 + 10 + 10 * SID_MAX_SUB_AUTHORITIES];
    WCHAR *p = buffer;
    unsigned int i;

    strcpyW( p, prefixW );
    p += strlenW( prefixW );
    p += sprintfW( p, formatW, sid->Revision );
    p += sprintfW( p, formatW, MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5],
                                                   sid->IdentifierAuthority.Value[4] ),
                                         MAKEWORD( sid->IdentifierAuthority.Value[3],
                                                   sid->IdentifierAuthority.Value[2] )));
    for (i = 0; i < sid->SubAuthorityCount; i++)
        p += sprintfW( p, formatW, sid->SubAuthority[i] );

1641 1642 1643
    path->len = (p - buffer) * sizeof(WCHAR);
    path->str = p = memdup( buffer, path->len );
    return p;
1644 1645
}

1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673
/* get the cpu architectures that can be supported in the current prefix */
unsigned int get_prefix_cpu_mask(void)
{
    /* Allowed server/client/prefix combinations:
     *
     *              prefix
     *            32     64
     *  server +------+------+ client
     *         |  ok  | fail | 32
     *      32 +------+------+---
     *         | fail | fail | 64
     *      ---+------+------+---
     *         |  ok  |  ok  | 32
     *      64 +------+------+---
     *         | fail |  ok  | 64
     *      ---+------+------+---
     */
    switch (prefix_type)
    {
    case PREFIX_64BIT:
        /* 64-bit prefix requires 64-bit server */
        return sizeof(void *) > sizeof(int) ? ~0 : 0;
    case PREFIX_32BIT:
    default:
        return ~CPU_64BIT_MASK;  /* only 32-bit cpus supported on 32-bit prefix */
    }
}

1674 1675 1676
/* registry initialisation */
void init_registry(void)
{
1677 1678
    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' };
1679 1680 1681
    static const WCHAR classes[] = {'S','o','f','t','w','a','r','e','\\',
                                    'C','l','a','s','s','e','s','\\',
                                    'W','o','w','6','4','3','2','N','o','d','e'};
1682 1683 1684
    static const struct unicode_str root_name = { NULL, 0 };
    static const struct unicode_str HKLM_name = { HKLM, sizeof(HKLM) };
    static const struct unicode_str HKU_name = { HKU_default, sizeof(HKU_default) };
1685
    static const struct unicode_str classes_name = { classes, sizeof(classes) };
1686

1687
    WCHAR *current_user_path;
1688
    struct unicode_str current_user_str;
1689
    struct key *key, *hklm, *hkcu;
1690

1691 1692 1693 1694
    /* switch to the config dir */

    if (fchdir( config_dir_fd ) == -1) fatal_perror( "chdir to config dir" );

1695
    /* create the root key */
1696
    root_key = alloc_key( &root_name, current_time );
1697
    assert( root_key );
1698
    make_object_static( &root_key->obj );
1699

1700 1701
    /* load system.reg into Registry\Machine */

1702
    if (!(hklm = create_key_recursive( root_key, &HKLM_name, current_time )))
1703 1704
        fatal_error( "could not create Machine registry key\n" );

1705 1706 1707 1708
    if (!load_init_registry_from_file( "system.reg", hklm ))
        prefix_type = sizeof(void *) > sizeof(int) ? PREFIX_64BIT : PREFIX_32BIT;
    else if (prefix_type == PREFIX_UNKNOWN)
        prefix_type = PREFIX_32BIT;
1709 1710 1711

    /* load userdef.reg into Registry\User\.Default */

1712
    if (!(key = create_key_recursive( root_key, &HKU_name, current_time )))
1713 1714
        fatal_error( "could not create User\\.Default registry key\n" );

1715
    load_init_registry_from_file( "userdef.reg", key );
1716 1717
    release_object( key );

1718 1719
    /* load user.reg into HKEY_CURRENT_USER */

1720
    /* FIXME: match default user in token.c. should get from process token instead */
1721
    current_user_path = format_user_registry_path( security_local_user_sid, &current_user_str );
1722
    if (!current_user_path ||
1723
        !(hkcu = create_key_recursive( root_key, &current_user_str, current_time )))
1724
        fatal_error( "could not create HKEY_CURRENT_USER registry key\n" );
1725
    free( current_user_path );
1726 1727 1728
    load_init_registry_from_file( "user.reg", hkcu );

    /* set the shared flag on Software\Classes\Wow6432Node */
1729
    if (prefix_type == PREFIX_64BIT)
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740
    {
        if ((key = create_key_recursive( hklm, &classes_name, current_time )))
        {
            key->flags |= KEY_WOWSHARE;
            release_object( key );
        }
        /* FIXME: handle HKCU too */
    }

    release_object( hklm );
    release_object( hkcu );
1741 1742 1743

    /* start the periodic save timer */
    set_periodic_save_timer();
1744 1745 1746

    /* go back to the server dir */
    if (fchdir( server_dir_fd ) == -1) fatal_perror( "chdir to server dir" );
1747 1748
}

1749 1750
/* save a registry branch to a file */
static void save_all_subkeys( struct key *key, FILE *f )
1751
{
1752 1753 1754 1755
    fprintf( f, "WINE REGISTRY Version 2\n" );
    fprintf( f, ";; All keys relative to " );
    dump_path( key, NULL, f );
    fprintf( f, "\n" );
1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766
    switch (prefix_type)
    {
    case PREFIX_32BIT:
        fprintf( f, "\n#arch=win32\n" );
        break;
    case PREFIX_64BIT:
        fprintf( f, "\n#arch=win64\n" );
        break;
    default:
        break;
    }
1767
    save_subkeys( key, key, f );
1768 1769 1770
}

/* save a registry branch to a file handle */
1771
static void save_registry( struct key *key, obj_handle_t handle )
1772
{
1773
    struct file *file;
1774 1775
    int fd;

1776
    if (!(file = get_file_obj( current->process, handle, FILE_WRITE_DATA ))) return;
1777 1778
    fd = dup( get_file_unix_fd( file ) );
    release_object( file );
1779 1780 1781 1782 1783
    if (fd != -1)
    {
        FILE *f = fdopen( fd, "w" );
        if (f)
        {
1784
            save_all_subkeys( key, f );
1785 1786 1787 1788 1789 1790 1791 1792 1793 1794
            if (fclose( f )) file_set_error();
        }
        else
        {
            file_set_error();
            close( fd );
        }
    }
}

1795 1796 1797
/* save a registry branch to a file */
static int save_branch( struct key *key, const char *path )
{
1798
    struct stat st;
1799 1800
    char *p, *tmp = NULL;
    int fd, count = 0, ret = 0;
1801 1802
    FILE *f;

1803 1804 1805 1806 1807 1808
    if (!(key->flags & KEY_DIRTY))
    {
        if (debug_level > 1) dump_operation( key, NULL, "Not saving clean" );
        return 1;
    }

1809 1810 1811 1812
    /* test the file type */

    if ((fd = open( path, O_WRONLY )) != -1)
    {
1813 1814
        /* if file is not a regular file or has multiple links or is accessed
         * via symbolic links, write directly into it; otherwise use a temp file */
1815
        if (!lstat( path, &st ) && (!S_ISREG(st.st_mode) || st.st_nlink > 1))
1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830
        {
            ftruncate( fd, 0 );
            goto save;
        }
        close( fd );
    }

    /* create a temp file in the same directory */

    if (!(tmp = malloc( strlen(path) + 20 ))) goto done;
    strcpy( tmp, path );
    if ((p = strrchr( tmp, '/' ))) p++;
    else p = tmp;
    for (;;)
    {
Patrik Stridvall's avatar
Patrik Stridvall committed
1831
        sprintf( p, "reg%lx%04x.tmp", (long) getpid(), count++ );
1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852
        if ((fd = open( tmp, O_CREAT | O_EXCL | O_WRONLY, 0666 )) != -1) break;
        if (errno != EEXIST) goto done;
        close( fd );
    }

    /* now save to it */

 save:
    if (!(f = fdopen( fd, "w" )))
    {
        if (tmp) unlink( tmp );
        close( fd );
        goto done;
    }

    if (debug_level > 1)
    {
        fprintf( stderr, "%s: ", path );
        dump_operation( key, NULL, "saving" );
    }

1853
    save_all_subkeys( key, f );
1854 1855 1856 1857 1858 1859 1860 1861 1862 1863
    ret = !fclose(f);

    if (tmp)
    {
        /* if successfully written, rename to final name */
        if (ret) ret = !rename( tmp, path );
        if (!ret) unlink( tmp );
    }

done:
1864
    free( tmp );
1865
    if (ret) make_clean( key );
1866 1867 1868 1869 1870 1871 1872
    return ret;
}

/* periodic saving of the registry */
static void periodic_save( void *arg )
{
    int i;
1873

1874
    if (fchdir( config_dir_fd ) == -1) return;
1875
    save_timeout_user = NULL;
1876 1877
    for (i = 0; i < save_branch_count; i++)
        save_branch( save_branch_info[i].key, save_branch_info[i].path );
1878
    if (fchdir( server_dir_fd ) == -1) fatal_perror( "chdir to server dir" );
1879 1880 1881 1882 1883 1884 1885
    set_periodic_save_timer();
}

/* start the periodic save timer */
static void set_periodic_save_timer(void)
{
    if (save_timeout_user) remove_timeout_user( save_timeout_user );
1886
    save_timeout_user = add_timeout_user( save_period, periodic_save, NULL );
1887 1888
}

1889 1890
/* save the modified registry branches to disk */
void flush_registry(void)
1891 1892 1893
{
    int i;

1894
    if (fchdir( config_dir_fd ) == -1) return;
1895 1896 1897 1898 1899 1900 1901 1902 1903
    for (i = 0; i < save_branch_count; i++)
    {
        if (!save_branch( save_branch_info[i].key, save_branch_info[i].path ))
        {
            fprintf( stderr, "wineserver: could not save registry branch to %s",
                     save_branch_info[i].path );
            perror( " " );
        }
    }
1904
    if (fchdir( server_dir_fd ) == -1) fatal_perror( "chdir to server dir" );
1905 1906
}

1907 1908 1909 1910 1911 1912
/* determine if the thread is wow64 (32-bit client running on 64-bit prefix) */
static int is_wow64_thread( struct thread *thread )
{
    return (prefix_type == PREFIX_64BIT && !(CPU_FLAG(thread->process->cpu) & CPU_64BIT_MASK));
}

1913

1914 1915 1916
/* create a registry key */
DECL_HANDLER(create_key)
{
1917
    struct key *key = NULL, *parent;
1918
    struct unicode_str name, class;
1919 1920
    unsigned int access = req->access;

1921 1922
    if (!is_wow64_thread( current )) access = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY;

1923
    reply->hkey = 0;
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939

    if (req->namelen > get_req_data_size())
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }
    class.str = (const WCHAR *)get_req_data() + req->namelen / sizeof(WCHAR);
    class.len = ((get_req_data_size() - req->namelen) / sizeof(WCHAR)) * sizeof(WCHAR);
    get_req_path( &name, !req->parent );
    if (name.str > class.str)
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }
    name.len = (class.str - name.str) * sizeof(WCHAR);

1940
    /* NOTE: no access rights are required from the parent handle to create a key */
1941
    if ((parent = get_parent_hkey_obj( req->parent )))
1942
    {
1943 1944
        if ((key = create_key( parent, &name, &class, req->options, access,
                               req->attributes, &reply->created )))
1945
        {
1946
            reply->hkey = alloc_handle( current->process, key, access, req->attributes );
1947 1948
            release_object( key );
        }
1949 1950 1951 1952 1953 1954 1955 1956
        release_object( parent );
    }
}

/* open a registry key */
DECL_HANDLER(open_key)
{
    struct key *key, *parent;
1957
    struct unicode_str name;
1958 1959
    unsigned int access = req->access;

1960 1961
    if (!is_wow64_thread( current )) access = (access & ~KEY_WOW64_32KEY) | KEY_WOW64_64KEY;

1962
    reply->hkey = 0;
1963
    /* NOTE: no access rights are required to open the parent key, only the child key */
1964
    if ((parent = get_parent_hkey_obj( req->parent )))
1965
    {
1966
        get_req_path( &name, !req->parent );
1967
        if ((key = open_key( parent, &name, access, req->attributes )))
1968
        {
1969
            reply->hkey = alloc_handle( current->process, key, access, req->attributes );
1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
            release_object( key );
        }
        release_object( parent );
    }
}

/* delete a registry key */
DECL_HANDLER(delete_key)
{
    struct key *key;

1981
    if ((key = get_hkey_obj( req->hkey, DELETE )))
1982
    {
1983
        delete_key( key, 0);
1984 1985 1986 1987
        release_object( key );
    }
}

1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998
/* flush a registry key */
DECL_HANDLER(flush_key)
{
    struct key *key = get_hkey_obj( req->hkey, 0 );
    if (key)
    {
        /* we don't need to do anything here with the current implementation */
        release_object( key );
    }
}

1999 2000 2001 2002 2003
/* enumerate registry subkeys */
DECL_HANDLER(enum_key)
{
    struct key *key;

2004 2005
    if ((key = get_hkey_obj( req->hkey,
                             req->index == -1 ? KEY_QUERY_VALUE : KEY_ENUMERATE_SUB_KEYS )))
2006
    {
2007
        enum_key( key, req->index, req->info_class, reply );
2008 2009 2010 2011 2012 2013 2014 2015
        release_object( key );
    }
}

/* set a value of a registry key */
DECL_HANDLER(set_key_value)
{
    struct key *key;
2016 2017 2018 2019 2020 2021 2022 2023 2024
    struct unicode_str name;

    if (req->namelen > get_req_data_size())
    {
        set_error( STATUS_INVALID_PARAMETER );
        return;
    }
    name.str = get_req_data();
    name.len = (req->namelen / sizeof(WCHAR)) * sizeof(WCHAR);
2025

2026 2027
    if ((key = get_hkey_obj( req->hkey, KEY_SET_VALUE )))
    {
2028
        data_size_t datalen = get_req_data_size() - req->namelen;
Eric Pouech's avatar
Eric Pouech committed
2029
        const char *data = (const char *)get_req_data() + req->namelen;
2030

2031
        set_value( key, &name, req->type, data, datalen );
2032 2033 2034 2035 2036 2037 2038 2039
        release_object( key );
    }
}

/* retrieve the value of a registry key */
DECL_HANDLER(get_key_value)
{
    struct key *key;
2040
    struct unicode_str name;
2041

2042
    reply->total = 0;
2043 2044
    if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE )))
    {
2045 2046
        get_req_unicode_str( &name );
        get_value( key, &name, &reply->type, &reply->total );
2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057
        release_object( key );
    }
}

/* enumerate the value of a registry key */
DECL_HANDLER(enum_key_value)
{
    struct key *key;

    if ((key = get_hkey_obj( req->hkey, KEY_QUERY_VALUE )))
    {
2058
        enum_value( key, req->index, req->info_class, reply );
2059 2060 2061 2062 2063 2064 2065 2066
        release_object( key );
    }
}

/* delete a value of a registry key */
DECL_HANDLER(delete_key_value)
{
    struct key *key;
2067
    struct unicode_str name;
2068 2069 2070

    if ((key = get_hkey_obj( req->hkey, KEY_SET_VALUE )))
    {
2071 2072
        get_req_unicode_str( &name );
        delete_value( key, &name );
2073 2074 2075 2076 2077 2078 2079
        release_object( key );
    }
}

/* load a registry branch from a file */
DECL_HANDLER(load_registry)
{
James Hawkins's avatar
James Hawkins committed
2080
    struct key *key, *parent;
2081
    struct token *token = thread_get_impersonation_token( current );
2082
    struct unicode_str name;
2083

2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096
    const LUID_AND_ATTRIBUTES privs[] =
    {
        { SeBackupPrivilege,  0 },
        { SeRestorePrivilege, 0 },
    };

    if (!token || !token_check_privileges( token, TRUE, privs,
                                           sizeof(privs)/sizeof(privs[0]), NULL ))
    {
        set_error( STATUS_PRIVILEGE_NOT_HELD );
        return;
    }

2097
    if ((parent = get_parent_hkey_obj( req->hkey )))
2098
    {
James Hawkins's avatar
James Hawkins committed
2099
        int dummy;
2100
        get_req_path( &name, !req->hkey );
2101
        if ((key = create_key( parent, &name, NULL, 0, KEY_WOW64_64KEY, 0, &dummy )))
James Hawkins's avatar
James Hawkins committed
2102 2103 2104 2105 2106
        {
            load_registry( key, req->file );
            release_object( key );
        }
        release_object( parent );
2107 2108 2109
    }
}

2110 2111 2112
DECL_HANDLER(unload_registry)
{
    struct key *key;
2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126
    struct token *token = thread_get_impersonation_token( current );

    const LUID_AND_ATTRIBUTES privs[] =
    {
        { SeBackupPrivilege,  0 },
        { SeRestorePrivilege, 0 },
    };

    if (!token || !token_check_privileges( token, TRUE, privs,
                                           sizeof(privs)/sizeof(privs[0]), NULL ))
    {
        set_error( STATUS_PRIVILEGE_NOT_HELD );
        return;
    }
2127 2128 2129 2130 2131 2132 2133 2134

    if ((key = get_hkey_obj( req->hkey, 0 )))
    {
        delete_key( key, 1 );     /* FIXME */
        release_object( key );
    }
}

2135 2136 2137 2138 2139
/* save a registry branch to a file */
DECL_HANDLER(save_registry)
{
    struct key *key;

2140 2141 2142 2143 2144 2145 2146
    if (!thread_single_check_privilege( current, &SeBackupPrivilege ))
    {
        set_error( STATUS_PRIVILEGE_NOT_HELD );
        return;
    }

    if ((key = get_hkey_obj( req->hkey, 0 )))
2147 2148 2149 2150 2151 2152
    {
        save_registry( key, req->file );
        release_object( key );
    }
}

2153 2154 2155 2156 2157 2158 2159 2160
/* add a registry key change notification */
DECL_HANDLER(set_registry_notification)
{
    struct key *key;
    struct event *event;
    struct notify *notify;

    key = get_hkey_obj( req->hkey, KEY_NOTIFY );
2161
    if (key)
2162 2163
    {
        event = get_event_obj( current->process, req->event, SYNCHRONIZE );
2164
        if (event)
2165
        {
2166
            notify = find_notify( key, current->process, req->hkey );
2167
            if (notify)
2168
            {
2169 2170
                if (notify->event)
                    release_object( notify->event );
2171 2172 2173 2174 2175
                grab_object( event );
                notify->event = event;
            }
            else
            {
2176
                notify = mem_alloc( sizeof(*notify) );
2177
                if (notify)
2178 2179 2180 2181 2182 2183
                {
                    grab_object( event );
                    notify->event   = event;
                    notify->subtree = req->subtree;
                    notify->filter  = req->filter;
                    notify->hkey    = req->hkey;
2184
                    notify->process = current->process;
2185
                    list_add_head( &key->notify_list, &notify->entry );
2186 2187 2188 2189 2190 2191 2192
                }
            }
            release_object( event );
        }
        release_object( key );
    }
}