s4:selftest: correctly copy a python list into a temporary variable
[Samba.git] / source4 / lib / registry / regf.c
blob4b7145e8d05eb84fe027740c55c42e5d3885d7e5
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 "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"
30 static struct hive_operations reg_backend_regf;
32 /**
33 * There are several places on the web where the REGF format is explained;
35 * TODO: Links
38 /* TODO:
39 * - Return error codes that make more sense
40 * - Locking
41 * - do more things in-memory
45 * Read HBIN blocks into memory
48 struct regf_data {
49 int fd;
50 struct hbin_block **hbins;
51 struct regf_hdr *header;
52 time_t last_write;
55 static WERROR regf_save_hbin(struct regf_data *data, bool flush);
57 struct regf_key_data {
58 struct hive_key key;
59 struct regf_data *hive;
60 uint32_t offset;
61 struct nk_block *nk;
64 static struct hbin_block *hbin_by_offset(const struct regf_data *data,
65 uint32_t offset, uint32_t *rel_offset)
67 unsigned int i;
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];
79 return NULL;
82 /**
83 * Validate a regf header
84 * For now, do nothing, but we should check the checksum
86 static uint32_t regf_hdr_checksum(const uint8_t *buffer)
88 uint32_t checksum = 0, x;
89 unsigned int i;
91 for (i = 0; i < 0x01FB; i+= 4) {
92 x = IVAL(buffer, i);
93 checksum ^= x;
96 return checksum;
99 /**
100 * Obtain the contents of a HBIN block
102 static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset)
104 DATA_BLOB ret;
105 struct hbin_block *hbin;
106 uint32_t rel_offset;
108 ret.data = NULL;
109 ret.length = 0;
111 hbin = hbin_by_offset(data, offset, &rel_offset);
113 if (hbin == NULL) {
114 DEBUG(1, ("Can't find HBIN at 0x%04x\n", offset));
115 return ret;
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;
124 /* remove high bit */
125 ret.length = (ret.length ^ 0xffffffff) + 1;
127 ret.length -= 4; /* 4 bytes for the length... */
128 ret.data = hbin->data +
129 (offset - hbin->offset_from_first - 0x20) + 4;
131 return ret;
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)
137 struct tdr_pull *pull = tdr_pull_init(regf);
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;
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;
152 talloc_free(pull);
154 return true;
157 /* Allocate some new data */
158 static DATA_BLOB hbin_alloc(struct regf_data *data, uint32_t size,
159 uint32_t *offset)
161 DATA_BLOB ret;
162 uint32_t rel_offset = (uint32_t) -1; /* Relative offset ! */
163 struct hbin_block *hbin = NULL;
164 unsigned int i;
166 if (offset != NULL) {
167 *offset = 0;
170 if (size == 0)
171 return data_blob(NULL, 0);
173 size += 4; /* Need to include int32 for the length */
175 /* Allocate as a multiple of 8 */
176 size = (size + 7) & ~7;
178 ret.data = NULL;
179 ret.length = 0;
181 for (i = 0; (hbin = data->hbins[i]); i++) {
182 int j;
183 int32_t my_size;
184 for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {
185 my_size = IVALS(hbin->data, j);
187 if (my_size == 0x0) {
188 DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
189 return ret;
192 if (my_size % 8 != 0) {
193 DEBUG(0, ("Encountered non-aligned block!\n"));
196 if (my_size < 0) { /* Used... */
197 my_size = -my_size;
198 } else if (my_size == size) { /* exact match */
199 rel_offset = j;
200 DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n",
201 size));
202 break;
203 } else if (my_size > size) { /* data will remain */
204 rel_offset = j;
205 /* Split this block and mark the next block as free */
206 SIVAL(hbin->data, rel_offset+size, my_size-size);
207 DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n",
208 my_size, size));
209 break;
213 if (rel_offset != -1)
214 break;
217 /* No space available in previous hbins,
218 * allocate new one */
219 if (data->hbins[i] == NULL) {
220 DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n",
221 size));
223 /* Add extra hbin block */
224 data->hbins = talloc_realloc(data, data->hbins,
225 struct hbin_block *, i+2);
226 hbin = talloc(data->hbins, struct hbin_block);
227 SMB_ASSERT(hbin != NULL);
229 data->hbins[i] = hbin;
230 data->hbins[i+1] = NULL;
232 /* Set hbin data */
233 hbin->HBIN_ID = talloc_strdup(hbin, "hbin");
234 hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);
235 hbin->offset_to_next = 0x1000;
236 hbin->unknown[0] = 0;
237 hbin->unknown[1] = 0;
238 unix_to_nt_time(&hbin->last_change, time(NULL));
239 hbin->block_size = hbin->offset_to_next;
240 hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);
241 /* Update the regf header */
242 data->header->last_block += hbin->offset_to_next;
244 /* Set the next block to it's proper size and set the
245 * rel_offset for this block */
246 SIVAL(hbin->data, size, hbin->block_size - size - 0x20);
247 rel_offset = 0x0;
250 /* Set size and mark as used */
251 SIVAL(hbin->data, rel_offset, -size);
253 ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */
254 ret.length = size - 0x4;
255 if (offset) {
256 uint32_t new_rel_offset = 0;
257 *offset = hbin->offset_from_first + rel_offset + 0x20;
258 SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);
259 SMB_ASSERT(new_rel_offset == rel_offset);
262 return ret;
265 /* Store a data blob. Return the offset at which it was stored */
266 static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob)
268 uint32_t ret;
269 DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);
271 memcpy(dest.data, blob.data, blob.length);
273 /* Make sure that we have no tailing garbage in the block */
274 if (dest.length > blob.length) {
275 memset(dest.data + blob.length, 0, dest.length - blob.length);
278 return ret;
281 static uint32_t hbin_store_tdr(struct regf_data *data,
282 tdr_push_fn_t push_fn, void *p)
284 struct tdr_push *push = tdr_push_init(data);
285 uint32_t ret;
287 if (NT_STATUS_IS_ERR(push_fn(push, p))) {
288 DEBUG(0, ("Error during push\n"));
289 return -1;
292 ret = hbin_store(data, push->data);
294 talloc_free(push);
296 return ret;
300 /* Free existing data */
301 static void hbin_free (struct regf_data *data, uint32_t offset)
303 int32_t size;
304 uint32_t rel_offset;
305 int32_t next_size;
306 struct hbin_block *hbin;
308 SMB_ASSERT (offset > 0);
310 hbin = hbin_by_offset(data, offset, &rel_offset);
312 if (hbin == NULL)
313 return;
315 /* Get original size */
316 size = IVALS(hbin->data, rel_offset);
318 if (size > 0) {
319 DEBUG(1, ("Trying to free already freed block at 0x%04x\n",
320 offset));
321 return;
323 /* Mark as unused */
324 size = -size;
326 /* If the next block is free, merge into big free block */
327 if (rel_offset + size < hbin->offset_to_next - 0x20) {
328 next_size = IVALS(hbin->data, rel_offset+size);
329 if (next_size > 0) {
330 size += next_size;
334 /* Write block size */
335 SIVALS(hbin->data, rel_offset, size);
339 * Store a data blob data was already stored, but has changed in size
340 * Will try to save it at the current location if possible, otherwise
341 * does a free + store */
342 static uint32_t hbin_store_resize(struct regf_data *data,
343 uint32_t orig_offset, DATA_BLOB blob)
345 uint32_t rel_offset;
346 struct hbin_block *hbin = hbin_by_offset(data, orig_offset,
347 &rel_offset);
348 int32_t my_size;
349 int32_t orig_size;
350 int32_t needed_size;
351 int32_t possible_size;
352 unsigned int i;
354 SMB_ASSERT(orig_offset > 0);
356 if (!hbin)
357 return hbin_store(data, blob);
359 /* Get original size */
360 orig_size = -IVALS(hbin->data, rel_offset);
362 needed_size = blob.length + 4; /* Add int32 containing length */
363 needed_size = (needed_size + 7) & ~7; /* Align */
365 /* Fits into current allocated block */
366 if (orig_size >= needed_size) {
367 memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);
368 /* If the difference in size is greater than 0x4, split the block
369 * and free/merge it */
370 if (orig_size - needed_size > 0x4) {
371 SIVALS(hbin->data, rel_offset, -needed_size);
372 SIVALS(hbin->data, rel_offset + needed_size,
373 needed_size-orig_size);
374 hbin_free(data, orig_offset + needed_size);
376 return orig_offset;
379 possible_size = orig_size;
381 /* Check if it can be combined with the next few free records */
382 for (i = rel_offset; i < hbin->offset_to_next - 0x20; i += my_size) {
383 if (IVALS(hbin->data, i) < 0) /* Used */
384 break;
386 my_size = IVALS(hbin->data, i);
388 if (my_size == 0x0) {
389 DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
390 break;
391 } else {
392 possible_size += my_size;
395 if (possible_size >= blob.length) {
396 SIVAL(hbin->data, rel_offset, -possible_size);
397 memcpy(hbin->data + rel_offset + 0x4,
398 blob.data, blob.length);
399 return orig_offset;
403 hbin_free(data, orig_offset);
404 return hbin_store(data, blob);
407 static uint32_t hbin_store_tdr_resize(struct regf_data *regf,
408 tdr_push_fn_t push_fn,
409 uint32_t orig_offset, void *p)
411 struct tdr_push *push = tdr_push_init(regf);
412 uint32_t ret;
414 if (NT_STATUS_IS_ERR(push_fn(push, p))) {
415 DEBUG(0, ("Error during push\n"));
416 return -1;
419 ret = hbin_store_resize(regf, orig_offset, push->data);
421 talloc_free(push);
423 return ret;
426 static uint32_t regf_create_lh_hash(const char *name)
428 char *hash_name;
429 uint32_t ret = 0;
430 uint16_t i;
432 hash_name = strupper_talloc(NULL, name);
433 for (i = 0; *(hash_name + i) != 0; i++) {
434 ret *= 37;
435 ret += *(hash_name + i);
437 talloc_free(hash_name);
438 return ret;
441 static WERROR regf_get_info(TALLOC_CTX *mem_ctx,
442 const struct hive_key *key,
443 const char **classname,
444 uint32_t *num_subkeys,
445 uint32_t *num_values,
446 NTTIME *last_mod_time,
447 uint32_t *max_subkeynamelen,
448 uint32_t *max_valnamelen,
449 uint32_t *max_valbufsize)
451 const struct regf_key_data *private_data =
452 (const struct regf_key_data *)key;
454 if (num_subkeys != NULL)
455 *num_subkeys = private_data->nk->num_subkeys;
457 if (num_values != NULL)
458 *num_values = private_data->nk->num_values;
460 if (classname != NULL) {
461 if (private_data->nk->clsname_offset != -1) {
462 DATA_BLOB data = hbin_get(private_data->hive,
463 private_data->nk->clsname_offset);
464 *classname = talloc_strndup(mem_ctx,
465 (char*)data.data,
466 private_data->nk->clsname_length);
467 W_ERROR_HAVE_NO_MEMORY(*classname);
468 } else
469 *classname = NULL;
472 /* TODO: Last mod time */
474 /* TODO: max valnamelen */
476 /* TODO: max valbufsize */
478 /* TODO: max subkeynamelen */
480 return WERR_OK;
483 static struct regf_key_data *regf_get_key(TALLOC_CTX *ctx,
484 struct regf_data *regf,
485 uint32_t offset)
487 struct nk_block *nk;
488 struct regf_key_data *ret;
490 ret = talloc_zero(ctx, struct regf_key_data);
491 ret->key.ops = &reg_backend_regf;
492 ret->hive = talloc_reference(ret, regf);
493 ret->offset = offset;
494 nk = talloc(ret, struct nk_block);
495 if (nk == NULL)
496 return NULL;
498 ret->nk = nk;
500 if (!hbin_get_tdr(regf, offset, nk,
501 (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {
502 DEBUG(0, ("Unable to find HBIN data for offset 0x%x\n", offset));
503 return NULL;
506 if (strcmp(nk->header, "nk") != 0) {
507 DEBUG(0, ("Expected nk record, got %s\n", nk->header));
508 talloc_free(ret);
509 return NULL;
512 return ret;
516 static WERROR regf_get_value(TALLOC_CTX *ctx, struct hive_key *key,
517 uint32_t idx, const char **name,
518 uint32_t *data_type, DATA_BLOB *data)
520 const struct regf_key_data *private_data =
521 (const struct regf_key_data *)key;
522 struct vk_block *vk;
523 struct regf_data *regf = private_data->hive;
524 uint32_t vk_offset;
525 DATA_BLOB tmp;
527 if (idx >= private_data->nk->num_values)
528 return WERR_NO_MORE_ITEMS;
530 tmp = hbin_get(regf, private_data->nk->values_offset);
531 if (!tmp.data) {
532 DEBUG(0, ("Unable to find value list at 0x%x\n",
533 private_data->nk->values_offset));
534 return WERR_GENERAL_FAILURE;
537 if (tmp.length < private_data->nk->num_values * 4) {
538 DEBUG(1, ("Value counts mismatch\n"));
541 vk_offset = IVAL(tmp.data, idx * 4);
543 vk = talloc(NULL, struct vk_block);
544 W_ERROR_HAVE_NO_MEMORY(vk);
546 if (!hbin_get_tdr(regf, vk_offset, vk,
547 (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {
548 DEBUG(0, ("Unable to get VK block at 0x%x\n", vk_offset));
549 talloc_free(vk);
550 return WERR_GENERAL_FAILURE;
553 /* FIXME: name character set ?*/
554 if (name != NULL) {
555 *name = talloc_strndup(ctx, vk->data_name, vk->name_length);
556 W_ERROR_HAVE_NO_MEMORY(*name);
559 if (data_type != NULL)
560 *data_type = vk->data_type;
562 if (vk->data_length & 0x80000000) {
563 /* this is data of type "REG_DWORD" or "REG_DWORD_BIG_ENDIAN" */
564 data->data = talloc_size(ctx, sizeof(uint32_t));
565 W_ERROR_HAVE_NO_MEMORY(data->data);
566 SIVAL(data->data, 0, vk->data_offset);
567 data->length = sizeof(uint32_t);
568 } else {
569 *data = hbin_get(regf, vk->data_offset);
572 if (data->length < vk->data_length) {
573 DEBUG(1, ("Read data less than indicated data length!\n"));
576 talloc_free(vk);
578 return WERR_OK;
581 static WERROR regf_get_value_by_name(TALLOC_CTX *mem_ctx,
582 struct hive_key *key, const char *name,
583 uint32_t *type, DATA_BLOB *data)
585 unsigned int i;
586 const char *vname;
587 WERROR error;
589 /* FIXME: Do binary search? Is this list sorted at all? */
591 for (i = 0; W_ERROR_IS_OK(error = regf_get_value(mem_ctx, key, i,
592 &vname, type, data));
593 i++) {
594 if (!strcmp(vname, name))
595 return WERR_OK;
598 if (W_ERROR_EQUAL(error, WERR_NO_MORE_ITEMS))
599 return WERR_BADFILE;
601 return error;
605 static WERROR regf_get_subkey_by_index(TALLOC_CTX *ctx,
606 const struct hive_key *key,
607 uint32_t idx, const char **name,
608 const char **classname,
609 NTTIME *last_mod_time)
611 DATA_BLOB data;
612 struct regf_key_data *ret;
613 const struct regf_key_data *private_data = (const struct regf_key_data *)key;
614 struct nk_block *nk = private_data->nk;
615 uint32_t key_off=0;
617 if (idx >= nk->num_subkeys)
618 return WERR_NO_MORE_ITEMS;
620 /* Make sure that we don't crash if the key is empty */
621 if (nk->subkeys_offset == -1) {
622 return WERR_NO_MORE_ITEMS;
625 data = hbin_get(private_data->hive, nk->subkeys_offset);
626 if (!data.data) {
627 DEBUG(0, ("Unable to find subkey list at 0x%x\n",
628 nk->subkeys_offset));
629 return WERR_GENERAL_FAILURE;
632 if (!strncmp((char *)data.data, "li", 2)) {
633 struct li_block li;
634 struct tdr_pull *pull = tdr_pull_init(private_data->hive);
636 DEBUG(10, ("Subkeys in LI list\n"));
637 pull->data = data;
639 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) {
640 DEBUG(0, ("Error parsing LI list\n"));
641 talloc_free(pull);
642 return WERR_GENERAL_FAILURE;
644 talloc_free(pull);
645 SMB_ASSERT(!strncmp(li.header, "li", 2));
647 if (li.key_count != nk->num_subkeys) {
648 DEBUG(0, ("Subkey counts don't match\n"));
649 return WERR_GENERAL_FAILURE;
651 key_off = li.nk_offset[idx];
653 } else if (!strncmp((char *)data.data, "lf", 2)) {
654 struct lf_block lf;
655 struct tdr_pull *pull = tdr_pull_init(private_data->hive);
657 DEBUG(10, ("Subkeys in LF list\n"));
658 pull->data = data;
660 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) {
661 DEBUG(0, ("Error parsing LF list\n"));
662 talloc_free(pull);
663 return WERR_GENERAL_FAILURE;
665 talloc_free(pull);
666 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
668 if (lf.key_count != nk->num_subkeys) {
669 DEBUG(0, ("Subkey counts don't match\n"));
670 return WERR_GENERAL_FAILURE;
673 key_off = lf.hr[idx].nk_offset;
674 } else if (!strncmp((char *)data.data, "lh", 2)) {
675 struct lh_block lh;
676 struct tdr_pull *pull = tdr_pull_init(private_data->hive);
678 DEBUG(10, ("Subkeys in LH list\n"));
679 pull->data = data;
681 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) {
682 DEBUG(0, ("Error parsing LH list\n"));
683 talloc_free(pull);
684 return WERR_GENERAL_FAILURE;
686 talloc_free(pull);
687 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
689 if (lh.key_count != nk->num_subkeys) {
690 DEBUG(0, ("Subkey counts don't match\n"));
691 return WERR_GENERAL_FAILURE;
693 key_off = lh.hr[idx].nk_offset;
694 } else if (!strncmp((char *)data.data, "ri", 2)) {
695 struct ri_block ri;
696 struct tdr_pull *pull = tdr_pull_init(ctx);
697 uint16_t i;
698 uint16_t sublist_count = 0;
700 DEBUG(10, ("Subkeys in RI list\n"));
701 pull->data = data;
703 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) {
704 DEBUG(0, ("Error parsing RI list\n"));
705 talloc_free(pull);
706 return WERR_GENERAL_FAILURE;
708 SMB_ASSERT(!strncmp(ri.header, "ri", 2));
710 for (i = 0; i < ri.key_count; i++) {
711 DATA_BLOB list_data;
713 /* Get sublist data blob */
714 list_data = hbin_get(private_data->hive, ri.offset[i]);
715 if (!list_data.data) {
716 DEBUG(0, ("Error getting RI list."));
717 talloc_free(pull);
718 return WERR_GENERAL_FAILURE;
721 pull->data = list_data;
723 if (!strncmp((char *)list_data.data, "li", 2)) {
724 struct li_block li;
726 DEBUG(10, ("Subkeys in RI->LI list\n"));
728 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull,
730 &li))) {
731 DEBUG(0, ("Error parsing LI list from RI\n"));
732 talloc_free(pull);
733 return WERR_GENERAL_FAILURE;
735 SMB_ASSERT(!strncmp(li.header, "li", 2));
737 /* Advance to next sublist if necessary */
738 if (idx >= sublist_count + li.key_count) {
739 sublist_count += li.key_count;
740 continue;
742 key_off = li.nk_offset[idx - sublist_count];
743 sublist_count += li.key_count;
744 break;
745 } else if (!strncmp((char *)list_data.data, "lh", 2)) {
746 struct lh_block lh;
748 DEBUG(10, ("Subkeys in RI->LH list\n"));
750 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull,
752 &lh))) {
753 DEBUG(0, ("Error parsing LH list from RI\n"));
754 talloc_free(pull);
755 return WERR_GENERAL_FAILURE;
757 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
759 /* Advance to next sublist if necessary */
760 if (idx >= sublist_count + lh.key_count) {
761 sublist_count += lh.key_count;
762 continue;
764 key_off = lh.hr[idx - sublist_count].nk_offset;
765 sublist_count += lh.key_count;
766 break;
767 } else {
768 DEBUG(0,("Unknown sublist in ri block\n"));
769 talloc_free(pull);
771 return WERR_GENERAL_FAILURE;
775 talloc_free(pull);
778 if (idx > sublist_count) {
779 return WERR_NO_MORE_ITEMS;
782 } else {
783 DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n",
784 nk->subkeys_offset, data.data[0], data.data[1]));
785 return WERR_GENERAL_FAILURE;
788 ret = regf_get_key (ctx, private_data->hive, key_off);
790 if (classname != NULL) {
791 if (ret->nk->clsname_offset != -1) {
792 DATA_BLOB db = hbin_get(ret->hive,
793 ret->nk->clsname_offset);
794 *classname = talloc_strndup(ctx,
795 (char*)db.data,
796 ret->nk->clsname_length);
797 W_ERROR_HAVE_NO_MEMORY(*classname);
798 } else
799 *classname = NULL;
802 if (last_mod_time != NULL)
803 *last_mod_time = ret->nk->last_change;
805 if (name != NULL)
806 *name = talloc_steal(ctx, ret->nk->key_name);
808 talloc_free(ret);
810 return WERR_OK;
813 static WERROR regf_match_subkey_by_name(TALLOC_CTX *ctx,
814 const struct hive_key *key,
815 uint32_t offset,
816 const char *name, uint32_t *ret)
818 DATA_BLOB subkey_data;
819 struct nk_block subkey;
820 struct tdr_pull *pull;
821 const struct regf_key_data *private_data =
822 (const struct regf_key_data *)key;
824 subkey_data = hbin_get(private_data->hive, offset);
825 if (!subkey_data.data) {
826 DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
827 return WERR_GENERAL_FAILURE;
830 pull = tdr_pull_init(ctx);
832 pull->data = subkey_data;
834 if (NT_STATUS_IS_ERR(tdr_pull_nk_block(pull, ctx, &subkey))) {
835 DEBUG(0, ("Error parsing NK structure.\n"));
836 talloc_free(pull);
837 return WERR_GENERAL_FAILURE;
839 talloc_free(pull);
841 if (strncmp(subkey.header, "nk", 2)) {
842 DEBUG(0, ("Not an NK structure.\n"));
843 return WERR_GENERAL_FAILURE;
846 if (!strcasecmp(subkey.key_name, name)) {
847 *ret = offset;
848 } else {
849 *ret = 0;
851 return WERR_OK;
854 static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx,
855 const struct hive_key *key,
856 const char *name,
857 struct hive_key **ret)
859 DATA_BLOB data;
860 const struct regf_key_data *private_data =
861 (const struct regf_key_data *)key;
862 struct nk_block *nk = private_data->nk;
863 uint32_t key_off = 0;
865 /* Make sure that we don't crash if the key is empty */
866 if (nk->subkeys_offset == -1) {
867 return WERR_BADFILE;
870 data = hbin_get(private_data->hive, nk->subkeys_offset);
871 if (!data.data) {
872 DEBUG(0, ("Unable to find subkey list\n"));
873 return WERR_GENERAL_FAILURE;
876 if (!strncmp((char *)data.data, "li", 2)) {
877 struct li_block li;
878 struct tdr_pull *pull = tdr_pull_init(ctx);
879 uint16_t i;
881 DEBUG(10, ("Subkeys in LI list\n"));
882 pull->data = data;
884 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, nk, &li))) {
885 DEBUG(0, ("Error parsing LI list\n"));
886 talloc_free(pull);
887 return WERR_GENERAL_FAILURE;
889 talloc_free(pull);
890 SMB_ASSERT(!strncmp(li.header, "li", 2));
892 if (li.key_count != nk->num_subkeys) {
893 DEBUG(0, ("Subkey counts don't match\n"));
894 return WERR_GENERAL_FAILURE;
897 for (i = 0; i < li.key_count; i++) {
898 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
899 li.nk_offset[i],
900 name,
901 &key_off));
902 if (key_off != 0)
903 break;
905 if (key_off == 0)
906 return WERR_BADFILE;
907 } else if (!strncmp((char *)data.data, "lf", 2)) {
908 struct lf_block lf;
909 struct tdr_pull *pull = tdr_pull_init(ctx);
910 uint16_t i;
912 DEBUG(10, ("Subkeys in LF list\n"));
913 pull->data = data;
915 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, nk, &lf))) {
916 DEBUG(0, ("Error parsing LF list\n"));
917 talloc_free(pull);
918 return WERR_GENERAL_FAILURE;
920 talloc_free(pull);
921 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
923 if (lf.key_count != nk->num_subkeys) {
924 DEBUG(0, ("Subkey counts don't match\n"));
925 return WERR_GENERAL_FAILURE;
928 for (i = 0; i < lf.key_count; i++) {
929 if (strncmp(lf.hr[i].hash, name, 4)) {
930 continue;
932 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk,
933 key,
934 lf.hr[i].nk_offset,
935 name,
936 &key_off));
937 if (key_off != 0)
938 break;
940 if (key_off == 0)
941 return WERR_BADFILE;
942 } else if (!strncmp((char *)data.data, "lh", 2)) {
943 struct lh_block lh;
944 struct tdr_pull *pull = tdr_pull_init(ctx);
945 uint16_t i;
946 uint32_t hash;
948 DEBUG(10, ("Subkeys in LH list\n"));
949 pull->data = data;
951 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, nk, &lh))) {
952 DEBUG(0, ("Error parsing LH list\n"));
953 talloc_free(pull);
954 return WERR_GENERAL_FAILURE;
956 talloc_free(pull);
957 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
959 if (lh.key_count != nk->num_subkeys) {
960 DEBUG(0, ("Subkey counts don't match\n"));
961 return WERR_GENERAL_FAILURE;
964 hash = regf_create_lh_hash(name);
965 for (i = 0; i < lh.key_count; i++) {
966 if (lh.hr[i].base37 != hash) {
967 continue;
969 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk,
970 key,
971 lh.hr[i].nk_offset,
972 name,
973 &key_off));
974 if (key_off != 0)
975 break;
977 if (key_off == 0)
978 return WERR_BADFILE;
979 } else if (!strncmp((char *)data.data, "ri", 2)) {
980 struct ri_block ri;
981 struct tdr_pull *pull = tdr_pull_init(ctx);
982 uint16_t i, j;
984 DEBUG(10, ("Subkeys in RI list\n"));
985 pull->data = data;
987 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull, nk, &ri))) {
988 DEBUG(0, ("Error parsing RI list\n"));
989 talloc_free(pull);
990 return WERR_GENERAL_FAILURE;
992 SMB_ASSERT(!strncmp(ri.header, "ri", 2));
994 for (i = 0; i < ri.key_count; i++) {
995 DATA_BLOB list_data;
997 /* Get sublist data blob */
998 list_data = hbin_get(private_data->hive, ri.offset[i]);
999 if (list_data.data == NULL) {
1000 DEBUG(0, ("Error getting RI list."));
1001 talloc_free(pull);
1002 return WERR_GENERAL_FAILURE;
1005 pull->data = list_data;
1007 if (!strncmp((char *)list_data.data, "li", 2)) {
1008 struct li_block li;
1010 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull,
1012 &li))) {
1013 DEBUG(0, ("Error parsing LI list from RI\n"));
1014 talloc_free(pull);
1015 return WERR_GENERAL_FAILURE;
1017 SMB_ASSERT(!strncmp(li.header, "li", 2));
1019 for (j = 0; j < li.key_count; j++) {
1020 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
1021 li.nk_offset[j],
1022 name,
1023 &key_off));
1024 if (key_off)
1025 break;
1027 } else if (!strncmp((char *)list_data.data, "lh", 2)) {
1028 struct lh_block lh;
1029 uint32_t hash;
1031 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull,
1033 &lh))) {
1034 DEBUG(0, ("Error parsing LH list from RI\n"));
1035 talloc_free(pull);
1036 return WERR_GENERAL_FAILURE;
1038 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1040 hash = regf_create_lh_hash(name);
1041 for (j = 0; j < lh.key_count; j++) {
1042 if (lh.hr[j].base37 != hash) {
1043 continue;
1045 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
1046 lh.hr[j].nk_offset,
1047 name,
1048 &key_off));
1049 if (key_off)
1050 break;
1053 if (key_off)
1054 break;
1056 talloc_free(pull);
1057 if (!key_off)
1058 return WERR_BADFILE;
1059 } else {
1060 DEBUG(0, ("Unknown subkey list type.\n"));
1061 return WERR_GENERAL_FAILURE;
1064 *ret = (struct hive_key *)regf_get_key(ctx, private_data->hive,
1065 key_off);
1066 return WERR_OK;
1069 static WERROR regf_set_sec_desc(struct hive_key *key,
1070 const struct security_descriptor *sec_desc)
1072 const struct regf_key_data *private_data =
1073 (const struct regf_key_data *)key;
1074 struct sk_block cur_sk, sk, new_sk;
1075 struct regf_data *regf = private_data->hive;
1076 struct nk_block root;
1077 DATA_BLOB data;
1078 uint32_t sk_offset, cur_sk_offset;
1079 bool update_cur_sk = false;
1081 /* Get the root nk */
1082 hbin_get_tdr(regf, regf->header->data_offset, regf,
1083 (tdr_pull_fn_t) tdr_pull_nk_block, &root);
1085 /* Push the security descriptor to a blob */
1086 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(&data, regf,
1087 sec_desc, (ndr_push_flags_fn_t)ndr_push_security_descriptor))) {
1088 DEBUG(0, ("Unable to push security descriptor\n"));
1089 return WERR_GENERAL_FAILURE;
1092 /* Get the current security descriptor for the key */
1093 if (!hbin_get_tdr(regf, private_data->nk->sk_offset, regf,
1094 (tdr_pull_fn_t) tdr_pull_sk_block, &cur_sk)) {
1095 DEBUG(0, ("Unable to find security descriptor for current key\n"));
1096 return WERR_BADFILE;
1098 /* If there's no change, change nothing. */
1099 if (memcmp(data.data, cur_sk.sec_desc,
1100 MIN(data.length, cur_sk.rec_size)) == 0) {
1101 return WERR_OK;
1104 /* Delete the current sk if only this key is using it */
1105 if (cur_sk.ref_cnt == 1) {
1106 /* Get the previous security descriptor for the key */
1107 if (!hbin_get_tdr(regf, cur_sk.prev_offset, regf,
1108 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1109 DEBUG(0, ("Unable to find prev security descriptor for current key\n"));
1110 return WERR_BADFILE;
1112 /* Change and store the previous security descriptor */
1113 sk.next_offset = cur_sk.next_offset;
1114 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block,
1115 cur_sk.prev_offset, &sk);
1117 /* Get the next security descriptor for the key */
1118 if (!hbin_get_tdr(regf, cur_sk.next_offset, regf,
1119 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1120 DEBUG(0, ("Unable to find next security descriptor for current key\n"));
1121 return WERR_BADFILE;
1123 /* Change and store the next security descriptor */
1124 sk.prev_offset = cur_sk.prev_offset;
1125 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_sk_block,
1126 cur_sk.next_offset, &sk);
1128 hbin_free(regf, private_data->nk->sk_offset);
1129 } else {
1130 /* This key will no longer be referring to this sk */
1131 cur_sk.ref_cnt--;
1132 update_cur_sk = true;
1135 sk_offset = root.sk_offset;
1137 do {
1138 cur_sk_offset = sk_offset;
1139 if (!hbin_get_tdr(regf, sk_offset, regf,
1140 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1141 DEBUG(0, ("Unable to find security descriptor\n"));
1142 return WERR_BADFILE;
1144 if (memcmp(data.data, sk.sec_desc, MIN(data.length, sk.rec_size)) == 0) {
1145 private_data->nk->sk_offset = sk_offset;
1146 sk.ref_cnt++;
1147 hbin_store_tdr_resize(regf,
1148 (tdr_push_fn_t) tdr_push_sk_block,
1149 sk_offset, &sk);
1150 hbin_store_tdr_resize(regf,
1151 (tdr_push_fn_t) tdr_push_nk_block,
1152 private_data->offset,
1153 private_data->nk);
1154 return WERR_OK;
1156 sk_offset = sk.next_offset;
1157 } while (sk_offset != root.sk_offset);
1159 ZERO_STRUCT(new_sk);
1160 new_sk.header = "sk";
1161 new_sk.prev_offset = cur_sk_offset;
1162 new_sk.next_offset = root.sk_offset;
1163 new_sk.ref_cnt = 1;
1164 new_sk.rec_size = data.length;
1165 new_sk.sec_desc = data.data;
1167 sk_offset = hbin_store_tdr(regf,
1168 (tdr_push_fn_t) tdr_push_sk_block,
1169 &new_sk);
1170 if (sk_offset == -1) {
1171 DEBUG(0, ("Error storing sk block\n"));
1172 return WERR_GENERAL_FAILURE;
1174 private_data->nk->sk_offset = sk_offset;
1176 if (update_cur_sk) {
1177 hbin_store_tdr_resize(regf,
1178 (tdr_push_fn_t) tdr_push_sk_block,
1179 private_data->nk->sk_offset, &cur_sk);
1182 /* Get the previous security descriptor for the key */
1183 if (!hbin_get_tdr(regf, new_sk.prev_offset, regf,
1184 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1185 DEBUG(0, ("Unable to find security descriptor for previous key\n"));
1186 return WERR_BADFILE;
1188 /* Change and store the previous security descriptor */
1189 sk.next_offset = sk_offset;
1190 hbin_store_tdr_resize(regf,
1191 (tdr_push_fn_t) tdr_push_sk_block,
1192 cur_sk.prev_offset, &sk);
1194 /* Get the next security descriptor for the key (always root, as we append) */
1195 if (!hbin_get_tdr(regf, new_sk.next_offset, regf,
1196 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1197 DEBUG(0, ("Unable to find security descriptor for current key\n"));
1198 return WERR_BADFILE;
1200 /* Change and store the next security descriptor (always root, as we append) */
1201 sk.prev_offset = sk_offset;
1202 hbin_store_tdr_resize(regf,
1203 (tdr_push_fn_t) tdr_push_sk_block,
1204 root.sk_offset, &sk);
1207 /* Store the nk. */
1208 hbin_store_tdr_resize(regf,
1209 (tdr_push_fn_t) tdr_push_sk_block,
1210 private_data->offset, private_data->nk);
1211 return WERR_OK;
1214 static WERROR regf_get_sec_desc(TALLOC_CTX *ctx, const struct hive_key *key,
1215 struct security_descriptor **sd)
1217 const struct regf_key_data *private_data =
1218 (const struct regf_key_data *)key;
1219 struct sk_block sk;
1220 struct regf_data *regf = private_data->hive;
1221 DATA_BLOB data;
1223 if (!hbin_get_tdr(regf, private_data->nk->sk_offset, ctx,
1224 (tdr_pull_fn_t) tdr_pull_sk_block, &sk)) {
1225 DEBUG(0, ("Unable to find security descriptor\n"));
1226 return WERR_GENERAL_FAILURE;
1229 if (strcmp(sk.header, "sk") != 0) {
1230 DEBUG(0, ("Expected 'sk', got '%s'\n", sk.header));
1231 return WERR_GENERAL_FAILURE;
1234 *sd = talloc(ctx, struct security_descriptor);
1235 W_ERROR_HAVE_NO_MEMORY(*sd);
1237 data.data = sk.sec_desc;
1238 data.length = sk.rec_size;
1239 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_struct_blob(&data, ctx, *sd,
1240 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor))) {
1241 DEBUG(0, ("Error parsing security descriptor\n"));
1242 return WERR_GENERAL_FAILURE;
1245 return WERR_OK;
1248 static WERROR regf_sl_add_entry(struct regf_data *regf, uint32_t list_offset,
1249 const char *name,
1250 uint32_t key_offset, uint32_t *ret)
1252 DATA_BLOB data;
1254 /* Create a new key if necessary */
1255 if (list_offset == -1) {
1256 if (regf->header->version.major != 1) {
1257 DEBUG(0, ("Can't store keys in unknown registry format\n"));
1258 return WERR_NOT_SUPPORTED;
1260 if (regf->header->version.minor < 3) {
1261 /* Store LI */
1262 struct li_block li;
1263 ZERO_STRUCT(li);
1264 li.header = "li";
1265 li.key_count = 1;
1267 li.nk_offset = talloc_array(regf, uint32_t, 1);
1268 W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
1269 li.nk_offset[0] = key_offset;
1271 *ret = hbin_store_tdr(regf,
1272 (tdr_push_fn_t) tdr_push_li_block,
1273 &li);
1275 talloc_free(li.nk_offset);
1276 } else if (regf->header->version.minor == 3 ||
1277 regf->header->version.minor == 4) {
1278 /* Store LF */
1279 struct lf_block lf;
1280 ZERO_STRUCT(lf);
1281 lf.header = "lf";
1282 lf.key_count = 1;
1284 lf.hr = talloc_array(regf, struct hash_record, 1);
1285 W_ERROR_HAVE_NO_MEMORY(lf.hr);
1286 lf.hr[0].nk_offset = key_offset;
1287 lf.hr[0].hash = talloc_strndup(lf.hr, name, 4);
1288 W_ERROR_HAVE_NO_MEMORY(lf.hr[0].hash);
1290 *ret = hbin_store_tdr(regf,
1291 (tdr_push_fn_t) tdr_push_lf_block,
1292 &lf);
1294 talloc_free(lf.hr);
1295 } else if (regf->header->version.minor == 5) {
1296 /* Store LH */
1297 struct lh_block lh;
1298 ZERO_STRUCT(lh);
1299 lh.header = "lh";
1300 lh.key_count = 1;
1302 lh.hr = talloc_array(regf, struct lh_hash, 1);
1303 W_ERROR_HAVE_NO_MEMORY(lh.hr);
1304 lh.hr[0].nk_offset = key_offset;
1305 lh.hr[0].base37 = regf_create_lh_hash(name);
1307 *ret = hbin_store_tdr(regf,
1308 (tdr_push_fn_t) tdr_push_lh_block,
1309 &lh);
1311 talloc_free(lh.hr);
1313 return WERR_OK;
1316 data = hbin_get(regf, list_offset);
1317 if (!data.data) {
1318 DEBUG(0, ("Unable to find subkey list\n"));
1319 return WERR_BADFILE;
1322 if (!strncmp((char *)data.data, "li", 2)) {
1323 struct tdr_pull *pull = tdr_pull_init(regf);
1324 struct li_block li;
1325 struct nk_block sub_nk;
1326 int32_t i, j;
1328 pull->data = data;
1330 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) {
1331 DEBUG(0, ("Error parsing LI list\n"));
1332 talloc_free(pull);
1333 return WERR_BADFILE;
1335 talloc_free(pull);
1337 if (strncmp(li.header, "li", 2) != 0) {
1338 abort();
1339 DEBUG(0, ("LI header corrupt\n"));
1340 return WERR_BADFILE;
1344 * Find the position to store the pointer
1345 * Extensive testing reveils that at least on windows 7 subkeys
1346 * *MUST* be stored in alphabetical order
1348 for (i = 0; i < li.key_count; i++) {
1349 /* Get the nk */
1350 hbin_get_tdr(regf, li.nk_offset[i], regf,
1351 (tdr_pull_fn_t) tdr_pull_nk_block, &sub_nk);
1352 if (strcasecmp(name, sub_nk.key_name) < 0) {
1353 break;
1357 li.nk_offset = talloc_realloc(regf, li.nk_offset,
1358 uint32_t, li.key_count+1);
1359 W_ERROR_HAVE_NO_MEMORY(li.nk_offset);
1361 /* Move everything behind this offset */
1362 for (j = li.key_count - 1; j >= i; j--) {
1363 li.nk_offset[j+1] = li.nk_offset[j];
1366 li.nk_offset[i] = key_offset;
1367 li.key_count++;
1368 *ret = hbin_store_tdr_resize(regf,
1369 (tdr_push_fn_t)tdr_push_li_block,
1370 list_offset, &li);
1372 talloc_free(li.nk_offset);
1373 } else if (!strncmp((char *)data.data, "lf", 2)) {
1374 struct tdr_pull *pull = tdr_pull_init(regf);
1375 struct lf_block lf;
1376 struct nk_block sub_nk;
1377 int32_t i, j;
1379 pull->data = data;
1381 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) {
1382 DEBUG(0, ("Error parsing LF list\n"));
1383 talloc_free(pull);
1384 return WERR_BADFILE;
1386 talloc_free(pull);
1387 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
1390 * Find the position to store the hash record
1391 * Extensive testing reveils that at least on windows 7 subkeys
1392 * *MUST* be stored in alphabetical order
1394 for (i = 0; i < lf.key_count; i++) {
1395 /* Get the nk */
1396 hbin_get_tdr(regf, lf.hr[i].nk_offset, regf,
1397 (tdr_pull_fn_t) tdr_pull_nk_block, &sub_nk);
1398 if (strcasecmp(name, sub_nk.key_name) < 0) {
1399 break;
1403 lf.hr = talloc_realloc(regf, lf.hr, struct hash_record,
1404 lf.key_count+1);
1405 W_ERROR_HAVE_NO_MEMORY(lf.hr);
1407 /* Move everything behind this hash record */
1408 for (j = lf.key_count - 1; j >= i; j--) {
1409 lf.hr[j+1] = lf.hr[j];
1412 lf.hr[i].nk_offset = key_offset;
1413 lf.hr[i].hash = talloc_strndup(lf.hr, name, 4);
1414 W_ERROR_HAVE_NO_MEMORY(lf.hr[lf.key_count].hash);
1415 lf.key_count++;
1416 *ret = hbin_store_tdr_resize(regf,
1417 (tdr_push_fn_t)tdr_push_lf_block,
1418 list_offset, &lf);
1420 talloc_free(lf.hr);
1421 } else if (!strncmp((char *)data.data, "lh", 2)) {
1422 struct tdr_pull *pull = tdr_pull_init(regf);
1423 struct lh_block lh;
1424 struct nk_block sub_nk;
1425 int32_t i, j;
1427 pull->data = data;
1429 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) {
1430 DEBUG(0, ("Error parsing LH list\n"));
1431 talloc_free(pull);
1432 return WERR_BADFILE;
1434 talloc_free(pull);
1435 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1438 * Find the position to store the hash record
1439 * Extensive testing reveils that at least on windows 7 subkeys
1440 * *MUST* be stored in alphabetical order
1442 for (i = 0; i < lh.key_count; i++) {
1443 /* Get the nk */
1444 hbin_get_tdr(regf, lh.hr[i].nk_offset, regf,
1445 (tdr_pull_fn_t) tdr_pull_nk_block, &sub_nk);
1446 if (strcasecmp(name, sub_nk.key_name) < 0) {
1447 break;
1451 lh.hr = talloc_realloc(regf, lh.hr, struct lh_hash,
1452 lh.key_count+1);
1453 W_ERROR_HAVE_NO_MEMORY(lh.hr);
1455 /* Move everything behind this hash record */
1456 for (j = lh.key_count - 1; j >= i; j--) {
1457 lh.hr[j+1] = lh.hr[j];
1460 lh.hr[i].nk_offset = key_offset;
1461 lh.hr[i].base37 = regf_create_lh_hash(name);
1462 lh.key_count++;
1463 *ret = hbin_store_tdr_resize(regf,
1464 (tdr_push_fn_t)tdr_push_lh_block,
1465 list_offset, &lh);
1467 talloc_free(lh.hr);
1468 } else if (!strncmp((char *)data.data, "ri", 2)) {
1469 /* FIXME */
1470 DEBUG(0, ("Adding to 'ri' subkey list is not supported yet.\n"));
1471 return WERR_NOT_SUPPORTED;
1472 } else {
1473 DEBUG(0, ("Cannot add to unknown subkey list\n"));
1474 return WERR_BADFILE;
1477 return WERR_OK;
1480 static WERROR regf_sl_del_entry(struct regf_data *regf, uint32_t list_offset,
1481 uint32_t key_offset, uint32_t *ret)
1483 DATA_BLOB data;
1485 data = hbin_get(regf, list_offset);
1486 if (!data.data) {
1487 DEBUG(0, ("Unable to find subkey list\n"));
1488 return WERR_BADFILE;
1491 if (strncmp((char *)data.data, "li", 2) == 0) {
1492 struct li_block li;
1493 struct tdr_pull *pull = tdr_pull_init(regf);
1494 uint16_t i;
1495 bool found_offset = false;
1497 DEBUG(10, ("Subkeys in LI list\n"));
1499 pull->data = data;
1501 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull, regf, &li))) {
1502 DEBUG(0, ("Error parsing LI list\n"));
1503 talloc_free(pull);
1504 return WERR_BADFILE;
1506 talloc_free(pull);
1508 SMB_ASSERT(!strncmp(li.header, "li", 2));
1510 for (i = 0; i < li.key_count; i++) {
1511 if (found_offset) {
1512 li.nk_offset[i-1] = li.nk_offset[i];
1514 if (li.nk_offset[i] == key_offset) {
1515 found_offset = true;
1516 continue;
1519 if (!found_offset) {
1520 DEBUG(2, ("Subkey not found\n"));
1521 return WERR_BADFILE;
1523 li.key_count--;
1525 /* If the there are no entries left, free the subkey list */
1526 if (li.key_count == 0) {
1527 hbin_free(regf, list_offset);
1528 *ret = -1;
1531 /* Store li block */
1532 *ret = hbin_store_tdr_resize(regf,
1533 (tdr_push_fn_t) tdr_push_li_block,
1534 list_offset, &li);
1535 } else if (strncmp((char *)data.data, "lf", 2) == 0) {
1536 struct lf_block lf;
1537 struct tdr_pull *pull = tdr_pull_init(regf);
1538 uint16_t i;
1539 bool found_offset = false;
1541 DEBUG(10, ("Subkeys in LF list\n"));
1543 pull->data = data;
1545 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull, regf, &lf))) {
1546 DEBUG(0, ("Error parsing LF list\n"));
1547 talloc_free(pull);
1548 return WERR_BADFILE;
1550 talloc_free(pull);
1552 SMB_ASSERT(!strncmp(lf.header, "lf", 2));
1554 for (i = 0; i < lf.key_count; i++) {
1555 if (found_offset) {
1556 lf.hr[i-1] = lf.hr[i];
1557 continue;
1559 if (lf.hr[i].nk_offset == key_offset) {
1560 found_offset = 1;
1561 continue;
1564 if (!found_offset) {
1565 DEBUG(2, ("Subkey not found\n"));
1566 return WERR_BADFILE;
1568 lf.key_count--;
1570 /* If the there are no entries left, free the subkey list */
1571 if (lf.key_count == 0) {
1572 hbin_free(regf, list_offset);
1573 *ret = -1;
1574 return WERR_OK;
1577 /* Store lf block */
1578 *ret = hbin_store_tdr_resize(regf,
1579 (tdr_push_fn_t) tdr_push_lf_block,
1580 list_offset, &lf);
1581 } else if (strncmp((char *)data.data, "lh", 2) == 0) {
1582 struct lh_block lh;
1583 struct tdr_pull *pull = tdr_pull_init(regf);
1584 uint16_t i;
1585 bool found_offset = false;
1587 DEBUG(10, ("Subkeys in LH list\n"));
1589 pull->data = data;
1591 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull, regf, &lh))) {
1592 DEBUG(0, ("Error parsing LF list\n"));
1593 talloc_free(pull);
1594 return WERR_BADFILE;
1596 talloc_free(pull);
1598 SMB_ASSERT(!strncmp(lh.header, "lh", 2));
1600 for (i = 0; i < lh.key_count; i++) {
1601 if (found_offset) {
1602 lh.hr[i-1] = lh.hr[i];
1603 continue;
1605 if (lh.hr[i].nk_offset == key_offset) {
1606 found_offset = 1;
1607 continue;
1610 if (!found_offset) {
1611 DEBUG(0, ("Subkey not found\n"));
1612 return WERR_BADFILE;
1614 lh.key_count--;
1616 /* If the there are no entries left, free the subkey list */
1617 if (lh.key_count == 0) {
1618 hbin_free(regf, list_offset);
1619 *ret = -1;
1620 return WERR_OK;
1623 /* Store lh block */
1624 *ret = hbin_store_tdr_resize(regf,
1625 (tdr_push_fn_t) tdr_push_lh_block,
1626 list_offset, &lh);
1627 } else if (strncmp((char *)data.data, "ri", 2) == 0) {
1628 /* FIXME */
1629 DEBUG(0, ("Sorry, deletion from ri block is not supported yet.\n"));
1630 return WERR_NOT_SUPPORTED;
1631 } else {
1632 DEBUG (0, ("Unknown header found in subkey list.\n"));
1633 return WERR_BADFILE;
1635 return WERR_OK;
1638 static WERROR regf_del_value(TALLOC_CTX *mem_ctx, struct hive_key *key,
1639 const char *name)
1641 struct regf_key_data *private_data = (struct regf_key_data *)key;
1642 struct regf_data *regf = private_data->hive;
1643 struct nk_block *nk = private_data->nk;
1644 struct vk_block vk;
1645 uint32_t vk_offset;
1646 bool found_offset = false;
1647 DATA_BLOB values;
1648 unsigned int i;
1650 if (nk->values_offset == -1) {
1651 return WERR_BADFILE;
1654 values = hbin_get(regf, nk->values_offset);
1656 for (i = 0; i < nk->num_values; i++) {
1657 if (found_offset) {
1658 ((uint32_t *)values.data)[i-1] = ((uint32_t *) values.data)[i];
1659 } else {
1660 vk_offset = IVAL(values.data, i * 4);
1661 if (!hbin_get_tdr(regf, vk_offset, private_data,
1662 (tdr_pull_fn_t)tdr_pull_vk_block,
1663 &vk)) {
1664 DEBUG(0, ("Unable to get VK block at %d\n",
1665 vk_offset));
1666 return WERR_BADFILE;
1668 if (strcmp(vk.data_name, name) == 0) {
1669 hbin_free(regf, vk_offset);
1670 found_offset = true;
1674 if (!found_offset) {
1675 return WERR_BADFILE;
1676 } else {
1677 nk->num_values--;
1678 values.length = (nk->num_values)*4;
1681 /* Store values list and nk */
1682 if (nk->num_values == 0) {
1683 hbin_free(regf, nk->values_offset);
1684 nk->values_offset = -1;
1685 } else {
1686 nk->values_offset = hbin_store_resize(regf,
1687 nk->values_offset,
1688 values);
1690 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
1691 private_data->offset, nk);
1693 return regf_save_hbin(private_data->hive, 0);
1697 static WERROR regf_del_key(TALLOC_CTX *mem_ctx, const struct hive_key *parent,
1698 const char *name)
1700 const struct regf_key_data *private_data =
1701 (const struct regf_key_data *)parent;
1702 struct regf_key_data *key;
1703 struct nk_block *parent_nk;
1704 WERROR error;
1706 SMB_ASSERT(private_data);
1708 parent_nk = private_data->nk;
1710 if (parent_nk->subkeys_offset == -1) {
1711 DEBUG(4, ("Subkey list is empty, this key cannot contain subkeys.\n"));
1712 return WERR_BADFILE;
1715 /* Find the key */
1716 if (!W_ERROR_IS_OK(regf_get_subkey_by_name(parent_nk, parent, name,
1717 (struct hive_key **)&key))) {
1718 DEBUG(2, ("Key '%s' not found\n", name));
1719 return WERR_BADFILE;
1722 if (key->nk->subkeys_offset != -1) {
1723 struct hive_key *sk = (struct hive_key *)key;
1724 unsigned int i = key->nk->num_subkeys;
1725 while (i--) {
1726 char *sk_name;
1727 const char *p = NULL;
1729 /* Get subkey information. */
1730 error = regf_get_subkey_by_index(parent_nk, sk, 0,
1732 NULL, NULL);
1733 if (!W_ERROR_IS_OK(error)) {
1734 DEBUG(0, ("Can't retrieve subkey by index.\n"));
1735 return error;
1737 sk_name = discard_const_p(char, p);
1739 /* Delete subkey. */
1740 error = regf_del_key(NULL, sk, sk_name);
1741 if (!W_ERROR_IS_OK(error)) {
1742 DEBUG(0, ("Can't delete key '%s'.\n", sk_name));
1743 return error;
1746 talloc_free(sk_name);
1750 if (key->nk->values_offset != -1) {
1751 struct hive_key *sk = (struct hive_key *)key;
1752 DATA_BLOB data;
1753 unsigned int i = key->nk->num_values;
1754 while (i--) {
1755 char *val_name;
1756 const char *p = NULL;
1758 /* Get value information. */
1759 error = regf_get_value(parent_nk, sk, 0,
1761 NULL, &data);
1762 if (!W_ERROR_IS_OK(error)) {
1763 DEBUG(0, ("Can't retrieve value by index.\n"));
1764 return error;
1766 val_name = discard_const_p(char, p);
1768 /* Delete value. */
1769 error = regf_del_value(NULL, sk, val_name);
1770 if (!W_ERROR_IS_OK(error)) {
1771 DEBUG(0, ("Can't delete value '%s'.\n", val_name));
1772 return error;
1775 talloc_free(val_name);
1779 /* Delete it from the subkey list. */
1780 error = regf_sl_del_entry(private_data->hive, parent_nk->subkeys_offset,
1781 key->offset, &parent_nk->subkeys_offset);
1782 if (!W_ERROR_IS_OK(error)) {
1783 DEBUG(0, ("Can't store new subkey list for parent key. Won't delete.\n"));
1784 return error;
1787 /* Re-store parent key */
1788 parent_nk->num_subkeys--;
1789 hbin_store_tdr_resize(private_data->hive,
1790 (tdr_push_fn_t) tdr_push_nk_block,
1791 private_data->offset, parent_nk);
1793 if (key->nk->clsname_offset != -1) {
1794 hbin_free(private_data->hive, key->nk->clsname_offset);
1796 hbin_free(private_data->hive, key->offset);
1798 return regf_save_hbin(private_data->hive, 0);
1801 static WERROR regf_add_key(TALLOC_CTX *ctx, const struct hive_key *parent,
1802 const char *name, const char *classname,
1803 struct security_descriptor *sec_desc,
1804 struct hive_key **ret)
1806 const struct regf_key_data *private_data =
1807 (const struct regf_key_data *)parent;
1808 struct nk_block *parent_nk = private_data->nk, nk;
1809 struct nk_block *root;
1810 struct regf_data *regf = private_data->hive;
1811 uint32_t offset;
1812 WERROR error;
1814 nk.header = "nk";
1815 nk.type = REG_SUB_KEY;
1816 unix_to_nt_time(&nk.last_change, time(NULL));
1817 nk.uk1 = 0;
1818 nk.parent_offset = private_data->offset;
1819 nk.num_subkeys = 0;
1820 nk.uk2 = 0;
1821 nk.subkeys_offset = -1;
1822 nk.unknown_offset = -1;
1823 nk.num_values = 0;
1824 nk.values_offset = -1;
1825 memset(nk.unk3, 0, sizeof(nk.unk3));
1826 nk.clsname_offset = -1; /* FIXME: fill in */
1827 nk.clsname_length = 0;
1828 nk.key_name = name;
1830 /* Get the security descriptor of the root key */
1831 root = talloc_zero(ctx, struct nk_block);
1832 W_ERROR_HAVE_NO_MEMORY(root);
1834 if (!hbin_get_tdr(regf, regf->header->data_offset, root,
1835 (tdr_pull_fn_t)tdr_pull_nk_block, root)) {
1836 DEBUG(0, ("Unable to find HBIN data for offset 0x%x\n",
1837 regf->header->data_offset));
1838 return WERR_GENERAL_FAILURE;
1840 nk.sk_offset = root->sk_offset;
1841 talloc_free(root);
1843 /* Store the new nk key */
1844 offset = hbin_store_tdr(regf, (tdr_push_fn_t) tdr_push_nk_block, &nk);
1846 error = regf_sl_add_entry(regf, parent_nk->subkeys_offset, name, offset,
1847 &parent_nk->subkeys_offset);
1848 if (!W_ERROR_IS_OK(error)) {
1849 hbin_free(regf, offset);
1850 return error;
1853 parent_nk->num_subkeys++;
1855 /* Since the subkey offset of the parent can change, store it again */
1856 hbin_store_tdr_resize(regf, (tdr_push_fn_t) tdr_push_nk_block,
1857 nk.parent_offset, parent_nk);
1859 *ret = (struct hive_key *)regf_get_key(ctx, regf, offset);
1861 DEBUG(9, ("Storing key %s\n", name));
1862 return regf_save_hbin(private_data->hive, 0);
1865 static WERROR regf_set_value(struct hive_key *key, const char *name,
1866 uint32_t type, const DATA_BLOB data)
1868 struct regf_key_data *private_data = (struct regf_key_data *)key;
1869 struct regf_data *regf = private_data->hive;
1870 struct nk_block *nk = private_data->nk;
1871 struct vk_block vk;
1872 uint32_t i;
1873 uint32_t tmp_vk_offset, vk_offset, old_vk_offset = (uint32_t) -1;
1874 DATA_BLOB values = {0};
1876 ZERO_STRUCT(vk);
1878 /* find the value offset, if it exists */
1879 if (nk->values_offset != -1) {
1880 values = hbin_get(regf, nk->values_offset);
1882 for (i = 0; i < nk->num_values; i++) {
1883 tmp_vk_offset = IVAL(values.data, i * 4);
1884 if (!hbin_get_tdr(regf, tmp_vk_offset, private_data,
1885 (tdr_pull_fn_t)tdr_pull_vk_block,
1886 &vk)) {
1887 DEBUG(0, ("Unable to get VK block at 0x%x\n",
1888 tmp_vk_offset));
1889 return WERR_GENERAL_FAILURE;
1891 if (strcmp(vk.data_name, name) == 0) {
1892 old_vk_offset = tmp_vk_offset;
1893 break;
1898 /* If it's new, create the vk struct, if it's old, free the old data. */
1899 if (old_vk_offset == -1) {
1900 vk.header = "vk";
1901 if (name != NULL && name[0] != '\0') {
1902 vk.flag = 1;
1903 vk.data_name = name;
1904 vk.name_length = strlen(name);
1905 } else {
1906 vk.flag = 0;
1907 vk.data_name = NULL;
1908 vk.name_length = 0;
1910 } else {
1911 /* Free data, if any */
1912 if (!(vk.data_length & 0x80000000)) {
1913 hbin_free(regf, vk.data_offset);
1917 /* Set the type and data */
1918 vk.data_length = data.length;
1919 vk.data_type = type;
1920 if ((type == REG_DWORD) || (type == REG_DWORD_BIG_ENDIAN)) {
1921 if (vk.data_length != sizeof(uint32_t)) {
1922 DEBUG(0, ("DWORD or DWORD_BIG_ENDIAN value with size other than 4 byte!\n"));
1923 return WERR_NOT_SUPPORTED;
1925 vk.data_length |= 0x80000000;
1926 vk.data_offset = IVAL(data.data, 0);
1927 } else {
1928 /* Store data somewhere */
1929 vk.data_offset = hbin_store(regf, data);
1931 if (old_vk_offset == -1) {
1932 /* Store new vk */
1933 vk_offset = hbin_store_tdr(regf,
1934 (tdr_push_fn_t) tdr_push_vk_block,
1935 &vk);
1936 } else {
1937 /* Store vk at offset */
1938 vk_offset = hbin_store_tdr_resize(regf,
1939 (tdr_push_fn_t) tdr_push_vk_block,
1940 old_vk_offset ,&vk);
1943 /* Re-allocate the value list */
1944 if (nk->values_offset == -1) {
1945 nk->values_offset = hbin_store_tdr(regf,
1946 (tdr_push_fn_t) tdr_push_uint32,
1947 &vk_offset);
1948 nk->num_values = 1;
1949 } else {
1951 /* Change if we're changing, otherwise we're adding the value */
1952 if (old_vk_offset != -1) {
1953 /* Find and overwrite the offset. */
1954 for (i = 0; i < nk->num_values; i++) {
1955 if (IVAL(values.data, i * 4) == old_vk_offset) {
1956 SIVAL(values.data, i * 4, vk_offset);
1957 break;
1960 } else {
1961 /* Create a new value list */
1962 DATA_BLOB value_list;
1964 value_list.length = (nk->num_values+1)*4;
1965 value_list.data = (uint8_t *)talloc_array(private_data,
1966 uint32_t,
1967 nk->num_values+1);
1968 W_ERROR_HAVE_NO_MEMORY(value_list.data);
1969 memcpy(value_list.data, values.data, nk->num_values * 4);
1971 SIVAL(value_list.data, nk->num_values * 4, vk_offset);
1972 nk->num_values++;
1973 nk->values_offset = hbin_store_resize(regf,
1974 nk->values_offset,
1975 value_list);
1979 hbin_store_tdr_resize(regf,
1980 (tdr_push_fn_t) tdr_push_nk_block,
1981 private_data->offset, nk);
1982 return regf_save_hbin(private_data->hive, 0);
1985 static WERROR regf_save_hbin(struct regf_data *regf, bool flush)
1987 struct tdr_push *push = tdr_push_init(regf);
1988 unsigned int i;
1990 W_ERROR_HAVE_NO_MEMORY(push);
1992 /* Only write once every 5 seconds, or when flush is set */
1993 if (!flush && regf->last_write + 5 >= time(NULL)) {
1994 return WERR_OK;
1997 regf->last_write = time(NULL);
1999 if (lseek(regf->fd, 0, SEEK_SET) == -1) {
2000 DEBUG(0, ("Error lseeking in regf file\n"));
2001 return WERR_GENERAL_FAILURE;
2004 /* Recompute checksum */
2005 if (NT_STATUS_IS_ERR(tdr_push_regf_hdr(push, regf->header))) {
2006 DEBUG(0, ("Failed to push regf header\n"));
2007 return WERR_GENERAL_FAILURE;
2009 regf->header->chksum = regf_hdr_checksum(push->data.data);
2010 talloc_free(push);
2012 if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd,
2013 (tdr_push_fn_t)tdr_push_regf_hdr,
2014 regf->header))) {
2015 DEBUG(0, ("Error writing registry file header\n"));
2016 return WERR_GENERAL_FAILURE;
2019 if (lseek(regf->fd, 0x1000, SEEK_SET) == -1) {
2020 DEBUG(0, ("Error lseeking to 0x1000 in regf file\n"));
2021 return WERR_GENERAL_FAILURE;
2024 for (i = 0; regf->hbins[i]; i++) {
2025 if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf->fd,
2026 (tdr_push_fn_t)tdr_push_hbin_block,
2027 regf->hbins[i]))) {
2028 DEBUG(0, ("Error writing HBIN block\n"));
2029 return WERR_GENERAL_FAILURE;
2033 return WERR_OK;
2036 WERROR reg_create_regf_file(TALLOC_CTX *parent_ctx,
2037 const char *location,
2038 int minor_version, struct hive_key **key)
2040 struct regf_data *regf;
2041 struct regf_hdr *regf_hdr;
2042 struct nk_block nk;
2043 struct sk_block sk;
2044 WERROR error;
2045 DATA_BLOB data;
2046 struct security_descriptor *sd;
2047 uint32_t sk_offset;
2049 regf = (struct regf_data *)talloc_zero(NULL, struct regf_data);
2051 W_ERROR_HAVE_NO_MEMORY(regf);
2053 DEBUG(5, ("Attempting to create registry file\n"));
2055 /* Get the header */
2056 regf->fd = creat(location, 0644);
2058 if (regf->fd == -1) {
2059 DEBUG(0,("Could not create file: %s, %s\n", location,
2060 strerror(errno)));
2061 talloc_free(regf);
2062 return WERR_GENERAL_FAILURE;
2065 regf_hdr = talloc_zero(regf, struct regf_hdr);
2066 W_ERROR_HAVE_NO_MEMORY(regf_hdr);
2067 regf_hdr->REGF_ID = "regf";
2068 unix_to_nt_time(&regf_hdr->modtime, time(NULL));
2069 regf_hdr->version.major = 1;
2070 regf_hdr->version.minor = minor_version;
2071 regf_hdr->last_block = 0x1000; /* Block size */
2072 regf_hdr->description = talloc_strdup(regf_hdr,
2073 "Registry created by Samba 4");
2074 W_ERROR_HAVE_NO_MEMORY(regf_hdr->description);
2075 regf_hdr->chksum = 0;
2077 regf->header = regf_hdr;
2079 /* Create all hbin blocks */
2080 regf->hbins = talloc_array(regf, struct hbin_block *, 1);
2081 W_ERROR_HAVE_NO_MEMORY(regf->hbins);
2082 regf->hbins[0] = NULL;
2084 nk.header = "nk";
2085 nk.type = REG_ROOT_KEY;
2086 unix_to_nt_time(&nk.last_change, time(NULL));
2087 nk.uk1 = 0;
2088 nk.parent_offset = -1;
2089 nk.num_subkeys = 0;
2090 nk.uk2 = 0;
2091 nk.subkeys_offset = -1;
2092 nk.unknown_offset = -1;
2093 nk.num_values = 0;
2094 nk.values_offset = -1;
2095 memset(nk.unk3, 0, 5);
2096 nk.clsname_offset = -1;
2097 nk.clsname_length = 0;
2098 nk.sk_offset = 0x80;
2099 nk.key_name = "SambaRootKey";
2102 * It should be noted that changing the key_name to something shorter
2103 * creates a shorter nk block, which makes the position of the sk block
2104 * change. All Windows registries I've seen have the sk at 0x80.
2105 * I therefore recommend that our regf files share that offset -- Wilco
2108 /* Create a security descriptor. */
2109 sd = security_descriptor_dacl_create(regf,
2111 NULL, NULL,
2112 SID_NT_AUTHENTICATED_USERS,
2113 SEC_ACE_TYPE_ACCESS_ALLOWED,
2114 SEC_GENERIC_ALL,
2115 SEC_ACE_FLAG_OBJECT_INHERIT,
2116 NULL);
2118 /* Push the security descriptor to a blob */
2119 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(&data, regf,
2120 sd, (ndr_push_flags_fn_t)ndr_push_security_descriptor))) {
2121 DEBUG(0, ("Unable to push security descriptor\n"));
2122 return WERR_GENERAL_FAILURE;
2125 ZERO_STRUCT(sk);
2126 sk.header = "sk";
2127 sk.prev_offset = 0x80;
2128 sk.next_offset = 0x80;
2129 sk.ref_cnt = 1;
2130 sk.rec_size = data.length;
2131 sk.sec_desc = data.data;
2133 /* Store the new nk key */
2134 regf->header->data_offset = hbin_store_tdr(regf,
2135 (tdr_push_fn_t)tdr_push_nk_block,
2136 &nk);
2137 /* Store the sk block */
2138 sk_offset = hbin_store_tdr(regf,
2139 (tdr_push_fn_t) tdr_push_sk_block,
2140 &sk);
2141 if (sk_offset != 0x80) {
2142 DEBUG(0, ("Error storing sk block, should be at 0x80, stored at 0x%x\n", nk.sk_offset));
2143 return WERR_GENERAL_FAILURE;
2147 *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
2148 regf->header->data_offset);
2150 error = regf_save_hbin(regf, 1);
2151 if (!W_ERROR_IS_OK(error)) {
2152 return error;
2155 /* We can drop our own reference now that *key will have created one */
2156 talloc_unlink(NULL, regf);
2158 return WERR_OK;
2161 static WERROR regf_flush_key(struct hive_key *key)
2163 struct regf_key_data *private_data = (struct regf_key_data *)key;
2164 struct regf_data *regf = private_data->hive;
2165 WERROR error;
2167 error = regf_save_hbin(regf, 1);
2168 if (!W_ERROR_IS_OK(error)) {
2169 DEBUG(0, ("Failed to flush regf to disk\n"));
2170 return error;
2173 return WERR_OK;
2176 static int regf_destruct(struct regf_data *regf)
2178 WERROR error;
2180 /* Write to disk */
2181 error = regf_save_hbin(regf, 1);
2182 if (!W_ERROR_IS_OK(error)) {
2183 DEBUG(0, ("Failed to flush registry to disk\n"));
2184 return -1;
2187 /* Close file descriptor */
2188 close(regf->fd);
2190 return 0;
2193 WERROR reg_open_regf_file(TALLOC_CTX *parent_ctx, const char *location,
2194 struct hive_key **key)
2196 struct regf_data *regf;
2197 struct regf_hdr *regf_hdr;
2198 struct tdr_pull *pull;
2199 unsigned int i;
2201 regf = (struct regf_data *)talloc_zero(parent_ctx, struct regf_data);
2202 W_ERROR_HAVE_NO_MEMORY(regf);
2204 talloc_set_destructor(regf, regf_destruct);
2206 DEBUG(5, ("Attempting to load registry file\n"));
2208 /* Get the header */
2209 regf->fd = open(location, O_RDWR);
2211 if (regf->fd == -1) {
2212 DEBUG(0,("Could not load file: %s, %s\n", location,
2213 strerror(errno)));
2214 talloc_free(regf);
2215 return WERR_GENERAL_FAILURE;
2218 pull = tdr_pull_init(regf);
2220 pull->data.data = (uint8_t*)fd_load(regf->fd, &pull->data.length, 0, regf);
2222 if (pull->data.data == NULL) {
2223 DEBUG(0, ("Error reading data from file: %s\n", location));
2224 talloc_free(regf);
2225 return WERR_GENERAL_FAILURE;
2228 regf_hdr = talloc(regf, struct regf_hdr);
2229 W_ERROR_HAVE_NO_MEMORY(regf_hdr);
2231 if (NT_STATUS_IS_ERR(tdr_pull_regf_hdr(pull, regf_hdr, regf_hdr))) {
2232 DEBUG(0, ("Failed to pull regf header from file: %s\n", location));
2233 talloc_free(regf);
2234 return WERR_GENERAL_FAILURE;
2237 regf->header = regf_hdr;
2239 if (strcmp(regf_hdr->REGF_ID, "regf") != 0) {
2240 DEBUG(0, ("Unrecognized NT registry header id: %s, %s\n",
2241 regf_hdr->REGF_ID, location));
2242 talloc_free(regf);
2243 return WERR_GENERAL_FAILURE;
2246 /* Validate the header ... */
2247 if (regf_hdr_checksum(pull->data.data) != regf_hdr->chksum) {
2248 DEBUG(0, ("Registry file checksum error: %s: %d,%d\n",
2249 location, regf_hdr->chksum,
2250 regf_hdr_checksum(pull->data.data)));
2251 talloc_free(regf);
2252 return WERR_GENERAL_FAILURE;
2255 pull->offset = 0x1000;
2257 i = 0;
2258 /* Read in all hbin blocks */
2259 regf->hbins = talloc_array(regf, struct hbin_block *, 1);
2260 W_ERROR_HAVE_NO_MEMORY(regf->hbins);
2262 regf->hbins[0] = NULL;
2264 while (pull->offset < pull->data.length &&
2265 pull->offset <= regf->header->last_block) {
2266 struct hbin_block *hbin = talloc(regf->hbins,
2267 struct hbin_block);
2269 W_ERROR_HAVE_NO_MEMORY(hbin);
2271 if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(pull, hbin, hbin))) {
2272 DEBUG(0, ("[%d] Error parsing HBIN block\n", i));
2273 talloc_free(regf);
2274 return WERR_FOOBAR;
2277 if (strcmp(hbin->HBIN_ID, "hbin") != 0) {
2278 DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n",
2279 i, hbin->HBIN_ID));
2280 talloc_free(regf);
2281 return WERR_FOOBAR;
2284 regf->hbins[i] = hbin;
2285 i++;
2286 regf->hbins = talloc_realloc(regf, regf->hbins,
2287 struct hbin_block *, i+2);
2288 regf->hbins[i] = NULL;
2291 talloc_free(pull);
2293 DEBUG(1, ("%d HBIN blocks read\n", i));
2295 *key = (struct hive_key *)regf_get_key(parent_ctx, regf,
2296 regf->header->data_offset);
2298 /* We can drop our own reference now that *key will have created one */
2299 talloc_unlink(parent_ctx, regf);
2301 return WERR_OK;
2304 static struct hive_operations reg_backend_regf = {
2305 .name = "regf",
2306 .get_key_info = regf_get_info,
2307 .enum_key = regf_get_subkey_by_index,
2308 .get_key_by_name = regf_get_subkey_by_name,
2309 .get_value_by_name = regf_get_value_by_name,
2310 .enum_value = regf_get_value,
2311 .get_sec_desc = regf_get_sec_desc,
2312 .set_sec_desc = regf_set_sec_desc,
2313 .add_key = regf_add_key,
2314 .set_value = regf_set_value,
2315 .del_key = regf_del_key,
2316 .delete_value = regf_del_value,
2317 .flush_key = regf_flush_key