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