ctdb-server: Remove duplicate logic
[samba4-gss.git] / source4 / lib / registry / regf.c
blobebe5202922472ed010bafb28463ece8e44f91ed6
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
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.
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.
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/>. */
20 #include "includes.h"
21 #include "lib/util/util_file.h"
22 #include "system/filesys.h"
23 #include "system/time.h"
24 #include "lib/registry/tdr_regf.h"
25 #include "librpc/gen_ndr/ndr_security.h"
26 #include "librpc/gen_ndr/winreg.h"
27 #include "lib/registry/registry.h"
28 #include "libcli/security/security.h"
30 #undef strcasecmp
32 static struct hive_operations reg_backend_regf;
34 /**
35 * There are several places on the web where the REGF format is explained;
37 * TODO: Links
40 /* TODO:
41 * - Return error codes that make more sense
42 * - Locking
43 * - do more things in-memory
47 * Read HBIN blocks into memory
50 struct regf_data {
51 int fd;
52 struct hbin_block **hbins;
53 struct regf_hdr *header;
54 time_t last_write;
57 static WERROR regf_save_hbin(struct regf_data *data, bool flush);
59 struct regf_key_data {
60 struct hive_key key;
61 struct regf_data *hive;
62 uint32_t offset;
63 struct nk_block *nk;
66 static struct hbin_block *hbin_by_offset(const struct regf_data *data,
67 uint32_t offset, uint32_t *rel_offset)
69 unsigned int i;
71 for (i = 0; data->hbins[i]; i++) {
72 if (offset >= data->hbins[i]->offset_from_first &&
73 offset < data->hbins[i]->offset_from_first+
74 data->hbins[i]->offset_to_next) {
75 if (rel_offset != NULL)
76 *rel_offset = offset - data->hbins[i]->offset_from_first - 0x20;
77 return data->hbins[i];
81 return NULL;
84 /**
85 * Validate a regf header
86 * For now, do nothing, but we should check the checksum
88 static uint32_t regf_hdr_checksum(const uint8_t *buffer)
90 uint32_t checksum = 0, x;
91 unsigned int i;
93 for (i = 0; i < 0x01FB; i+= 4) {
94 x = IVAL(buffer, i);
95 checksum ^= x;
98 return checksum;
102 * Obtain the contents of a HBIN block
104 static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset)
106 DATA_BLOB ret;
107 struct hbin_block *hbin;
108 uint32_t rel_offset;
110 ret.data = NULL;
111 ret.length = 0;
113 hbin = hbin_by_offset(data, offset, &rel_offset);
115 if (hbin == NULL) {
116 DEBUG(1, ("Can't find HBIN at 0x%04x\n", offset));
117 return ret;
120 ret.length = IVAL(hbin->data, rel_offset);
121 if (!(ret.length & 0x80000000)) {
122 DEBUG(0, ("Trying to use dirty block at 0x%04x\n", offset));
123 return ret;
126 /* remove high bit */
127 ret.length = (ret.length ^ 0xffffffff) + 1;
129 ret.length -= 4; /* 4 bytes for the length... */
130 ret.data = hbin->data +
131 (offset - hbin->offset_from_first - 0x20) + 4;
133 return ret;
136 static bool hbin_get_tdr(struct regf_data *regf, uint32_t offset,
137 TALLOC_CTX *ctx, tdr_pull_fn_t pull_fn, void *p)
139 struct tdr_pull *pull = tdr_pull_init(regf);
141 pull->data = hbin_get(regf, offset);
142 if (!pull->data.data) {
143 DEBUG(1, ("Unable to get data at 0x%04x\n", offset));
144 talloc_free(pull);
145 return false;
148 if (NT_STATUS_IS_ERR(pull_fn(pull, ctx, p))) {
149 DEBUG(1, ("Error parsing record at 0x%04x using tdr\n",
150 offset));
151 talloc_free(pull);
152 return false;
154 talloc_free(pull);
156 return true;
159 /* Allocate some new data */
160 static DATA_BLOB hbin_alloc(struct regf_data *data, uint32_t size,
161 uint32_t *offset)
163 DATA_BLOB ret;
164 uint32_t rel_offset = (uint32_t) -1; /* Relative offset ! */
165 struct hbin_block *hbin = NULL;
166 unsigned int i;
168 if (offset != NULL) {
169 *offset = 0;
172 if (size == 0)
173 return data_blob(NULL, 0);
175 size += 4; /* Need to include int32 for the length */
177 /* Allocate as a multiple of 8 */
178 size = (size + 7) & ~7;
180 ret.data = NULL;
181 ret.length = 0;
183 for (i = 0; (hbin = data->hbins[i]); i++) {
184 int j;
185 int32_t my_size;
186 for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
187 my_size = IVALS(hbin->data, j);
189 if (my_size == 0x0) {
190 DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
191 return ret;
194 if (my_size % 8 != 0) {
195 DEBUG(0, ("Encountered non-aligned block!\n"));
198 if (my_size < 0) { /* Used... */
199 my_size = -my_size;
200 } else if (my_size == size) { /* exact match */
201 rel_offset = j;
202 DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n",
203 size));
204 break;
205 } else if (my_size > size) { /* data will remain */
206 rel_offset = j;
207 /* Split this block and mark the next block as free */
208 SIVAL(hbin->data, rel_offset+size, my_size-size);
209 DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n",
210 my_size, size));
211 break;
215 if (rel_offset != -1)
216 break;
219 /* No space available in previous hbins,
220 * allocate new one */
221 if (data->hbins[i] == NULL) {
222 DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n",
223 size));
225 /* Add extra hbin block */
226 data->hbins = talloc_realloc(data, data->hbins,
227 struct hbin_block *, i+2);
228 hbin = talloc(data->hbins, struct hbin_block);
229 SMB_ASSERT(hbin != NULL);
231 data->hbins[i] = hbin;
232 data->hbins[i+1] = NULL;
234 /* Set hbin data */
235 hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
236 hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
237 hbin->offset_to_next = 0x1000;
238 hbin->unknown[0] = 0;
239 hbin->unknown[1] = 0;
240 unix_to_nt_time(&hbin->last_change, time(NULL));
241 hbin->block_size = hbin->offset_to_next;
242 hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
243 /* Update the regf header */
244 data->header->last_block += hbin->offset_to_next;
246 /* Set the next block to it's proper size and set the
247 * rel_offset for this block */
248 SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
249 rel_offset = 0x0;
252 /* Set size and mark as used */
253 SIVAL(hbin->data, rel_offset, -size);
255 ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
256 ret.length = size - 0x4;
257 if (offset) {
258 uint32_t new_rel_offset = 0;
259 *offset = hbin->offset_from_first + rel_offset + 0x20;
260 SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);
261 SMB_ASSERT(new_rel_offset == rel_offset);
264 return ret;
267 /* Store a data blob. Return the offset at which it was stored */
268 static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
270 uint32_t ret;
271 DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
273 memcpy(dest.data, blob.data, blob.length);
275 /* Make sure that we have no tailing garbage in the block */
276 if (dest.length > blob.length) {
277 memset(dest.data + blob.length, 0, dest.length - blob.length);
280 return ret;
283 static uint32_t hbin_store_tdr(struct regf_data *data,
284 tdr_push_fn_t push_fn, void *p)
286 struct tdr_push *push = tdr_push_init(data);
287 uint32_t ret;
289 if (NT_STATUS_IS_ERR(push_fn(push, p))) {
290 DEBUG(0, ("Error during push\n"));
291 return -1;
294 ret = hbin_store(data, push->data);
296 talloc_free(push);
298 return ret;
302 /* Free existing data */
303 static void hbin_free (struct regf_data *data, uint32_t offset)
305 int32_t size;
306 uint32_t rel_offset;
307 int32_t next_size;
308 struct hbin_block *hbin;
310 SMB_ASSERT (offset > 0);
312 hbin = hbin_by_offset(data, offset, &rel_offset);
314 if (hbin == NULL)
315 return;
317 /* Get original size */
318 size = IVALS(hbin->data, rel_offset);
320 if (size > 0) {
321 DEBUG(1, ("Trying to free already freed block at 0x%04x\n",
322 offset));
323 return;
325 /* Mark as unused */
326 size = -size;
328 /* If the next block is free, merge into big free block */
329 if (rel_offset + size < hbin->offset_to_next - 0x20) {
330 next_size = IVALS(hbin->data, rel_offset+size);
331 if (next_size > 0) {
332 size += next_size;
336 /* Write block size */
337 SIVALS(hbin->data, rel_offset, size);
341 * Store a data blob data was already stored, but has changed in size
342 * Will try to save it at the current location if possible, otherwise
343 * does a free + store */
344 static uint32_t hbin_store_resize(struct regf_data *data,
345 uint32_t orig_offset, DATA_BLOB blob)
347 uint32_t rel_offset;
348 struct hbin_block *hbin = hbin_by_offset(data, orig_offset,
349 &rel_offset);
350 int32_t my_size;
351 int32_t orig_size;
352 int32_t needed_size;
353 int32_t possible_size;
354 unsigned int i;
356 SMB_ASSERT(orig_offset > 0);
358 if (!hbin)
359 return hbin_store(data, blob);
361 /* Get original size */
362 orig_size = -IVALS(hbin->data, rel_offset);
364 needed_size = blob.length + 4; /* Add int32 containing length */
365 needed_size = (needed_size + 7) & ~7; /* Align */
367 /* Fits into current allocated block */
368 if (orig_size >= needed_size) {
369 memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
370 /* If the difference in size is greater than 0x4, split the block
371 * and free/merge it */
372 if (orig_size - needed_size > 0x4) {
373 SIVALS(hbin->data, rel_offset, -needed_size);
374 SIVALS(hbin->data, rel_offset + needed_size,
375 needed_size-orig_size);
376 hbin_free(data, orig_offset + needed_size);
378 return orig_offset;
381 possible_size = orig_size;
383 /* Check if it can be combined with the next few free records */
384 for (i = rel_offset; i < hbin->offset_to_next - 0x20; i += my_size) {
385 if (IVALS(hbin->data, i) < 0) /* Used */
386 break;
388 my_size = IVALS(hbin->data, i);
390 if (my_size == 0x0) {
391 DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
392 break;
393 } else {
394 possible_size += my_size;
397 if (possible_size >= blob.length) {
398 SIVAL(hbin->data, rel_offset, -possible_size);
399 memcpy(hbin->data + rel_offset + 0x4,
400 blob.data, blob.length);
401 return orig_offset;
405 hbin_free(data, orig_offset);
406 return hbin_store(data, blob);
409 static uint32_t hbin_store_tdr_resize(struct regf_data *regf,
410 tdr_push_fn_t push_fn,
411 uint32_t orig_offset, void *p)
413 struct tdr_push *push = tdr_push_init(regf);
414 uint32_t ret;
416 if (NT_STATUS_IS_ERR(push_fn(push, p))) {
417 DEBUG(0, ("Error during push\n"));
418 return -1;
421 ret = hbin_store_resize(regf, orig_offset, push->data);
423 talloc_free(push);
425 return ret;
428 static uint32_t regf_create_lh_hash(const char *name)
430 char *hash_name;
431 uint32_t ret = 0;
432 uint16_t i;
434 hash_name = strupper_talloc(NULL, name);
435 for (i = 0; *(hash_name + i) != 0; i++) {
436 ret *= 37;
437 ret += *(hash_name + i);
439 talloc_free(hash_name);
440 return ret;
443 static WERROR regf_get_info(TALLOC_CTX *mem_ctx,
444 const struct hive_key *key,
445 const char **classname,
446 uint32_t *num_subkeys,
447 uint32_t *num_values,
448 NTTIME *last_mod_time,
449 uint32_t *max_subkeynamelen,
450 uint32_t *max_valnamelen,
451 uint32_t *max_valbufsize)
453 const struct regf_key_data *private_data =
454 (const struct regf_key_data *)key;
456 if (num_subkeys != NULL)
457 *num_subkeys = private_data->nk->num_subkeys;
459 if (num_values != NULL)
460 *num_values = private_data->nk->num_values;
462 if (classname != NULL) {
463 if (private_data->nk->clsname_offset != -1) {
464 DATA_BLOB data = hbin_get(private_data->hive,
465 private_data->nk->clsname_offset);
466 *classname = talloc_strndup(mem_ctx,
467 (char*)data.data,
468 private_data->nk->clsname_length);
469 W_ERROR_HAVE_NO_MEMORY(*classname);
470 } else
471 *classname = NULL;
474 /* TODO: Last mod time */
476 /* TODO: max valnamelen */
478 /* TODO: max valbufsize */
480 /* TODO: max subkeynamelen */
482 return WERR_OK;
485 static struct regf_key_data *regf_get_key(TALLOC_CTX *ctx,
486 struct regf_data *regf,
487 uint32_t offset)
489 struct nk_block *nk;
490 struct regf_key_data *ret;
492 ret = talloc_zero(ctx, struct regf_key_data);
493 ret->key.ops = &reg_backend_regf;
494 ret->hive = talloc_reference(ret, regf);
495 ret->offset = offset;
496 nk = talloc(ret, struct nk_block);
497 if (nk == NULL)
498 return NULL;
500 ret->nk = nk;
502 if (!hbin_get_tdr(regf, offset, nk,
503 (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
504 DEBUG(0, ("Unable to find HBIN data for offset 0x%x\n", offset));
505 return NULL;
508 if (strcmp(nk->header, "nk") != 0) {
509 DEBUG(0, ("Expected nk record, got %s\n", nk->header));
510 talloc_free(ret);
511 return NULL;
514 return ret;
518 static WERROR regf_get_value(TALLOC_CTX *ctx, struct hive_key *key,
519 uint32_t idx, const char **name,
520 uint32_t *data_type, DATA_BLOB *data)
522 const struct regf_key_data *private_data =
523 (const struct regf_key_data *)key;
524 struct vk_block *vk;
525 struct regf_data *regf = private_data->hive;
526 uint32_t vk_offset;
527 DATA_BLOB tmp;
529 if (idx >= private_data->nk->num_values)
530 return WERR_NO_MORE_ITEMS;
532 tmp = hbin_get(regf, private_data->nk->values_offset);
533 if (!tmp.data) {
534 DEBUG(0, ("Unable to find value list at 0x%x\n",
535 private_data->nk->values_offset));
536 return WERR_GEN_FAILURE;
539 if (tmp.length < private_data->nk->num_values * 4) {
540 DEBUG(1, ("Value counts mismatch\n"));
543 vk_offset = IVAL(tmp.data, idx * 4);
545 vk = talloc(NULL, struct vk_block);
546 W_ERROR_HAVE_NO_MEMORY(vk);
548 if (!hbin_get_tdr(regf, vk_offset, vk,
549 (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
550 DEBUG(0, ("Unable to get VK block at 0x%x\n", vk_offset));
551 talloc_free(vk);
552 return WERR_GEN_FAILURE;
555 /* FIXME: name character set ?*/
556 if (name != NULL) {
557 *name = talloc_strndup(ctx, vk->data_name, vk->name_length);
558 W_ERROR_HAVE_NO_MEMORY(*name);
561 if (data_type != NULL)
562 *data_type = vk->data_type;
564 if (vk->data_length & 0x80000000) {
565 /* this is data of type "REG_DWORD" or "REG_DWORD_BIG_ENDIAN" */
566 data->data = talloc_size(ctx, sizeof(uint32_t));
567 W_ERROR_HAVE_NO_MEMORY(data->data);
568 SIVAL(data->data, 0, vk->data_offset);
569 data->length = sizeof(uint32_t);
570 } else {
571 *data = hbin_get(regf, vk->data_offset);
574 if (data->length < vk->data_length) {
575 DEBUG(1, ("Read data less than indicated data length!\n"));
578 talloc_free(vk);
580 return WERR_OK;
583 static WERROR regf_get_value_by_name(TALLOC_CTX *mem_ctx,
584 struct hive_key *key, const char *name,
585 uint32_t *type, DATA_BLOB *data)
587 unsigned int i;
588 const char *vname;
589 WERROR error;
591 /* FIXME: Do binary search? Is this list sorted at all? */
593 for (i = 0; W_ERROR_IS_OK(error = regf_get_value(mem_ctx, key, i,
594 &vname, type, data));
595 i++) {
596 if (!strcmp(vname, name))
597 return WERR_OK;
600 if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
601 return WERR_FILE_NOT_FOUND;
603 return error;
607 static WERROR regf_get_subkey_by_index(TALLOC_CTX *ctx,
608 const struct hive_key *key,
609 uint32_t idx, const char **name,
610 const char **classname,
611 NTTIME *last_mod_time)
613 DATA_BLOB data;
614 struct regf_key_data *ret;
615 const struct regf_key_data *private_data = (const struct regf_key_data *)key;
616 struct nk_block *nk = private_data->nk;
617 uint32_t key_off=0;
619 if (idx >= nk->num_subkeys)
620 return WERR_NO_MORE_ITEMS;
622 /* Make sure that we don't crash if the key is empty */
623 if (nk->subkeys_offset == -1) {
624 return WERR_NO_MORE_ITEMS;
627 data = hbin_get(private_data->hive, nk->subkeys_offset);
628 if (!data.data) {
629 DEBUG(0, ("Unable to find subkey list at 0x%x\n",
630 nk->subkeys_offset));
631 return WERR_GEN_FAILURE;
634 if (!strncmp((char *)data.data, "li", 2)) {
635 struct li_block li;
636 struct tdr_pull *pull = tdr_pull_init(private_data->hive);
638 DEBUG(10, ("Subkeys in LI list\n"));
639 pull->data = data;
641 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) {
642 DEBUG(0, ("Error parsing LI list\n"));
643 talloc_free(pull);
644 return WERR_GEN_FAILURE;
646 talloc_free(pull);
647 SMB_ASSERT(!strncmp(li.header, "li", 2));
649 if (li.key_count != nk->num_subkeys) {
650 DEBUG(0, ("Subkey counts don't match\n"));
651 return WERR_GEN_FAILURE;
653 key_off = li.nk_offset[idx];
655 } else if (!strncmp((char *)data.data, "lf", 2)) {
656 struct lf_block lf;
657 struct tdr_pull *pull = tdr_pull_init(private_data->hive);
659 DEBUG(10, ("Subkeys in LF list\n"));
660 pull->data = data;
662 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) {
663 DEBUG(0, ("Error parsing LF list\n"));
664 talloc_free(pull);
665 return WERR_GEN_FAILURE;
667 talloc_free(pull);
668 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
670 if (lf.key_count != nk->num_subkeys) {
671 DEBUG(0, ("Subkey counts don't match\n"));
672 return WERR_GEN_FAILURE;
675 key_off = lf.hr[idx].nk_offset;
676 } else if (!strncmp((char *)data.data, "lh", 2)) {
677 struct lh_block lh;
678 struct tdr_pull *pull = tdr_pull_init(private_data->hive);
680 DEBUG(10, ("Subkeys in LH list\n"));
681 pull->data = data;
683 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) {
684 DEBUG(0, ("Error parsing LH list\n"));
685 talloc_free(pull);
686 return WERR_GEN_FAILURE;
688 talloc_free(pull);
689 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
691 if (lh.key_count != nk->num_subkeys) {
692 DEBUG(0, ("Subkey counts don't match\n"));
693 return WERR_GEN_FAILURE;
695 key_off = lh.hr[idx].nk_offset;
696 } else if (!strncmp((char *)data.data, "ri", 2)) {
697 struct ri_block ri;
698 struct tdr_pull *pull = tdr_pull_init(ctx);
699 uint16_t i;
700 uint16_t sublist_count = 0;
702 DEBUG(10, ("Subkeys in RI list\n"));
703 pull->data = data;
705 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) {
706 DEBUG(0, ("Error parsing RI list\n"));
707 talloc_free(pull);
708 return WERR_GEN_FAILURE;
710 SMB_ASSERT(!strncmp(ri.header, "ri", 2));
712 for (i = 0; i < ri.key_count; i++) {
713 DATA_BLOB list_data;
715 /* Get sublist data blob */
716 list_data = hbin_get(private_data->hive, ri.offset[i]);
717 if (!list_data.data) {
718 DEBUG(0, ("Error getting RI list.\n"));
719 talloc_free(pull);
720 return WERR_GEN_FAILURE;
723 pull->data = list_data;
725 if (!strncmp((char *)list_data.data, "li", 2)) {
726 struct li_block li;
728 DEBUG(10, ("Subkeys in RI->LI list\n"));
730 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull,
732 &li))) {
733 DEBUG(0, ("Error parsing LI list from RI\n"));
734 talloc_free(pull);
735 return WERR_GEN_FAILURE;
737 SMB_ASSERT(!strncmp(li.header, "li", 2));
739 /* Advance to next sublist if necessary */
740 if (idx >= sublist_count + li.key_count) {
741 sublist_count += li.key_count;
742 continue;
744 key_off = li.nk_offset[idx - sublist_count];
745 sublist_count += li.key_count;
746 break;
747 } else if (!strncmp((char *)list_data.data, "lh", 2)) {
748 struct lh_block lh;
750 DEBUG(10, ("Subkeys in RI->LH list\n"));
752 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull,
754 &lh))) {
755 DEBUG(0, ("Error parsing LH list from RI\n"));
756 talloc_free(pull);
757 return WERR_GEN_FAILURE;
759 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
761 /* Advance to next sublist if necessary */
762 if (idx >= sublist_count + lh.key_count) {
763 sublist_count += lh.key_count;
764 continue;
766 key_off = lh.hr[idx - sublist_count].nk_offset;
767 sublist_count += lh.key_count;
768 break;
769 } else {
770 DEBUG(0,("Unknown sublist in ri block\n"));
771 talloc_free(pull);
773 return WERR_GEN_FAILURE;
777 talloc_free(pull);
780 if (idx > sublist_count) {
781 return WERR_NO_MORE_ITEMS;
784 } else {
785 DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n",
786 nk->subkeys_offset, data.data[0], data.data[1]));
787 return WERR_GEN_FAILURE;
790 ret = regf_get_key (ctx, private_data->hive, key_off);
792 if (classname != NULL) {
793 if (ret->nk->clsname_offset != -1) {
794 DATA_BLOB db = hbin_get(ret->hive,
795 ret->nk->clsname_offset);
796 *classname = talloc_strndup(ctx,
797 (char*)db.data,
798 ret->nk->clsname_length);
799 W_ERROR_HAVE_NO_MEMORY(*classname);
800 } else
801 *classname = NULL;
804 if (last_mod_time != NULL)
805 *last_mod_time = ret->nk->last_change;
807 if (name != NULL)
808 *name = talloc_steal(ctx, ret->nk->key_name);
810 talloc_free(ret);
812 return WERR_OK;
815 static WERROR regf_match_subkey_by_name(TALLOC_CTX *ctx,
816 const struct hive_key *key,
817 uint32_t offset,
818 const char *name, uint32_t *ret)
820 DATA_BLOB subkey_data;
821 struct nk_block subkey;
822 struct tdr_pull *pull;
823 const struct regf_key_data *private_data =
824 (const struct regf_key_data *)key;
826 subkey_data = hbin_get(private_data->hive, offset);
827 if (!subkey_data.data) {
828 DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
829 return WERR_GEN_FAILURE;
832 pull = tdr_pull_init(ctx);
834 pull->data = subkey_data;
836 if (NT_STATUS_IS_ERR(tdr_pull_nk_block(pull, ctx, &subkey))) {
837 DEBUG(0, ("Error parsing NK structure.\n"));
838 talloc_free(pull);
839 return WERR_GEN_FAILURE;
841 talloc_free(pull);
843 if (strncmp(subkey.header, "nk", 2)) {
844 DEBUG(0, ("Not an NK structure.\n"));
845 return WERR_GEN_FAILURE;
848 if (!strcasecmp(subkey.key_name, name)) {
849 *ret = offset;
850 } else {
851 *ret = 0;
853 return WERR_OK;
856 static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx,
857 const struct hive_key *key,
858 const char *name,
859 struct hive_key **ret)
861 DATA_BLOB data;
862 const struct regf_key_data *private_data =
863 (const struct regf_key_data *)key;
864 struct nk_block *nk = private_data->nk;
865 uint32_t key_off = 0;
867 /* Make sure that we don't crash if the key is empty */
868 if (nk->subkeys_offset == -1) {
869 return WERR_FILE_NOT_FOUND;
872 data = hbin_get(private_data->hive, nk->subkeys_offset);
873 if (!data.data) {
874 DEBUG(0, ("Unable to find subkey list\n"));
875 return WERR_GEN_FAILURE;
878 if (!strncmp((char *)data.data, "li", 2)) {
879 struct li_block li;
880 struct tdr_pull *pull = tdr_pull_init(ctx);
881 uint16_t i;
883 DEBUG(10, ("Subkeys in LI list\n"));
884 pull->data = data;
886 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) {
887 DEBUG(0, ("Error parsing LI list\n"));
888 talloc_free(pull);
889 return WERR_GEN_FAILURE;
891 talloc_free(pull);
892 SMB_ASSERT(!strncmp(li.header, "li", 2));
894 if (li.key_count != nk->num_subkeys) {
895 DEBUG(0, ("Subkey counts don't match\n"));
896 return WERR_GEN_FAILURE;
899 for (i = 0; i < li.key_count; i++) {
900 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
901 li.nk_offset[i],
902 name,
903 &key_off));
904 if (key_off != 0)
905 break;
907 if (key_off == 0)
908 return WERR_FILE_NOT_FOUND;
909 } else if (!strncmp((char *)data.data, "lf", 2)) {
910 struct lf_block lf;
911 struct tdr_pull *pull = tdr_pull_init(ctx);
912 uint16_t i;
914 DEBUG(10, ("Subkeys in LF list\n"));
915 pull->data = data;
917 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) {
918 DEBUG(0, ("Error parsing LF list\n"));
919 talloc_free(pull);
920 return WERR_GEN_FAILURE;
922 talloc_free(pull);
923 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
925 if (lf.key_count != nk->num_subkeys) {
926 DEBUG(0, ("Subkey counts don't match\n"));
927 return WERR_GEN_FAILURE;
930 for (i = 0; i < lf.key_count; i++) {
931 if (strncmp(lf.hr[i].hash, name, 4)) {
932 continue;
934 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk,
935 key,
936 lf.hr[i].nk_offset,
937 name,
938 &key_off));
939 if (key_off != 0)
940 break;
942 if (key_off == 0)
943 return WERR_FILE_NOT_FOUND;
944 } else if (!strncmp((char *)data.data, "lh", 2)) {
945 struct lh_block lh;
946 struct tdr_pull *pull = tdr_pull_init(ctx);
947 uint16_t i;
948 uint32_t hash;
950 DEBUG(10, ("Subkeys in LH list\n"));
951 pull->data = data;
953 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) {
954 DEBUG(0, ("Error parsing LH list\n"));
955 talloc_free(pull);
956 return WERR_GEN_FAILURE;
958 talloc_free(pull);
959 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
961 if (lh.key_count != nk->num_subkeys) {
962 DEBUG(0, ("Subkey counts don't match\n"));
963 return WERR_GEN_FAILURE;
966 hash = regf_create_lh_hash(name);
967 for (i = 0; i < lh.key_count; i++) {
968 if (lh.hr[i].base37 != hash) {
969 continue;
971 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk,
972 key,
973 lh.hr[i].nk_offset,
974 name,
975 &key_off));
976 if (key_off != 0)
977 break;
979 if (key_off == 0)
980 return WERR_FILE_NOT_FOUND;
981 } else if (!strncmp((char *)data.data, "ri", 2)) {
982 struct ri_block ri;
983 struct tdr_pull *pull = tdr_pull_init(ctx);
984 uint16_t i, j;
986 DEBUG(10, ("Subkeys in RI list\n"));
987 pull->data = data;
989 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) {
990 DEBUG(0, ("Error parsing RI list\n"));
991 talloc_free(pull);
992 return WERR_GEN_FAILURE;
994 SMB_ASSERT(!strncmp(ri.header, "ri", 2));
996 for (i = 0; i < ri.key_count; i++) {
997 DATA_BLOB list_data;
999 /* Get sublist data blob */
1000 list_data = hbin_get(private_data->hive, ri.offset[i]);
1001 if (list_data.data == NULL) {
1002 DEBUG(0, ("Error getting RI list.\n"));
1003 talloc_free(pull);
1004 return WERR_GEN_FAILURE;
1007 pull->data = list_data;
1009 if (!strncmp((char *)list_data.data, "li", 2)) {
1010 struct li_block li;
1012 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull,
1014 &li))) {
1015 DEBUG(0, ("Error parsing LI list from RI\n"));
1016 talloc_free(pull);
1017 return WERR_GEN_FAILURE;
1019 SMB_ASSERT(!strncmp(li.header, "li", 2));
1021 for (j = 0; j < li.key_count; j++) {
1022 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
1023 li.nk_offset[j],
1024 name,
1025 &key_off));
1026 if (key_off)
1027 break;
1029 } else if (!strncmp((char *)list_data.data, "lh", 2)) {
1030 struct lh_block lh;
1031 uint32_t hash;
1033 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull,
1035 &lh))) {
1036 DEBUG(0, ("Error parsing LH list from RI\n"));
1037 talloc_free(pull);
1038 return WERR_GEN_FAILURE;
1040 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1042 hash = regf_create_lh_hash(name);
1043 for (j = 0; j < lh.key_count; j++) {
1044 if (lh.hr[j].base37 != hash) {
1045 continue;
1047 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
1048 lh.hr[j].nk_offset,
1049 name,
1050 &key_off));
1051 if (key_off)
1052 break;
1055 if (key_off)
1056 break;
1058 talloc_free(pull);
1059 if (!key_off)
1060 return WERR_FILE_NOT_FOUND;
1061 } else {
1062 DEBUG(0, ("Unknown subkey list type.\n"));
1063 return WERR_GEN_FAILURE;
1066 *ret = (struct hive_key *)regf_get_key(ctx, private_data->hive,
1067 key_off);
1068 return WERR_OK;
1071 static WERROR regf_set_sec_desc(struct hive_key *key,
1072 const struct security_descriptor *sec_desc)
1074 const struct regf_key_data *private_data =
1075 (const struct regf_key_data *)key;
1076 struct sk_block cur_sk, sk, new_sk;
1077 struct regf_data *regf = private_data->hive;
1078 struct nk_block root;
1079 DATA_BLOB data;
1080 uint32_t sk_offset, cur_sk_offset;
1081 bool update_cur_sk = false;
1083 /* Get the root nk */
1084 hbin_get_tdr(regf, regf->header->data_offset, regf,
1085 (tdr_pull_fn_t) tdr_pull_nk_block, &root);
1087 /* Push the security descriptor to a blob */
1088 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(&data, regf,
1089 sec_desc, (ndr_push_flags_fn_t)ndr_push_security_descriptor))) {
1090 DEBUG(0, ("Unable to push security descriptor\n"));
1091 return WERR_GEN_FAILURE;
1094 /* Get the current security descriptor for the key */
1095 if (!hbin_get_tdr(regf, private_data->nk->sk_offset, regf,
1096 (tdr_pull_fn_t) tdr_pull_sk_block, &cur_sk)) {
1097 DEBUG(0, ("Unable to find security descriptor for current key\n"));
1098 return WERR_FILE_NOT_FOUND;
1100 /* If there's no change, change nothing. */
1101 if (memcmp(data.data, cur_sk.sec_desc,
1102 MIN(data.length, cur_sk.rec_size)) == 0) {
1103 return WERR_OK;
1106 /* Delete the current sk if only this key is using it */
1107 if (cur_sk.ref_cnt == 1) {
1108 /* Get the previous security descriptor for the key */
1109 if (!hbin_get_tdr(regf, cur_sk.prev_offset, regf,
1110 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1111 DEBUG(0, ("Unable to find prev security descriptor for current key\n"));
1112 return WERR_FILE_NOT_FOUND;
1114 /* Change and store the previous security descriptor */
1115 sk.next_offset = cur_sk.next_offset;
1116 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block,
1117 cur_sk.prev_offset, &sk);
1119 /* Get the next security descriptor for the key */
1120 if (!hbin_get_tdr(regf, cur_sk.next_offset, regf,
1121 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1122 DEBUG(0, ("Unable to find next security descriptor for current key\n"));
1123 return WERR_FILE_NOT_FOUND;
1125 /* Change and store the next security descriptor */
1126 sk.prev_offset = cur_sk.prev_offset;
1127 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block,
1128 cur_sk.next_offset, &sk);
1130 hbin_free(regf, private_data->nk->sk_offset);
1131 } else {
1132 /* This key will no longer be referring to this sk */
1133 cur_sk.ref_cnt--;
1134 update_cur_sk = true;
1137 sk_offset = root.sk_offset;
1139 do {
1140 cur_sk_offset = sk_offset;
1141 if (!hbin_get_tdr(regf, sk_offset, regf,
1142 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1143 DEBUG(0, ("Unable to find security descriptor\n"));
1144 return WERR_FILE_NOT_FOUND;
1146 if (memcmp(data.data, sk.sec_desc, MIN(data.length, sk.rec_size)) == 0) {
1147 private_data->nk->sk_offset = sk_offset;
1148 sk.ref_cnt++;
1149 hbin_store_tdr_resize(regf,
1150 (tdr_push_fn_t) tdr_push_sk_block,
1151 sk_offset, &sk);
1152 hbin_store_tdr_resize(regf,
1153 (tdr_push_fn_t) tdr_push_nk_block,
1154 private_data->offset,
1155 private_data->nk);
1156 return WERR_OK;
1158 sk_offset = sk.next_offset;
1159 } while (sk_offset != root.sk_offset);
1161 ZERO_STRUCT(new_sk);
1162 new_sk.header = "sk";
1163 new_sk.prev_offset = cur_sk_offset;
1164 new_sk.next_offset = root.sk_offset;
1165 new_sk.ref_cnt = 1;
1166 new_sk.rec_size = data.length;
1167 new_sk.sec_desc = data.data;
1169 sk_offset = hbin_store_tdr(regf,
1170 (tdr_push_fn_t) tdr_push_sk_block,
1171 &new_sk);
1172 if (sk_offset == -1) {
1173 DEBUG(0, ("Error storing sk block\n"));
1174 return WERR_GEN_FAILURE;
1176 private_data->nk->sk_offset = sk_offset;
1178 if (update_cur_sk) {
1179 hbin_store_tdr_resize(regf,
1180 (tdr_push_fn_t) tdr_push_sk_block,
1181 private_data->nk->sk_offset, &cur_sk);
1184 /* Get the previous security descriptor for the key */
1185 if (!hbin_get_tdr(regf, new_sk.prev_offset, regf,
1186 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1187 DEBUG(0, ("Unable to find security descriptor for previous key\n"));
1188 return WERR_FILE_NOT_FOUND;
1190 /* Change and store the previous security descriptor */
1191 sk.next_offset = sk_offset;
1192 hbin_store_tdr_resize(regf,
1193 (tdr_push_fn_t) tdr_push_sk_block,
1194 cur_sk.prev_offset, &sk);
1196 /* Get the next security descriptor for the key (always root, as we append) */
1197 if (!hbin_get_tdr(regf, new_sk.next_offset, regf,
1198 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1199 DEBUG(0, ("Unable to find security descriptor for current key\n"));
1200 return WERR_FILE_NOT_FOUND;
1202 /* Change and store the next security descriptor (always root, as we append) */
1203 sk.prev_offset = sk_offset;
1204 hbin_store_tdr_resize(regf,
1205 (tdr_push_fn_t) tdr_push_sk_block,
1206 root.sk_offset, &sk);
1209 /* Store the nk. */
1210 hbin_store_tdr_resize(regf,
1211 (tdr_push_fn_t) tdr_push_sk_block,
1212 private_data->offset, private_data->nk);
1213 return WERR_OK;
1216 static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct hive_key *key,
1217 struct security_descriptor **sd)
1219 const struct regf_key_data *private_data =
1220 (const struct regf_key_data *)key;
1221 struct sk_block sk;
1222 struct regf_data *regf = private_data->hive;
1223 DATA_BLOB data;
1225 if (!hbin_get_tdr(regf, private_data->nk->sk_offset, ctx,
1226 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1227 DEBUG(0, ("Unable to find security descriptor\n"));
1228 return WERR_GEN_FAILURE;
1231 if (strcmp(sk.header, "sk") != 0) {
1232 DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
1233 return WERR_GEN_FAILURE;
1236 *sd = talloc(ctx, struct security_descriptor);
1237 W_ERROR_HAVE_NO_MEMORY(*sd);
1239 data.data = sk.sec_desc;
1240 data.length = sk.rec_size;
1241 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&data, ctx, *sd,
1242 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
1243 DEBUG(0, ("Error parsing security descriptor\n"));
1244 return WERR_GEN_FAILURE;
1247 return WERR_OK;
1250 static WERROR regf_sl_add_entry(struct regf_data *regf, uint32_t list_offset,
1251 const char *name,
1252 uint32_t key_offset, uint32_t *ret)
1254 DATA_BLOB data;
1256 /* Create a new key if necessary */
1257 if (list_offset == -1) {
1258 if (regf->header->version.major != 1) {
1259 DEBUG(0, ("Can't store keys in unknown registry format\n"));
1260 return WERR_NOT_SUPPORTED;
1262 if (regf->header->version.minor < 3) {
1263 /* Store LI */
1264 struct li_block li;
1265 ZERO_STRUCT(li);
1266 li.header = "li";
1267 li.key_count = 1;
1269 li.nk_offset = talloc_array(regf, uint32_t, 1);
1270 W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
1271 li.nk_offset[0] = key_offset;
1273 *ret = hbin_store_tdr(regf,
1274 (tdr_push_fn_t) tdr_push_li_block,
1275 &li);
1277 talloc_free(li.nk_offset);
1278 } else if (regf->header->version.minor == 3 ||
1279 regf->header->version.minor == 4) {
1280 /* Store LF */
1281 struct lf_block lf;
1282 ZERO_STRUCT(lf);
1283 lf.header = "lf";
1284 lf.key_count = 1;
1286 lf.hr = talloc_array(regf, struct hash_record, 1);
1287 W_ERROR_HAVE_NO_MEMORY(lf.hr);
1288 lf.hr[0].nk_offset = key_offset;
1289 lf.hr[0].hash = talloc_strndup(lf.hr, name, 4);
1290 W_ERROR_HAVE_NO_MEMORY(lf.hr[0].hash);
1292 *ret = hbin_store_tdr(regf,
1293 (tdr_push_fn_t) tdr_push_lf_block,
1294 &lf);
1296 talloc_free(lf.hr);
1297 } else if (regf->header->version.minor == 5) {
1298 /* Store LH */
1299 struct lh_block lh;
1300 ZERO_STRUCT(lh);
1301 lh.header = "lh";
1302 lh.key_count = 1;
1304 lh.hr = talloc_array(regf, struct lh_hash, 1);
1305 W_ERROR_HAVE_NO_MEMORY(lh.hr);
1306 lh.hr[0].nk_offset = key_offset;
1307 lh.hr[0].base37 = regf_create_lh_hash(name);
1309 *ret = hbin_store_tdr(regf,
1310 (tdr_push_fn_t) tdr_push_lh_block,
1311 &lh);
1313 talloc_free(lh.hr);
1315 return WERR_OK;
1318 data = hbin_get(regf, list_offset);
1319 if (!data.data) {
1320 DEBUG(0, ("Unable to find subkey list\n"));
1321 return WERR_FILE_NOT_FOUND;
1324 if (!strncmp((char *)data.data, "li", 2)) {
1325 struct tdr_pull *pull = tdr_pull_init(regf);
1326 struct li_block li;
1327 struct nk_block sub_nk;
1328 int32_t i, j;
1330 pull->data = data;
1332 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) {
1333 DEBUG(0, ("Error parsing LI list\n"));
1334 talloc_free(pull);
1335 return WERR_FILE_NOT_FOUND;
1337 talloc_free(pull);
1339 if (strncmp(li.header, "li", 2) != 0) {
1340 abort();
1341 DEBUG(0, ("LI header corrupt\n"));
1342 return WERR_FILE_NOT_FOUND;
1346 * Find the position to store the pointer
1347 * Extensive testing reveils that at least on windows 7 subkeys
1348 * *MUST* be stored in alphabetical order
1350 for (i = 0; i < li.key_count; i++) {
1351 /* Get the nk */
1352 hbin_get_tdr(regf, li.nk_offset[i], regf,
1353 (tdr_pull_fn_t) tdr_pull_nk_block, &sub_nk);
1354 if (strcasecmp(name, sub_nk.key_name) < 0) {
1355 break;
1359 li.nk_offset = talloc_realloc(regf, li.nk_offset,
1360 uint32_t, li.key_count+1);
1361 W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
1363 /* Move everything behind this offset */
1364 for (j = li.key_count - 1; j >= i; j--) {
1365 li.nk_offset[j+1] = li.nk_offset[j];
1368 li.nk_offset[i] = key_offset;
1369 li.key_count++;
1370 *ret = hbin_store_tdr_resize(regf,
1371 (tdr_push_fn_t)tdr_push_li_block,
1372 list_offset, &li);
1374 talloc_free(li.nk_offset);
1375 } else if (!strncmp((char *)data.data, "lf", 2)) {
1376 struct tdr_pull *pull = tdr_pull_init(regf);
1377 struct lf_block lf;
1378 struct nk_block sub_nk;
1379 int32_t i, j;
1381 pull->data = data;
1383 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) {
1384 DEBUG(0, ("Error parsing LF list\n"));
1385 talloc_free(pull);
1386 return WERR_FILE_NOT_FOUND;
1388 talloc_free(pull);
1389 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
1392 * Find the position to store the hash record
1393 * Extensive testing reveils that at least on windows 7 subkeys
1394 * *MUST* be stored in alphabetical order
1396 for (i = 0; i < lf.key_count; i++) {
1397 /* Get the nk */
1398 hbin_get_tdr(regf, lf.hr[i].nk_offset, regf,
1399 (tdr_pull_fn_t) tdr_pull_nk_block, &sub_nk);
1400 if (strcasecmp(name, sub_nk.key_name) < 0) {
1401 break;
1405 lf.hr = talloc_realloc(regf, lf.hr, struct hash_record,
1406 lf.key_count+1);
1407 W_ERROR_HAVE_NO_MEMORY(lf.hr);
1409 /* Move everything behind this hash record */
1410 for (j = lf.key_count - 1; j >= i; j--) {
1411 lf.hr[j+1] = lf.hr[j];
1414 lf.hr[i].nk_offset = key_offset;
1415 lf.hr[i].hash = talloc_strndup(lf.hr, name, 4);
1416 W_ERROR_HAVE_NO_MEMORY(lf.hr[lf.key_count].hash);
1417 lf.key_count++;
1418 *ret = hbin_store_tdr_resize(regf,
1419 (tdr_push_fn_t)tdr_push_lf_block,
1420 list_offset, &lf);
1422 talloc_free(lf.hr);
1423 } else if (!strncmp((char *)data.data, "lh", 2)) {
1424 struct tdr_pull *pull = tdr_pull_init(regf);
1425 struct lh_block lh;
1426 struct nk_block sub_nk;
1427 int32_t i, j;
1429 pull->data = data;
1431 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) {
1432 DEBUG(0, ("Error parsing LH list\n"));
1433 talloc_free(pull);
1434 return WERR_FILE_NOT_FOUND;
1436 talloc_free(pull);
1437 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1440 * Find the position to store the hash record
1441 * Extensive testing reveils that at least on windows 7 subkeys
1442 * *MUST* be stored in alphabetical order
1444 for (i = 0; i < lh.key_count; i++) {
1445 /* Get the nk */
1446 hbin_get_tdr(regf, lh.hr[i].nk_offset, regf,
1447 (tdr_pull_fn_t) tdr_pull_nk_block, &sub_nk);
1448 if (strcasecmp(name, sub_nk.key_name) < 0) {
1449 break;
1453 lh.hr = talloc_realloc(regf, lh.hr, struct lh_hash,
1454 lh.key_count+1);
1455 W_ERROR_HAVE_NO_MEMORY(lh.hr);
1457 /* Move everything behind this hash record */
1458 for (j = lh.key_count - 1; j >= i; j--) {
1459 lh.hr[j+1] = lh.hr[j];
1462 lh.hr[i].nk_offset = key_offset;
1463 lh.hr[i].base37 = regf_create_lh_hash(name);
1464 lh.key_count++;
1465 *ret = hbin_store_tdr_resize(regf,
1466 (tdr_push_fn_t)tdr_push_lh_block,
1467 list_offset, &lh);
1469 talloc_free(lh.hr);
1470 } else if (!strncmp((char *)data.data, "ri", 2)) {
1471 /* FIXME */
1472 DEBUG(0, ("Adding to 'ri' subkey list is not supported yet.\n"));
1473 return WERR_NOT_SUPPORTED;
1474 } else {
1475 DEBUG(0, ("Cannot add to unknown subkey list\n"));
1476 return WERR_FILE_NOT_FOUND;
1479 return WERR_OK;
1482 static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset,
1483 uint32_t key_offset, uint32_t *ret)
1485 DATA_BLOB data;
1487 data = hbin_get(regf, list_offset);
1488 if (!data.data) {
1489 DEBUG(0, ("Unable to find subkey list\n"));
1490 return WERR_FILE_NOT_FOUND;
1493 if (strncmp((char *)data.data, "li", 2) == 0) {
1494 struct li_block li;
1495 struct tdr_pull *pull = tdr_pull_init(regf);
1496 uint16_t i;
1497 bool found_offset = false;
1499 DEBUG(10, ("Subkeys in LI list\n"));
1501 pull->data = data;
1503 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) {
1504 DEBUG(0, ("Error parsing LI list\n"));
1505 talloc_free(pull);
1506 return WERR_FILE_NOT_FOUND;
1508 talloc_free(pull);
1510 SMB_ASSERT(!strncmp(li.header, "li", 2));
1512 for (i = 0; i < li.key_count; i++) {
1513 if (found_offset) {
1514 li.nk_offset[i-1] = li.nk_offset[i];
1516 if (li.nk_offset[i] == key_offset) {
1517 found_offset = true;
1518 continue;
1521 if (!found_offset) {
1522 DEBUG(2, ("Subkey not found\n"));
1523 return WERR_FILE_NOT_FOUND;
1525 li.key_count--;
1527 /* If there are no entries left, free the subkey list */
1528 if (li.key_count == 0) {
1529 hbin_free(regf, list_offset);
1530 *ret = -1;
1533 /* Store li block */
1534 *ret = hbin_store_tdr_resize(regf,
1535 (tdr_push_fn_t) tdr_push_li_block,
1536 list_offset, &li);
1537 } else if (strncmp((char *)data.data, "lf", 2) == 0) {
1538 struct lf_block lf;
1539 struct tdr_pull *pull = tdr_pull_init(regf);
1540 uint16_t i;
1541 bool found_offset = false;
1543 DEBUG(10, ("Subkeys in LF list\n"));
1545 pull->data = data;
1547 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) {
1548 DEBUG(0, ("Error parsing LF list\n"));
1549 talloc_free(pull);
1550 return WERR_FILE_NOT_FOUND;
1552 talloc_free(pull);
1554 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
1556 for (i = 0; i < lf.key_count; i++) {
1557 if (found_offset) {
1558 lf.hr[i-1] = lf.hr[i];
1559 continue;
1561 if (lf.hr[i].nk_offset == key_offset) {
1562 found_offset = 1;
1563 continue;
1566 if (!found_offset) {
1567 DEBUG(2, ("Subkey not found\n"));
1568 return WERR_FILE_NOT_FOUND;
1570 lf.key_count--;
1572 /* If there are no entries left, free the subkey list */
1573 if (lf.key_count == 0) {
1574 hbin_free(regf, list_offset);
1575 *ret = -1;
1576 return WERR_OK;
1579 /* Store lf block */
1580 *ret = hbin_store_tdr_resize(regf,
1581 (tdr_push_fn_t) tdr_push_lf_block,
1582 list_offset, &lf);
1583 } else if (strncmp((char *)data.data, "lh", 2) == 0) {
1584 struct lh_block lh;
1585 struct tdr_pull *pull = tdr_pull_init(regf);
1586 uint16_t i;
1587 bool found_offset = false;
1589 DEBUG(10, ("Subkeys in LH list\n"));
1591 pull->data = data;
1593 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) {
1594 DEBUG(0, ("Error parsing LF list\n"));
1595 talloc_free(pull);
1596 return WERR_FILE_NOT_FOUND;
1598 talloc_free(pull);
1600 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1602 for (i = 0; i < lh.key_count; i++) {
1603 if (found_offset) {
1604 lh.hr[i-1] = lh.hr[i];
1605 continue;
1607 if (lh.hr[i].nk_offset == key_offset) {
1608 found_offset = 1;
1609 continue;
1612 if (!found_offset) {
1613 DEBUG(0, ("Subkey not found\n"));
1614 return WERR_FILE_NOT_FOUND;
1616 lh.key_count--;
1618 /* If there are no entries left, free the subkey list */
1619 if (lh.key_count == 0) {
1620 hbin_free(regf, list_offset);
1621 *ret = -1;
1622 return WERR_OK;
1625 /* Store lh block */
1626 *ret = hbin_store_tdr_resize(regf,
1627 (tdr_push_fn_t) tdr_push_lh_block,
1628 list_offset, &lh);
1629 } else if (strncmp((char *)data.data, "ri", 2) == 0) {
1630 /* FIXME */
1631 DEBUG(0, ("Sorry, deletion from ri block is not supported yet.\n"));
1632 return WERR_NOT_SUPPORTED;
1633 } else {
1634 DEBUG (0, ("Unknown header found in subkey list.\n"));
1635 return WERR_FILE_NOT_FOUND;
1637 return WERR_OK;
1640 static WERROR regf_del_value(TALLOC_CTX *mem_ctx, struct hive_key *key,
1641 const char *name)
1643 struct regf_key_data *private_data = (struct regf_key_data *)key;
1644 struct regf_data *regf = private_data->hive;
1645 struct nk_block *nk = private_data->nk;
1646 struct vk_block vk;
1647 uint32_t vk_offset;
1648 bool found_offset = false;
1649 DATA_BLOB values;
1650 unsigned int i;
1652 if (nk->values_offset == -1) {
1653 return WERR_FILE_NOT_FOUND;
1656 values = hbin_get(regf, nk->values_offset);
1658 for (i = 0; i < nk->num_values; i++) {
1659 if (found_offset) {
1660 ((uint32_t *)values.data)[i-1] = ((uint32_t *) values.data)[i];
1661 } else {
1662 vk_offset = IVAL(values.data, i * 4);
1663 if (!hbin_get_tdr(regf, vk_offset, private_data,
1664 (tdr_pull_fn_t)tdr_pull_vk_block,
1665 &vk)) {
1666 DEBUG(0, ("Unable to get VK block at %d\n",
1667 vk_offset));
1668 return WERR_FILE_NOT_FOUND;
1670 if (strcmp(vk.data_name, name) == 0) {
1671 hbin_free(regf, vk_offset);
1672 found_offset = true;
1676 if (!found_offset) {
1677 return WERR_FILE_NOT_FOUND;
1678 } else {
1679 nk->num_values--;
1680 values.length = (nk->num_values)*4;
1683 /* Store values list and nk */
1684 if (nk->num_values == 0) {
1685 hbin_free(regf, nk->values_offset);
1686 nk->values_offset = -1;
1687 } else {
1688 nk->values_offset = hbin_store_resize(regf,
1689 nk->values_offset,
1690 values);
1692 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
1693 private_data->offset, nk);
1695 return regf_save_hbin(private_data->hive, 0);
1699 static WERROR regf_del_key(TALLOC_CTX *mem_ctx, const struct hive_key *parent,
1700 const char *name)
1702 const struct regf_key_data *private_data =
1703 (const struct regf_key_data *)parent;
1704 struct regf_key_data *key;
1705 struct nk_block *parent_nk;
1706 WERROR error;
1708 SMB_ASSERT(private_data);
1710 parent_nk = private_data->nk;
1712 if (parent_nk->subkeys_offset == -1) {
1713 DEBUG(4, ("Subkey list is empty, this key cannot contain subkeys.\n"));
1714 return WERR_FILE_NOT_FOUND;
1717 /* Find the key */
1718 if (!W_ERROR_IS_OK(regf_get_subkey_by_name(parent_nk, parent, name,
1719 (struct hive_key **)&key))) {
1720 DEBUG(2, ("Key '%s' not found\n", name));
1721 return WERR_FILE_NOT_FOUND;
1724 if (key->nk->subkeys_offset != -1) {
1725 struct hive_key *sk = (struct hive_key *)key;
1726 unsigned int i = key->nk->num_subkeys;
1727 while (i--) {
1728 char *sk_name;
1729 const char *p = NULL;
1731 /* Get subkey information. */
1732 error = regf_get_subkey_by_index(parent_nk, sk, 0,
1734 NULL, NULL);
1735 if (!W_ERROR_IS_OK(error)) {
1736 DEBUG(0, ("Can't retrieve subkey by index.\n"));
1737 return error;
1739 sk_name = discard_const_p(char, p);
1741 /* Delete subkey. */
1742 error = regf_del_key(NULL, sk, sk_name);
1743 if (!W_ERROR_IS_OK(error)) {
1744 DEBUG(0, ("Can't delete key '%s'.\n", sk_name));
1745 return error;
1748 talloc_free(sk_name);
1752 if (key->nk->values_offset != -1) {
1753 struct hive_key *sk = (struct hive_key *)key;
1754 DATA_BLOB data;
1755 unsigned int i = key->nk->num_values;
1756 while (i--) {
1757 char *val_name;
1758 const char *p = NULL;
1760 /* Get value information. */
1761 error = regf_get_value(parent_nk, sk, 0,
1763 NULL, &data);
1764 if (!W_ERROR_IS_OK(error)) {
1765 DEBUG(0, ("Can't retrieve value by index.\n"));
1766 return error;
1768 val_name = discard_const_p(char, p);
1770 /* Delete value. */
1771 error = regf_del_value(NULL, sk, val_name);
1772 if (!W_ERROR_IS_OK(error)) {
1773 DEBUG(0, ("Can't delete value '%s'.\n", val_name));
1774 return error;
1777 talloc_free(val_name);
1781 /* Delete it from the subkey list. */
1782 error = regf_sl_del_entry(private_data->hive, parent_nk->subkeys_offset,
1783 key->offset, &parent_nk->subkeys_offset);
1784 if (!W_ERROR_IS_OK(error)) {
1785 DEBUG(0, ("Can't store new subkey list for parent key. Won't delete.\n"));
1786 return error;
1789 /* Re-store parent key */
1790 parent_nk->num_subkeys--;
1791 hbin_store_tdr_resize(private_data->hive,
1792 (tdr_push_fn_t) tdr_push_nk_block,
1793 private_data->offset, parent_nk);
1795 if (key->nk->clsname_offset != -1) {
1796 hbin_free(private_data->hive, key->nk->clsname_offset);
1798 hbin_free(private_data->hive, key->offset);
1800 return regf_save_hbin(private_data->hive, 0);
1803 static WERROR regf_add_key(TALLOC_CTX *ctx, const struct hive_key *parent,
1804 const char *name, const char *classname,
1805 struct security_descriptor *sec_desc,
1806 struct hive_key **ret)
1808 const struct regf_key_data *private_data =
1809 (const struct regf_key_data *)parent;
1810 struct nk_block *parent_nk = private_data->nk, nk;
1811 struct nk_block *root;
1812 struct regf_data *regf = private_data->hive;
1813 uint32_t offset;
1814 WERROR error;
1816 nk.header = "nk";
1817 nk.type = REG_SUB_KEY;
1818 unix_to_nt_time(&nk.last_change, time(NULL));
1819 nk.uk1 = 0;
1820 nk.parent_offset = private_data->offset;
1821 nk.num_subkeys = 0;
1822 nk.uk2 = 0;
1823 nk.subkeys_offset = -1;
1824 nk.unknown_offset = -1;
1825 nk.num_values = 0;
1826 nk.values_offset = -1;
1827 memset(nk.unk3, 0, sizeof(nk.unk3));
1828 nk.clsname_offset = -1; /* FIXME: fill in */
1829 nk.clsname_length = 0;
1830 nk.key_name = name;
1832 /* Get the security descriptor of the root key */
1833 root = talloc_zero(ctx, struct nk_block);
1834 W_ERROR_HAVE_NO_MEMORY(root);
1836 if (!hbin_get_tdr(regf, regf->header->data_offset, root,
1837 (tdr_pull_fn_t)tdr_pull_nk_block, root)) {
1838 DEBUG(0, ("Unable to find HBIN data for offset 0x%x\n",
1839 regf->header->data_offset));
1840 return WERR_GEN_FAILURE;
1842 nk.sk_offset = root->sk_offset;
1843 talloc_free(root);
1845 /* Store the new nk key */
1846 offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
1848 error = regf_sl_add_entry(regf, parent_nk->subkeys_offset, name, offset,
1849 &parent_nk->subkeys_offset);
1850 if (!W_ERROR_IS_OK(error)) {
1851 hbin_free(regf, offset);
1852 return error;
1855 parent_nk->num_subkeys++;
1857 /* Since the subkey offset of the parent can change, store it again */
1858 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
1859 nk.parent_offset, parent_nk);
1861 *ret = (struct hive_key *)regf_get_key(ctx, regf, offset);
1863 DEBUG(9, ("Storing key %s\n", name));
1864 return regf_save_hbin(private_data->hive, 0);
1867 static WERROR regf_set_value(struct hive_key *key, const char *name,
1868 uint32_t type, const DATA_BLOB data)
1870 struct regf_key_data *private_data = (struct regf_key_data *)key;
1871 struct regf_data *regf = private_data->hive;
1872 struct nk_block *nk = private_data->nk;
1873 struct vk_block vk;
1874 uint32_t i;
1875 uint32_t tmp_vk_offset, vk_offset, old_vk_offset = (uint32_t) -1;
1876 DATA_BLOB values = {0};
1878 ZERO_STRUCT(vk);
1880 /* find the value offset, if it exists */
1881 if (nk->values_offset != -1) {
1882 values = hbin_get(regf, nk->values_offset);
1884 for (i = 0; i < nk->num_values; i++) {
1885 tmp_vk_offset = IVAL(values.data, i * 4);
1886 if (!hbin_get_tdr(regf, tmp_vk_offset, private_data,
1887 (tdr_pull_fn_t)tdr_pull_vk_block,
1888 &vk)) {
1889 DEBUG(0, ("Unable to get VK block at 0x%x\n",
1890 tmp_vk_offset));
1891 return WERR_GEN_FAILURE;
1893 if (strcmp(vk.data_name, name) == 0) {
1894 old_vk_offset = tmp_vk_offset;
1895 break;
1900 /* If it's new, create the vk struct, if it's old, free the old data. */
1901 if (old_vk_offset == -1) {
1902 vk.header = "vk";
1903 if (name != NULL && name[0] != '\0') {
1904 vk.flag = 1;
1905 vk.data_name = name;
1906 vk.name_length = strlen(name);
1907 } else {
1908 vk.flag = 0;
1909 vk.data_name = NULL;
1910 vk.name_length = 0;
1912 } else {
1913 /* Free data, if any */
1914 if (!(vk.data_length & 0x80000000)) {
1915 hbin_free(regf, vk.data_offset);
1919 /* Set the type and data */
1920 vk.data_length = data.length;
1921 vk.data_type = type;
1922 if ((type == REG_DWORD) || (type == REG_DWORD_BIG_ENDIAN)) {
1923 if (vk.data_length != sizeof(uint32_t)) {
1924 DEBUG(0, ("DWORD or DWORD_BIG_ENDIAN value with size other than 4 byte!\n"));
1925 return WERR_NOT_SUPPORTED;
1927 vk.data_length |= 0x80000000;
1928 vk.data_offset = IVAL(data.data, 0);
1929 } else {
1930 /* Store data somewhere */
1931 vk.data_offset = hbin_store(regf, data);
1933 if (old_vk_offset == -1) {
1934 /* Store new vk */
1935 vk_offset = hbin_store_tdr(regf,
1936 (tdr_push_fn_t) tdr_push_vk_block,
1937 &vk);
1938 } else {
1939 /* Store vk at offset */
1940 vk_offset = hbin_store_tdr_resize(regf,
1941 (tdr_push_fn_t) tdr_push_vk_block,
1942 old_vk_offset ,&vk);
1945 /* Re-allocate the value list */
1946 if (nk->values_offset == -1) {
1947 nk->values_offset = hbin_store_tdr(regf,
1948 (tdr_push_fn_t) tdr_push_uint32,
1949 &vk_offset);
1950 nk->num_values = 1;
1951 } else {
1953 /* Change if we're changing, otherwise we're adding the value */
1954 if (old_vk_offset != -1) {
1955 /* Find and overwrite the offset. */
1956 for (i = 0; i < nk->num_values; i++) {
1957 if (IVAL(values.data, i * 4) == old_vk_offset) {
1958 SIVAL(values.data, i * 4, vk_offset);
1959 break;
1962 } else {
1963 /* Create a new value list */
1964 DATA_BLOB value_list;
1966 value_list.length = (nk->num_values+1)*4;
1967 value_list.data = (uint8_t *)talloc_array(private_data,
1968 uint32_t,
1969 nk->num_values+1);
1970 W_ERROR_HAVE_NO_MEMORY(value_list.data);
1971 memcpy(value_list.data, values.data, nk->num_values * 4);
1973 SIVAL(value_list.data, nk->num_values * 4, vk_offset);
1974 nk->num_values++;
1975 nk->values_offset = hbin_store_resize(regf,
1976 nk->values_offset,
1977 value_list);
1981 hbin_store_tdr_resize(regf,
1982 (tdr_push_fn_t) tdr_push_nk_block,
1983 private_data->offset, nk);
1984 return regf_save_hbin(private_data->hive, 0);
1987 static WERROR regf_save_hbin(struct regf_data *regf, bool flush)
1989 struct tdr_push *push = tdr_push_init(regf);
1990 unsigned int i;
1992 W_ERROR_HAVE_NO_MEMORY(push);
1994 /* Only write once every 5 seconds, or when flush is set */
1995 if (!flush && regf->last_write + 5 >= time(NULL)) {
1996 return WERR_OK;
1999 regf->last_write = time(NULL);
2001 if (lseek(regf->fd, 0, SEEK_SET) == -1) {
2002 DEBUG(0, ("Error lseeking in regf file\n"));
2003 return WERR_GEN_FAILURE;
2006 /* Recompute checksum */
2007 if (NT_STATUS_IS_ERR(tdr_push_regf_hdr(push, regf->header))) {
2008 DEBUG(0, ("Failed to push regf header\n"));
2009 return WERR_GEN_FAILURE;
2011 regf->header->chksum = regf_hdr_checksum(push->data.data);
2012 talloc_free(push);
2014 if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd,
2015 (tdr_push_fn_t)tdr_push_regf_hdr,
2016 regf->header))) {
2017 DEBUG(0, ("Error writing registry file header\n"));
2018 return WERR_GEN_FAILURE;
2021 if (lseek(regf->fd, 0x1000, SEEK_SET) == -1) {
2022 DEBUG(0, ("Error lseeking to 0x1000 in regf file\n"));
2023 return WERR_GEN_FAILURE;
2026 for (i = 0; regf->hbins[i]; i++) {
2027 if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd,
2028 (tdr_push_fn_t)tdr_push_hbin_block,
2029 regf->hbins[i]))) {
2030 DEBUG(0, ("Error writing HBIN block\n"));
2031 return WERR_GEN_FAILURE;
2035 return WERR_OK;
2038 WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx,
2039 const char *location,
2040 int minor_version, struct hive_key **key)
2042 struct regf_data *regf;
2043 struct regf_hdr *regf_hdr;
2044 struct nk_block nk;
2045 struct sk_block sk;
2046 WERROR error;
2047 DATA_BLOB data;
2048 struct security_descriptor *sd;
2049 uint32_t sk_offset;
2051 regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
2053 W_ERROR_HAVE_NO_MEMORY(regf);
2055 DEBUG(5, ("Attempting to create registry file\n"));
2057 /* Get the header */
2058 regf->fd = creat(location, 0644);
2060 if (regf->fd == -1) {
2061 DEBUG(0,("Could not create file: %s, %s\n", location,
2062 strerror(errno)));
2063 talloc_free(regf);
2064 return WERR_GEN_FAILURE;
2067 regf_hdr = talloc_zero(regf, struct regf_hdr);
2068 W_ERROR_HAVE_NO_MEMORY(regf_hdr);
2069 regf_hdr->REGF_ID = "regf";
2070 unix_to_nt_time(&regf_hdr->modtime, time(NULL));
2071 regf_hdr->version.major = 1;
2072 regf_hdr->version.minor = minor_version;
2073 regf_hdr->last_block = 0x1000; /* Block size */
2074 regf_hdr->description = talloc_strdup(regf_hdr,
2075 "Registry created by Samba 4");
2076 W_ERROR_HAVE_NO_MEMORY(regf_hdr->description);
2077 regf_hdr->chksum = 0;
2079 regf->header = regf_hdr;
2081 /* Create all hbin blocks */
2082 regf->hbins = talloc_array(regf, struct hbin_block *, 1);
2083 W_ERROR_HAVE_NO_MEMORY(regf->hbins);
2084 regf->hbins[0] = NULL;
2086 nk.header = "nk";
2087 nk.type = REG_ROOT_KEY;
2088 unix_to_nt_time(&nk.last_change, time(NULL));
2089 nk.uk1 = 0;
2090 nk.parent_offset = -1;
2091 nk.num_subkeys = 0;
2092 nk.uk2 = 0;
2093 nk.subkeys_offset = -1;
2094 nk.unknown_offset = -1;
2095 nk.num_values = 0;
2096 nk.values_offset = -1;
2097 memset(nk.unk3, 0, 5 * sizeof(uint32_t));
2098 nk.clsname_offset = -1;
2099 nk.clsname_length = 0;
2100 nk.sk_offset = 0x80;
2101 nk.key_name = "SambaRootKey";
2104 * It should be noted that changing the key_name to something shorter
2105 * creates a shorter nk block, which makes the position of the sk block
2106 * change. All Windows registries I've seen have the sk at 0x80.
2107 * I therefore recommend that our regf files share that offset -- Wilco
2110 /* Create a security descriptor. */
2111 sd = security_descriptor_dacl_create(regf,
2113 NULL, NULL,
2114 SID_NT_AUTHENTICATED_USERS,
2115 SEC_ACE_TYPE_ACCESS_ALLOWED,
2116 SEC_GENERIC_ALL,
2117 SEC_ACE_FLAG_OBJECT_INHERIT,
2118 NULL);
2120 /* Push the security descriptor to a blob */
2121 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(&data, regf,
2122 sd, (ndr_push_flags_fn_t)ndr_push_security_descriptor))) {
2123 DEBUG(0, ("Unable to push security descriptor\n"));
2124 return WERR_GEN_FAILURE;
2127 ZERO_STRUCT(sk);
2128 sk.header = "sk";
2129 sk.prev_offset = 0x80;
2130 sk.next_offset = 0x80;
2131 sk.ref_cnt = 1;
2132 sk.rec_size = data.length;
2133 sk.sec_desc = data.data;
2135 /* Store the new nk key */
2136 regf->header->data_offset = hbin_store_tdr(regf,
2137 (tdr_push_fn_t)tdr_push_nk_block,
2138 &nk);
2139 /* Store the sk block */
2140 sk_offset = hbin_store_tdr(regf,
2141 (tdr_push_fn_t) tdr_push_sk_block,
2142 &sk);
2143 if (sk_offset != 0x80) {
2144 DEBUG(0, ("Error storing sk block, should be at 0x80, stored at 0x%x\n", nk.sk_offset));
2145 return WERR_GEN_FAILURE;
2149 *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
2150 regf->header->data_offset);
2152 error = regf_save_hbin(regf, 1);
2153 if (!W_ERROR_IS_OK(error)) {
2154 return error;
2157 /* We can drop our own reference now that *key will have created one */
2158 talloc_unlink(NULL, regf);
2160 return WERR_OK;
2163 static WERROR regf_flush_key(struct hive_key *key)
2165 struct regf_key_data *private_data = (struct regf_key_data *)key;
2166 struct regf_data *regf = private_data->hive;
2167 WERROR error;
2169 error = regf_save_hbin(regf, 1);
2170 if (!W_ERROR_IS_OK(error)) {
2171 DEBUG(0, ("Failed to flush regf to disk\n"));
2172 return error;
2175 return WERR_OK;
2178 static int regf_destruct(struct regf_data *regf)
2180 WERROR error;
2182 /* Write to disk */
2183 error = regf_save_hbin(regf, 1);
2184 if (!W_ERROR_IS_OK(error)) {
2185 DEBUG(0, ("Failed to flush registry to disk\n"));
2186 return -1;
2189 /* Close file descriptor */
2190 close(regf->fd);
2192 return 0;
2195 WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx, const char *location,
2196 struct hive_key **key)
2198 struct regf_data *regf;
2199 struct regf_hdr *regf_hdr;
2200 struct tdr_pull *pull;
2201 unsigned int i;
2203 regf = (struct regf_data *)talloc_zero(parent_ctx, struct regf_data);
2204 W_ERROR_HAVE_NO_MEMORY(regf);
2206 talloc_set_destructor(regf, regf_destruct);
2208 DEBUG(5, ("Attempting to load registry file\n"));
2210 /* Get the header */
2211 regf->fd = open(location, O_RDWR);
2213 if (regf->fd == -1) {
2214 DEBUG(0,("Could not load file: %s, %s\n", location,
2215 strerror(errno)));
2216 talloc_free(regf);
2217 return WERR_GEN_FAILURE;
2220 pull = tdr_pull_init(regf);
2222 pull->data.data = (uint8_t*)
2223 fd_load(regf->fd, &pull->data.length, 0, regf);
2225 if (pull->data.data == NULL) {
2226 DEBUG(0, ("Error reading data from file: %s\n", location));
2227 talloc_free(regf);
2228 return WERR_GEN_FAILURE;
2231 regf_hdr = talloc(regf, struct regf_hdr);
2232 W_ERROR_HAVE_NO_MEMORY(regf_hdr);
2234 if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(pull, regf_hdr, regf_hdr))) {
2235 DEBUG(0, ("Failed to pull regf header from file: %s\n", location));
2236 talloc_free(regf);
2237 return WERR_GEN_FAILURE;
2240 regf->header = regf_hdr;
2242 if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
2243 DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
2244 regf_hdr->REGF_ID, location));
2245 talloc_free(regf);
2246 return WERR_GEN_FAILURE;
2249 /* Validate the header ... */
2250 if (regf_hdr_checksum(pull->data.data) != regf_hdr->chksum) {
2251 DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
2252 location, regf_hdr->chksum,
2253 regf_hdr_checksum(pull->data.data)));
2254 talloc_free(regf);
2255 return WERR_GEN_FAILURE;
2258 pull->offset = 0x1000;
2260 i = 0;
2261 /* Read in all hbin blocks */
2262 regf->hbins = talloc_array(regf, struct hbin_block *, 1);
2263 W_ERROR_HAVE_NO_MEMORY(regf->hbins);
2265 regf->hbins[0] = NULL;
2267 while (pull->offset < pull->data.length &&
2268 pull->offset <= regf->header->last_block) {
2269 struct hbin_block *hbin = talloc(regf->hbins,
2270 struct hbin_block);
2272 W_ERROR_HAVE_NO_MEMORY(hbin);
2274 if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(pull, hbin, hbin))) {
2275 DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
2276 talloc_free(regf);
2277 return WERR_FOOBAR;
2280 if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
2281 DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n",
2282 i, hbin->HBIN_ID));
2283 talloc_free(regf);
2284 return WERR_FOOBAR;
2287 regf->hbins[i] = hbin;
2288 i++;
2289 regf->hbins = talloc_realloc(regf, regf->hbins,
2290 struct hbin_block *, i+2);
2291 regf->hbins[i] = NULL;
2294 talloc_free(pull);
2296 DEBUG(1, ("%d HBIN blocks read\n", i));
2298 *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
2299 regf->header->data_offset);
2301 /* We can drop our own reference now that *key will have created one */
2302 talloc_unlink(parent_ctx, regf);
2304 return WERR_OK;
2307 static struct hive_operations reg_backend_regf = {
2308 .name = "regf",
2309 .get_key_info = regf_get_info,
2310 .enum_key = regf_get_subkey_by_index,
2311 .get_key_by_name = regf_get_subkey_by_name,
2312 .get_value_by_name = regf_get_value_by_name,
2313 .enum_value = regf_get_value,
2314 .get_sec_desc = regf_get_sec_desc,
2315 .set_sec_desc = regf_set_sec_desc,
2316 .add_key = regf_add_key,
2317 .set_value = regf_set_value,
2318 .del_key = regf_del_key,
2319 .delete_value = regf_del_value,
2320 .flush_key = regf_flush_key