Merge commit 'release-4-0-0alpha2' into v4-0-test
[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 {
433         const struct regf_key_data *private_data =
434                 (const struct regf_key_data *)key;
435
436         if (num_subkeys != NULL)
437                 *num_subkeys = private_data->nk->num_subkeys;
438
439         if (num_values != NULL)
440                 *num_values = private_data->nk->num_values;
441
442         if (classname != NULL) {
443                 if (private_data->nk->clsname_offset != -1) {
444                         DATA_BLOB data = hbin_get(private_data->hive,
445                                                   private_data->nk->clsname_offset);
446                         *classname = talloc_strndup(mem_ctx,
447                                                     (char*)data.data,
448                                                     private_data->nk->clsname_length);
449                 } else
450                         *classname = NULL;
451         }
452
453         /* TODO: Last mod time */
454
455         return WERR_OK;
456 }
457
458 static struct regf_key_data *regf_get_key(TALLOC_CTX *ctx,
459                                           struct regf_data *regf,
460                                           uint32_t offset)
461 {
462         struct nk_block *nk;
463         struct regf_key_data *ret;
464
465         ret = talloc_zero(ctx, struct regf_key_data);
466         ret->key.ops = &reg_backend_regf;
467         ret->hive = talloc_reference(ret, regf);
468         ret->offset = offset;
469         nk = talloc(ret, struct nk_block);
470         if (nk == NULL)
471                 return NULL;
472
473         ret->nk = nk;
474
475         if (!hbin_get_tdr(regf, offset, nk,
476                           (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
477                 DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
478                 return NULL;
479         }
480
481         if (strcmp(nk->header, "nk") != 0) {
482                 DEBUG(0, ("Expected nk record, got %s\n", nk->header));
483                 talloc_free(ret);
484                 return NULL;
485         }
486
487         return ret;
488 }
489
490
491 static WERROR regf_get_value(TALLOC_CTX *ctx, struct hive_key *key,
492                              int idx, const char **name,
493                              uint32_t *data_type, DATA_BLOB *data)
494 {
495         const struct regf_key_data *private_data =
496                         (const struct regf_key_data *)key;
497         struct vk_block *vk;
498         struct regf_data *regf = private_data->hive;
499         uint32_t vk_offset;
500         DATA_BLOB tmp;
501
502         if (idx >= private_data->nk->num_values)
503                 return WERR_NO_MORE_ITEMS;
504
505         tmp = hbin_get(regf, private_data->nk->values_offset);
506         if (!tmp.data) {
507                 DEBUG(0, ("Unable to find value list\n"));
508                 return WERR_GENERAL_FAILURE;
509         }
510
511         if (tmp.length < private_data->nk->num_values * 4) {
512                 DEBUG(1, ("Value counts mismatch\n"));
513         }
514
515         vk_offset = IVAL(tmp.data, idx * 4);
516
517         vk = talloc(NULL, struct vk_block);
518         W_ERROR_HAVE_NO_MEMORY(vk);
519
520         if (!hbin_get_tdr(regf, vk_offset, vk,
521                           (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
522                 DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));
523                 talloc_free(vk);
524                 return WERR_GENERAL_FAILURE;
525         }
526
527         /* FIXME: name character set ?*/
528         if (name != NULL)
529                 *name = talloc_strndup(ctx, vk->data_name, vk->name_length);
530
531         if (data_type != NULL)
532                 *data_type = vk->data_type;
533
534         if (vk->data_length & 0x80000000) {
535                 vk->data_length &=~0x80000000;
536                 data->data = (uint8_t *)&vk->data_offset;
537                 data->length = vk->data_length;
538         } else {
539                 *data = hbin_get(regf, vk->data_offset);
540         }
541
542         if (data->length < vk->data_length) {
543                 DEBUG(1, ("Read data less than indicated data length!\n"));
544         }
545
546         talloc_free(vk);
547
548         return WERR_OK;
549 }
550
551 static WERROR regf_get_value_by_name(TALLOC_CTX *mem_ctx,
552                                      struct hive_key *key, const char *name,
553                                      uint32_t *type, DATA_BLOB *data)
554 {
555         int i;
556         const char *vname;
557         WERROR error;
558
559         /* FIXME: Do binary search? Is this list sorted at all? */
560
561         for (i = 0; W_ERROR_IS_OK(error = regf_get_value(mem_ctx, key, i,
562                                                          &vname, type, data));
563                                                          i++) {
564                 if (!strcmp(vname, name))
565                         return WERR_OK;
566         }
567
568         if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
569                 return WERR_NOT_FOUND;
570
571         return error;
572 }
573
574
575 static WERROR regf_get_subkey_by_index(TALLOC_CTX *ctx,
576                                        const struct hive_key *key,
577                                        uint32_t idx, const char **name,
578                                        const char **classname,
579                                        NTTIME *last_mod_time)
580 {
581         DATA_BLOB data;
582         struct regf_key_data *ret;
583         const struct regf_key_data *private_data = (const struct regf_key_data *)key;
584         struct nk_block *nk = private_data->nk;
585         uint32_t key_off=0;
586
587         if (idx >= nk->num_subkeys)
588                 return WERR_NO_MORE_ITEMS;
589
590         data = hbin_get(private_data->hive, nk->subkeys_offset);
591         if (!data.data) {
592                 DEBUG(0, ("Unable to find subkey list\n"));
593                 return WERR_GENERAL_FAILURE;
594         }
595
596         if (!strncmp((char *)data.data, "li", 2)) {
597                 struct li_block li;
598                 struct tdr_pull *pull = tdr_pull_init(private_data->hive, private_data->hive->iconv_convenience);
599
600                 DEBUG(10, ("Subkeys in LI list\n"));
601                 pull->data = data;
602
603                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) {
604                         DEBUG(0, ("Error parsing LI list\n"));
605                         talloc_free(pull);
606                         return WERR_GENERAL_FAILURE;
607                 }
608                 talloc_free(pull);
609                 SMB_ASSERT(!strncmp(li.header, "li", 2));
610
611                 if (li.key_count != nk->num_subkeys) {
612                         DEBUG(0, ("Subkey counts don't match\n"));
613                         return WERR_GENERAL_FAILURE;
614                 }
615                 key_off = li.nk_offset[idx];
616
617         } else if (!strncmp((char *)data.data, "lf", 2)) {
618                 struct lf_block lf;
619                 struct tdr_pull *pull = tdr_pull_init(private_data->hive, private_data->hive->iconv_convenience);
620
621                 DEBUG(10, ("Subkeys in LF list\n"));
622                 pull->data = data;
623
624                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) {
625                         DEBUG(0, ("Error parsing LF list\n"));
626                         talloc_free(pull);
627                         return WERR_GENERAL_FAILURE;
628                 }
629                 talloc_free(pull);
630                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
631
632                 if (lf.key_count != nk->num_subkeys) {
633                         DEBUG(0, ("Subkey counts don't match\n"));
634                         return WERR_GENERAL_FAILURE;
635                 }
636
637                 key_off = lf.hr[idx].nk_offset;
638         } else if (!strncmp((char *)data.data, "lh", 2)) {
639                 struct lh_block lh;
640                 struct tdr_pull *pull = tdr_pull_init(private_data->hive, private_data->hive->iconv_convenience);
641
642                 DEBUG(10, ("Subkeys in LH list\n"));
643                 pull->data = data;
644
645                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) {
646                         DEBUG(0, ("Error parsing LH list\n"));
647                         talloc_free(pull);
648                         return WERR_GENERAL_FAILURE;
649                 }
650                 talloc_free(pull);
651                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
652
653                 if (lh.key_count != nk->num_subkeys) {
654                         DEBUG(0, ("Subkey counts don't match\n"));
655                         return WERR_GENERAL_FAILURE;
656                 }
657                 key_off = lh.hr[idx].nk_offset;
658         } else if (!strncmp((char *)data.data, "ri", 2)) {
659                 struct ri_block ri;
660                 struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
661                 uint16_t i;
662                 uint16_t sublist_count = 0;
663
664                 DEBUG(10, ("Subkeys in RI list\n"));
665                 pull->data = data;
666
667                 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) {
668                         DEBUG(0, ("Error parsing RI list\n"));
669                         talloc_free(pull);
670                         return WERR_GENERAL_FAILURE;
671                 }
672                 SMB_ASSERT(!strncmp(ri.header, "ri", 2));
673
674                 for (i = 0; i < ri.key_count; i++) {
675                         DATA_BLOB list_data;
676
677                         /* Get sublist data blob */
678                         list_data = hbin_get(private_data->hive, ri.offset[i]);
679                         if (!list_data.data) {
680                                 DEBUG(0, ("Error getting RI list."));
681                                 talloc_free(pull);
682                                 return WERR_GENERAL_FAILURE;
683                         }
684
685                         pull->data = list_data;
686
687                         if (!strncmp((char *)list_data.data, "li", 2)) {
688                                 struct li_block li;
689
690                                 DEBUG(10, ("Subkeys in RI->LI list\n"));
691
692                                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull,
693                                                                        nk,
694                                                                        &li))) {
695                                         DEBUG(0, ("Error parsing LI list from RI\n"));
696                                         talloc_free(pull);
697                                         return WERR_GENERAL_FAILURE;
698                                 }
699                                 SMB_ASSERT(!strncmp(li.header, "li", 2));
700
701                                 /* Advance to next sublist if necessary */
702                                 if (idx >= sublist_count + li.key_count) {
703                                         sublist_count += li.key_count;
704                                         continue;
705                                 }
706                                 key_off = li.nk_offset[idx - sublist_count];
707                                 sublist_count += li.key_count;
708                                 break;
709                         } else if (!strncmp((char *)list_data.data, "lh", 2)) {
710                                 struct lh_block lh;
711
712                                 DEBUG(10, ("Subkeys in RI->LH list\n"));
713
714                                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull,
715                                                                        nk,
716                                                                        &lh))) {
717                                         DEBUG(0, ("Error parsing LH list from RI\n"));
718                                         talloc_free(pull);
719                                         return WERR_GENERAL_FAILURE;
720                                 }
721                                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
722
723                                 /* Advance to next sublist if necessary */
724                                 if (idx >= sublist_count + lh.key_count) {
725                                         sublist_count += lh.key_count;
726                                         continue;
727                                 }
728                                 key_off = lh.hr[idx - sublist_count].nk_offset;
729                                 sublist_count += lh.key_count;
730                                 break;
731                         } else {
732                                 DEBUG(0,("Unknown sublist in ri block\n"));
733                                 talloc_free(pull);
734
735                                 return WERR_GENERAL_FAILURE;
736                         }
737
738                 }
739                 talloc_free(pull);
740
741
742                 if (idx > sublist_count) {
743                         return WERR_NO_MORE_ITEMS;
744                 }
745
746         } else {
747                 DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n",
748                                   nk->subkeys_offset, data.data[0], data.data[1]));
749                 return WERR_GENERAL_FAILURE;
750         }
751
752         ret = regf_get_key (ctx, private_data->hive, key_off);
753
754         if (classname != NULL) {
755                 if (ret->nk->clsname_offset != -1) {
756                         DATA_BLOB db = hbin_get(ret->hive,
757                                                 ret->nk->clsname_offset);
758                         *classname = talloc_strndup(ctx,
759                                                     (char*)db.data,
760                                                     ret->nk->clsname_length);
761                 } else
762                         *classname = NULL;
763         }
764
765         if (last_mod_time != NULL)
766                 *last_mod_time = ret->nk->last_change;
767
768         if (name != NULL)
769                 *name = talloc_steal(ctx, ret->nk->key_name);
770
771         talloc_free(ret);
772
773         return WERR_OK;
774 }
775
776 static WERROR regf_match_subkey_by_name(TALLOC_CTX *ctx,
777                                         const struct hive_key *key,
778                                         uint32_t offset,
779                                         const char *name, uint32_t *ret)
780 {
781         DATA_BLOB subkey_data;
782         struct nk_block subkey;
783         struct tdr_pull *pull;
784         const struct regf_key_data *private_data =
785                 (const struct regf_key_data *)key;
786
787         subkey_data = hbin_get(private_data->hive, offset);
788         if (!subkey_data.data) {
789                 DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
790                 return WERR_GENERAL_FAILURE;
791         }
792
793         pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
794
795         pull->data = subkey_data;
796
797         if (NT_STATUS_IS_ERR(tdr_pull_nk_block(pull, ctx, &subkey))) {
798                 DEBUG(0, ("Error parsing NK structure.\n"));
799                 talloc_free(pull);
800                 return WERR_GENERAL_FAILURE;
801         }
802         talloc_free(pull);
803
804         if (strncmp(subkey.header, "nk", 2)) {
805                 DEBUG(0, ("Not an NK structure.\n"));
806                 return WERR_GENERAL_FAILURE;
807         }
808
809         if (!strcasecmp(subkey.key_name, name)) {
810                 *ret = offset;
811         } else {
812                 *ret = 0;
813         }
814         return WERR_OK;
815 }
816
817 static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx,
818                                       const struct hive_key *key,
819                                       const char *name,
820                                       struct hive_key **ret)
821 {
822         DATA_BLOB data;
823         const struct regf_key_data *private_data =
824                 (const struct regf_key_data *)key;
825         struct nk_block *nk = private_data->nk;
826         uint32_t key_off = 0;
827
828         data = hbin_get(private_data->hive, nk->subkeys_offset);
829         if (!data.data) {
830                 DEBUG(0, ("Unable to find subkey list\n"));
831                 return WERR_GENERAL_FAILURE;
832         }
833
834         if (!strncmp((char *)data.data, "li", 2)) {
835                 struct li_block li;
836                 struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
837                 uint16_t i;
838
839                 DEBUG(10, ("Subkeys in LI list\n"));
840                 pull->data = data;
841
842                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) {
843                         DEBUG(0, ("Error parsing LI list\n"));
844                         talloc_free(pull);
845                         return WERR_GENERAL_FAILURE;
846                 }
847                 talloc_free(pull);
848                 SMB_ASSERT(!strncmp(li.header, "li", 2));
849
850                 if (li.key_count != nk->num_subkeys) {
851                         DEBUG(0, ("Subkey counts don't match\n"));
852                         return WERR_GENERAL_FAILURE;
853                 }
854
855                 for (i = 0; i < li.key_count; i++) {
856                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
857                                                                         li.nk_offset[i],
858                                                                         name,
859                                                                         &key_off));
860                         if (key_off != 0)
861                                 break;
862                 }
863                 if (key_off == 0)
864                         return WERR_NOT_FOUND;
865         } else if (!strncmp((char *)data.data, "lf", 2)) {
866                 struct lf_block lf;
867                 struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
868                 uint16_t i;
869
870                 DEBUG(10, ("Subkeys in LF list\n"));
871                 pull->data = data;
872
873                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) {
874                         DEBUG(0, ("Error parsing LF list\n"));
875                         talloc_free(pull);
876                         return WERR_GENERAL_FAILURE;
877                 }
878                 talloc_free(pull);
879                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
880
881                 if (lf.key_count != nk->num_subkeys) {
882                         DEBUG(0, ("Subkey counts don't match\n"));
883                         return WERR_GENERAL_FAILURE;
884                 }
885
886                 for (i = 0; i < lf.key_count; i++) {
887                         if (strncmp(lf.hr[i].hash, name, 4)) {
888                                 continue;
889                         }
890                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk,
891                                                                         key,
892                                                                         lf.hr[i].nk_offset,
893                                                                         name,
894                                                                         &key_off));
895                         if (key_off != 0)
896                                 break;
897                 }
898                 if (key_off == 0)
899                         return WERR_NOT_FOUND;
900         } else if (!strncmp((char *)data.data, "lh", 2)) {
901                 struct lh_block lh;
902                 struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
903                 uint16_t i;
904                 uint32_t hash;
905
906                 DEBUG(10, ("Subkeys in LH list\n"));
907                 pull->data = data;
908
909                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) {
910                         DEBUG(0, ("Error parsing LH list\n"));
911                         talloc_free(pull);
912                         return WERR_GENERAL_FAILURE;
913                 }
914                 talloc_free(pull);
915                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
916
917                 if (lh.key_count != nk->num_subkeys) {
918                         DEBUG(0, ("Subkey counts don't match\n"));
919                         return WERR_GENERAL_FAILURE;
920                 }
921
922                 hash = regf_create_lh_hash(name);
923                 for (i = 0; i < lh.key_count; i++) {
924                         if (lh.hr[i].base37 != hash) {
925                                 continue;
926                         }
927                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk,
928                                                                         key,
929                                                                         lh.hr[i].nk_offset,
930                                                                         name,
931                                                                         &key_off));
932                         if (key_off != 0)
933                                 break;
934                 }
935                 if (key_off == 0)
936                         return WERR_NOT_FOUND;
937         } else if (!strncmp((char *)data.data, "ri", 2)) {
938                 struct ri_block ri;
939                 struct tdr_pull *pull = tdr_pull_init(ctx, private_data->hive->iconv_convenience);
940                 uint16_t i, j;
941
942                 DEBUG(10, ("Subkeys in RI list\n"));
943                 pull->data = data;
944
945                 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) {
946                         DEBUG(0, ("Error parsing RI list\n"));
947                         talloc_free(pull);
948                         return WERR_GENERAL_FAILURE;
949                 }
950                 SMB_ASSERT(!strncmp(ri.header, "ri", 2));
951
952                 for (i = 0; i < ri.key_count; i++) {
953                         DATA_BLOB list_data;
954
955                         /* Get sublist data blob */
956                         list_data = hbin_get(private_data->hive, ri.offset[i]);
957                         if (list_data.data == NULL) {
958                                 DEBUG(0, ("Error getting RI list."));
959                                 talloc_free(pull);
960                                 return WERR_GENERAL_FAILURE;
961                         }
962
963                         pull->data = list_data;
964
965                         if (!strncmp((char *)list_data.data, "li", 2)) {
966                                 struct li_block li;
967
968                                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull,
969                                                                        nk,
970                                                                        &li))) {
971                                         DEBUG(0, ("Error parsing LI list from RI\n"));
972                                         talloc_free(pull);
973                                         return WERR_GENERAL_FAILURE;
974                                 }
975                                 SMB_ASSERT(!strncmp(li.header, "li", 2));
976
977                                 for (j = 0; j < li.key_count; j++) {
978                                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
979                                                                                         li.nk_offset[j],
980                                                                                         name,
981                                                                                         &key_off));
982                                         if (key_off)
983                                                 break;
984                                 }
985                         } else if (!strncmp((char *)list_data.data, "lh", 2)) {
986                                 struct lh_block lh;
987                                 uint32_t hash;
988
989                                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull,
990                                                                        nk,
991                                                                        &lh))) {
992                                         DEBUG(0, ("Error parsing LH list from RI\n"));
993                                         talloc_free(pull);
994                                         return WERR_GENERAL_FAILURE;
995                                 }
996                                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
997
998                                 hash = regf_create_lh_hash(name);
999                                 for (j = 0; j < lh.key_count; j++) {
1000                                         if (lh.hr[j].base37 != hash) {
1001                                                 continue;
1002                                         }
1003                                         W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
1004                                                                                         lh.hr[j].nk_offset,
1005                                                                                         name,
1006                                                                                         &key_off));
1007                                         if (key_off)
1008                                                 break;
1009                                 }
1010                         }
1011                         if (key_off)
1012                                 break;
1013                 }
1014                 talloc_free(pull);
1015                 if (!key_off)
1016                         return WERR_NOT_FOUND;
1017         } else {
1018                 DEBUG(0, ("Unknown subkey list type.\n"));
1019                 return WERR_GENERAL_FAILURE;
1020         }
1021
1022         *ret = (struct hive_key *)regf_get_key(ctx, private_data->hive,
1023                                                key_off);
1024         return WERR_OK;
1025 }
1026
1027 static WERROR regf_set_sec_desc(struct hive_key *key,
1028                                 const struct security_descriptor *sec_desc)
1029 {
1030         const struct regf_key_data *private_data =
1031                 (const struct regf_key_data *)key;
1032         struct sk_block cur_sk, sk, new_sk;
1033         struct regf_data *regf = private_data->hive;
1034         struct nk_block root;
1035         DATA_BLOB data;
1036         uint32_t sk_offset, cur_sk_offset;
1037         bool update_cur_sk = false;
1038
1039         /* Get the root nk */
1040         hbin_get_tdr(regf, regf->header->data_offset, regf,
1041                      (tdr_pull_fn_t) tdr_pull_nk_block, &root);
1042
1043         /* Push the security descriptor to a blob */
1044         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(&data, regf, sec_desc,
1045                              (ndr_push_flags_fn_t)ndr_push_security_descriptor))) {
1046                 DEBUG(0, ("Unable to push security descriptor\n"));
1047                 return WERR_GENERAL_FAILURE;
1048         }
1049
1050         /* Get the current security descriptor for the key */
1051         if (!hbin_get_tdr(regf, private_data->nk->sk_offset, regf,
1052                           (tdr_pull_fn_t) tdr_pull_sk_block, &cur_sk)) {
1053                 DEBUG(0, ("Unable to find security descriptor for current key\n"));
1054                 return WERR_BADFILE;
1055         }
1056         /* If there's no change, change nothing. */
1057         if (memcmp(data.data, cur_sk.sec_desc,
1058                    MIN(data.length, cur_sk.rec_size)) == 0) {
1059                 return WERR_OK;
1060         }
1061
1062         /* Delete the current sk if only this key is using it */
1063         if (cur_sk.ref_cnt == 1) {
1064                 /* Get the previous security descriptor for the key */
1065                 if (!hbin_get_tdr(regf, cur_sk.prev_offset, regf,
1066                                   (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1067                         DEBUG(0, ("Unable to find prev security descriptor for current key\n"));
1068                         return WERR_BADFILE;
1069                 }
1070                 /* Change and store the previous security descriptor */
1071                 sk.next_offset = cur_sk.next_offset;
1072                 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block,
1073                                       cur_sk.prev_offset, &sk);
1074
1075                 /* Get the next security descriptor for the key */
1076                 if (!hbin_get_tdr(regf, cur_sk.next_offset, regf,
1077                                   (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1078                         DEBUG(0, ("Unable to find next security descriptor for current key\n"));
1079                         return WERR_BADFILE;
1080                 }
1081                 /* Change and store the next security descriptor */
1082                 sk.prev_offset = cur_sk.prev_offset;
1083                 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block,
1084                                       cur_sk.next_offset, &sk);
1085
1086                 hbin_free(regf, private_data->nk->sk_offset);
1087         } else {
1088                 /* This key will no longer be referring to this sk */
1089                 cur_sk.ref_cnt--;
1090                 update_cur_sk = true;
1091         }
1092
1093         sk_offset = root.sk_offset;
1094
1095         do {
1096                 cur_sk_offset = sk_offset;
1097                 if (!hbin_get_tdr(regf, sk_offset, regf,
1098                                   (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1099                         DEBUG(0, ("Unable to find security descriptor\n"));
1100                         return WERR_BADFILE;
1101                 }
1102                 if (memcmp(data.data, sk.sec_desc, MIN(data.length, sk.rec_size)) == 0) {
1103                         private_data->nk->sk_offset = sk_offset;
1104                         sk.ref_cnt++;
1105                         hbin_store_tdr_resize(regf,
1106                                               (tdr_push_fn_t) tdr_push_sk_block,
1107                                               sk_offset, &sk);
1108                         hbin_store_tdr_resize(regf,
1109                                               (tdr_push_fn_t) tdr_push_nk_block,
1110                                               private_data->offset,
1111                                               private_data->nk);
1112                         return WERR_OK;
1113                 }
1114                 sk_offset = sk.next_offset;
1115         } while (sk_offset != root.sk_offset);
1116
1117         ZERO_STRUCT(new_sk);
1118         new_sk.header = "sk";
1119         new_sk.prev_offset = cur_sk_offset;
1120         new_sk.next_offset = root.sk_offset;
1121         new_sk.ref_cnt = 1;
1122         new_sk.rec_size = data.length;
1123         new_sk.sec_desc = data.data;
1124
1125         sk_offset = hbin_store_tdr(regf,
1126                                    (tdr_push_fn_t) tdr_push_sk_block,
1127                                    &new_sk);
1128         if (sk_offset == -1) {
1129                 DEBUG(0, ("Error storing sk block\n"));
1130                 return WERR_GENERAL_FAILURE;
1131         }
1132         private_data->nk->sk_offset = sk_offset;
1133
1134         if (update_cur_sk) {
1135                 hbin_store_tdr_resize(regf,
1136                                       (tdr_push_fn_t) tdr_push_sk_block,
1137                                       private_data->nk->sk_offset, &cur_sk);
1138         }
1139
1140         /* Get the previous security descriptor for the key */
1141         if (!hbin_get_tdr(regf, new_sk.prev_offset, regf,
1142                           (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1143                 DEBUG(0, ("Unable to find security descriptor for previous key\n"));
1144                 return WERR_BADFILE;
1145         }
1146         /* Change and store the previous security descriptor */
1147         sk.next_offset = sk_offset;
1148         hbin_store_tdr_resize(regf,
1149                               (tdr_push_fn_t) tdr_push_sk_block,
1150                               cur_sk.prev_offset, &sk);
1151
1152         /* Get the next security descriptor for the key (always root, as we append) */
1153         if (!hbin_get_tdr(regf, new_sk.next_offset, regf,
1154                           (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1155                 DEBUG(0, ("Unable to find security descriptor for current key\n"));
1156                 return WERR_BADFILE;
1157         }
1158         /* Change and store the next security descriptor (always root, as we append) */
1159         sk.prev_offset = sk_offset;
1160         hbin_store_tdr_resize(regf,
1161                               (tdr_push_fn_t) tdr_push_sk_block,
1162                               root.sk_offset, &sk);
1163
1164
1165         /* Store the nk. */
1166         hbin_store_tdr_resize(regf,
1167                               (tdr_push_fn_t) tdr_push_sk_block,
1168                               private_data->offset, private_data->nk);
1169         return WERR_OK;
1170 }
1171
1172 static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct hive_key *key,
1173                                 struct security_descriptor **sd)
1174 {
1175         const struct regf_key_data *private_data =
1176                 (const struct regf_key_data *)key;
1177         struct sk_block sk;
1178         struct regf_data *regf = private_data->hive;
1179         DATA_BLOB data;
1180
1181         if (!hbin_get_tdr(regf, private_data->nk->sk_offset, ctx,
1182                           (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1183                 DEBUG(0, ("Unable to find security descriptor\n"));
1184                 return WERR_GENERAL_FAILURE;
1185         }
1186
1187         if (strcmp(sk.header, "sk") != 0) {
1188                 DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
1189                 return WERR_GENERAL_FAILURE;
1190         }
1191
1192         *sd = talloc(ctx, struct security_descriptor);
1193         W_ERROR_HAVE_NO_MEMORY(*sd);
1194
1195         data.data = sk.sec_desc;
1196         data.length = sk.rec_size;
1197         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&data, ctx, *sd,
1198                                                   (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
1199                 DEBUG(0, ("Error parsing security descriptor\n"));
1200                 return WERR_GENERAL_FAILURE;
1201         }
1202
1203         return WERR_OK;
1204 }
1205
1206 static WERROR regf_sl_add_entry(struct regf_data *regf, uint32_t list_offset,
1207                                 const char *name,
1208                                 uint32_t key_offset, uint32_t *ret)
1209 {
1210         DATA_BLOB data;
1211
1212         /* Create a new key if necessary */
1213         if (list_offset == -1) {
1214                 if (regf->header->version.major != 1) {
1215                         DEBUG(0, ("Can't store keys in unknown registry format\n"));
1216                         return WERR_NOT_SUPPORTED;
1217                 }
1218                 if (regf->header->version.minor < 3) {
1219                         /* Store LI */
1220                         struct li_block li;
1221                         ZERO_STRUCT(li);
1222                         li.header = "li";
1223                         li.key_count = 1;
1224
1225                         li.nk_offset = talloc_array(regf, uint32_t, 1);
1226                         W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
1227                         li.nk_offset[0] = key_offset;
1228
1229                         *ret = hbin_store_tdr(regf,
1230                                               (tdr_push_fn_t) tdr_push_li_block,
1231                                               &li);
1232
1233                         talloc_free(li.nk_offset);
1234                 } else if (regf->header->version.minor == 3 ||
1235                            regf->header->version.minor == 4) {
1236                         /* Store LF */
1237                         struct lf_block lf;
1238                         ZERO_STRUCT(lf);
1239                         lf.header = "lf";
1240                         lf.key_count = 1;
1241
1242                         lf.hr = talloc_array(regf, struct hash_record, 1);
1243                         W_ERROR_HAVE_NO_MEMORY(lf.hr);
1244                         lf.hr[0].nk_offset = key_offset;
1245                         lf.hr[0].hash = talloc_strndup(lf.hr, name, 4);
1246                         W_ERROR_HAVE_NO_MEMORY(lf.hr[0].hash);
1247
1248                         *ret = hbin_store_tdr(regf,
1249                                               (tdr_push_fn_t) tdr_push_lf_block,
1250                                               &lf);
1251
1252                         talloc_free(lf.hr);
1253                 } else if (regf->header->version.minor == 5) {
1254                         /* Store LH */
1255                         struct lh_block lh;
1256                         ZERO_STRUCT(lh);
1257                         lh.header = "lh";
1258                         lh.key_count = 1;
1259
1260                         lh.hr = talloc_array(regf, struct lh_hash, 1);
1261                         W_ERROR_HAVE_NO_MEMORY(lh.hr);
1262                         lh.hr[0].nk_offset = key_offset;
1263                         lh.hr[0].base37 = regf_create_lh_hash(name);
1264
1265                         *ret = hbin_store_tdr(regf,
1266                                               (tdr_push_fn_t) tdr_push_lh_block,
1267                                               &lh);
1268
1269                         talloc_free(lh.hr);
1270                 }
1271                 return WERR_OK;
1272         }
1273
1274         data = hbin_get(regf, list_offset);
1275         if (!data.data) {
1276                 DEBUG(0, ("Unable to find subkey list\n"));
1277                 return WERR_BADFILE;
1278         }
1279
1280         if (!strncmp((char *)data.data, "li", 2)) {
1281                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1282                 struct li_block li;
1283
1284                 pull->data = data;
1285
1286                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) {
1287                         DEBUG(0, ("Error parsing LI list\n"));
1288                         talloc_free(pull);
1289                         return WERR_BADFILE;
1290                 }
1291                 talloc_free(pull);
1292
1293                 if (strncmp(li.header, "li", 2) != 0) {
1294                         abort();
1295                         DEBUG(0, ("LI header corrupt\n"));
1296                         return WERR_BADFILE;
1297                 }
1298
1299                 li.nk_offset = talloc_realloc(regf, li.nk_offset,
1300                                               uint32_t, li.key_count+1);
1301                 W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
1302                 li.nk_offset[li.key_count] = key_offset;
1303                 li.key_count++;
1304                 *ret = hbin_store_tdr_resize(regf,
1305                                              (tdr_push_fn_t)tdr_push_li_block,
1306                                              list_offset, &li);
1307
1308                 talloc_free(li.nk_offset);
1309         } else if (!strncmp((char *)data.data, "lf", 2)) {
1310                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1311                 struct lf_block lf;
1312
1313                 pull->data = data;
1314
1315                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) {
1316                         DEBUG(0, ("Error parsing LF list\n"));
1317                         talloc_free(pull);
1318                         return WERR_BADFILE;
1319                 }
1320                 talloc_free(pull);
1321                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
1322
1323                 lf.hr = talloc_realloc(regf, lf.hr, struct hash_record,
1324                                        lf.key_count+1);
1325                 W_ERROR_HAVE_NO_MEMORY(lf.hr);
1326                 lf.hr[lf.key_count].nk_offset = key_offset;
1327                 lf.hr[lf.key_count].hash = talloc_strndup(lf.hr, name, 4);
1328                 W_ERROR_HAVE_NO_MEMORY(lf.hr[lf.key_count].hash);
1329                 lf.key_count++;
1330                 *ret = hbin_store_tdr_resize(regf,
1331                                              (tdr_push_fn_t)tdr_push_lf_block,
1332                                              list_offset, &lf);
1333
1334                 talloc_free(lf.hr);
1335         } else if (!strncmp((char *)data.data, "lh", 2)) {
1336                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1337                 struct lh_block lh;
1338
1339                 pull->data = data;
1340
1341                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) {
1342                         DEBUG(0, ("Error parsing LH list\n"));
1343                         talloc_free(pull);
1344                         return WERR_BADFILE;
1345                 }
1346                 talloc_free(pull);
1347                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1348
1349                 lh.hr = talloc_realloc(regf, lh.hr, struct lh_hash,
1350                                        lh.key_count+1);
1351                 W_ERROR_HAVE_NO_MEMORY(lh.hr);
1352                 lh.hr[lh.key_count].nk_offset = key_offset;
1353                 lh.hr[lh.key_count].base37 = regf_create_lh_hash(name);
1354                 lh.key_count++;
1355                 *ret = hbin_store_tdr_resize(regf,
1356                                              (tdr_push_fn_t)tdr_push_lh_block,
1357                                              list_offset, &lh);
1358
1359                 talloc_free(lh.hr);
1360         } else if (!strncmp((char *)data.data, "ri", 2)) {
1361                 /* FIXME */
1362                 DEBUG(0, ("Adding to 'ri' subkey list is not supported yet.\n"));
1363                 return WERR_NOT_SUPPORTED;
1364         } else {
1365                 DEBUG(0, ("Cannot add to unknown subkey list\n"));
1366                 return WERR_BADFILE;
1367         }
1368
1369         return WERR_OK;
1370 }
1371
1372 static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset,
1373                                 uint32_t key_offset, uint32_t *ret)
1374 {
1375         DATA_BLOB data;
1376
1377         data = hbin_get(regf, list_offset);
1378         if (!data.data) {
1379                 DEBUG(0, ("Unable to find subkey list\n"));
1380                 return WERR_BADFILE;
1381         }
1382
1383         if (strncmp((char *)data.data, "li", 2) == 0) {
1384                 struct li_block li;
1385                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1386                 uint16_t i;
1387                 bool found_offset = false;
1388
1389                 DEBUG(10, ("Subkeys in LI list\n"));
1390
1391                 pull->data = data;
1392
1393                 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) {
1394                         DEBUG(0, ("Error parsing LI list\n"));
1395                         talloc_free(pull);
1396                         return WERR_BADFILE;
1397                 }
1398                 talloc_free(pull);
1399
1400                 SMB_ASSERT(!strncmp(li.header, "li", 2));
1401
1402                 for (i = 0; i < li.key_count; i++) {
1403                         if (found_offset) {
1404                                 li.nk_offset[i-1] = li.nk_offset[i];
1405                         }
1406                         if (li.nk_offset[i] == key_offset) {
1407                                 found_offset = true;
1408                                 continue;
1409                         }
1410                 }
1411                 if (!found_offset) {
1412                         DEBUG(2, ("Subkey not found\n"));
1413                         return WERR_NOT_FOUND;
1414                 }
1415                 li.key_count--;
1416
1417                 /* If the there are no entries left, free the subkey list */
1418                 if (li.key_count == 0) {
1419                         hbin_free(regf, list_offset);
1420                         *ret = -1;
1421                 }
1422
1423                 /* Store li block */
1424                 *ret = hbin_store_tdr_resize(regf,
1425                                              (tdr_push_fn_t) tdr_push_li_block,
1426                                              list_offset, &li);
1427         } else if (strncmp((char *)data.data, "lf", 2) == 0) {
1428                 struct lf_block lf;
1429                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1430                 uint16_t i;
1431                 bool found_offset = false;
1432
1433                 DEBUG(10, ("Subkeys in LF list\n"));
1434
1435                 pull->data = data;
1436
1437                 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) {
1438                         DEBUG(0, ("Error parsing LF list\n"));
1439                         talloc_free(pull);
1440                         return WERR_BADFILE;
1441                 }
1442                 talloc_free(pull);
1443
1444                 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
1445
1446                 for (i = 0; i < lf.key_count; i++) {
1447                         if (found_offset) {
1448                                 lf.hr[i-1] = lf.hr[i];
1449                                 continue;
1450                         }
1451                         if (lf.hr[i].nk_offset == key_offset) {
1452                                 found_offset = 1;
1453                                 continue;
1454                         }
1455                 }
1456                 if (!found_offset) {
1457                         DEBUG(2, ("Subkey not found\n"));
1458                         return WERR_NOT_FOUND;
1459                 }
1460                 lf.key_count--;
1461
1462                 /* If the there are no entries left, free the subkey list */
1463                 if (lf.key_count == 0) {
1464                         hbin_free(regf, list_offset);
1465                         *ret = -1;
1466                         return WERR_OK;
1467                 }
1468
1469                 /* Store lf block */
1470                 *ret = hbin_store_tdr_resize(regf,
1471                                              (tdr_push_fn_t) tdr_push_lf_block,
1472                                              list_offset, &lf);
1473         } else if (strncmp((char *)data.data, "lh", 2) == 0) {
1474                 struct lh_block lh;
1475                 struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);
1476                 uint16_t i;
1477                 bool found_offset = false;
1478
1479                 DEBUG(10, ("Subkeys in LH list\n"));
1480
1481                 pull->data = data;
1482
1483                 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) {
1484                         DEBUG(0, ("Error parsing LF list\n"));
1485                         talloc_free(pull);
1486                         return WERR_BADFILE;
1487                 }
1488                 talloc_free(pull);
1489
1490                 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1491
1492                 for (i = 0; i < lh.key_count; i++) {
1493                         if (found_offset) {
1494                                 lh.hr[i-1] = lh.hr[i];
1495                                 continue;
1496                         }
1497                         if (lh.hr[i].nk_offset == key_offset) {
1498                                 found_offset = 1;
1499                                 continue;
1500                         }
1501                 }
1502                 if (!found_offset) {
1503                         DEBUG(0, ("Subkey not found\n"));
1504                         return WERR_NOT_FOUND;
1505                 }
1506                 lh.key_count--;
1507
1508                 /* If the there are no entries left, free the subkey list */
1509                 if (lh.key_count == 0) {
1510                         hbin_free(regf, list_offset);
1511                         *ret = -1;
1512                         return WERR_OK;
1513                 }
1514
1515                 /* Store lh block */
1516                 *ret = hbin_store_tdr_resize(regf,
1517                                              (tdr_push_fn_t) tdr_push_lh_block,
1518                                              list_offset, &lh);
1519         } else if (strncmp((char *)data.data, "ri", 2) == 0) {
1520                 /* FIXME */
1521                 DEBUG(0, ("Sorry, deletion from ri block is not supported yet.\n"));
1522                 return WERR_NOT_SUPPORTED;
1523         } else {
1524                 DEBUG (0, ("Unknown header found in subkey list.\n"));
1525                 return WERR_BADFILE;
1526         }
1527         return WERR_OK;
1528 }
1529
1530 static WERROR regf_del_value (struct hive_key *key, const char *name)
1531 {
1532         struct regf_key_data *private_data = (struct regf_key_data *)key;
1533         struct regf_data *regf = private_data->hive;
1534         struct nk_block *nk = private_data->nk;
1535         struct vk_block vk;
1536         uint32_t vk_offset;
1537         bool found_offset = false;
1538         DATA_BLOB values;
1539         uint32_t i;
1540
1541         if (nk->values_offset == -1) {
1542                 return WERR_NOT_FOUND;
1543         }
1544
1545         values = hbin_get(regf, nk->values_offset);
1546
1547         for (i = 0; i < nk->num_values; i++) {
1548                 if (found_offset) {
1549                         ((uint32_t *)values.data)[i-1] = ((uint32_t *) values.data)[i];
1550                 } else {
1551                         vk_offset = IVAL(values.data, i * 4);
1552                         if (!hbin_get_tdr(regf, vk_offset, private_data,
1553                                           (tdr_pull_fn_t)tdr_pull_vk_block,
1554                                           &vk)) {
1555                                 DEBUG(0, ("Unable to get VK block at %d\n",
1556                                         vk_offset));
1557                                 return WERR_BADFILE;
1558                         }
1559                         if (strcmp(vk.data_name, name) == 0) {
1560                                 hbin_free(regf, vk_offset);
1561                                 found_offset = true;
1562                         }
1563                 }
1564         }
1565         if (!found_offset) {
1566                 return WERR_NOT_FOUND;
1567         } else {
1568                 nk->num_values--;
1569                 values.length = (nk->num_values)*4;
1570         }
1571
1572         /* Store values list and nk */
1573         if (nk->num_values == 0) {
1574                 hbin_free(regf, nk->values_offset);
1575                 nk->values_offset = -1;
1576         } else {
1577                 nk->values_offset = hbin_store_resize(regf,
1578                                                       nk->values_offset,
1579                                                       values);
1580         }
1581         hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
1582                               private_data->offset, nk);
1583
1584         return regf_save_hbin(private_data->hive);
1585 }
1586
1587
1588 static WERROR regf_del_key(const struct hive_key *parent, const char *name)
1589 {
1590         const struct regf_key_data *private_data =
1591                 (const struct regf_key_data *)parent;
1592         struct regf_key_data *key;
1593         struct nk_block *parent_nk;
1594         WERROR error;
1595
1596         SMB_ASSERT(private_data);
1597
1598         parent_nk = private_data->nk;
1599
1600         if (parent_nk->subkeys_offset == -1) {
1601                 DEBUG(4, ("Subkey list is empty, this key cannot contain subkeys.\n"));
1602                 return WERR_NOT_FOUND;
1603         }
1604
1605         /* Find the key */
1606         if (!W_ERROR_IS_OK(regf_get_subkey_by_name(parent_nk, parent, name,
1607                                                    (struct hive_key **)&key))) {
1608                 DEBUG(2, ("Key '%s' not found\n", name));
1609                 return WERR_NOT_FOUND;
1610         }
1611
1612         if (key->nk->subkeys_offset != -1 ||
1613                 key->nk->values_offset != -1) {
1614                 DEBUG(0, ("Key '%s' is not empty.\n", name));
1615                 return WERR_FILE_EXISTS;
1616         }
1617
1618         /* Delete it from the subkey list. */
1619         error = regf_sl_del_entry(private_data->hive, parent_nk->subkeys_offset,
1620                                   key->offset, &parent_nk->subkeys_offset);
1621         if (!W_ERROR_IS_OK(error)) {
1622                 DEBUG(0, ("Can't store new subkey list for parent key. Won't delete.\n"));
1623                 return error;
1624         }
1625
1626         /* Re-store parent key */
1627         parent_nk->num_subkeys--;
1628         hbin_store_tdr_resize(private_data->hive,
1629                               (tdr_push_fn_t) tdr_push_nk_block,
1630                               private_data->offset, parent_nk);
1631
1632         if (key->nk->clsname_offset != -1) {
1633                 hbin_free(private_data->hive, key->nk->clsname_offset);
1634         }
1635         hbin_free(private_data->hive, key->offset);
1636
1637         return regf_save_hbin(private_data->hive);
1638 }
1639
1640 static WERROR regf_add_key(TALLOC_CTX *ctx, const struct hive_key *parent,
1641                            const char *name, const char *classname,
1642                            struct security_descriptor *sec_desc,
1643                            struct hive_key **ret)
1644 {
1645         const struct regf_key_data *private_data =
1646                 (const struct regf_key_data *)parent;
1647         struct nk_block *parent_nk = private_data->nk, nk;
1648         struct nk_block *root;
1649         struct regf_data *regf = private_data->hive;
1650         uint32_t offset;
1651         WERROR error;
1652
1653         nk.header = "nk";
1654         nk.type = REG_SUB_KEY;
1655         unix_to_nt_time(&nk.last_change, time(NULL));
1656         nk.uk1 = 0;
1657         nk.parent_offset = private_data->offset;
1658         nk.num_subkeys = 0;
1659         nk.uk2 = 0;
1660         nk.subkeys_offset = -1;
1661         nk.unknown_offset = -1;
1662         nk.num_values = 0;
1663         nk.values_offset = -1;
1664         memset(nk.unk3, 0, 5);
1665         nk.clsname_offset = -1; /* FIXME: fill in */
1666         nk.clsname_length = 0;
1667         nk.key_name = name;
1668
1669         /* Get the security descriptor of the root key */
1670         root = talloc_zero(ctx, struct nk_block);
1671         W_ERROR_HAVE_NO_MEMORY(root);
1672
1673         if (!hbin_get_tdr(regf, regf->header->data_offset, root,
1674                           (tdr_pull_fn_t)tdr_pull_nk_block, root)) {
1675                 DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));
1676                 return WERR_GENERAL_FAILURE;
1677         }
1678         nk.sk_offset = root->sk_offset;
1679         talloc_free(root);
1680
1681         /* Store the new nk key */
1682         offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
1683
1684         error = regf_sl_add_entry(regf, parent_nk->subkeys_offset, name, offset,
1685                                   &parent_nk->subkeys_offset);
1686         if (!W_ERROR_IS_OK(error)) {
1687                 hbin_free(regf, offset);
1688                 return error;
1689         }
1690
1691         parent_nk->num_subkeys++;
1692
1693         /* Since the subkey offset of the parent can change, store it again */
1694         hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
1695                                                   nk.parent_offset, parent_nk);
1696
1697         *ret = (struct hive_key *)regf_get_key(ctx, regf, offset);
1698
1699         return regf_save_hbin(private_data->hive);
1700 }
1701
1702 static WERROR regf_set_value(struct hive_key *key, const char *name,
1703                              uint32_t type, const DATA_BLOB data)
1704 {
1705         struct regf_key_data *private_data = (struct regf_key_data *)key;
1706         struct regf_data *regf = private_data->hive;
1707         struct nk_block *nk = private_data->nk;
1708         struct vk_block vk;
1709         uint32_t i;
1710         uint32_t tmp_vk_offset, vk_offset, old_vk_offset = -1;
1711         DATA_BLOB values;
1712
1713         ZERO_STRUCT(vk);
1714
1715         /* find the value offset, if it exists */
1716         if (nk->values_offset != -1) {
1717                 values = hbin_get(regf, nk->values_offset);
1718
1719                 for (i = 0; i < nk->num_values; i++) {
1720                         tmp_vk_offset = IVAL(values.data, i * 4);
1721                         if (!hbin_get_tdr(regf, tmp_vk_offset, private_data,
1722                                           (tdr_pull_fn_t)tdr_pull_vk_block,
1723                                           &vk)) {
1724                                 DEBUG(0, ("Unable to get VK block at %d\n",
1725                                         tmp_vk_offset));
1726                                 return WERR_GENERAL_FAILURE;
1727                         }
1728                         if (strcmp(vk.data_name, name) == 0) {
1729                                 old_vk_offset = tmp_vk_offset;
1730                                 break;
1731                         }
1732                 }
1733                 /* Free data, if any */
1734                 if (!(vk.data_length & 0x80000000)) {
1735                         hbin_free(regf, vk.data_offset);
1736                 }
1737         }
1738         if (old_vk_offset == -1) {
1739                 vk.header = "vk";
1740                 vk.name_length = strlen(name);
1741                 if (name != NULL && name[0] != 0) {
1742                         vk.flag = 1;
1743                         vk.data_name = name;
1744                 } else {
1745                         vk.data_name = NULL;
1746                         vk.flag = 0;
1747                 }
1748         }
1749         /* Set the type and data */
1750         vk.data_length = data.length;
1751         vk.data_type = type;
1752         if (type == REG_DWORD) {
1753                 vk.data_length |= 0x80000000;
1754                 vk.data_offset = *(uint32_t *)data.data;
1755         } else {
1756                 /* Store data somewhere */
1757                 vk.data_offset = hbin_store(regf, data);
1758         }
1759         if (old_vk_offset == -1) {
1760                 /* Store new vk */
1761                 vk_offset = hbin_store_tdr(regf,
1762                                            (tdr_push_fn_t) tdr_push_vk_block,
1763                                            &vk);
1764         } else {
1765                 /* Store vk at offset */
1766                 vk_offset = hbin_store_tdr_resize(regf,
1767                                                   (tdr_push_fn_t) tdr_push_vk_block,
1768                                                   old_vk_offset ,&vk);
1769         }
1770
1771         /* Re-allocate the value list */
1772         if (nk->values_offset == -1) {
1773                 nk->values_offset = hbin_store_tdr(regf,
1774                                                    (tdr_push_fn_t) tdr_push_uint32,
1775                                                    &vk_offset);
1776                 nk->num_values = 1;
1777         } else {
1778
1779                 /* Change if we're changing, otherwise we're adding the value */
1780                 if (old_vk_offset != -1) {
1781                         /* Find and overwrite the offset. */
1782                         for (i = 0; i < nk->num_values; i++) {
1783                                 if (IVAL(values.data, i * 4) == old_vk_offset) {
1784                                         SIVAL(values.data, i * 4, vk_offset);
1785                                         break;
1786                                 }
1787                         }
1788                 } else {
1789                         /* Create a new value list */
1790                         DATA_BLOB value_list;
1791
1792                         value_list.length = (nk->num_values+1)*4;
1793                         value_list.data = (uint8_t *)talloc_array(private_data,
1794                                                                   uint32_t,
1795                                                                   nk->num_values+1);
1796                         W_ERROR_HAVE_NO_MEMORY(value_list.data);
1797                         memcpy(value_list.data, values.data, nk->num_values * 4);
1798
1799                         SIVAL(value_list.data, nk->num_values * 4, vk_offset);
1800                         nk->num_values++;
1801                         nk->values_offset = hbin_store_resize(regf,
1802                                                               nk->values_offset,
1803                                                               value_list);
1804                 }
1805
1806         }
1807         hbin_store_tdr_resize(regf,
1808                               (tdr_push_fn_t) tdr_push_nk_block,
1809                               private_data->offset, nk);
1810         return regf_save_hbin(private_data->hive);
1811 }
1812
1813 static WERROR regf_save_hbin(struct regf_data *regf)
1814 {
1815         struct tdr_push *push = tdr_push_init(regf, regf->iconv_convenience);
1816         int i;
1817
1818         W_ERROR_HAVE_NO_MEMORY(push);
1819
1820         if (lseek(regf->fd, 0, SEEK_SET) == -1) {
1821                 DEBUG(0, ("Error lseeking in regf file\n"));
1822                 return WERR_GENERAL_FAILURE;
1823         }
1824
1825         /* Recompute checksum */
1826         if (NT_STATUS_IS_ERR(tdr_push_regf_hdr(push, regf->header))) {
1827                 DEBUG(0, ("Failed to push regf header\n"));
1828                 return WERR_GENERAL_FAILURE;
1829         }
1830         regf->header->chksum = regf_hdr_checksum(push->data.data);
1831         talloc_free(push);
1832
1833         if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, regf->iconv_convenience,
1834                                             (tdr_push_fn_t)tdr_push_regf_hdr,
1835                                             regf->header))) {
1836                 DEBUG(0, ("Error writing registry file header\n"));
1837                 return WERR_GENERAL_FAILURE;
1838         }
1839
1840         if (lseek(regf->fd, 0x1000, SEEK_SET) == -1) {
1841                 DEBUG(0, ("Error lseeking to 0x1000 in regf file\n"));
1842                 return WERR_GENERAL_FAILURE;
1843         }
1844
1845         for (i = 0; regf->hbins[i]; i++) {
1846                 if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd, regf->iconv_convenience,
1847                                                     (tdr_push_fn_t)tdr_push_hbin_block,
1848                                                     regf->hbins[i]))) {
1849                         DEBUG(0, ("Error writing HBIN block\n"));
1850                         return WERR_GENERAL_FAILURE;
1851                 }
1852         }
1853
1854         return WERR_OK;
1855 }
1856
1857 WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx, const char *location,
1858                             int minor_version, struct hive_key **key)
1859 {
1860         struct regf_data *regf;
1861         struct regf_hdr *regf_hdr;
1862         int i;
1863         struct nk_block nk;
1864         WERROR error;
1865
1866         regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
1867
1868         regf->iconv_convenience = lp_iconv_convenience(global_loadparm);
1869
1870         W_ERROR_HAVE_NO_MEMORY(regf);
1871
1872         DEBUG(5, ("Attempting to create registry file\n"));
1873
1874         /* Get the header */
1875         regf->fd = creat(location, 0644);
1876
1877         if (regf->fd == -1) {
1878                 DEBUG(0,("Could not create file: %s, %s\n", location,
1879                                  strerror(errno)));
1880                 talloc_free(regf);
1881                 return WERR_GENERAL_FAILURE;
1882         }
1883
1884         regf_hdr = talloc_zero(regf, struct regf_hdr);
1885         W_ERROR_HAVE_NO_MEMORY(regf_hdr);
1886         regf_hdr->REGF_ID = "regf";
1887         unix_to_nt_time(&regf_hdr->modtime, time(NULL));
1888         regf_hdr->version.major = 1;
1889         regf_hdr->version.minor = minor_version;
1890         regf_hdr->last_block = 0x1000; /* Block size */
1891         regf_hdr->description = talloc_strdup(regf_hdr,
1892                                               "registry created by Samba 4");
1893         W_ERROR_HAVE_NO_MEMORY(regf_hdr->description);
1894         regf_hdr->chksum = 0;
1895
1896         regf->header = regf_hdr;
1897
1898         i = 0;
1899         /* Create all hbin blocks */
1900         regf->hbins = talloc_array(regf, struct hbin_block *, 1);
1901         W_ERROR_HAVE_NO_MEMORY(regf->hbins);
1902         regf->hbins[0] = NULL;
1903
1904         regf_hdr->data_offset = -1; /* FIXME */
1905
1906         nk.header = "nk";
1907         nk.type = REG_SUB_KEY;
1908         unix_to_nt_time(&nk.last_change, time(NULL));
1909         nk.uk1 = 0;
1910         nk.parent_offset = -1;
1911         nk.num_subkeys = 0;
1912         nk.uk2 = 0;
1913         nk.subkeys_offset = -1;
1914         nk.unknown_offset = -1;
1915         nk.num_values = 0;
1916         nk.values_offset = -1;
1917         memset(nk.unk3, 0, 5);
1918         nk.clsname_offset = -1; /* FIXME: fill in */
1919         nk.clsname_length = 0;
1920         nk.key_name = "";
1921
1922         nk.sk_offset = -1; /* FIXME: fill in */
1923
1924         /* Store the new nk key */
1925         regf->header->data_offset = hbin_store_tdr(regf,
1926                                                    (tdr_push_fn_t)tdr_push_nk_block,
1927                                                    &nk);
1928
1929         *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
1930                                                regf->header->data_offset);
1931
1932         /* We can drop our own reference now that *key will have created one */
1933         talloc_free(regf);
1934
1935         error = regf_save_hbin(regf);
1936         if (!W_ERROR_IS_OK(error)) {
1937                 return error;
1938         }
1939
1940         return WERR_OK;
1941 }
1942
1943 WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx, const char *location, 
1944                           struct loadparm_context *lp_ctx, struct hive_key **key)
1945 {
1946         struct regf_data *regf;
1947         struct regf_hdr *regf_hdr;
1948         struct tdr_pull *pull;
1949         int i;
1950
1951         regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
1952
1953         regf->iconv_convenience = lp_iconv_convenience(lp_ctx);
1954
1955         W_ERROR_HAVE_NO_MEMORY(regf);
1956
1957         DEBUG(5, ("Attempting to load registry file\n"));
1958
1959         /* Get the header */
1960         regf->fd = open(location, O_RDWR);
1961
1962         if (regf->fd == -1) {
1963                 DEBUG(0,("Could not load file: %s, %s\n", location,
1964                                  strerror(errno)));
1965                 talloc_free(regf);
1966                 return WERR_GENERAL_FAILURE;
1967         }
1968
1969         pull = tdr_pull_init(regf, regf->iconv_convenience);
1970
1971         pull->data.data = (uint8_t*)fd_load(regf->fd, &pull->data.length, regf);
1972
1973         if (pull->data.data == NULL) {
1974                 DEBUG(0, ("Error reading data\n"));
1975                 talloc_free(regf);
1976                 return WERR_GENERAL_FAILURE;
1977         }
1978
1979         regf_hdr = talloc(regf, struct regf_hdr);
1980         W_ERROR_HAVE_NO_MEMORY(regf_hdr);
1981
1982         if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(pull, regf_hdr, regf_hdr))) {
1983                 talloc_free(regf);
1984                 return WERR_GENERAL_FAILURE;
1985         }
1986
1987         regf->header = regf_hdr;
1988
1989         if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
1990                 DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
1991                         regf_hdr->REGF_ID, location));
1992                 talloc_free(regf);
1993                 return WERR_GENERAL_FAILURE;
1994         }
1995
1996         /* Validate the header ... */
1997         if (regf_hdr_checksum(pull->data.data) != regf_hdr->chksum) {
1998                 DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
1999                         location, regf_hdr->chksum,
2000                         regf_hdr_checksum(pull->data.data)));
2001                 talloc_free(regf);
2002                 return WERR_GENERAL_FAILURE;
2003         }
2004
2005         pull->offset = 0x1000;
2006
2007         i = 0;
2008         /* Read in all hbin blocks */
2009         regf->hbins = talloc_array(regf, struct hbin_block *, 1);
2010         W_ERROR_HAVE_NO_MEMORY(regf->hbins);
2011
2012         regf->hbins[0] = NULL;
2013
2014         while (pull->offset < pull->data.length &&
2015                pull->offset <= regf->header->last_block) {
2016                 struct hbin_block *hbin = talloc(regf->hbins,
2017                                                  struct hbin_block);
2018
2019                 W_ERROR_HAVE_NO_MEMORY(hbin);
2020
2021                 if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(pull, hbin, hbin))) {
2022                         DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
2023                         talloc_free(regf);
2024                         return WERR_FOOBAR;
2025                 }
2026
2027                 if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
2028                         DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n",
2029                                 i, hbin->HBIN_ID));
2030                         talloc_free(regf);
2031                         return WERR_FOOBAR;
2032                 }
2033
2034                 regf->hbins[i] = hbin;
2035                 i++;
2036                 regf->hbins = talloc_realloc(regf, regf->hbins,
2037                                              struct hbin_block *, i+2);
2038                 regf->hbins[i] = NULL;
2039         }
2040
2041         talloc_free(pull);
2042
2043         DEBUG(1, ("%d HBIN blocks read\n", i));
2044
2045         *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
2046                                                regf->header->data_offset);
2047
2048         /* We can drop our own reference now that *key will have created one */
2049         talloc_free(regf);
2050
2051         return WERR_OK;
2052 }
2053
2054 static struct hive_operations reg_backend_regf = {
2055         .name = "regf",
2056         .get_key_info = regf_get_info,
2057         .enum_key = regf_get_subkey_by_index,
2058         .get_key_by_name = regf_get_subkey_by_name,
2059         .get_value_by_name = regf_get_value_by_name,
2060         .enum_value = regf_get_value,
2061         .get_sec_desc = regf_get_sec_desc,
2062         .set_sec_desc = regf_set_sec_desc,
2063         .add_key = regf_add_key,
2064         .set_value = regf_set_value,
2065         .del_key = regf_del_key,
2066         .delete_value = regf_del_value,
2067 };