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