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