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