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