r26689: registry: Return max_subkeynamelen, max_valnamelen and max_valbufsize in...
[bbaumbach/samba-autobuild/.git] / source4 / lib / registry / regf.c
1 /*
2    Samba CIFS implementation
3    Registry backend for REGF files
4    Copyright (C) 2005-2007 Jelmer Vernooij, jelmer@samba.org
5    Copyright (C) 2006 Wilco Baan Hofman, wilco@baanhofman.nl
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 #include "includes.h"
21 #include "lib/registry/hive.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "lib/registry/tdr_regf.h"
25 #include "librpc/gen_ndr/ndr_security.h"
26 #include "librpc/gen_ndr/winreg.h"
27 #include "param/param.h"
28
29 static struct hive_operations reg_backend_regf;
30
31 /**
32  * There are several places on the web where the REGF format is explained;
33  *
34  * TODO: Links
35  */
36
37 /* TODO:
38  *  - Return error codes that make more sense
39  *  - Locking
40  *  - do more things in-memory
41  */
42
43 /*
44  * Read HBIN blocks into memory
45  */
46
47 struct regf_data {
48         int fd;
49         struct hbin_block **hbins;
50         struct regf_hdr *header;
51         struct smb_iconv_convenience *iconv_convenience;
52 };
53
54 static WERROR regf_save_hbin(struct regf_data *data);
55
56 struct regf_key_data {
57         struct hive_key key;
58         struct regf_data *hive;
59         uint32_t offset;
60         struct nk_block *nk;
61 };
62
63 static struct hbin_block *hbin_by_offset(const struct regf_data *data,
64                                          uint32_t offset, uint32_t *rel_offset)
65 {
66         int i;
67
68         for (i = 0; data->hbins[i]; i++) {
69                 if (offset >= data->hbins[i]->offset_from_first &&
70                         offset < data->hbins[i]->offset_from_first+
71                                          data->hbins[i]->offset_to_next) {
72                         if (rel_offset != NULL)
73                                 *rel_offset = offset - data->hbins[i]->offset_from_first - 0x20;
74                         return data->hbins[i];
75                 }
76         }
77
78         return NULL;
79 }
80
81 /**
82  * Validate a regf header
83  * For now, do nothing, but we should check the checksum
84  */
85 static uint32_t regf_hdr_checksum(const uint8_t *buffer)
86 {
87         uint32_t checksum = 0, x;
88         int i;
89
90         for (i = 0; i < 0x01FB; i+= 4) {
91                 x = IVAL(buffer, i);
92                 checksum ^= x;
93         }
94
95         return checksum;
96 }
97
98 /**
99  * Obtain the contents of a HBIN block
100  */
101 static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset)
102 {
103         DATA_BLOB ret;
104         struct hbin_block *hbin;
105         uint32_t rel_offset;
106
107         ret.data = NULL;
108         ret.length = 0;
109
110         hbin = hbin_by_offset(data, offset, &rel_offset);
111
112         if (hbin == NULL) {
113                 DEBUG(1, ("Can't find HBIN containing 0x%04x\n", offset));
114                 return ret;
115         }
116
117         ret.length = IVAL(hbin->data, rel_offset);
118         if (!(ret.length & 0x80000000)) {
119                 DEBUG(0, ("Trying to use dirty block at 0x%04x\n", offset));
120                 return ret;
121         }
122
123         /* remove high bit */
124         ret.length = (ret.length ^ 0xffffffff) + 1;
125
126         ret.length -= 4; /* 4 bytes for the length... */
127         ret.data = hbin->data +
128                 (offset - hbin->offset_from_first - 0x20) + 4;
129
130         return ret;
131 }
132
133 static bool hbin_get_tdr(struct regf_data *regf, uint32_t offset,
134                          TALLOC_CTX *ctx, tdr_pull_fn_t pull_fn, void *p)
135 {
136         struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
137
138         pull->data = hbin_get(regf, offset);
139         if (!pull->data.data) {
140                 DEBUG(1, ("Unable to get data at 0x%04x\n", offset));
141                 talloc_free(pull);
142                 return false;
143         }
144
145         if (NT_STATUS_IS_ERR(pull_fn(pull, ctx, p))) {
146                 DEBUG(1, ("Error parsing record at 0x%04x using tdr\n",
147                         offset));
148                 talloc_free(pull);
149                 return false;
150         }
151         talloc_free(pull);
152
153         return true;
154 }
155
156 /* Allocate some new data */
157 static DATA_BLOB hbin_alloc(struct regf_data *data, uint32_t size,
158                             uint32_t *offset)
159 {
160         DATA_BLOB ret;
161         uint32_t rel_offset = -1; /* Relative offset ! */
162         struct hbin_block *hbin = NULL;
163         int i;
164
165         *offset = 0;
166
167         if (size == 0)
168                 return data_blob(NULL, 0);
169
170         size += 4; /* Need to include int32 for the length */
171
172         /* Allocate as a multiple of 8 */
173         size = (size + 7) & ~7;
174
175         ret.data = NULL;
176         ret.length = 0;
177
178         for (i = 0; (hbin = data->hbins[i]); i++) {
179                 int j;
180                 int32_t my_size;
181                 for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
182                         my_size = IVALS(hbin->data, j);
183
184                         if (my_size == 0x0) {
185                                 DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
186                                 return ret;
187                         }
188
189                         if (my_size % 8 != 0) {
190                                 DEBUG(0, ("Encountered non-aligned block!\n"));
191                         }
192
193                         if (my_size < 0) { /* Used... */
194                                 my_size = -my_size;
195                         } else if (my_size == size) { /* exact match */
196                                 rel_offset = j;
197                                 DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n",
198                                         size));
199                                 break;
200                         } else if (my_size > size) { /* data will remain */
201                                 rel_offset = j;
202                                 /* Split this block and mark the next block as free */
203                                 SIVAL(hbin->data, rel_offset+size, my_size-size);
204                                 DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n",
205                                         my_size, size));
206                                 break;
207                         }
208                 }
209
210                 if (rel_offset != -1)
211                         break;
212         }
213
214         /* No space available in previous hbins,
215          * allocate new one */
216         if (data->hbins[i] == NULL) {
217                 DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n",
218                         size));
219                 data->hbins = talloc_realloc(data, data->hbins,
220                                              struct hbin_block *, i+2);
221                 hbin = talloc(data->hbins, struct hbin_block);
222                 SMB_ASSERT(hbin != NULL);
223
224                 data->hbins[i] = hbin;
225                 data->hbins[i+1] = NULL;
226
227                 hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
228                 hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
229                 hbin->offset_to_next = 0x1000;
230                 hbin->unknown[0] = 0;
231                 hbin->unknown[0] = 0;
232                 unix_to_nt_time(&hbin->last_change, time(NULL));
233                 hbin->block_size = hbin->offset_to_next;
234                 hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
235
236                 rel_offset = 0x0;
237                 SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
238         }
239
240         /* Set size and mark as used */
241         SIVAL(hbin->data, rel_offset, -size);
242
243         ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
244         ret.length = size - 0x4;
245         if (offset) {
246                 uint32_t new_rel_offset;
247                 *offset = hbin->offset_from_first + rel_offset + 0x20;
248                 SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);
249                 SMB_ASSERT(new_rel_offset == rel_offset);
250         }
251
252         return ret;
253 }
254
255 /* Store a data blob. Return the offset at which it was stored */
256 static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
257 {
258         uint32_t ret;
259         DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
260
261         memcpy(dest.data, blob.data, blob.length);
262
263         return ret;
264 }
265
266 static uint32_t hbin_store_tdr(struct regf_data *data,
267                                tdr_push_fn_t push_fn, void *p)
268 {
269         struct tdr_push *push = tdr_push_init(data, data->iconv_convenience);
270         uint32_t ret;
271
272         if (NT_STATUS_IS_ERR(push_fn(push, p))) {
273                 DEBUG(0, ("Error during push\n"));
274                 return -1;
275         }
276
277         ret = hbin_store(data, push->data);
278
279         talloc_free(push);
280
281         return ret;
282 }
283
284
285 /* Free existing data */
286 static void hbin_free (struct regf_data *data, uint32_t offset)
287 {
288         int32_t size;
289         uint32_t rel_offset;
290         int32_t next_size;
291         struct hbin_block *hbin;
292
293         SMB_ASSERT (offset > 0);
294
295         hbin = hbin_by_offset(data, offset, &rel_offset);
296
297         if (hbin == NULL)
298                 return;
299
300         /* Get original size */
301         size = IVALS(hbin->data, rel_offset);
302
303         if (size > 0) {
304                 DEBUG(1, ("Trying to free already freed block at 0x%04x\n",
305                         offset));
306                 return;
307         }
308         /* Mark as unused */
309         size = -size;
310
311         /* If the next block is free, merge into big free block */
312         if (rel_offset + size < hbin->offset_to_next) {
313                 next_size = IVALS(hbin->data, rel_offset+size);
314                 if (next_size > 0) {
315                         size += next_size;
316                 }
317         }
318
319         /* Write block size */
320         SIVALS(hbin->data, rel_offset, size);
321 }
322
323 /**
324  * Store a data blob data was already stored, but has changed in size
325  * Will try to save it at the current location if possible, otherwise
326  * does a free + store */
327 static uint32_t hbin_store_resize(struct regf_data *data,
328                                   uint32_t orig_offset, DATA_BLOB blob)
329 {
330         uint32_t rel_offset;
331         struct hbin_block *hbin = hbin_by_offset(data, orig_offset,
332                                                  &rel_offset);
333         int32_t my_size;
334         int32_t orig_size;
335         int32_t needed_size;
336         int32_t possible_size;
337         int i;
338
339         SMB_ASSERT(orig_offset > 0);
340
341         if (!hbin)
342                 return hbin_store(data, blob);
343
344         /* Get original size */
345         orig_size = -IVALS(hbin->data, rel_offset);
346
347         needed_size = blob.length + 4; /* Add int32 containing length */
348         needed_size = (needed_size + 7) & ~7; /* Align */
349
350         /* Fits into current allocated block */
351         if (orig_size >= needed_size) {
352                 memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
353                 /* If the difference in size is greater than 0x4, split the block
354                  * and free/merge it */
355                 if (orig_size - needed_size > 0x4) {
356                         SIVALS(hbin->data, rel_offset, -needed_size);
357                         SIVALS(hbin->data, rel_offset + needed_size,
358                                needed_size-orig_size);
359                         hbin_free(data, orig_offset + needed_size);
360                 }
361                 return orig_offset;
362         }
363
364         possible_size = orig_size;
365
366         /* Check if it can be combined with the next few free records */
367         for (i = rel_offset; i < hbin->offset_to_next - 0x20; i += my_size) {
368                 if (IVALS(hbin->data, i) < 0) /* Used */
369                         break;
370
371                 my_size = IVALS(hbin->data, i);
372
373                 if (my_size == 0x0) {
374                         DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
375                         break;
376                 } else {
377                         possible_size += my_size;
378                 }
379
380                 if (possible_size >= blob.length) {
381                         SIVAL(hbin->data, rel_offset, -possible_size);
382                         memcpy(hbin->data + rel_offset + 0x4,
383                                blob.data, blob.length);
384                         return orig_offset;
385                 }
386         }
387
388         hbin_free(data, orig_offset);
389         return hbin_store(data, blob);
390 }
391
392 static uint32_t hbin_store_tdr_resize(struct regf_data *regf,
393                                       tdr_push_fn_t push_fn,
394                                       uint32_t orig_offset, void *p)
395 {
396         struct tdr_push *push = tdr_push_init(regf, regf->iconv_convenience);
397         uint32_t ret;
398
399         if (NT_STATUS_IS_ERR(push_fn(push, p))) {
400                 DEBUG(0, ("Error during push\n"));
401                 return -1;
402         }
403
404         ret = hbin_store_resize(regf, orig_offset, push->data);
405
406         talloc_free(push);
407
408         return ret;
409 }
410
411 static uint32_t regf_create_lh_hash(const char *name)
412 {
413         char *hash_name;
414         uint32_t ret = 0;
415         uint16_t i;
416
417         hash_name = strupper_talloc(NULL, name);
418         for (i = 0; *(hash_name + i) != 0; i++) {
419                 ret *= 37;
420                 ret += *(hash_name + i);
421         }
422         talloc_free(hash_name);
423         return ret;
424 }
425
426 static WERROR regf_get_info(TALLOC_CTX *mem_ctx,
427                             const struct hive_key *key,
428                             const char **classname,
429                             uint32_t *num_subkeys,
430                             uint32_t *num_values,
431                             NTTIME *last_mod_time,
432                             uint32_t *max_subkeynamelen,
433                             uint32_t *max_valnamelen,
434                             uint32_t *max_valbufsize)
435 {
436         const struct regf_key_data *private_data =
437                 (const struct regf_key_data *)key;
438
439         if (num_subkeys != NULL)
440                 *num_subkeys = private_data->nk->num_subkeys;
441
442         if (num_values != NULL)
443                 *num_values = private_data->nk->num_values;
444
445         if (classname != NULL) {
446                 if (private_data->nk->clsname_offset != -1) {
447                         DATA_BLOB data = hbin_get(private_data->hive,
448                                                   private_data->nk->clsname_offset);
449                         *classname = talloc_strndup(mem_ctx,
450                                                     (char*)data.data,
451                                                     private_data->nk->clsname_length);
452                 } else
453                         *classname = NULL;
454         }
455
456         /* TODO: Last mod time */
457
458         /* TODO: max valnamelen */
459         
460         /* TODO: max valbufsize */
461
462         /* TODO: max subkeynamelen */
463
464         return WERR_OK;
465 }
466
467 static struct regf_key_data *regf_get_key(TALLOC_CTX *ctx,
468                                           struct regf_data *regf,
469                                           uint32_t offset)
470 {
471         struct nk_block *nk;
472         struct regf_key_data *ret;
473
474         ret = talloc_zero(ctx, struct regf_key_data);
475         ret->key.ops = &reg_backend_regf;
476         ret->hive = talloc_reference(ret, regf);
477         ret->offset = offset;
478         nk = talloc(ret, struct nk_block);
479         if (nk == NULL)
480                 return NULL;
481
482         ret->nk = nk;
483
484         if (!hbin_get_tdr(regf, offset, nk,
485                           (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
486                 DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
487                 return NULL;
488         }
489
490         if (strcmp(nk->header, "nk") != 0) {
491                 DEBUG(0, ("Expected nk record, got %s\n", nk->header));
492                 talloc_free(ret);
493                 return NULL;
494         }
495
496         return ret;
497 }
498
499
500 static WERROR regf_get_value(TALLOC_CTX *ctx, struct hive_key *key,
501                              int idx, const char **name,
502                              uint32_t *data_type, DATA_BLOB *data)
503 {
504         const struct regf_key_data *private_data =
505                         (const struct regf_key_data *)key;
506         struct vk_block *vk;
507         struct regf_data *regf = private_data->hive;
508         uint32_t vk_offset;
509         DATA_BLOB tmp;
510
511         if (idx >= private_data->nk->num_values)
512                 return WERR_NO_MORE_ITEMS;
513
514         tmp = hbin_get(regf, private_data->nk->values_offset);
515         if (!tmp.data) {
516                 DEBUG(0, ("Unable to find value list\n"));
517                 return WERR_GENERAL_FAILURE;
518         }
519
520         if (tmp.length < private_data->nk->num_values * 4) {
521                 DEBUG(1, ("Value counts mismatch\n"));
522         }
523
524         vk_offset = IVAL(tmp.data, idx * 4);
525
526         vk = talloc(NULL, struct vk_block);
527         W_ERROR_HAVE_NO_MEMORY(vk);
528
529         if (!hbin_get_tdr(regf, vk_offset, vk,
530                           (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
531                 DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
532                 talloc_free(vk);
533                 return WERR_GENERAL_FAILURE;
534         }
535
536         /* FIXME: name character set ?*/
537         if (name != NULL)
538                 *name = talloc_strndup(ctx, vk->data_name, vk->name_length);
539
540         if (data_type != NULL)
541                 *data_type = vk->data_type;
542
543         if (vk->data_length & 0x80000000) {
544                 vk->data_length &=~0x80000000;
545                 data->data = (uint8_t *)&vk->data_offset;
546                 data->length = vk->data_length;
547         } else {
548                 *data = hbin_get(regf, vk->data_offset);
549         }
550
551         if (data->length < vk->data_length) {
552                 DEBUG(1, ("Read data less than indicated data length!\n"));
553         }
554
555         talloc_free(vk);
556
557         return WERR_OK;
558 }
559
560 static WERROR regf_get_value_by_name(TALLOC_CTX *mem_ctx,
561                                      struct hive_key *key, const char *name,
562                                      uint32_t *type, DATA_BLOB *data)
563 {
564         int i;
565         const char *vname;
566         WERROR error;
567
568         /* FIXME: Do binary search? Is this list sorted at all? */
569
570         for (i = 0; W_ERROR_IS_OK(error = regf_get_value(mem_ctx, key, i,
571                                                          &vname, type, data));
572                                                          i++) {
573                 if (!strcmp(vname, name))
574                         return WERR_OK;
575         }
576
577         if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
578                 return WERR_NOT_FOUND;
579
580         return error;
581 }
582
583
584 static WERROR regf_get_subkey_by_index(TALLOC_CTX *ctx,
585                                        const struct hive_key *key,
586                                        uint32_t idx, const char **name,
587                                        const char **classname,
588                                        NTTIME *last_mod_time)
589 {
590         DATA_BLOB data;
591         struct regf_key_data *ret;
592         const struct regf_key_data *private_data = (const struct regf_key_data *)key;
593         struct nk_block *nk = private_data->nk;
594         uint32_t key_off=0;
595
596         if (idx >= nk->num_subkeys)
597                 return WERR_NO_MORE_ITEMS;
598
599         data = hbin_get(private_data->hive, nk->subkeys_offset);
600         if (!data.data) {
601                 DEBUG(0, ("Unable to find subkey list\n"));
602                 return WERR_GENERAL_FAILURE;
603         }
604
605         if (!strncmp((char *)data.data, "li", 2)) {
606                 struct li_block li;
607                 struct tdr_pull *pull = tdr_pull_init(private_data->hive, private_data->hive->iconv_convenience);
608
609                 DEBUG(10, ("Subkeys in LI list\n"));
610                 pull->data = data;
611
612                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) {
613                         DEBUG(0, ("Error parsing LI list\n"));
614                         talloc_free(pull);
615                         return WERR_GENERAL_FAILURE;
616                 }
617                 talloc_free(pull);
618                 SMB_ASSERT(!strncmp(li.header, "li", 2));
619
620                 if (li.key_count != nk->num_subkeys) {
621                         DEBUG(0, ("Subkey counts don't match\n"));
622                         return WERR_GENERAL_FAILURE;
623                 }
624                 key_off = li.nk_offset[idx];
625
626         } else if (!strncmp((char *)data.data, "lf", 2)) {
627                 struct lf_block lf;
628                 struct tdr_pull *pull = tdr_pull_init(private_data->hive, private_data->hive->iconv_convenience);
629
630                 DEBUG(10, ("Subkeys in LF list\n"));
631                 pull->data = data;
632
633                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) {
634                         DEBUG(0, ("Error parsing LF list\n"));
635                         talloc_free(pull);
636                         return WERR_GENERAL_FAILURE;
637                 }
638                 talloc_free(pull);
639                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
640
641                 if (lf.key_count != nk->num_subkeys) {
642                         DEBUG(0, ("Subkey counts don't match\n"));
643                         return WERR_GENERAL_FAILURE;
644                 }
645
646                 key_off = lf.hr[idx].nk_offset;
647         } else if (!strncmp((char *)data.data, "lh", 2)) {
648                 struct lh_block lh;
649                 struct tdr_pull *pull = tdr_pull_init(private_data->hive, private_data->hive->iconv_convenience);
650
651                 DEBUG(10, ("Subkeys in LH list\n"));
652                 pull->data = data;
653
654                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) {
655                         DEBUG(0, ("Error parsing LH list\n"));
656                         talloc_free(pull);
657                         return WERR_GENERAL_FAILURE;
658                 }
659                 talloc_free(pull);
660                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
661
662                 if (lh.key_count != nk->num_subkeys) {
663                         DEBUG(0, ("Subkey counts don't match\n"));
664                         return WERR_GENERAL_FAILURE;
665                 }
666                 key_off = lh.hr[idx].nk_offset;
667         } else if (!strncmp((char *)data.data, "ri", 2)) {
668                 struct ri_block ri;
669                 struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
670                 uint16_t i;
671                 uint16_t sublist_count = 0;
672
673                 DEBUG(10, ("Subkeys in RI list\n"));
674                 pull->data = data;
675
676                 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) {
677                         DEBUG(0, ("Error parsing RI list\n"));
678                         talloc_free(pull);
679                         return WERR_GENERAL_FAILURE;
680                 }
681                 SMB_ASSERT(!strncmp(ri.header, "ri", 2));
682
683                 for (i = 0; i < ri.key_count; i++) {
684                         DATA_BLOB list_data;
685
686                         /* Get sublist data blob */
687                         list_data = hbin_get(private_data->hive, ri.offset[i]);
688                         if (!list_data.data) {
689                                 DEBUG(0, ("Error getting RI list."));
690                                 talloc_free(pull);
691                                 return WERR_GENERAL_FAILURE;
692                         }
693
694                         pull->data = list_data;
695
696                         if (!strncmp((char *)list_data.data, "li", 2)) {
697                                 struct li_block li;
698
699                                 DEBUG(10, ("Subkeys in RI->LI list\n"));
700
701                                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull,
702                                                                        nk,
703                                                                        &li))) {
704                                         DEBUG(0, ("Error parsing LI list from RI\n"));
705                                         talloc_free(pull);
706                                         return WERR_GENERAL_FAILURE;
707                                 }
708                                 SMB_ASSERT(!strncmp(li.header, "li", 2));
709
710                                 /* Advance to next sublist if necessary */
711                                 if (idx >= sublist_count + li.key_count) {
712                                         sublist_count += li.key_count;
713                                         continue;
714                                 }
715                                 key_off = li.nk_offset[idx - sublist_count];
716                                 sublist_count += li.key_count;
717                                 break;
718                         } else if (!strncmp((char *)list_data.data, "lh", 2)) {
719                                 struct lh_block lh;
720
721                                 DEBUG(10, ("Subkeys in RI->LH list\n"));
722
723                                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull,
724                                                                        nk,
725                                                                        &lh))) {
726                                         DEBUG(0, ("Error parsing LH list from RI\n"));
727                                         talloc_free(pull);
728                                         return WERR_GENERAL_FAILURE;
729                                 }
730                                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
731
732                                 /* Advance to next sublist if necessary */
733                                 if (idx >= sublist_count + lh.key_count) {
734                                         sublist_count += lh.key_count;
735                                         continue;
736                                 }
737                                 key_off = lh.hr[idx - sublist_count].nk_offset;
738                                 sublist_count += lh.key_count;
739                                 break;
740                         } else {
741                                 DEBUG(0,("Unknown sublist in ri block\n"));
742                                 talloc_free(pull);
743
744                                 return WERR_GENERAL_FAILURE;
745                         }
746
747                 }
748                 talloc_free(pull);
749
750
751                 if (idx > sublist_count) {
752                         return WERR_NO_MORE_ITEMS;
753                 }
754
755         } else {
756                 DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n",
757                                   nk->subkeys_offset, data.data[0], data.data[1]));
758                 return WERR_GENERAL_FAILURE;
759         }
760
761         ret = regf_get_key (ctx, private_data->hive, key_off);
762
763         if (classname != NULL) {
764                 if (ret->nk->clsname_offset != -1) {
765                         DATA_BLOB db = hbin_get(ret->hive,
766                                                 ret->nk->clsname_offset);
767                         *classname = talloc_strndup(ctx,
768                                                     (char*)db.data,
769                                                     ret->nk->clsname_length);
770                 } else
771                         *classname = NULL;
772         }
773
774         if (last_mod_time != NULL)
775                 *last_mod_time = ret->nk->last_change;
776
777         if (name != NULL)
778                 *name = talloc_steal(ctx, ret->nk->key_name);
779
780         talloc_free(ret);
781
782         return WERR_OK;
783 }
784
785 static WERROR regf_match_subkey_by_name(TALLOC_CTX *ctx,
786                                         const struct hive_key *key,
787                                         uint32_t offset,
788                                         const char *name, uint32_t *ret)
789 {
790         DATA_BLOB subkey_data;
791         struct nk_block subkey;
792         struct tdr_pull *pull;
793         const struct regf_key_data *private_data =
794                 (const struct regf_key_data *)key;
795
796         subkey_data = hbin_get(private_data->hive, offset);
797         if (!subkey_data.data) {
798                 DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
799                 return WERR_GENERAL_FAILURE;
800         }
801
802         pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
803
804         pull->data = subkey_data;
805
806         if (NT_STATUS_IS_ERR(tdr_pull_nk_block(pull, ctx, &subkey))) {
807                 DEBUG(0, ("Error parsing NK structure.\n"));
808                 talloc_free(pull);
809                 return WERR_GENERAL_FAILURE;
810         }
811         talloc_free(pull);
812
813         if (strncmp(subkey.header, "nk", 2)) {
814                 DEBUG(0, ("Not an NK structure.\n"));
815                 return WERR_GENERAL_FAILURE;
816         }
817
818         if (!strcasecmp(subkey.key_name, name)) {
819                 *ret = offset;
820         } else {
821                 *ret = 0;
822         }
823         return WERR_OK;
824 }
825
826 static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx,
827                                       const struct hive_key *key,
828                                       const char *name,
829                                       struct hive_key **ret)
830 {
831         DATA_BLOB data;
832         const struct regf_key_data *private_data =
833                 (const struct regf_key_data *)key;
834         struct nk_block *nk = private_data->nk;
835         uint32_t key_off = 0;
836
837         data = hbin_get(private_data->hive, nk->subkeys_offset);
838         if (!data.data) {
839                 DEBUG(0, ("Unable to find subkey list\n"));
840                 return WERR_GENERAL_FAILURE;
841         }
842
843         if (!strncmp((char *)data.data, "li", 2)) {
844                 struct li_block li;
845                 struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
846                 uint16_t i;
847
848                 DEBUG(10, ("Subkeys in LI list\n"));
849                 pull->data = data;
850
851                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) {
852                         DEBUG(0, ("Error parsing LI list\n"));
853                         talloc_free(pull);
854                         return WERR_GENERAL_FAILURE;
855                 }
856                 talloc_free(pull);
857                 SMB_ASSERT(!strncmp(li.header, "li", 2));
858
859                 if (li.key_count != nk->num_subkeys) {
860                         DEBUG(0, ("Subkey counts don't match\n"));
861                         return WERR_GENERAL_FAILURE;
862                 }
863
864                 for (i = 0; i < li.key_count; i++) {
865                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
866                                                                         li.nk_offset[i],
867                                                                         name,
868                                                                         &key_off));
869                         if (key_off != 0)
870                                 break;
871                 }
872                 if (key_off == 0)
873                         return WERR_NOT_FOUND;
874         } else if (!strncmp((char *)data.data, "lf", 2)) {
875                 struct lf_block lf;
876                 struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
877                 uint16_t i;
878
879                 DEBUG(10, ("Subkeys in LF list\n"));
880                 pull->data = data;
881
882                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) {
883                         DEBUG(0, ("Error parsing LF list\n"));
884                         talloc_free(pull);
885                         return WERR_GENERAL_FAILURE;
886                 }
887                 talloc_free(pull);
888                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
889
890                 if (lf.key_count != nk->num_subkeys) {
891                         DEBUG(0, ("Subkey counts don't match\n"));
892                         return WERR_GENERAL_FAILURE;
893                 }
894
895                 for (i = 0; i < lf.key_count; i++) {
896                         if (strncmp(lf.hr[i].hash, name, 4)) {
897                                 continue;
898                         }
899                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk,
900                                                                         key,
901                                                                         lf.hr[i].nk_offset,
902                                                                         name,
903                                                                         &key_off));
904                         if (key_off != 0)
905                                 break;
906                 }
907                 if (key_off == 0)
908                         return WERR_NOT_FOUND;
909         } else if (!strncmp((char *)data.data, "lh", 2)) {
910                 struct lh_block lh;
911                 struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
912                 uint16_t i;
913                 uint32_t hash;
914
915                 DEBUG(10, ("Subkeys in LH list\n"));
916                 pull->data = data;
917
918                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) {
919                         DEBUG(0, ("Error parsing LH list\n"));
920                         talloc_free(pull);
921                         return WERR_GENERAL_FAILURE;
922                 }
923                 talloc_free(pull);
924                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
925
926                 if (lh.key_count != nk->num_subkeys) {
927                         DEBUG(0, ("Subkey counts don't match\n"));
928                         return WERR_GENERAL_FAILURE;
929                 }
930
931                 hash = regf_create_lh_hash(name);
932                 for (i = 0; i < lh.key_count; i++) {
933                         if (lh.hr[i].base37 != hash) {
934                                 continue;
935                         }
936                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk,
937                                                                         key,
938                                                                         lh.hr[i].nk_offset,
939                                                                         name,
940                                                                         &key_off));
941                         if (key_off != 0)
942                                 break;
943                 }
944                 if (key_off == 0)
945                         return WERR_NOT_FOUND;
946         } else if (!strncmp((char *)data.data, "ri", 2)) {
947                 struct ri_block ri;
948                 struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
949                 uint16_t i, j;
950
951                 DEBUG(10, ("Subkeys in RI list\n"));
952                 pull->data = data;
953
954                 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) {
955                         DEBUG(0, ("Error parsing RI list\n"));
956                         talloc_free(pull);
957                         return WERR_GENERAL_FAILURE;
958                 }
959                 SMB_ASSERT(!strncmp(ri.header, "ri", 2));
960
961                 for (i = 0; i < ri.key_count; i++) {
962                         DATA_BLOB list_data;
963
964                         /* Get sublist data blob */
965                         list_data = hbin_get(private_data->hive, ri.offset[i]);
966                         if (list_data.data == NULL) {
967                                 DEBUG(0, ("Error getting RI list."));
968                                 talloc_free(pull);
969                                 return WERR_GENERAL_FAILURE;
970                         }
971
972                         pull->data = list_data;
973
974                         if (!strncmp((char *)list_data.data, "li", 2)) {
975                                 struct li_block li;
976
977                                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull,
978                                                                        nk,
979                                                                        &li))) {
980                                         DEBUG(0, ("Error parsing LI list from RI\n"));
981                                         talloc_free(pull);
982                                         return WERR_GENERAL_FAILURE;
983                                 }
984                                 SMB_ASSERT(!strncmp(li.header, "li", 2));
985
986                                 for (j = 0; j < li.key_count; j++) {
987                                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
988                                                                                         li.nk_offset[j],
989                                                                                         name,
990                                                                                         &key_off));
991                                         if (key_off)
992                                                 break;
993                                 }
994                         } else if (!strncmp((char *)list_data.data, "lh", 2)) {
995                                 struct lh_block lh;
996                                 uint32_t hash;
997
998                                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull,
999                                                                        nk,
1000                                                                        &lh))) {
1001                                         DEBUG(0, ("Error parsing LH list from RI\n"));
1002                                         talloc_free(pull);
1003                                         return WERR_GENERAL_FAILURE;
1004                                 }
1005                                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1006
1007                                 hash = regf_create_lh_hash(name);
1008                                 for (j = 0; j < lh.key_count; j++) {
1009                                         if (lh.hr[j].base37 != hash) {
1010                                                 continue;
1011                                         }
1012                                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
1013                                                                                         lh.hr[j].nk_offset,
1014                                                                                         name,
1015                                                                                         &key_off));
1016                                         if (key_off)
1017                                                 break;
1018                                 }
1019                         }
1020                         if (key_off)
1021                                 break;
1022                 }
1023                 talloc_free(pull);
1024                 if (!key_off)
1025                         return WERR_NOT_FOUND;
1026         } else {
1027                 DEBUG(0, ("Unknown subkey list type.\n"));
1028                 return WERR_GENERAL_FAILURE;
1029         }
1030
1031         *ret = (struct hive_key *)regf_get_key(ctx, private_data->hive,
1032                                                key_off);
1033         return WERR_OK;
1034 }
1035
1036 static WERROR regf_set_sec_desc(struct hive_key *key,
1037                                 const struct security_descriptor *sec_desc)
1038 {
1039         const struct regf_key_data *private_data =
1040                 (const struct regf_key_data *)key;
1041         struct sk_block cur_sk, sk, new_sk;
1042         struct regf_data *regf = private_data->hive;
1043         struct nk_block root;
1044         DATA_BLOB data;
1045         uint32_t sk_offset, cur_sk_offset;
1046         bool update_cur_sk = false;
1047
1048         /* Get the root nk */
1049         hbin_get_tdr(regf, regf->header->data_offset, regf,
1050                      (tdr_pull_fn_t) tdr_pull_nk_block, &root);
1051
1052         /* Push the security descriptor to a blob */
1053         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(&data, regf, NULL, 
1054                                                           sec_desc, (ndr_push_flags_fn_t)ndr_push_security_descriptor))) {
1055                 DEBUG(0, ("Unable to push security descriptor\n"));
1056                 return WERR_GENERAL_FAILURE;
1057         }
1058
1059         /* Get the current security descriptor for the key */
1060         if (!hbin_get_tdr(regf, private_data->nk->sk_offset, regf,
1061                           (tdr_pull_fn_t) tdr_pull_sk_block, &cur_sk)) {
1062                 DEBUG(0, ("Unable to find security descriptor for current key\n"));
1063                 return WERR_BADFILE;
1064         }
1065         /* If there's no change, change nothing. */
1066         if (memcmp(data.data, cur_sk.sec_desc,
1067                    MIN(data.length, cur_sk.rec_size)) == 0) {
1068                 return WERR_OK;
1069         }
1070
1071         /* Delete the current sk if only this key is using it */
1072         if (cur_sk.ref_cnt == 1) {
1073                 /* Get the previous security descriptor for the key */
1074                 if (!hbin_get_tdr(regf, cur_sk.prev_offset, regf,
1075                                   (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1076                         DEBUG(0, ("Unable to find prev security descriptor for current key\n"));
1077                         return WERR_BADFILE;
1078                 }
1079                 /* Change and store the previous security descriptor */
1080                 sk.next_offset = cur_sk.next_offset;
1081                 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block,
1082                                       cur_sk.prev_offset, &sk);
1083
1084                 /* Get the next security descriptor for the key */
1085                 if (!hbin_get_tdr(regf, cur_sk.next_offset, regf,
1086                                   (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1087                         DEBUG(0, ("Unable to find next security descriptor for current key\n"));
1088                         return WERR_BADFILE;
1089                 }
1090                 /* Change and store the next security descriptor */
1091                 sk.prev_offset = cur_sk.prev_offset;
1092                 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block,
1093                                       cur_sk.next_offset, &sk);
1094
1095                 hbin_free(regf, private_data->nk->sk_offset);
1096         } else {
1097                 /* This key will no longer be referring to this sk */
1098                 cur_sk.ref_cnt--;
1099                 update_cur_sk = true;
1100         }
1101
1102         sk_offset = root.sk_offset;
1103
1104         do {
1105                 cur_sk_offset = sk_offset;
1106                 if (!hbin_get_tdr(regf, sk_offset, regf,
1107                                   (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1108                         DEBUG(0, ("Unable to find security descriptor\n"));
1109                         return WERR_BADFILE;
1110                 }
1111                 if (memcmp(data.data, sk.sec_desc, MIN(data.length, sk.rec_size)) == 0) {
1112                         private_data->nk->sk_offset = sk_offset;
1113                         sk.ref_cnt++;
1114                         hbin_store_tdr_resize(regf,
1115                                               (tdr_push_fn_t) tdr_push_sk_block,
1116                                               sk_offset, &sk);
1117                         hbin_store_tdr_resize(regf,
1118                                               (tdr_push_fn_t) tdr_push_nk_block,
1119                                               private_data->offset,
1120                                               private_data->nk);
1121                         return WERR_OK;
1122                 }
1123                 sk_offset = sk.next_offset;
1124         } while (sk_offset != root.sk_offset);
1125
1126         ZERO_STRUCT(new_sk);
1127         new_sk.header = "sk";
1128         new_sk.prev_offset = cur_sk_offset;
1129         new_sk.next_offset = root.sk_offset;
1130         new_sk.ref_cnt = 1;
1131         new_sk.rec_size = data.length;
1132         new_sk.sec_desc = data.data;
1133
1134         sk_offset = hbin_store_tdr(regf,
1135                                    (tdr_push_fn_t) tdr_push_sk_block,
1136                                    &new_sk);
1137         if (sk_offset == -1) {
1138                 DEBUG(0, ("Error storing sk block\n"));
1139                 return WERR_GENERAL_FAILURE;
1140         }
1141         private_data->nk->sk_offset = sk_offset;
1142
1143         if (update_cur_sk) {
1144                 hbin_store_tdr_resize(regf,
1145                                       (tdr_push_fn_t) tdr_push_sk_block,
1146                                       private_data->nk->sk_offset, &cur_sk);
1147         }
1148
1149         /* Get the previous security descriptor for the key */
1150         if (!hbin_get_tdr(regf, new_sk.prev_offset, regf,
1151                           (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1152                 DEBUG(0, ("Unable to find security descriptor for previous key\n"));
1153                 return WERR_BADFILE;
1154         }
1155         /* Change and store the previous security descriptor */
1156         sk.next_offset = sk_offset;
1157         hbin_store_tdr_resize(regf,
1158                               (tdr_push_fn_t) tdr_push_sk_block,
1159                               cur_sk.prev_offset, &sk);
1160
1161         /* Get the next security descriptor for the key (always root, as we append) */
1162         if (!hbin_get_tdr(regf, new_sk.next_offset, regf,
1163                           (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1164                 DEBUG(0, ("Unable to find security descriptor for current key\n"));
1165                 return WERR_BADFILE;
1166         }
1167         /* Change and store the next security descriptor (always root, as we append) */
1168         sk.prev_offset = sk_offset;
1169         hbin_store_tdr_resize(regf,
1170                               (tdr_push_fn_t) tdr_push_sk_block,
1171                               root.sk_offset, &sk);
1172
1173
1174         /* Store the nk. */
1175         hbin_store_tdr_resize(regf,
1176                               (tdr_push_fn_t) tdr_push_sk_block,
1177                               private_data->offset, private_data->nk);
1178         return WERR_OK;
1179 }
1180
1181 static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct hive_key *key,
1182                                 struct security_descriptor **sd)
1183 {
1184         const struct regf_key_data *private_data =
1185                 (const struct regf_key_data *)key;
1186         struct sk_block sk;
1187         struct regf_data *regf = private_data->hive;
1188         DATA_BLOB data;
1189
1190         if (!hbin_get_tdr(regf, private_data->nk->sk_offset, ctx,
1191                           (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1192                 DEBUG(0, ("Unable to find security descriptor\n"));
1193                 return WERR_GENERAL_FAILURE;
1194         }
1195
1196         if (strcmp(sk.header, "sk") != 0) {
1197                 DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
1198                 return WERR_GENERAL_FAILURE;
1199         }
1200
1201         *sd = talloc(ctx, struct security_descriptor);
1202         W_ERROR_HAVE_NO_MEMORY(*sd);
1203
1204         data.data = sk.sec_desc;
1205         data.length = sk.rec_size;
1206         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&data, ctx, NULL, *sd,
1207                                                   (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
1208                 DEBUG(0, ("Error parsing security descriptor\n"));
1209                 return WERR_GENERAL_FAILURE;
1210         }
1211
1212         return WERR_OK;
1213 }
1214
1215 static WERROR regf_sl_add_entry(struct regf_data *regf, uint32_t list_offset,
1216                                 const char *name,
1217                                 uint32_t key_offset, uint32_t *ret)
1218 {
1219         DATA_BLOB data;
1220
1221         /* Create a new key if necessary */
1222         if (list_offset == -1) {
1223                 if (regf->header->version.major != 1) {
1224                         DEBUG(0, ("Can't store keys in unknown registry format\n"));
1225                         return WERR_NOT_SUPPORTED;
1226                 }
1227                 if (regf->header->version.minor < 3) {
1228                         /* Store LI */
1229                         struct li_block li;
1230                         ZERO_STRUCT(li);
1231                         li.header = "li";
1232                         li.key_count = 1;
1233
1234                         li.nk_offset = talloc_array(regf, uint32_t, 1);
1235                         W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
1236                         li.nk_offset[0] = key_offset;
1237
1238                         *ret = hbin_store_tdr(regf,
1239                                               (tdr_push_fn_t) tdr_push_li_block,
1240                                               &li);
1241
1242                         talloc_free(li.nk_offset);
1243                 } else if (regf->header->version.minor == 3 ||
1244                            regf->header->version.minor == 4) {
1245                         /* Store LF */
1246                         struct lf_block lf;
1247                         ZERO_STRUCT(lf);
1248                         lf.header = "lf";
1249                         lf.key_count = 1;
1250
1251                         lf.hr = talloc_array(regf, struct hash_record, 1);
1252                         W_ERROR_HAVE_NO_MEMORY(lf.hr);
1253                         lf.hr[0].nk_offset = key_offset;
1254                         lf.hr[0].hash = talloc_strndup(lf.hr, name, 4);
1255                         W_ERROR_HAVE_NO_MEMORY(lf.hr[0].hash);
1256
1257                         *ret = hbin_store_tdr(regf,
1258                                               (tdr_push_fn_t) tdr_push_lf_block,
1259                                               &lf);
1260
1261                         talloc_free(lf.hr);
1262                 } else if (regf->header->version.minor == 5) {
1263                         /* Store LH */
1264                         struct lh_block lh;
1265                         ZERO_STRUCT(lh);
1266                         lh.header = "lh";
1267                         lh.key_count = 1;
1268
1269                         lh.hr = talloc_array(regf, struct lh_hash, 1);
1270                         W_ERROR_HAVE_NO_MEMORY(lh.hr);
1271                         lh.hr[0].nk_offset = key_offset;
1272                         lh.hr[0].base37 = regf_create_lh_hash(name);
1273
1274                         *ret = hbin_store_tdr(regf,
1275                                               (tdr_push_fn_t) tdr_push_lh_block,
1276                                               &lh);
1277
1278                         talloc_free(lh.hr);
1279                 }
1280                 return WERR_OK;
1281         }
1282
1283         data = hbin_get(regf, list_offset);
1284         if (!data.data) {
1285                 DEBUG(0, ("Unable to find subkey list\n"));
1286                 return WERR_BADFILE;
1287         }
1288
1289         if (!strncmp((char *)data.data, "li", 2)) {
1290                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1291                 struct li_block li;
1292
1293                 pull->data = data;
1294
1295                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) {
1296                         DEBUG(0, ("Error parsing LI list\n"));
1297                         talloc_free(pull);
1298                         return WERR_BADFILE;
1299                 }
1300                 talloc_free(pull);
1301
1302                 if (strncmp(li.header, "li", 2) != 0) {
1303                         abort();
1304                         DEBUG(0, ("LI header corrupt\n"));
1305                         return WERR_BADFILE;
1306                 }
1307
1308                 li.nk_offset = talloc_realloc(regf, li.nk_offset,
1309                                               uint32_t, li.key_count+1);
1310                 W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
1311                 li.nk_offset[li.key_count] = key_offset;
1312                 li.key_count++;
1313                 *ret = hbin_store_tdr_resize(regf,
1314                                              (tdr_push_fn_t)tdr_push_li_block,
1315                                              list_offset, &li);
1316
1317                 talloc_free(li.nk_offset);
1318         } else if (!strncmp((char *)data.data, "lf", 2)) {
1319                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1320                 struct lf_block lf;
1321
1322                 pull->data = data;
1323
1324                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) {
1325                         DEBUG(0, ("Error parsing LF list\n"));
1326                         talloc_free(pull);
1327                         return WERR_BADFILE;
1328                 }
1329                 talloc_free(pull);
1330                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
1331
1332                 lf.hr = talloc_realloc(regf, lf.hr, struct hash_record,
1333                                        lf.key_count+1);
1334                 W_ERROR_HAVE_NO_MEMORY(lf.hr);
1335                 lf.hr[lf.key_count].nk_offset = key_offset;
1336                 lf.hr[lf.key_count].hash = talloc_strndup(lf.hr, name, 4);
1337                 W_ERROR_HAVE_NO_MEMORY(lf.hr[lf.key_count].hash);
1338                 lf.key_count++;
1339                 *ret = hbin_store_tdr_resize(regf,
1340                                              (tdr_push_fn_t)tdr_push_lf_block,
1341                                              list_offset, &lf);
1342
1343                 talloc_free(lf.hr);
1344         } else if (!strncmp((char *)data.data, "lh", 2)) {
1345                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1346                 struct lh_block lh;
1347
1348                 pull->data = data;
1349
1350                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) {
1351                         DEBUG(0, ("Error parsing LH list\n"));
1352                         talloc_free(pull);
1353                         return WERR_BADFILE;
1354                 }
1355                 talloc_free(pull);
1356                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1357
1358                 lh.hr = talloc_realloc(regf, lh.hr, struct lh_hash,
1359                                        lh.key_count+1);
1360                 W_ERROR_HAVE_NO_MEMORY(lh.hr);
1361                 lh.hr[lh.key_count].nk_offset = key_offset;
1362                 lh.hr[lh.key_count].base37 = regf_create_lh_hash(name);
1363                 lh.key_count++;
1364                 *ret = hbin_store_tdr_resize(regf,
1365                                              (tdr_push_fn_t)tdr_push_lh_block,
1366                                              list_offset, &lh);
1367
1368                 talloc_free(lh.hr);
1369         } else if (!strncmp((char *)data.data, "ri", 2)) {
1370                 /* FIXME */
1371                 DEBUG(0, ("Adding to 'ri' subkey list is not supported yet.\n"));
1372                 return WERR_NOT_SUPPORTED;
1373         } else {
1374                 DEBUG(0, ("Cannot add to unknown subkey list\n"));
1375                 return WERR_BADFILE;
1376         }
1377
1378         return WERR_OK;
1379 }
1380
1381 static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset,
1382                                 uint32_t key_offset, uint32_t *ret)
1383 {
1384         DATA_BLOB data;
1385
1386         data = hbin_get(regf, list_offset);
1387         if (!data.data) {
1388                 DEBUG(0, ("Unable to find subkey list\n"));
1389                 return WERR_BADFILE;
1390         }
1391
1392         if (strncmp((char *)data.data, "li", 2) == 0) {
1393                 struct li_block li;
1394                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1395                 uint16_t i;
1396                 bool found_offset = false;
1397
1398                 DEBUG(10, ("Subkeys in LI list\n"));
1399
1400                 pull->data = data;
1401
1402                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) {
1403                         DEBUG(0, ("Error parsing LI list\n"));
1404                         talloc_free(pull);
1405                         return WERR_BADFILE;
1406                 }
1407                 talloc_free(pull);
1408
1409                 SMB_ASSERT(!strncmp(li.header, "li", 2));
1410
1411                 for (i = 0; i < li.key_count; i++) {
1412                         if (found_offset) {
1413                                 li.nk_offset[i-1] = li.nk_offset[i];
1414                         }
1415                         if (li.nk_offset[i] == key_offset) {
1416                                 found_offset = true;
1417                                 continue;
1418                         }
1419                 }
1420                 if (!found_offset) {
1421                         DEBUG(2, ("Subkey not found\n"));
1422                         return WERR_NOT_FOUND;
1423                 }
1424                 li.key_count--;
1425
1426                 /* If the there are no entries left, free the subkey list */
1427                 if (li.key_count == 0) {
1428                         hbin_free(regf, list_offset);
1429                         *ret = -1;
1430                 }
1431
1432                 /* Store li block */
1433                 *ret = hbin_store_tdr_resize(regf,
1434                                              (tdr_push_fn_t) tdr_push_li_block,
1435                                              list_offset, &li);
1436         } else if (strncmp((char *)data.data, "lf", 2) == 0) {
1437                 struct lf_block lf;
1438                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1439                 uint16_t i;
1440                 bool found_offset = false;
1441
1442                 DEBUG(10, ("Subkeys in LF list\n"));
1443
1444                 pull->data = data;
1445
1446                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) {
1447                         DEBUG(0, ("Error parsing LF list\n"));
1448                         talloc_free(pull);
1449                         return WERR_BADFILE;
1450                 }
1451                 talloc_free(pull);
1452
1453                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
1454
1455                 for (i = 0; i < lf.key_count; i++) {
1456                         if (found_offset) {
1457                                 lf.hr[i-1] = lf.hr[i];
1458                                 continue;
1459                         }
1460                         if (lf.hr[i].nk_offset == key_offset) {
1461                                 found_offset = 1;
1462                                 continue;
1463                         }
1464                 }
1465                 if (!found_offset) {
1466                         DEBUG(2, ("Subkey not found\n"));
1467                         return WERR_NOT_FOUND;
1468                 }
1469                 lf.key_count--;
1470
1471                 /* If the there are no entries left, free the subkey list */
1472                 if (lf.key_count == 0) {
1473                         hbin_free(regf, list_offset);
1474                         *ret = -1;
1475                         return WERR_OK;
1476                 }
1477
1478                 /* Store lf block */
1479                 *ret = hbin_store_tdr_resize(regf,
1480                                              (tdr_push_fn_t) tdr_push_lf_block,
1481                                              list_offset, &lf);
1482         } else if (strncmp((char *)data.data, "lh", 2) == 0) {
1483                 struct lh_block lh;
1484                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1485                 uint16_t i;
1486                 bool found_offset = false;
1487
1488                 DEBUG(10, ("Subkeys in LH list\n"));
1489
1490                 pull->data = data;
1491
1492                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) {
1493                         DEBUG(0, ("Error parsing LF list\n"));
1494                         talloc_free(pull);
1495                         return WERR_BADFILE;
1496                 }
1497                 talloc_free(pull);
1498
1499                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1500
1501                 for (i = 0; i < lh.key_count; i++) {
1502                         if (found_offset) {
1503                                 lh.hr[i-1] = lh.hr[i];
1504                                 continue;
1505                         }
1506                         if (lh.hr[i].nk_offset == key_offset) {
1507                                 found_offset = 1;
1508                                 continue;
1509                         }
1510                 }
1511                 if (!found_offset) {
1512                         DEBUG(0, ("Subkey not found\n"));
1513                         return WERR_NOT_FOUND;
1514                 }
1515                 lh.key_count--;
1516
1517                 /* If the there are no entries left, free the subkey list */
1518                 if (lh.key_count == 0) {
1519                         hbin_free(regf, list_offset);
1520                         *ret = -1;
1521                         return WERR_OK;
1522                 }
1523
1524                 /* Store lh block */
1525                 *ret = hbin_store_tdr_resize(regf,
1526                                              (tdr_push_fn_t) tdr_push_lh_block,
1527                                              list_offset, &lh);
1528         } else if (strncmp((char *)data.data, "ri", 2) == 0) {
1529                 /* FIXME */
1530                 DEBUG(0, ("Sorry, deletion from ri block is not supported yet.\n"));
1531                 return WERR_NOT_SUPPORTED;
1532         } else {
1533                 DEBUG (0, ("Unknown header found in subkey list.\n"));
1534                 return WERR_BADFILE;
1535         }
1536         return WERR_OK;
1537 }
1538
1539 static WERROR regf_del_value (struct hive_key *key, const char *name)
1540 {
1541         struct regf_key_data *private_data = (struct regf_key_data *)key;
1542         struct regf_data *regf = private_data->hive;
1543         struct nk_block *nk = private_data->nk;
1544         struct vk_block vk;
1545         uint32_t vk_offset;
1546         bool found_offset = false;
1547         DATA_BLOB values;
1548         uint32_t i;
1549
1550         if (nk->values_offset == -1) {
1551                 return WERR_NOT_FOUND;
1552         }
1553
1554         values = hbin_get(regf, nk->values_offset);
1555
1556         for (i = 0; i < nk->num_values; i++) {
1557                 if (found_offset) {
1558                         ((uint32_t *)values.data)[i-1] = ((uint32_t *) values.data)[i];
1559                 } else {
1560                         vk_offset = IVAL(values.data, i * 4);
1561                         if (!hbin_get_tdr(regf, vk_offset, private_data,
1562                                           (tdr_pull_fn_t)tdr_pull_vk_block,
1563                                           &vk)) {
1564                                 DEBUG(0, ("Unable to get VK block at %d\n",
1565                                         vk_offset));
1566                                 return WERR_BADFILE;
1567                         }
1568                         if (strcmp(vk.data_name, name) == 0) {
1569                                 hbin_free(regf, vk_offset);
1570                                 found_offset = true;
1571                         }
1572                 }
1573         }
1574         if (!found_offset) {
1575                 return WERR_NOT_FOUND;
1576         } else {
1577                 nk->num_values--;
1578                 values.length = (nk->num_values)*4;
1579         }
1580
1581         /* Store values list and nk */
1582         if (nk->num_values == 0) {
1583                 hbin_free(regf, nk->values_offset);
1584                 nk->values_offset = -1;
1585         } else {
1586                 nk->values_offset = hbin_store_resize(regf,
1587                                                       nk->values_offset,
1588                                                       values);
1589         }
1590         hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
1591                               private_data->offset, nk);
1592
1593         return regf_save_hbin(private_data->hive);
1594 }
1595
1596
1597 static WERROR regf_del_key(const struct hive_key *parent, const char *name)
1598 {
1599         const struct regf_key_data *private_data =
1600                 (const struct regf_key_data *)parent;
1601         struct regf_key_data *key;
1602         struct nk_block *parent_nk;
1603         WERROR error;
1604
1605         SMB_ASSERT(private_data);
1606
1607         parent_nk = private_data->nk;
1608
1609         if (parent_nk->subkeys_offset == -1) {
1610                 DEBUG(4, ("Subkey list is empty, this key cannot contain subkeys.\n"));
1611                 return WERR_NOT_FOUND;
1612         }
1613
1614         /* Find the key */
1615         if (!W_ERROR_IS_OK(regf_get_subkey_by_name(parent_nk, parent, name,
1616                                                    (struct hive_key **)&key))) {
1617                 DEBUG(2, ("Key '%s' not found\n", name));
1618                 return WERR_NOT_FOUND;
1619         }
1620
1621         if (key->nk->subkeys_offset != -1 ||
1622                 key->nk->values_offset != -1) {
1623                 DEBUG(0, ("Key '%s' is not empty.\n", name));
1624                 return WERR_FILE_EXISTS;
1625         }
1626
1627         /* Delete it from the subkey list. */
1628         error = regf_sl_del_entry(private_data->hive, parent_nk->subkeys_offset,
1629                                   key->offset, &parent_nk->subkeys_offset);
1630         if (!W_ERROR_IS_OK(error)) {
1631                 DEBUG(0, ("Can't store new subkey list for parent key. Won't delete.\n"));
1632                 return error;
1633         }
1634
1635         /* Re-store parent key */
1636         parent_nk->num_subkeys--;
1637         hbin_store_tdr_resize(private_data->hive,
1638                               (tdr_push_fn_t) tdr_push_nk_block,
1639                               private_data->offset, parent_nk);
1640
1641         if (key->nk->clsname_offset != -1) {
1642                 hbin_free(private_data->hive, key->nk->clsname_offset);
1643         }
1644         hbin_free(private_data->hive, key->offset);
1645
1646         return regf_save_hbin(private_data->hive);
1647 }
1648
1649 static WERROR regf_add_key(TALLOC_CTX *ctx, const struct hive_key *parent,
1650                            const char *name, const char *classname,
1651                            struct security_descriptor *sec_desc,
1652                            struct hive_key **ret)
1653 {
1654         const struct regf_key_data *private_data =
1655                 (const struct regf_key_data *)parent;
1656         struct nk_block *parent_nk = private_data->nk, nk;
1657         struct nk_block *root;
1658         struct regf_data *regf = private_data->hive;
1659         uint32_t offset;
1660         WERROR error;
1661
1662         nk.header = "nk";
1663         nk.type = REG_SUB_KEY;
1664         unix_to_nt_time(&nk.last_change, time(NULL));
1665         nk.uk1 = 0;
1666         nk.parent_offset = private_data->offset;
1667         nk.num_subkeys = 0;
1668         nk.uk2 = 0;
1669         nk.subkeys_offset = -1;
1670         nk.unknown_offset = -1;
1671         nk.num_values = 0;
1672         nk.values_offset = -1;
1673         memset(nk.unk3, 0, 5);
1674         nk.clsname_offset = -1; /* FIXME: fill in */
1675         nk.clsname_length = 0;
1676         nk.key_name = name;
1677
1678         /* Get the security descriptor of the root key */
1679         root = talloc_zero(ctx, struct nk_block);
1680         W_ERROR_HAVE_NO_MEMORY(root);
1681
1682         if (!hbin_get_tdr(regf, regf->header->data_offset, root,
1683                           (tdr_pull_fn_t)tdr_pull_nk_block, root)) {
1684                 DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
1685                 return WERR_GENERAL_FAILURE;
1686         }
1687         nk.sk_offset = root->sk_offset;
1688         talloc_free(root);
1689
1690         /* Store the new nk key */
1691         offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
1692
1693         error = regf_sl_add_entry(regf, parent_nk->subkeys_offset, name, offset,
1694                                   &parent_nk->subkeys_offset);
1695         if (!W_ERROR_IS_OK(error)) {
1696                 hbin_free(regf, offset);
1697                 return error;
1698         }
1699
1700         parent_nk->num_subkeys++;
1701
1702         /* Since the subkey offset of the parent can change, store it again */
1703         hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
1704                                                   nk.parent_offset, parent_nk);
1705
1706         *ret = (struct hive_key *)regf_get_key(ctx, regf, offset);
1707
1708         return regf_save_hbin(private_data->hive);
1709 }
1710
1711 static WERROR regf_set_value(struct hive_key *key, const char *name,
1712                              uint32_t type, const DATA_BLOB data)
1713 {
1714         struct regf_key_data *private_data = (struct regf_key_data *)key;
1715         struct regf_data *regf = private_data->hive;
1716         struct nk_block *nk = private_data->nk;
1717         struct vk_block vk;
1718         uint32_t i;
1719         uint32_t tmp_vk_offset, vk_offset, old_vk_offset = -1;
1720         DATA_BLOB values;
1721
1722         ZERO_STRUCT(vk);
1723
1724         /* find the value offset, if it exists */
1725         if (nk->values_offset != -1) {
1726                 values = hbin_get(regf, nk->values_offset);
1727
1728                 for (i = 0; i < nk->num_values; i++) {
1729                         tmp_vk_offset = IVAL(values.data, i * 4);
1730                         if (!hbin_get_tdr(regf, tmp_vk_offset, private_data,
1731                                           (tdr_pull_fn_t)tdr_pull_vk_block,
1732                                           &vk)) {
1733                                 DEBUG(0, ("Unable to get VK block at %d\n",
1734                                         tmp_vk_offset));
1735                                 return WERR_GENERAL_FAILURE;
1736                         }
1737                         if (strcmp(vk.data_name, name) == 0) {
1738                                 old_vk_offset = tmp_vk_offset;
1739                                 break;
1740                         }
1741                 }
1742                 /* Free data, if any */
1743                 if (!(vk.data_length & 0x80000000)) {
1744                         hbin_free(regf, vk.data_offset);
1745                 }
1746         }
1747         if (old_vk_offset == -1) {
1748                 vk.header = "vk";
1749                 vk.name_length = strlen(name);
1750                 if (name != NULL && name[0] != 0) {
1751                         vk.flag = 1;
1752                         vk.data_name = name;
1753                 } else {
1754                         vk.data_name = NULL;
1755                         vk.flag = 0;
1756                 }
1757         }
1758         /* Set the type and data */
1759         vk.data_length = data.length;
1760         vk.data_type = type;
1761         if (type == REG_DWORD) {
1762                 vk.data_length |= 0x80000000;
1763                 vk.data_offset = *(uint32_t *)data.data;
1764         } else {
1765                 /* Store data somewhere */
1766                 vk.data_offset = hbin_store(regf, data);
1767         }
1768         if (old_vk_offset == -1) {
1769                 /* Store new vk */
1770                 vk_offset = hbin_store_tdr(regf,
1771                                            (tdr_push_fn_t) tdr_push_vk_block,
1772                                            &vk);
1773         } else {
1774                 /* Store vk at offset */
1775                 vk_offset = hbin_store_tdr_resize(regf,
1776                                                   (tdr_push_fn_t) tdr_push_vk_block,
1777                                                   old_vk_offset ,&vk);
1778         }
1779
1780         /* Re-allocate the value list */
1781         if (nk->values_offset == -1) {
1782                 nk->values_offset = hbin_store_tdr(regf,
1783                                                    (tdr_push_fn_t) tdr_push_uint32,
1784                                                    &vk_offset);
1785                 nk->num_values = 1;
1786         } else {
1787
1788                 /* Change if we're changing, otherwise we're adding the value */
1789                 if (old_vk_offset != -1) {
1790                         /* Find and overwrite the offset. */
1791                         for (i = 0; i < nk->num_values; i++) {
1792                                 if (IVAL(values.data, i * 4) == old_vk_offset) {
1793                                         SIVAL(values.data, i * 4, vk_offset);
1794                                         break;
1795                                 }
1796                         }
1797                 } else {
1798                         /* Create a new value list */
1799                         DATA_BLOB value_list;
1800
1801                         value_list.length = (nk->num_values+1)*4;
1802                         value_list.data = (uint8_t *)talloc_array(private_data,
1803                                                                   uint32_t,
1804                                                                   nk->num_values+1);
1805                         W_ERROR_HAVE_NO_MEMORY(value_list.data);
1806                         memcpy(value_list.data, values.data, nk->num_values * 4);
1807
1808                         SIVAL(value_list.data, nk->num_values * 4, vk_offset);
1809                         nk->num_values++;
1810                         nk->values_offset = hbin_store_resize(regf,
1811                                                               nk->values_offset,
1812                                                               value_list);
1813                 }
1814
1815         }
1816         hbin_store_tdr_resize(regf,
1817                               (tdr_push_fn_t) tdr_push_nk_block,
1818                               private_data->offset, nk);
1819         return regf_save_hbin(private_data->hive);
1820 }
1821
1822 static WERROR regf_save_hbin(struct regf_data *regf)
1823 {
1824         struct tdr_push *push = tdr_push_init(regf, regf->iconv_convenience);
1825         int i;
1826
1827         W_ERROR_HAVE_NO_MEMORY(push);
1828
1829         if (lseek(regf->fd, 0, SEEK_SET) == -1) {
1830                 DEBUG(0, ("Error lseeking in regf file\n"));
1831                 return WERR_GENERAL_FAILURE;
1832         }
1833
1834         /* Recompute checksum */
1835         if (NT_STATUS_IS_ERR(tdr_push_regf_hdr(push, regf->header))) {
1836                 DEBUG(0, ("Failed to push regf header\n"));
1837                 return WERR_GENERAL_FAILURE;
1838         }
1839         regf->header->chksum = regf_hdr_checksum(push->data.data);
1840         talloc_free(push);
1841
1842         if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, regf->iconv_convenience,
1843                                             (tdr_push_fn_t)tdr_push_regf_hdr,
1844                                             regf->header))) {
1845                 DEBUG(0, ("Error writing registry file header\n"));
1846                 return WERR_GENERAL_FAILURE;
1847         }
1848
1849         if (lseek(regf->fd, 0x1000, SEEK_SET) == -1) {
1850                 DEBUG(0, ("Error lseeking to 0x1000 in regf file\n"));
1851                 return WERR_GENERAL_FAILURE;
1852         }
1853
1854         for (i = 0; regf->hbins[i]; i++) {
1855                 if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, regf->iconv_convenience,
1856                                                     (tdr_push_fn_t)tdr_push_hbin_block,
1857                                                     regf->hbins[i]))) {
1858                         DEBUG(0, ("Error writing HBIN block\n"));
1859                         return WERR_GENERAL_FAILURE;
1860                 }
1861         }
1862
1863         return WERR_OK;
1864 }
1865
1866 WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx, const char *location,
1867                             int minor_version, struct hive_key **key)
1868 {
1869         struct regf_data *regf;
1870         struct regf_hdr *regf_hdr;
1871         int i;
1872         struct nk_block nk;
1873         WERROR error;
1874
1875         regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
1876
1877         regf->iconv_convenience = lp_iconv_convenience(global_loadparm);
1878
1879         W_ERROR_HAVE_NO_MEMORY(regf);
1880
1881         DEBUG(5, ("Attempting to create registry file\n"));
1882
1883         /* Get the header */
1884         regf->fd = creat(location, 0644);
1885
1886         if (regf->fd == -1) {
1887                 DEBUG(0,("Could not create file: %s, %s\n", location,
1888                                  strerror(errno)));
1889                 talloc_free(regf);
1890                 return WERR_GENERAL_FAILURE;
1891         }
1892
1893         regf_hdr = talloc_zero(regf, struct regf_hdr);
1894         W_ERROR_HAVE_NO_MEMORY(regf_hdr);
1895         regf_hdr->REGF_ID = "regf";
1896         unix_to_nt_time(&regf_hdr->modtime, time(NULL));
1897         regf_hdr->version.major = 1;
1898         regf_hdr->version.minor = minor_version;
1899         regf_hdr->last_block = 0x1000; /* Block size */
1900         regf_hdr->description = talloc_strdup(regf_hdr,
1901                                               "registry created by Samba 4");
1902         W_ERROR_HAVE_NO_MEMORY(regf_hdr->description);
1903         regf_hdr->chksum = 0;
1904
1905         regf->header = regf_hdr;
1906
1907         i = 0;
1908         /* Create all hbin blocks */
1909         regf->hbins = talloc_array(regf, struct hbin_block *, 1);
1910         W_ERROR_HAVE_NO_MEMORY(regf->hbins);
1911         regf->hbins[0] = NULL;
1912
1913         regf_hdr->data_offset = -1; /* FIXME */
1914
1915         nk.header = "nk";
1916         nk.type = REG_SUB_KEY;
1917         unix_to_nt_time(&nk.last_change, time(NULL));
1918         nk.uk1 = 0;
1919         nk.parent_offset = -1;
1920         nk.num_subkeys = 0;
1921         nk.uk2 = 0;
1922         nk.subkeys_offset = -1;
1923         nk.unknown_offset = -1;
1924         nk.num_values = 0;
1925         nk.values_offset = -1;
1926         memset(nk.unk3, 0, 5);
1927         nk.clsname_offset = -1; /* FIXME: fill in */
1928         nk.clsname_length = 0;
1929         nk.key_name = "";
1930
1931         nk.sk_offset = -1; /* FIXME: fill in */
1932
1933         /* Store the new nk key */
1934         regf->header->data_offset = hbin_store_tdr(regf,
1935                                                    (tdr_push_fn_t)tdr_push_nk_block,
1936                                                    &nk);
1937
1938         *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
1939                                                regf->header->data_offset);
1940
1941         /* We can drop our own reference now that *key will have created one */
1942         talloc_free(regf);
1943
1944         error = regf_save_hbin(regf);
1945         if (!W_ERROR_IS_OK(error)) {
1946                 return error;
1947         }
1948
1949         return WERR_OK;
1950 }
1951
1952 WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx, const char *location, 
1953                           struct loadparm_context *lp_ctx, struct hive_key **key)
1954 {
1955         struct regf_data *regf;
1956         struct regf_hdr *regf_hdr;
1957         struct tdr_pull *pull;
1958         int i;
1959
1960         regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
1961
1962         regf->iconv_convenience = lp_iconv_convenience(lp_ctx);
1963
1964         W_ERROR_HAVE_NO_MEMORY(regf);
1965
1966         DEBUG(5, ("Attempting to load registry file\n"));
1967
1968         /* Get the header */
1969         regf->fd = open(location, O_RDWR);
1970
1971         if (regf->fd == -1) {
1972                 DEBUG(0,("Could not load file: %s, %s\n", location,
1973                                  strerror(errno)));
1974                 talloc_free(regf);
1975                 return WERR_GENERAL_FAILURE;
1976         }
1977
1978         pull = tdr_pull_init(regf, regf->iconv_convenience);
1979
1980         pull->data.data = (uint8_t*)fd_load(regf->fd, &pull->data.length, regf);
1981
1982         if (pull->data.data == NULL) {
1983                 DEBUG(0, ("Error reading data\n"));
1984                 talloc_free(regf);
1985                 return WERR_GENERAL_FAILURE;
1986         }
1987
1988         regf_hdr = talloc(regf, struct regf_hdr);
1989         W_ERROR_HAVE_NO_MEMORY(regf_hdr);
1990
1991         if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(pull, regf_hdr, regf_hdr))) {
1992                 talloc_free(regf);
1993                 return WERR_GENERAL_FAILURE;
1994         }
1995
1996         regf->header = regf_hdr;
1997
1998         if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
1999                 DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
2000                         regf_hdr->REGF_ID, location));
2001                 talloc_free(regf);
2002                 return WERR_GENERAL_FAILURE;
2003         }
2004
2005         /* Validate the header ... */
2006         if (regf_hdr_checksum(pull->data.data) != regf_hdr->chksum) {
2007                 DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
2008                         location, regf_hdr->chksum,
2009                         regf_hdr_checksum(pull->data.data)));
2010                 talloc_free(regf);
2011                 return WERR_GENERAL_FAILURE;
2012         }
2013
2014         pull->offset = 0x1000;
2015
2016         i = 0;
2017         /* Read in all hbin blocks */
2018         regf->hbins = talloc_array(regf, struct hbin_block *, 1);
2019         W_ERROR_HAVE_NO_MEMORY(regf->hbins);
2020
2021         regf->hbins[0] = NULL;
2022
2023         while (pull->offset < pull->data.length &&
2024                pull->offset <= regf->header->last_block) {
2025                 struct hbin_block *hbin = talloc(regf->hbins,
2026                                                  struct hbin_block);
2027
2028                 W_ERROR_HAVE_NO_MEMORY(hbin);
2029
2030                 if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(pull, hbin, hbin))) {
2031                         DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
2032                         talloc_free(regf);
2033                         return WERR_FOOBAR;
2034                 }
2035
2036                 if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
2037                         DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n",
2038                                 i, hbin->HBIN_ID));
2039                         talloc_free(regf);
2040                         return WERR_FOOBAR;
2041                 }
2042
2043                 regf->hbins[i] = hbin;
2044                 i++;
2045                 regf->hbins = talloc_realloc(regf, regf->hbins,
2046                                              struct hbin_block *, i+2);
2047                 regf->hbins[i] = NULL;
2048         }
2049
2050         talloc_free(pull);
2051
2052         DEBUG(1, ("%d HBIN blocks read\n", i));
2053
2054         *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
2055                                                regf->header->data_offset);
2056
2057         /* We can drop our own reference now that *key will have created one */
2058         talloc_free(regf);
2059
2060         return WERR_OK;
2061 }
2062
2063 static struct hive_operations reg_backend_regf = {
2064         .name = "regf",
2065         .get_key_info = regf_get_info,
2066         .enum_key = regf_get_subkey_by_index,
2067         .get_key_by_name = regf_get_subkey_by_name,
2068         .get_value_by_name = regf_get_value_by_name,
2069         .enum_value = regf_get_value,
2070         .get_sec_desc = regf_get_sec_desc,
2071         .set_sec_desc = regf_set_sec_desc,
2072         .add_key = regf_add_key,
2073         .set_value = regf_set_value,
2074         .del_key = regf_del_key,
2075         .delete_value = regf_del_value,
2076 };