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/>. */
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"
32 static struct hive_operations reg_backend_regf
;
35 * There are several places on the web where the REGF format is explained;
41 * - Return error codes that make more sense
43 * - do more things in-memory
47 * Read HBIN blocks into memory
52 struct hbin_block
**hbins
;
53 struct regf_hdr
*header
;
57 static WERROR
regf_save_hbin(struct regf_data
*data
, bool flush
);
59 struct regf_key_data
{
61 struct regf_data
*hive
;
66 static struct hbin_block
*hbin_by_offset(const struct regf_data
*data
,
67 uint32_t offset
, uint32_t *rel_offset
)
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
];
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
;
93 for (i
= 0; i
< 0x01FB; i
+= 4) {
102 * Obtain the contents of a HBIN block
104 static DATA_BLOB
hbin_get(const struct regf_data
*data
, uint32_t offset
)
107 struct hbin_block
*hbin
;
113 hbin
= hbin_by_offset(data
, offset
, &rel_offset
);
116 DEBUG(1, ("Can't find HBIN at 0x%04x\n", offset
));
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
));
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;
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
));
148 if (NT_STATUS_IS_ERR(pull_fn(pull
, ctx
, p
))) {
149 DEBUG(1, ("Error parsing record at 0x%04x using tdr\n",
159 /* Allocate some new data */
160 static DATA_BLOB
hbin_alloc(struct regf_data
*data
, uint32_t size
,
164 uint32_t rel_offset
= (uint32_t) -1; /* Relative offset ! */
165 struct hbin_block
*hbin
= NULL
;
168 if (offset
!= NULL
) {
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;
183 for (i
= 0; (hbin
= data
->hbins
[i
]); i
++) {
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"));
194 if (my_size
% 8 != 0) {
195 DEBUG(0, ("Encountered non-aligned block!\n"));
198 if (my_size
< 0) { /* Used... */
200 } else if (my_size
== size
) { /* exact match */
202 DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n",
205 } else if (my_size
> size
) { /* data will remain */
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",
215 if (rel_offset
!= -1)
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",
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
;
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);
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;
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
);
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
)
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
);
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
);
289 if (NT_STATUS_IS_ERR(push_fn(push
, p
))) {
290 DEBUG(0, ("Error during push\n"));
294 ret
= hbin_store(data
, push
->data
);
302 /* Free existing data */
303 static void hbin_free (struct regf_data
*data
, uint32_t offset
)
308 struct hbin_block
*hbin
;
310 SMB_ASSERT (offset
> 0);
312 hbin
= hbin_by_offset(data
, offset
, &rel_offset
);
317 /* Get original size */
318 size
= IVALS(hbin
->data
, rel_offset
);
321 DEBUG(1, ("Trying to free already freed block at 0x%04x\n",
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
);
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
)
348 struct hbin_block
*hbin
= hbin_by_offset(data
, orig_offset
,
353 int32_t possible_size
;
356 SMB_ASSERT(orig_offset
> 0);
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
);
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 */
388 my_size
= IVALS(hbin
->data
, i
);
390 if (my_size
== 0x0) {
391 DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));
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
);
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
);
416 if (NT_STATUS_IS_ERR(push_fn(push
, p
))) {
417 DEBUG(0, ("Error during push\n"));
421 ret
= hbin_store_resize(regf
, orig_offset
, push
->data
);
428 static uint32_t regf_create_lh_hash(const char *name
)
434 hash_name
= strupper_talloc(NULL
, name
);
435 for (i
= 0; *(hash_name
+ i
) != 0; i
++) {
437 ret
+= *(hash_name
+ i
);
439 talloc_free(hash_name
);
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
,
468 private_data
->nk
->clsname_length
);
469 W_ERROR_HAVE_NO_MEMORY(*classname
);
474 /* TODO: Last mod time */
476 /* TODO: max valnamelen */
478 /* TODO: max valbufsize */
480 /* TODO: max subkeynamelen */
485 static struct regf_key_data
*regf_get_key(TALLOC_CTX
*ctx
,
486 struct regf_data
*regf
,
490 struct regf_key_data
*ret
;
492 ret
= talloc_zero(ctx
, struct regf_key_data
);
493 ret
->key
.ops
= ®_backend_regf
;
494 ret
->hive
= talloc_reference(ret
, regf
);
495 ret
->offset
= offset
;
496 nk
= talloc(ret
, struct nk_block
);
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
));
508 if (strcmp(nk
->header
, "nk") != 0) {
509 DEBUG(0, ("Expected nk record, got %s\n", nk
->header
));
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
;
525 struct regf_data
*regf
= private_data
->hive
;
529 if (idx
>= private_data
->nk
->num_values
)
530 return WERR_NO_MORE_ITEMS
;
532 tmp
= hbin_get(regf
, private_data
->nk
->values_offset
);
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
));
552 return WERR_GEN_FAILURE
;
555 /* FIXME: name character set ?*/
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);
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"));
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
)
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
));
596 if (!strcmp(vname
, name
))
600 if (W_ERROR_EQUAL(error
, WERR_NO_MORE_ITEMS
))
601 return WERR_FILE_NOT_FOUND
;
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
)
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
;
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
);
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)) {
636 struct tdr_pull
*pull
= tdr_pull_init(private_data
->hive
);
638 DEBUG(10, ("Subkeys in LI list\n"));
641 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull
, nk
, &li
))) {
642 DEBUG(0, ("Error parsing LI list\n"));
644 return WERR_GEN_FAILURE
;
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)) {
657 struct tdr_pull
*pull
= tdr_pull_init(private_data
->hive
);
659 DEBUG(10, ("Subkeys in LF list\n"));
662 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull
, nk
, &lf
))) {
663 DEBUG(0, ("Error parsing LF list\n"));
665 return WERR_GEN_FAILURE
;
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)) {
678 struct tdr_pull
*pull
= tdr_pull_init(private_data
->hive
);
680 DEBUG(10, ("Subkeys in LH list\n"));
683 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull
, nk
, &lh
))) {
684 DEBUG(0, ("Error parsing LH list\n"));
686 return WERR_GEN_FAILURE
;
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)) {
698 struct tdr_pull
*pull
= tdr_pull_init(ctx
);
700 uint16_t sublist_count
= 0;
702 DEBUG(10, ("Subkeys in RI list\n"));
705 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull
, nk
, &ri
))) {
706 DEBUG(0, ("Error parsing RI list\n"));
708 return WERR_GEN_FAILURE
;
710 SMB_ASSERT(!strncmp(ri
.header
, "ri", 2));
712 for (i
= 0; i
< ri
.key_count
; i
++) {
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"));
720 return WERR_GEN_FAILURE
;
723 pull
->data
= list_data
;
725 if (!strncmp((char *)list_data
.data
, "li", 2)) {
728 DEBUG(10, ("Subkeys in RI->LI list\n"));
730 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull
,
733 DEBUG(0, ("Error parsing LI list from RI\n"));
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
;
744 key_off
= li
.nk_offset
[idx
- sublist_count
];
745 sublist_count
+= li
.key_count
;
747 } else if (!strncmp((char *)list_data
.data
, "lh", 2)) {
750 DEBUG(10, ("Subkeys in RI->LH list\n"));
752 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull
,
755 DEBUG(0, ("Error parsing LH list from RI\n"));
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
;
766 key_off
= lh
.hr
[idx
- sublist_count
].nk_offset
;
767 sublist_count
+= lh
.key_count
;
770 DEBUG(0,("Unknown sublist in ri block\n"));
773 return WERR_GEN_FAILURE
;
780 if (idx
> sublist_count
) {
781 return WERR_NO_MORE_ITEMS
;
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
,
798 ret
->nk
->clsname_length
);
799 W_ERROR_HAVE_NO_MEMORY(*classname
);
804 if (last_mod_time
!= NULL
)
805 *last_mod_time
= ret
->nk
->last_change
;
808 *name
= talloc_steal(ctx
, ret
->nk
->key_name
);
815 static WERROR
regf_match_subkey_by_name(TALLOC_CTX
*ctx
,
816 const struct hive_key
*key
,
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"));
839 return WERR_GEN_FAILURE
;
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
)) {
856 static WERROR
regf_get_subkey_by_name(TALLOC_CTX
*ctx
,
857 const struct hive_key
*key
,
859 struct hive_key
**ret
)
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
);
874 DEBUG(0, ("Unable to find subkey list\n"));
875 return WERR_GEN_FAILURE
;
878 if (!strncmp((char *)data
.data
, "li", 2)) {
880 struct tdr_pull
*pull
= tdr_pull_init(ctx
);
883 DEBUG(10, ("Subkeys in LI list\n"));
886 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull
, nk
, &li
))) {
887 DEBUG(0, ("Error parsing LI list\n"));
889 return WERR_GEN_FAILURE
;
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
,
908 return WERR_FILE_NOT_FOUND
;
909 } else if (!strncmp((char *)data
.data
, "lf", 2)) {
911 struct tdr_pull
*pull
= tdr_pull_init(ctx
);
914 DEBUG(10, ("Subkeys in LF list\n"));
917 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull
, nk
, &lf
))) {
918 DEBUG(0, ("Error parsing LF list\n"));
920 return WERR_GEN_FAILURE
;
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)) {
934 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk
,
943 return WERR_FILE_NOT_FOUND
;
944 } else if (!strncmp((char *)data
.data
, "lh", 2)) {
946 struct tdr_pull
*pull
= tdr_pull_init(ctx
);
950 DEBUG(10, ("Subkeys in LH list\n"));
953 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull
, nk
, &lh
))) {
954 DEBUG(0, ("Error parsing LH list\n"));
956 return WERR_GEN_FAILURE
;
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
) {
971 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk
,
980 return WERR_FILE_NOT_FOUND
;
981 } else if (!strncmp((char *)data
.data
, "ri", 2)) {
983 struct tdr_pull
*pull
= tdr_pull_init(ctx
);
986 DEBUG(10, ("Subkeys in RI list\n"));
989 if (NT_STATUS_IS_ERR(tdr_pull_ri_block(pull
, nk
, &ri
))) {
990 DEBUG(0, ("Error parsing RI list\n"));
992 return WERR_GEN_FAILURE
;
994 SMB_ASSERT(!strncmp(ri
.header
, "ri", 2));
996 for (i
= 0; i
< ri
.key_count
; i
++) {
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"));
1004 return WERR_GEN_FAILURE
;
1007 pull
->data
= list_data
;
1009 if (!strncmp((char *)list_data
.data
, "li", 2)) {
1012 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull
,
1015 DEBUG(0, ("Error parsing LI list from RI\n"));
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
,
1029 } else if (!strncmp((char *)list_data
.data
, "lh", 2)) {
1033 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull
,
1036 DEBUG(0, ("Error parsing LH list from RI\n"));
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
) {
1047 W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk
, key
,
1060 return WERR_FILE_NOT_FOUND
;
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
,
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
;
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) {
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
);
1132 /* This key will no longer be referring to this sk */
1134 update_cur_sk
= true;
1137 sk_offset
= root
.sk_offset
;
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
;
1149 hbin_store_tdr_resize(regf
,
1150 (tdr_push_fn_t
) tdr_push_sk_block
,
1152 hbin_store_tdr_resize(regf
,
1153 (tdr_push_fn_t
) tdr_push_nk_block
,
1154 private_data
->offset
,
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
;
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
,
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
);
1210 hbin_store_tdr_resize(regf
,
1211 (tdr_push_fn_t
) tdr_push_sk_block
,
1212 private_data
->offset
, private_data
->nk
);
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
;
1222 struct regf_data
*regf
= private_data
->hive
;
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
;
1250 static WERROR
regf_sl_add_entry(struct regf_data
*regf
, uint32_t list_offset
,
1252 uint32_t key_offset
, uint32_t *ret
)
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) {
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
,
1277 talloc_free(li
.nk_offset
);
1278 } else if (regf
->header
->version
.minor
== 3 ||
1279 regf
->header
->version
.minor
== 4) {
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
,
1297 } else if (regf
->header
->version
.minor
== 5) {
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
,
1318 data
= hbin_get(regf
, list_offset
);
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
);
1327 struct nk_block sub_nk
;
1332 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull
, regf
, &li
))) {
1333 DEBUG(0, ("Error parsing LI list\n"));
1335 return WERR_FILE_NOT_FOUND
;
1339 if (strncmp(li
.header
, "li", 2) != 0) {
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
++) {
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) {
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
;
1370 *ret
= hbin_store_tdr_resize(regf
,
1371 (tdr_push_fn_t
)tdr_push_li_block
,
1374 talloc_free(li
.nk_offset
);
1375 } else if (!strncmp((char *)data
.data
, "lf", 2)) {
1376 struct tdr_pull
*pull
= tdr_pull_init(regf
);
1378 struct nk_block sub_nk
;
1383 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull
, regf
, &lf
))) {
1384 DEBUG(0, ("Error parsing LF list\n"));
1386 return WERR_FILE_NOT_FOUND
;
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
++) {
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) {
1405 lf
.hr
= talloc_realloc(regf
, lf
.hr
, struct hash_record
,
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
);
1418 *ret
= hbin_store_tdr_resize(regf
,
1419 (tdr_push_fn_t
)tdr_push_lf_block
,
1423 } else if (!strncmp((char *)data
.data
, "lh", 2)) {
1424 struct tdr_pull
*pull
= tdr_pull_init(regf
);
1426 struct nk_block sub_nk
;
1431 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull
, regf
, &lh
))) {
1432 DEBUG(0, ("Error parsing LH list\n"));
1434 return WERR_FILE_NOT_FOUND
;
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
++) {
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) {
1453 lh
.hr
= talloc_realloc(regf
, lh
.hr
, struct lh_hash
,
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
);
1465 *ret
= hbin_store_tdr_resize(regf
,
1466 (tdr_push_fn_t
)tdr_push_lh_block
,
1470 } else if (!strncmp((char *)data
.data
, "ri", 2)) {
1472 DEBUG(0, ("Adding to 'ri' subkey list is not supported yet.\n"));
1473 return WERR_NOT_SUPPORTED
;
1475 DEBUG(0, ("Cannot add to unknown subkey list\n"));
1476 return WERR_FILE_NOT_FOUND
;
1482 static WERROR
regf_sl_del_entry(struct regf_data
*regf
, uint32_t list_offset
,
1483 uint32_t key_offset
, uint32_t *ret
)
1487 data
= hbin_get(regf
, list_offset
);
1489 DEBUG(0, ("Unable to find subkey list\n"));
1490 return WERR_FILE_NOT_FOUND
;
1493 if (strncmp((char *)data
.data
, "li", 2) == 0) {
1495 struct tdr_pull
*pull
= tdr_pull_init(regf
);
1497 bool found_offset
= false;
1499 DEBUG(10, ("Subkeys in LI list\n"));
1503 if (NT_STATUS_IS_ERR(tdr_pull_li_block(pull
, regf
, &li
))) {
1504 DEBUG(0, ("Error parsing LI list\n"));
1506 return WERR_FILE_NOT_FOUND
;
1510 SMB_ASSERT(!strncmp(li
.header
, "li", 2));
1512 for (i
= 0; i
< li
.key_count
; i
++) {
1514 li
.nk_offset
[i
-1] = li
.nk_offset
[i
];
1516 if (li
.nk_offset
[i
] == key_offset
) {
1517 found_offset
= true;
1521 if (!found_offset
) {
1522 DEBUG(2, ("Subkey not found\n"));
1523 return WERR_FILE_NOT_FOUND
;
1527 /* If there are no entries left, free the subkey list */
1528 if (li
.key_count
== 0) {
1529 hbin_free(regf
, list_offset
);
1533 /* Store li block */
1534 *ret
= hbin_store_tdr_resize(regf
,
1535 (tdr_push_fn_t
) tdr_push_li_block
,
1537 } else if (strncmp((char *)data
.data
, "lf", 2) == 0) {
1539 struct tdr_pull
*pull
= tdr_pull_init(regf
);
1541 bool found_offset
= false;
1543 DEBUG(10, ("Subkeys in LF list\n"));
1547 if (NT_STATUS_IS_ERR(tdr_pull_lf_block(pull
, regf
, &lf
))) {
1548 DEBUG(0, ("Error parsing LF list\n"));
1550 return WERR_FILE_NOT_FOUND
;
1554 SMB_ASSERT(!strncmp(lf
.header
, "lf", 2));
1556 for (i
= 0; i
< lf
.key_count
; i
++) {
1558 lf
.hr
[i
-1] = lf
.hr
[i
];
1561 if (lf
.hr
[i
].nk_offset
== key_offset
) {
1566 if (!found_offset
) {
1567 DEBUG(2, ("Subkey not found\n"));
1568 return WERR_FILE_NOT_FOUND
;
1572 /* If there are no entries left, free the subkey list */
1573 if (lf
.key_count
== 0) {
1574 hbin_free(regf
, list_offset
);
1579 /* Store lf block */
1580 *ret
= hbin_store_tdr_resize(regf
,
1581 (tdr_push_fn_t
) tdr_push_lf_block
,
1583 } else if (strncmp((char *)data
.data
, "lh", 2) == 0) {
1585 struct tdr_pull
*pull
= tdr_pull_init(regf
);
1587 bool found_offset
= false;
1589 DEBUG(10, ("Subkeys in LH list\n"));
1593 if (NT_STATUS_IS_ERR(tdr_pull_lh_block(pull
, regf
, &lh
))) {
1594 DEBUG(0, ("Error parsing LF list\n"));
1596 return WERR_FILE_NOT_FOUND
;
1600 SMB_ASSERT(!strncmp(lh
.header
, "lh", 2));
1602 for (i
= 0; i
< lh
.key_count
; i
++) {
1604 lh
.hr
[i
-1] = lh
.hr
[i
];
1607 if (lh
.hr
[i
].nk_offset
== key_offset
) {
1612 if (!found_offset
) {
1613 DEBUG(0, ("Subkey not found\n"));
1614 return WERR_FILE_NOT_FOUND
;
1618 /* If there are no entries left, free the subkey list */
1619 if (lh
.key_count
== 0) {
1620 hbin_free(regf
, list_offset
);
1625 /* Store lh block */
1626 *ret
= hbin_store_tdr_resize(regf
,
1627 (tdr_push_fn_t
) tdr_push_lh_block
,
1629 } else if (strncmp((char *)data
.data
, "ri", 2) == 0) {
1631 DEBUG(0, ("Sorry, deletion from ri block is not supported yet.\n"));
1632 return WERR_NOT_SUPPORTED
;
1634 DEBUG (0, ("Unknown header found in subkey list.\n"));
1635 return WERR_FILE_NOT_FOUND
;
1640 static WERROR
regf_del_value(TALLOC_CTX
*mem_ctx
, struct hive_key
*key
,
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
;
1648 bool found_offset
= false;
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
++) {
1660 ((uint32_t *)values
.data
)[i
-1] = ((uint32_t *) values
.data
)[i
];
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
,
1666 DEBUG(0, ("Unable to get VK block at %d\n",
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
;
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;
1688 nk
->values_offset
= hbin_store_resize(regf
,
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
,
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
;
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
;
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
;
1729 const char *p
= NULL
;
1731 /* Get subkey information. */
1732 error
= regf_get_subkey_by_index(parent_nk
, sk
, 0,
1735 if (!W_ERROR_IS_OK(error
)) {
1736 DEBUG(0, ("Can't retrieve subkey by index.\n"));
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
));
1748 talloc_free(sk_name
);
1752 if (key
->nk
->values_offset
!= -1) {
1753 struct hive_key
*sk
= (struct hive_key
*)key
;
1755 unsigned int i
= key
->nk
->num_values
;
1758 const char *p
= NULL
;
1760 /* Get value information. */
1761 error
= regf_get_value(parent_nk
, sk
, 0,
1764 if (!W_ERROR_IS_OK(error
)) {
1765 DEBUG(0, ("Can't retrieve value by index.\n"));
1768 val_name
= discard_const_p(char, p
);
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
));
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"));
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
;
1817 nk
.type
= REG_SUB_KEY
;
1818 unix_to_nt_time(&nk
.last_change
, time(NULL
));
1820 nk
.parent_offset
= private_data
->offset
;
1823 nk
.subkeys_offset
= -1;
1824 nk
.unknown_offset
= -1;
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;
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
;
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
);
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
;
1875 uint32_t tmp_vk_offset
, vk_offset
, old_vk_offset
= (uint32_t) -1;
1876 DATA_BLOB values
= {0};
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
,
1889 DEBUG(0, ("Unable to get VK block at 0x%x\n",
1891 return WERR_GEN_FAILURE
;
1893 if (strcmp(vk
.data_name
, name
) == 0) {
1894 old_vk_offset
= tmp_vk_offset
;
1900 /* If it's new, create the vk struct, if it's old, free the old data. */
1901 if (old_vk_offset
== -1) {
1903 if (name
!= NULL
&& name
[0] != '\0') {
1905 vk
.data_name
= name
;
1906 vk
.name_length
= strlen(name
);
1909 vk
.data_name
= NULL
;
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);
1930 /* Store data somewhere */
1931 vk
.data_offset
= hbin_store(regf
, data
);
1933 if (old_vk_offset
== -1) {
1935 vk_offset
= hbin_store_tdr(regf
,
1936 (tdr_push_fn_t
) tdr_push_vk_block
,
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
,
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
);
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
,
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
);
1975 nk
->values_offset
= hbin_store_resize(regf
,
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
);
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
)) {
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
);
2014 if (NT_STATUS_IS_ERR(tdr_push_to_fd(regf
->fd
,
2015 (tdr_push_fn_t
)tdr_push_regf_hdr
,
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
,
2030 DEBUG(0, ("Error writing HBIN block\n"));
2031 return WERR_GEN_FAILURE
;
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
;
2048 struct security_descriptor
*sd
;
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
,
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(®f_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
;
2087 nk
.type
= REG_ROOT_KEY
;
2088 unix_to_nt_time(&nk
.last_change
, time(NULL
));
2090 nk
.parent_offset
= -1;
2093 nk
.subkeys_offset
= -1;
2094 nk
.unknown_offset
= -1;
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
,
2114 SID_NT_AUTHENTICATED_USERS
,
2115 SEC_ACE_TYPE_ACCESS_ALLOWED
,
2117 SEC_ACE_FLAG_OBJECT_INHERIT
,
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
;
2129 sk
.prev_offset
= 0x80;
2130 sk
.next_offset
= 0x80;
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
,
2139 /* Store the sk block */
2140 sk_offset
= hbin_store_tdr(regf
,
2141 (tdr_push_fn_t
) tdr_push_sk_block
,
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
)) {
2157 /* We can drop our own reference now that *key will have created one */
2158 talloc_unlink(NULL
, regf
);
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
;
2169 error
= regf_save_hbin(regf
, 1);
2170 if (!W_ERROR_IS_OK(error
)) {
2171 DEBUG(0, ("Failed to flush regf to disk\n"));
2178 static int regf_destruct(struct regf_data
*regf
)
2183 error
= regf_save_hbin(regf
, 1);
2184 if (!W_ERROR_IS_OK(error
)) {
2185 DEBUG(0, ("Failed to flush registry to disk\n"));
2189 /* Close file descriptor */
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
;
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
,
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
));
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
));
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
));
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
)));
2255 return WERR_GEN_FAILURE
;
2258 pull
->offset
= 0x1000;
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
,
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
));
2280 if (strcmp(hbin
->HBIN_ID
, "hbin") != 0) {
2281 DEBUG(0, ("[%d] Expected 'hbin', got '%s'\n",
2287 regf
->hbins
[i
] = hbin
;
2289 regf
->hbins
= talloc_realloc(regf
, regf
->hbins
,
2290 struct hbin_block
*, i
+2);
2291 regf
->hbins
[i
] = NULL
;
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
);
2307 static struct hive_operations reg_backend_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