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