ocaml: Fix binding for Hivex.value_type
[hivex.git] / lib / hivex.c
1 /* hivex - Windows Registry "hive" extraction library.
2  * Copyright (C) 2009-2011 Red Hat Inc.
3  * Derived from code by Petter Nordahl-Hagen under a compatible license:
4  *   Copyright (c) 1997-2007 Petter Nordahl-Hagen.
5  * Derived from code by Markus Stephany under a compatible license:
6  *   Copyright (c) 2000-2004, Markus Stephany.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation;
11  * version 2.1 of the License.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * See file LICENSE for the full license.
19  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <stddef.h>
27 #include <inttypes.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <iconv.h>
33 #include <sys/mman.h>
34 #include <sys/stat.h>
35 #include <assert.h>
36
37 #include "c-ctype.h"
38 #include "full-read.h"
39 #include "full-write.h"
40
41 #define STREQ(a,b) (strcmp((a),(b)) == 0)
42 #define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
43 //#define STRNEQ(a,b) (strcmp((a),(b)) != 0)
44 //#define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0)
45 #define STREQLEN(a,b,n) (strncmp((a),(b),(n)) == 0)
46 //#define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0)
47 //#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0)
48 //#define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0)
49 #define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0)
50
51 #include "hivex.h"
52 #include "byte_conversions.h"
53
54 /* These limits are in place to stop really stupid stuff and/or exploits. */
55 #define HIVEX_MAX_SUBKEYS       15000
56 #define HIVEX_MAX_VALUES        10000
57 #define HIVEX_MAX_VALUE_LEN   1000000
58 #define HIVEX_MAX_ALLOCATION  1000000
59
60 static char *windows_utf16_to_utf8 (/* const */ char *input, size_t len);
61 static size_t utf16_string_len_in_bytes_max (const char *str, size_t len);
62
63 struct hive_h {
64   char *filename;
65   int fd;
66   size_t size;
67   int msglvl;
68   int writable;
69
70   /* Registry file, memory mapped if read-only, or malloc'd if writing. */
71   union {
72     char *addr;
73     struct ntreg_header *hdr;
74   };
75
76   /* Use a bitmap to store which file offsets are valid (point to a
77    * used block).  We only need to store 1 bit per 32 bits of the file
78    * (because blocks are 4-byte aligned).  We found that the average
79    * block size in a registry file is ~50 bytes.  So roughly 1 in 12
80    * bits in the bitmap will be set, making it likely a more efficient
81    * structure than a hash table.
82    */
83   char *bitmap;
84 #define BITMAP_SET(bitmap,off) (bitmap[(off)>>5] |= 1 << (((off)>>2)&7))
85 #define BITMAP_CLR(bitmap,off) (bitmap[(off)>>5] &= ~ (1 << (((off)>>2)&7)))
86 #define BITMAP_TST(bitmap,off) (bitmap[(off)>>5] & (1 << (((off)>>2)&7)))
87 #define IS_VALID_BLOCK(h,off)               \
88   (((off) & 3) == 0 &&                      \
89    (off) >= 0x1000 &&                       \
90    (off) < (h)->size &&                     \
91    BITMAP_TST((h)->bitmap,(off)))
92
93   /* Fields from the header, extracted from little-endianness hell. */
94   size_t rootoffs;              /* Root key offset (always an nk-block). */
95   size_t endpages;              /* Offset of end of pages. */
96   int64_t last_modified;        /* mtime of base block. */
97
98   /* For writing. */
99   size_t endblocks;             /* Offset to next block allocation (0
100                                    if not allocated anything yet). */
101 };
102
103 /* NB. All fields are little endian. */
104 struct ntreg_header {
105   char magic[4];                /* "regf" */
106   uint32_t sequence1;
107   uint32_t sequence2;
108   int64_t last_modified;
109   uint32_t major_ver;           /* 1 */
110   uint32_t minor_ver;           /* 3 */
111   uint32_t unknown5;            /* 0 */
112   uint32_t unknown6;            /* 1 */
113   uint32_t offset;              /* offset of root key record - 4KB */
114   uint32_t blocks;              /* pointer AFTER last hbin in file - 4KB */
115   uint32_t unknown7;            /* 1 */
116   /* 0x30 */
117   char name[64];                /* original file name of hive */
118   char unknown_guid1[16];
119   char unknown_guid2[16];
120   /* 0x90 */
121   uint32_t unknown8;
122   char unknown_guid3[16];
123   uint32_t unknown9;
124   /* 0xa8 */
125   char unknown10[340];
126   /* 0x1fc */
127   uint32_t csum;                /* checksum: xor of dwords 0-0x1fb. */
128   /* 0x200 */
129   char unknown11[3528];
130   /* 0xfc8 */
131   char unknown_guid4[16];
132   char unknown_guid5[16];
133   char unknown_guid6[16];
134   uint32_t unknown12;
135   uint32_t unknown13;
136   /* 0x1000 */
137 } __attribute__((__packed__));
138
139 struct ntreg_hbin_page {
140   char magic[4];                /* "hbin" */
141   uint32_t offset_first;        /* offset from 1st block */
142   uint32_t page_size;           /* size of this page (multiple of 4KB) */
143   char unknown[20];
144   /* Linked list of blocks follows here. */
145 } __attribute__((__packed__));
146
147 struct ntreg_hbin_block {
148   int32_t seg_len;              /* length of this block (-ve for used block) */
149   char id[2];                   /* the block type (eg. "nk" for nk record) */
150   /* Block data follows here. */
151 } __attribute__((__packed__));
152
153 #define BLOCK_ID_EQ(h,offs,eqid) \
154   (STREQLEN (((struct ntreg_hbin_block *)((h)->addr + (offs)))->id, (eqid), 2))
155
156 static size_t
157 block_len (hive_h *h, size_t blkoff, int *used)
158 {
159   struct ntreg_hbin_block *block;
160   block = (struct ntreg_hbin_block *) (h->addr + blkoff);
161
162   int32_t len = le32toh (block->seg_len);
163   if (len < 0) {
164     if (used) *used = 1;
165     len = -len;
166   } else {
167     if (used) *used = 0;
168   }
169
170   return (size_t) len;
171 }
172
173 struct ntreg_nk_record {
174   int32_t seg_len;              /* length (always -ve because used) */
175   char id[2];                   /* "nk" */
176   uint16_t flags;
177   int64_t timestamp;
178   uint32_t unknown1;
179   uint32_t parent;              /* offset of owner/parent */
180   uint32_t nr_subkeys;          /* number of subkeys */
181   uint32_t nr_subkeys_volatile;
182   uint32_t subkey_lf;           /* lf record containing list of subkeys */
183   uint32_t subkey_lf_volatile;
184   uint32_t nr_values;           /* number of values */
185   uint32_t vallist;             /* value-list record */
186   uint32_t sk;                  /* offset of sk-record */
187   uint32_t classname;           /* offset of classname record */
188   uint16_t max_subkey_name_len; /* maximum length of a subkey name in bytes
189                                    if the subkey was reencoded as UTF-16LE */
190   uint16_t unknown2;
191   uint32_t unknown3;
192   uint32_t max_vk_name_len;     /* maximum length of any vk name in bytes
193                                    if the name was reencoded as UTF-16LE */
194   uint32_t max_vk_data_len;     /* maximum length of any vk data in bytes */
195   uint32_t unknown6;
196   uint16_t name_len;            /* length of name */
197   uint16_t classname_len;       /* length of classname */
198   char name[1];                 /* name follows here */
199 } __attribute__((__packed__));
200
201 struct ntreg_lf_record {
202   int32_t seg_len;
203   char id[2];                   /* "lf"|"lh" */
204   uint16_t nr_keys;             /* number of keys in this record */
205   struct {
206     uint32_t offset;            /* offset of nk-record for this subkey */
207     char hash[4];               /* hash of subkey name */
208   } keys[1];
209 } __attribute__((__packed__));
210
211 struct ntreg_ri_record {
212   int32_t seg_len;
213   char id[2];                   /* "ri" */
214   uint16_t nr_offsets;          /* number of pointers to lh records */
215   uint32_t offset[1];           /* list of pointers to lh records */
216 } __attribute__((__packed__));
217
218 /* This has no ID header. */
219 struct ntreg_value_list {
220   int32_t seg_len;
221   uint32_t offset[1];           /* list of pointers to vk records */
222 } __attribute__((__packed__));
223
224 struct ntreg_vk_record {
225   int32_t seg_len;              /* length (always -ve because used) */
226   char id[2];                   /* "vk" */
227   uint16_t name_len;            /* length of name */
228   /* length of the data:
229    * If data_len is <= 4, then it's stored inline.
230    * Top bit is set to indicate inline.
231    */
232   uint32_t data_len;
233   uint32_t data_offset;         /* pointer to the data (or data if inline) */
234   uint32_t data_type;           /* type of the data */
235   uint16_t flags;               /* bit 0 set => key name ASCII,
236                                    bit 0 clr => key name UTF-16.
237                                    Only seen ASCII here in the wild.
238                                    NB: this is CLEAR for default key. */
239   uint16_t unknown2;
240   char name[1];                 /* key name follows here */
241 } __attribute__((__packed__));
242
243 struct ntreg_sk_record {
244   int32_t seg_len;              /* length (always -ve because used) */
245   char id[2];                   /* "sk" */
246   uint16_t unknown1;
247   uint32_t sk_next;             /* linked into a circular list */
248   uint32_t sk_prev;
249   uint32_t refcount;            /* reference count */
250   uint32_t sec_len;             /* length of security info */
251   char sec_desc[1];             /* security info follows */
252 } __attribute__((__packed__));
253
254 static uint32_t
255 header_checksum (const hive_h *h)
256 {
257   uint32_t *daddr = (uint32_t *) h->addr;
258   size_t i;
259   uint32_t sum = 0;
260
261   for (i = 0; i < 0x1fc / 4; ++i) {
262     sum ^= le32toh (*daddr);
263     daddr++;
264   }
265
266   return sum;
267 }
268
269 #define HIVEX_OPEN_MSGLVL_MASK (HIVEX_OPEN_VERBOSE|HIVEX_OPEN_DEBUG)
270
271 hive_h *
272 hivex_open (const char *filename, int flags)
273 {
274   hive_h *h = NULL;
275
276   assert (sizeof (struct ntreg_header) == 0x1000);
277   assert (offsetof (struct ntreg_header, csum) == 0x1fc);
278
279   h = calloc (1, sizeof *h);
280   if (h == NULL)
281     goto error;
282
283   h->msglvl = flags & HIVEX_OPEN_MSGLVL_MASK;
284
285   const char *debug = getenv ("HIVEX_DEBUG");
286   if (debug && STREQ (debug, "1"))
287     h->msglvl = 2;
288
289   if (h->msglvl >= 2)
290     fprintf (stderr, "hivex_open: created handle %p\n", h);
291
292   h->writable = !!(flags & HIVEX_OPEN_WRITE);
293   h->filename = strdup (filename);
294   if (h->filename == NULL)
295     goto error;
296
297 #ifdef O_CLOEXEC
298   h->fd = open (filename, O_RDONLY | O_CLOEXEC);
299 #else
300   h->fd = open (filename, O_RDONLY);
301 #endif
302   if (h->fd == -1)
303     goto error;
304 #ifndef O_CLOEXEC
305   fcntl (h->fd, F_SETFD, FD_CLOEXEC);
306 #endif
307
308   struct stat statbuf;
309   if (fstat (h->fd, &statbuf) == -1)
310     goto error;
311
312   h->size = statbuf.st_size;
313
314   if (!h->writable) {
315     h->addr = mmap (NULL, h->size, PROT_READ, MAP_SHARED, h->fd, 0);
316     if (h->addr == MAP_FAILED)
317       goto error;
318
319     if (h->msglvl >= 2)
320       fprintf (stderr, "hivex_open: mapped file at %p\n", h->addr);
321   } else {
322     h->addr = malloc (h->size);
323     if (h->addr == NULL)
324       goto error;
325
326     if (full_read (h->fd, h->addr, h->size) < h->size)
327       goto error;
328
329     /* We don't need the file descriptor along this path, since we
330      * have read all the data.
331      */
332     if (close (h->fd) == -1)
333       goto error;
334     h->fd = -1;
335   }
336
337   /* Check header. */
338   if (h->hdr->magic[0] != 'r' ||
339       h->hdr->magic[1] != 'e' ||
340       h->hdr->magic[2] != 'g' ||
341       h->hdr->magic[3] != 'f') {
342     fprintf (stderr, "hivex: %s: not a Windows NT Registry hive file\n",
343              filename);
344     errno = ENOTSUP;
345     goto error;
346   }
347
348   /* Check major version. */
349   uint32_t major_ver = le32toh (h->hdr->major_ver);
350   if (major_ver != 1) {
351     fprintf (stderr,
352              "hivex: %s: hive file major version %" PRIu32 " (expected 1)\n",
353              filename, major_ver);
354     errno = ENOTSUP;
355     goto error;
356   }
357
358   h->bitmap = calloc (1 + h->size / 32, 1);
359   if (h->bitmap == NULL)
360     goto error;
361
362   /* Header checksum. */
363   uint32_t sum = header_checksum (h);
364   if (sum != le32toh (h->hdr->csum)) {
365     fprintf (stderr, "hivex: %s: bad checksum in hive header\n", filename);
366     errno = EINVAL;
367     goto error;
368   }
369
370   /* Last modified time. */
371   h->last_modified = le64toh ((int64_t) h->hdr->last_modified);
372
373   if (h->msglvl >= 2) {
374     char *name = windows_utf16_to_utf8 (h->hdr->name, 64);
375
376     fprintf (stderr,
377              "hivex_open: header fields:\n"
378              "  file version             %" PRIu32 ".%" PRIu32 "\n"
379              "  sequence nos             %" PRIu32 " %" PRIu32 "\n"
380              "    (sequences nos should match if hive was synched at shutdown)\n"
381              "  last modified            %" PRIu64 "\n"
382              "    (Windows filetime, x 100 ns since 1601-01-01)\n"
383              "  original file name       %s\n"
384              "    (only 32 chars are stored, name is probably truncated)\n"
385              "  root offset              0x%x + 0x1000\n"
386              "  end of last page         0x%x + 0x1000 (total file size 0x%zx)\n"
387              "  checksum                 0x%x (calculated 0x%x)\n",
388              major_ver, le32toh (h->hdr->minor_ver),
389              le32toh (h->hdr->sequence1), le32toh (h->hdr->sequence2),
390              h->last_modified,
391              name ? name : "(conversion failed)",
392              le32toh (h->hdr->offset),
393              le32toh (h->hdr->blocks), h->size,
394              le32toh (h->hdr->csum), sum);
395     free (name);
396   }
397
398   h->rootoffs = le32toh (h->hdr->offset) + 0x1000;
399   h->endpages = le32toh (h->hdr->blocks) + 0x1000;
400
401   if (h->msglvl >= 2)
402     fprintf (stderr, "hivex_open: root offset = 0x%zx\n", h->rootoffs);
403
404   /* We'll set this flag when we see a block with the root offset (ie.
405    * the root block).
406    */
407   int seen_root_block = 0, bad_root_block = 0;
408
409   /* Collect some stats. */
410   size_t pages = 0;           /* Number of hbin pages read. */
411   size_t smallest_page = SIZE_MAX, largest_page = 0;
412   size_t blocks = 0;          /* Total number of blocks found. */
413   size_t smallest_block = SIZE_MAX, largest_block = 0, blocks_bytes = 0;
414   size_t used_blocks = 0;     /* Total number of used blocks found. */
415   size_t used_size = 0;       /* Total size (bytes) of used blocks. */
416
417   /* Read the pages and blocks.  The aim here is to be robust against
418    * corrupt or malicious registries.  So we make sure the loops
419    * always make forward progress.  We add the address of each block
420    * we read to a hash table so pointers will only reference the start
421    * of valid blocks.
422    */
423   size_t off;
424   struct ntreg_hbin_page *page;
425   for (off = 0x1000; off < h->size; off += le32toh (page->page_size)) {
426     if (off >= h->endpages)
427       break;
428
429     page = (struct ntreg_hbin_page *) (h->addr + off);
430     if (page->magic[0] != 'h' ||
431         page->magic[1] != 'b' ||
432         page->magic[2] != 'i' ||
433         page->magic[3] != 'n') {
434       fprintf (stderr, "hivex: %s: trailing garbage at end of file "
435                "(at 0x%zx, after %zu pages)\n",
436                filename, off, pages);
437       errno = ENOTSUP;
438       goto error;
439     }
440
441     size_t page_size = le32toh (page->page_size);
442     if (h->msglvl >= 2)
443       fprintf (stderr, "hivex_open: page at 0x%zx, size %zu\n", off, page_size);
444     pages++;
445     if (page_size < smallest_page) smallest_page = page_size;
446     if (page_size > largest_page) largest_page = page_size;
447
448     if (page_size <= sizeof (struct ntreg_hbin_page) ||
449         (page_size & 0x0fff) != 0) {
450       fprintf (stderr, "hivex: %s: page size %zu at 0x%zx, bad registry\n",
451                filename, page_size, off);
452       errno = ENOTSUP;
453       goto error;
454     }
455
456     /* Read the blocks in this page. */
457     size_t blkoff;
458     struct ntreg_hbin_block *block;
459     size_t seg_len;
460     for (blkoff = off + 0x20;
461          blkoff < off + page_size;
462          blkoff += seg_len) {
463       blocks++;
464
465       int is_root = blkoff == h->rootoffs;
466       if (is_root)
467         seen_root_block = 1;
468
469       block = (struct ntreg_hbin_block *) (h->addr + blkoff);
470       int used;
471       seg_len = block_len (h, blkoff, &used);
472       if (seg_len <= 4 || (seg_len & 3) != 0) {
473         fprintf (stderr, "hivex: %s: block size %" PRIu32 " at 0x%zx,"
474                  " bad registry\n",
475                  filename, le32toh (block->seg_len), blkoff);
476         errno = ENOTSUP;
477         goto error;
478       }
479
480       if (h->msglvl >= 2)
481         fprintf (stderr, "hivex_open: %s block id %d,%d at 0x%zx size %zu%s\n",
482                  used ? "used" : "free", block->id[0], block->id[1], blkoff,
483                  seg_len, is_root ? " (root)" : "");
484
485       blocks_bytes += seg_len;
486       if (seg_len < smallest_block) smallest_block = seg_len;
487       if (seg_len > largest_block) largest_block = seg_len;
488
489       if (is_root && !used)
490         bad_root_block = 1;
491
492       if (used) {
493         used_blocks++;
494         used_size += seg_len;
495
496         /* Root block must be an nk-block. */
497         if (is_root && (block->id[0] != 'n' || block->id[1] != 'k'))
498           bad_root_block = 1;
499
500         /* Note this blkoff is a valid address. */
501         BITMAP_SET (h->bitmap, blkoff);
502       }
503     }
504   }
505
506   if (!seen_root_block) {
507     fprintf (stderr, "hivex: %s: no root block found\n", filename);
508     errno = ENOTSUP;
509     goto error;
510   }
511
512   if (bad_root_block) {
513     fprintf (stderr, "hivex: %s: bad root block (free or not nk)\n", filename);
514     errno = ENOTSUP;
515     goto error;
516   }
517
518   if (h->msglvl >= 1)
519     fprintf (stderr,
520              "hivex_open: successfully read Windows Registry hive file:\n"
521              "  pages:          %zu [sml: %zu, lge: %zu]\n"
522              "  blocks:         %zu [sml: %zu, avg: %zu, lge: %zu]\n"
523              "  blocks used:    %zu\n"
524              "  bytes used:     %zu\n",
525              pages, smallest_page, largest_page,
526              blocks, smallest_block, blocks_bytes / blocks, largest_block,
527              used_blocks, used_size);
528
529   return h;
530
531  error:;
532   int err = errno;
533   if (h) {
534     free (h->bitmap);
535     if (h->addr && h->size && h->addr != MAP_FAILED) {
536       if (!h->writable)
537         munmap (h->addr, h->size);
538       else
539         free (h->addr);
540     }
541     if (h->fd >= 0)
542       close (h->fd);
543     free (h->filename);
544     free (h);
545   }
546   errno = err;
547   return NULL;
548 }
549
550 int
551 hivex_close (hive_h *h)
552 {
553   int r;
554
555   if (h->msglvl >= 1)
556     fprintf (stderr, "hivex_close\n");
557
558   free (h->bitmap);
559   if (!h->writable)
560     munmap (h->addr, h->size);
561   else
562     free (h->addr);
563   if (h->fd >= 0)
564     r = close (h->fd);
565   else
566     r = 0;
567   free (h->filename);
568   free (h);
569
570   return r;
571 }
572
573 /*----------------------------------------------------------------------
574  * Reading.
575  */
576
577 hive_node_h
578 hivex_root (hive_h *h)
579 {
580   hive_node_h ret = h->rootoffs;
581   if (!IS_VALID_BLOCK (h, ret)) {
582     errno = HIVEX_NO_KEY;
583     return 0;
584   }
585   return ret;
586 }
587
588 char *
589 hivex_node_name (hive_h *h, hive_node_h node)
590 {
591   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
592     errno = EINVAL;
593     return NULL;
594   }
595
596   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
597
598   /* AFAIK the node name is always plain ASCII, so no conversion
599    * to UTF-8 is necessary.  However we do need to nul-terminate
600    * the string.
601    */
602
603   /* nk->name_len is unsigned, 16 bit, so this is safe ...  However
604    * we have to make sure the length doesn't exceed the block length.
605    */
606   size_t len = le16toh (nk->name_len);
607   size_t seg_len = block_len (h, node, NULL);
608   if (sizeof (struct ntreg_nk_record) + len - 1 > seg_len) {
609     if (h->msglvl >= 2)
610       fprintf (stderr, "hivex_node_name: returning EFAULT because node name"
611                " is too long (%zu, %zu)\n",
612               len, seg_len);
613     errno = EFAULT;
614     return NULL;
615   }
616
617   char *ret = malloc (len + 1);
618   if (ret == NULL)
619     return NULL;
620   memcpy (ret, nk->name, len);
621   ret[len] = '\0';
622   return ret;
623 }
624
625 static int64_t
626 timestamp_check (hive_h *h, hive_node_h node, int64_t timestamp)
627 {
628   if (timestamp < 0) {
629     if (h->msglvl >= 2)
630       fprintf (stderr, "hivex: timestamp_check: "
631                "negative time reported at %zu: %" PRIi64 "\n",
632                node, timestamp);
633     errno = EINVAL;
634     return -1;
635   }
636
637   return timestamp;
638 }
639
640 int64_t
641 hivex_last_modified (hive_h *h)
642 {
643   return timestamp_check (h, 0, h->last_modified);
644 }
645
646 int64_t
647 hivex_node_timestamp (hive_h *h, hive_node_h node)
648 {
649   int64_t ret;
650
651   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
652     errno = EINVAL;
653     return -1;
654   }
655
656   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
657
658   ret = le64toh (nk->timestamp);
659   return timestamp_check (h, node, ret);
660 }
661
662 #if 0
663 /* I think the documentation for the sk and classname fields in the nk
664  * record is wrong, or else the offset field is in the wrong place.
665  * Otherwise this makes no sense.  Disabled this for now -- it's not
666  * useful for reading the registry anyway.
667  */
668
669 hive_security_h
670 hivex_node_security (hive_h *h, hive_node_h node)
671 {
672   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
673     errno = EINVAL;
674     return 0;
675   }
676
677   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
678
679   hive_node_h ret = le32toh (nk->sk);
680   ret += 0x1000;
681   if (!IS_VALID_BLOCK (h, ret)) {
682     errno = EFAULT;
683     return 0;
684   }
685   return ret;
686 }
687
688 hive_classname_h
689 hivex_node_classname (hive_h *h, hive_node_h node)
690 {
691   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
692     errno = EINVAL;
693     return 0;
694   }
695
696   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
697
698   hive_node_h ret = le32toh (nk->classname);
699   ret += 0x1000;
700   if (!IS_VALID_BLOCK (h, ret)) {
701     errno = EFAULT;
702     return 0;
703   }
704   return ret;
705 }
706 #endif
707
708 /* Structure for returning 0-terminated lists of offsets (nodes,
709  * values, etc).
710  */
711 struct offset_list {
712   size_t *offsets;
713   size_t len;
714   size_t alloc;
715 };
716
717 static void
718 init_offset_list (struct offset_list *list)
719 {
720   list->len = 0;
721   list->alloc = 0;
722   list->offsets = NULL;
723 }
724
725 #define INIT_OFFSET_LIST(name) \
726   struct offset_list name; \
727   init_offset_list (&name)
728
729 /* Preallocates the offset_list, but doesn't make the contents longer. */
730 static int
731 grow_offset_list (struct offset_list *list, size_t alloc)
732 {
733   assert (alloc >= list->len);
734   size_t *p = realloc (list->offsets, alloc * sizeof (size_t));
735   if (p == NULL)
736     return -1;
737   list->offsets = p;
738   list->alloc = alloc;
739   return 0;
740 }
741
742 static int
743 add_to_offset_list (struct offset_list *list, size_t offset)
744 {
745   if (list->len >= list->alloc) {
746     if (grow_offset_list (list, list->alloc ? list->alloc * 2 : 4) == -1)
747       return -1;
748   }
749   list->offsets[list->len] = offset;
750   list->len++;
751   return 0;
752 }
753
754 static void
755 free_offset_list (struct offset_list *list)
756 {
757   free (list->offsets);
758 }
759
760 static size_t *
761 return_offset_list (struct offset_list *list)
762 {
763   if (add_to_offset_list (list, 0) == -1)
764     return NULL;
765   return list->offsets;         /* caller frees */
766 }
767
768 /* Iterate over children, returning child nodes and intermediate blocks. */
769 #define GET_CHILDREN_NO_CHECK_NK 1
770
771 static int
772 get_children (hive_h *h, hive_node_h node,
773               hive_node_h **children_ret, size_t **blocks_ret,
774               int flags)
775 {
776   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
777     errno = EINVAL;
778     return -1;
779   }
780
781   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
782
783   size_t nr_subkeys_in_nk = le32toh (nk->nr_subkeys);
784
785   INIT_OFFSET_LIST (children);
786   INIT_OFFSET_LIST (blocks);
787
788   /* Deal with the common "no subkeys" case quickly. */
789   if (nr_subkeys_in_nk == 0)
790     goto ok;
791
792   /* Arbitrarily limit the number of subkeys we will ever deal with. */
793   if (nr_subkeys_in_nk > HIVEX_MAX_SUBKEYS) {
794     if (h->msglvl >= 2)
795       fprintf (stderr, "hivex: get_children: returning ERANGE because "
796                "nr_subkeys_in_nk > HIVEX_MAX_SUBKEYS (%zu > %d)\n",
797                nr_subkeys_in_nk, HIVEX_MAX_SUBKEYS);
798     errno = ERANGE;
799     goto error;
800   }
801
802   /* Preallocate space for the children. */
803   if (grow_offset_list (&children, nr_subkeys_in_nk) == -1)
804     goto error;
805
806   /* The subkey_lf field can point either to an lf-record, which is
807    * the common case, or if there are lots of subkeys, to an
808    * ri-record.
809    */
810   size_t subkey_lf = le32toh (nk->subkey_lf);
811   subkey_lf += 0x1000;
812   if (!IS_VALID_BLOCK (h, subkey_lf)) {
813     if (h->msglvl >= 2)
814       fprintf (stderr, "hivex_node_children: returning EFAULT"
815                " because subkey_lf is not a valid block (0x%zx)\n",
816                subkey_lf);
817     errno = EFAULT;
818     goto error;
819   }
820
821   if (add_to_offset_list (&blocks, subkey_lf) == -1)
822     goto error;
823
824   struct ntreg_hbin_block *block =
825     (struct ntreg_hbin_block *) (h->addr + subkey_lf);
826
827   /* Points to lf-record?  (Note, also "lh" but that is basically the
828    * same as "lf" as far as we are concerned here).
829    */
830   if (block->id[0] == 'l' && (block->id[1] == 'f' || block->id[1] == 'h')) {
831     struct ntreg_lf_record *lf = (struct ntreg_lf_record *) block;
832
833     /* Check number of subkeys in the nk-record matches number of subkeys
834      * in the lf-record.
835      */
836     size_t nr_subkeys_in_lf = le16toh (lf->nr_keys);
837
838     if (h->msglvl >= 2)
839       fprintf (stderr, "hivex_node_children: nr_subkeys_in_nk = %zu,"
840                " nr_subkeys_in_lf = %zu\n",
841                nr_subkeys_in_nk, nr_subkeys_in_lf);
842
843     if (nr_subkeys_in_nk != nr_subkeys_in_lf) {
844       errno = ENOTSUP;
845       goto error;
846     }
847
848     size_t len = block_len (h, subkey_lf, NULL);
849     if (8 + nr_subkeys_in_lf * 8 > len) {
850       if (h->msglvl >= 2)
851         fprintf (stderr, "hivex_node_children: returning EFAULT"
852                  " because too many subkeys (%zu, %zu)\n",
853                  nr_subkeys_in_lf, len);
854       errno = EFAULT;
855       goto error;
856     }
857
858     size_t i;
859     for (i = 0; i < nr_subkeys_in_lf; ++i) {
860       hive_node_h subkey = le32toh (lf->keys[i].offset);
861       subkey += 0x1000;
862       if (!(flags & GET_CHILDREN_NO_CHECK_NK)) {
863         if (!IS_VALID_BLOCK (h, subkey)) {
864           if (h->msglvl >= 2)
865             fprintf (stderr, "hivex_node_children: returning EFAULT"
866                      " because subkey is not a valid block (0x%zx)\n",
867                      subkey);
868           errno = EFAULT;
869           goto error;
870         }
871       }
872       if (add_to_offset_list (&children, subkey) == -1)
873         goto error;
874     }
875     goto ok;
876   }
877   /* Points to ri-record? */
878   else if (block->id[0] == 'r' && block->id[1] == 'i') {
879     struct ntreg_ri_record *ri = (struct ntreg_ri_record *) block;
880
881     size_t nr_offsets = le16toh (ri->nr_offsets);
882
883     /* Count total number of children. */
884     size_t i, count = 0;
885     for (i = 0; i < nr_offsets; ++i) {
886       hive_node_h offset = le32toh (ri->offset[i]);
887       offset += 0x1000;
888       if (!IS_VALID_BLOCK (h, offset)) {
889         if (h->msglvl >= 2)
890           fprintf (stderr, "hivex_node_children: returning EFAULT"
891                    " because ri-offset is not a valid block (0x%zx)\n",
892                    offset);
893         errno = EFAULT;
894         goto error;
895       }
896       if (!BLOCK_ID_EQ (h, offset, "lf") && !BLOCK_ID_EQ (h, offset, "lh")) {
897         if (h->msglvl >= 2)
898           fprintf (stderr, "get_children: returning ENOTSUP"
899                    " because ri-record offset does not point to lf/lh (0x%zx)\n",
900                    offset);
901         errno = ENOTSUP;
902         goto error;
903       }
904
905       if (add_to_offset_list (&blocks, offset) == -1)
906         goto error;
907
908       struct ntreg_lf_record *lf =
909         (struct ntreg_lf_record *) (h->addr + offset);
910
911       count += le16toh (lf->nr_keys);
912     }
913
914     if (h->msglvl >= 2)
915       fprintf (stderr, "hivex_node_children: nr_subkeys_in_nk = %zu,"
916                " counted = %zu\n",
917                nr_subkeys_in_nk, count);
918
919     if (nr_subkeys_in_nk != count) {
920       errno = ENOTSUP;
921       goto error;
922     }
923
924     /* Copy list of children.  Note nr_subkeys_in_nk is limited to
925      * something reasonable above.
926      */
927     for (i = 0; i < nr_offsets; ++i) {
928       hive_node_h offset = le32toh (ri->offset[i]);
929       offset += 0x1000;
930       if (!IS_VALID_BLOCK (h, offset)) {
931         if (h->msglvl >= 2)
932           fprintf (stderr, "hivex_node_children: returning EFAULT"
933                    " because ri-offset is not a valid block (0x%zx)\n",
934                    offset);
935         errno = EFAULT;
936         goto error;
937       }
938       if (!BLOCK_ID_EQ (h, offset, "lf") && !BLOCK_ID_EQ (h, offset, "lh")) {
939         if (h->msglvl >= 2)
940           fprintf (stderr, "get_children: returning ENOTSUP"
941                    " because ri-record offset does not point to lf/lh (0x%zx)\n",
942                    offset);
943         errno = ENOTSUP;
944         goto error;
945       }
946
947       struct ntreg_lf_record *lf =
948         (struct ntreg_lf_record *) (h->addr + offset);
949
950       size_t j;
951       for (j = 0; j < le16toh (lf->nr_keys); ++j) {
952         hive_node_h subkey = le32toh (lf->keys[j].offset);
953         subkey += 0x1000;
954         if (!(flags & GET_CHILDREN_NO_CHECK_NK)) {
955           if (!IS_VALID_BLOCK (h, subkey)) {
956             if (h->msglvl >= 2)
957               fprintf (stderr, "hivex_node_children: returning EFAULT"
958                        " because indirect subkey is not a valid block (0x%zx)\n",
959                        subkey);
960             errno = EFAULT;
961             goto error;
962           }
963         }
964         if (add_to_offset_list (&children, subkey) == -1)
965           goto error;
966       }
967     }
968     goto ok;
969   }
970   /* else not supported, set errno and fall through */
971   if (h->msglvl >= 2)
972     fprintf (stderr, "get_children: returning ENOTSUP"
973              " because subkey block is not lf/lh/ri (0x%zx, %d, %d)\n",
974              subkey_lf, block->id[0], block->id[1]);
975   errno = ENOTSUP;
976  error:
977   free_offset_list (&children);
978   free_offset_list (&blocks);
979   return -1;
980
981  ok:
982   *children_ret = return_offset_list (&children);
983   *blocks_ret = return_offset_list (&blocks);
984   if (!*children_ret || !*blocks_ret)
985     goto error;
986   return 0;
987 }
988
989 hive_node_h *
990 hivex_node_children (hive_h *h, hive_node_h node)
991 {
992   hive_node_h *children;
993   size_t *blocks;
994
995   if (get_children (h, node, &children, &blocks, 0) == -1)
996     return NULL;
997
998   free (blocks);
999   return children;
1000 }
1001
1002 /* Very inefficient, but at least having a separate API call
1003  * allows us to make it more efficient in future.
1004  */
1005 hive_node_h
1006 hivex_node_get_child (hive_h *h, hive_node_h node, const char *nname)
1007 {
1008   hive_node_h *children = NULL;
1009   char *name = NULL;
1010   hive_node_h ret = 0;
1011
1012   children = hivex_node_children (h, node);
1013   if (!children) goto error;
1014
1015   size_t i;
1016   for (i = 0; children[i] != 0; ++i) {
1017     name = hivex_node_name (h, children[i]);
1018     if (!name) goto error;
1019     if (STRCASEEQ (name, nname)) {
1020       ret = children[i];
1021       break;
1022     }
1023     free (name); name = NULL;
1024   }
1025
1026  error:
1027   free (children);
1028   free (name);
1029   return ret;
1030 }
1031
1032 hive_node_h
1033 hivex_node_parent (hive_h *h, hive_node_h node)
1034 {
1035   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
1036     errno = EINVAL;
1037     return 0;
1038   }
1039
1040   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
1041
1042   hive_node_h ret = le32toh (nk->parent);
1043   ret += 0x1000;
1044   if (!IS_VALID_BLOCK (h, ret)) {
1045     if (h->msglvl >= 2)
1046       fprintf (stderr, "hivex_node_parent: returning EFAULT"
1047                " because parent is not a valid block (0x%zx)\n",
1048               ret);
1049     errno = EFAULT;
1050     return 0;
1051   }
1052   return ret;
1053 }
1054
1055 static int
1056 get_values (hive_h *h, hive_node_h node,
1057             hive_value_h **values_ret, size_t **blocks_ret)
1058 {
1059   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
1060     errno = EINVAL;
1061     return -1;
1062   }
1063
1064   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
1065
1066   size_t nr_values = le32toh (nk->nr_values);
1067
1068   if (h->msglvl >= 2)
1069     fprintf (stderr, "hivex_node_values: nr_values = %zu\n", nr_values);
1070
1071   INIT_OFFSET_LIST (values);
1072   INIT_OFFSET_LIST (blocks);
1073
1074   /* Deal with the common "no values" case quickly. */
1075   if (nr_values == 0)
1076     goto ok;
1077
1078   /* Arbitrarily limit the number of values we will ever deal with. */
1079   if (nr_values > HIVEX_MAX_VALUES) {
1080     if (h->msglvl >= 2)
1081       fprintf (stderr, "hivex: get_values: returning ERANGE"
1082                " because nr_values > HIVEX_MAX_VALUES (%zu > %d)\n",
1083                nr_values, HIVEX_MAX_VALUES);
1084     errno = ERANGE;
1085     goto error;
1086   }
1087
1088   /* Preallocate space for the values. */
1089   if (grow_offset_list (&values, nr_values) == -1)
1090     goto error;
1091
1092   /* Get the value list and check it looks reasonable. */
1093   size_t vlist_offset = le32toh (nk->vallist);
1094   vlist_offset += 0x1000;
1095   if (!IS_VALID_BLOCK (h, vlist_offset)) {
1096     if (h->msglvl >= 2)
1097       fprintf (stderr, "hivex_node_values: returning EFAULT"
1098                " because value list is not a valid block (0x%zx)\n",
1099                vlist_offset);
1100     errno = EFAULT;
1101     goto error;
1102   }
1103
1104   if (add_to_offset_list (&blocks, vlist_offset) == -1)
1105     goto error;
1106
1107   struct ntreg_value_list *vlist =
1108     (struct ntreg_value_list *) (h->addr + vlist_offset);
1109
1110   size_t len = block_len (h, vlist_offset, NULL);
1111   if (4 + nr_values * 4 > len) {
1112     if (h->msglvl >= 2)
1113       fprintf (stderr, "hivex_node_values: returning EFAULT"
1114                " because value list is too long (%zu, %zu)\n",
1115                nr_values, len);
1116     errno = EFAULT;
1117     goto error;
1118   }
1119
1120   size_t i;
1121   for (i = 0; i < nr_values; ++i) {
1122     hive_node_h value = le32toh (vlist->offset[i]);
1123     value += 0x1000;
1124     if (!IS_VALID_BLOCK (h, value)) {
1125       if (h->msglvl >= 2)
1126         fprintf (stderr, "hivex_node_values: returning EFAULT"
1127                  " because value is not a valid block (0x%zx)\n",
1128                  value);
1129       errno = EFAULT;
1130       goto error;
1131     }
1132     if (add_to_offset_list (&values, value) == -1)
1133       goto error;
1134   }
1135
1136  ok:
1137   *values_ret = return_offset_list (&values);
1138   *blocks_ret = return_offset_list (&blocks);
1139   if (!*values_ret || !*blocks_ret)
1140     goto error;
1141   return 0;
1142
1143  error:
1144   free_offset_list (&values);
1145   free_offset_list (&blocks);
1146   return -1;
1147 }
1148
1149 hive_value_h *
1150 hivex_node_values (hive_h *h, hive_node_h node)
1151 {
1152   hive_value_h *values;
1153   size_t *blocks;
1154
1155   if (get_values (h, node, &values, &blocks) == -1)
1156     return NULL;
1157
1158   free (blocks);
1159   return values;
1160 }
1161
1162 /* Very inefficient, but at least having a separate API call
1163  * allows us to make it more efficient in future.
1164  */
1165 hive_value_h
1166 hivex_node_get_value (hive_h *h, hive_node_h node, const char *key)
1167 {
1168   hive_value_h *values = NULL;
1169   char *name = NULL;
1170   hive_value_h ret = 0;
1171
1172   values = hivex_node_values (h, node);
1173   if (!values) goto error;
1174
1175   size_t i;
1176   for (i = 0; values[i] != 0; ++i) {
1177     name = hivex_value_key (h, values[i]);
1178     if (!name) goto error;
1179     if (STRCASEEQ (name, key)) {
1180       ret = values[i];
1181       break;
1182     }
1183     free (name); name = NULL;
1184   }
1185
1186  error:
1187   free (values);
1188   free (name);
1189   return ret;
1190 }
1191
1192 char *
1193 hivex_value_key (hive_h *h, hive_value_h value)
1194 {
1195   if (!IS_VALID_BLOCK (h, value) || !BLOCK_ID_EQ (h, value, "vk")) {
1196     errno = EINVAL;
1197     return 0;
1198   }
1199
1200   struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + value);
1201
1202   /* AFAIK the key is always plain ASCII, so no conversion to UTF-8 is
1203    * necessary.  However we do need to nul-terminate the string.
1204    */
1205
1206   /* vk->name_len is unsigned, 16 bit, so this is safe ...  However
1207    * we have to make sure the length doesn't exceed the block length.
1208    */
1209   size_t len = le16toh (vk->name_len);
1210   size_t seg_len = block_len (h, value, NULL);
1211   if (sizeof (struct ntreg_vk_record) + len - 1 > seg_len) {
1212     if (h->msglvl >= 2)
1213       fprintf (stderr, "hivex_value_key: returning EFAULT"
1214                " because key length is too long (%zu, %zu)\n",
1215                len, seg_len);
1216     errno = EFAULT;
1217     return NULL;
1218   }
1219
1220   char *ret = malloc (len + 1);
1221   if (ret == NULL)
1222     return NULL;
1223   memcpy (ret, vk->name, len);
1224   ret[len] = '\0';
1225   return ret;
1226 }
1227
1228 int
1229 hivex_value_type (hive_h *h, hive_value_h value, hive_type *t, size_t *len)
1230 {
1231   if (!IS_VALID_BLOCK (h, value) || !BLOCK_ID_EQ (h, value, "vk")) {
1232     errno = EINVAL;
1233     return -1;
1234   }
1235
1236   struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + value);
1237
1238   if (t)
1239     *t = le32toh (vk->data_type);
1240
1241   if (len) {
1242     *len = le32toh (vk->data_len);
1243     *len &= 0x7fffffff;         /* top bit indicates if data is stored inline */
1244   }
1245
1246   return 0;
1247 }
1248
1249 char *
1250 hivex_value_value (hive_h *h, hive_value_h value,
1251                    hive_type *t_rtn, size_t *len_rtn)
1252 {
1253   if (!IS_VALID_BLOCK (h, value) || !BLOCK_ID_EQ (h, value, "vk")) {
1254     errno = EINVAL;
1255     return NULL;
1256   }
1257
1258   struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + value);
1259
1260   hive_type t;
1261   size_t len;
1262   int is_inline;
1263
1264   t = le32toh (vk->data_type);
1265
1266   len = le32toh (vk->data_len);
1267   is_inline = !!(len & 0x80000000);
1268   len &= 0x7fffffff;
1269
1270   if (h->msglvl >= 2)
1271     fprintf (stderr, "hivex_value_value: value=0x%zx, t=%d, len=%zu, inline=%d\n",
1272              value, t, len, is_inline);
1273
1274   if (t_rtn)
1275     *t_rtn = t;
1276   if (len_rtn)
1277     *len_rtn = len;
1278
1279   if (is_inline && len > 4) {
1280     errno = ENOTSUP;
1281     return NULL;
1282   }
1283
1284   /* Arbitrarily limit the length that we will read. */
1285   if (len > HIVEX_MAX_VALUE_LEN) {
1286     if (h->msglvl >= 2)
1287       fprintf (stderr, "hivex_value_value: returning ERANGE because data "
1288                "length > HIVEX_MAX_VALUE_LEN (%zu > %d)\n",
1289                len, HIVEX_MAX_SUBKEYS);
1290     errno = ERANGE;
1291     return NULL;
1292   }
1293
1294   char *ret = malloc (len);
1295   if (ret == NULL)
1296     return NULL;
1297
1298   if (is_inline) {
1299     memcpy (ret, (char *) &vk->data_offset, len);
1300     return ret;
1301   }
1302
1303   size_t data_offset = le32toh (vk->data_offset);
1304   data_offset += 0x1000;
1305   if (!IS_VALID_BLOCK (h, data_offset)) {
1306     if (h->msglvl >= 2)
1307       fprintf (stderr, "hivex_value_value: returning EFAULT because data "
1308                "offset is not a valid block (0x%zx)\n",
1309                data_offset);
1310     errno = EFAULT;
1311     free (ret);
1312     return NULL;
1313   }
1314
1315   /* Check that the declared size isn't larger than the block its in.
1316    *
1317    * XXX Some apparently valid registries are seen to have this,
1318    * so turn this into a warning and substitute the smaller length
1319    * instead.
1320    */
1321   size_t blen = block_len (h, data_offset, NULL);
1322   if (len > blen - 4 /* subtract 4 for block header */) {
1323     if (h->msglvl >= 2)
1324       fprintf (stderr, "hivex_value_value: warning: declared data length "
1325                "is longer than the block it is in "
1326                "(data 0x%zx, data len %zu, block len %zu)\n",
1327                data_offset, len, blen);
1328     len = blen - 4;
1329
1330     /* Return the smaller length to the caller too. */
1331     if (len_rtn)
1332       *len_rtn = len;
1333   }
1334
1335   char *data = h->addr + data_offset + 4;
1336   memcpy (ret, data, len);
1337   return ret;
1338 }
1339
1340 static char *
1341 windows_utf16_to_utf8 (/* const */ char *input, size_t len)
1342 {
1343   iconv_t ic = iconv_open ("UTF-8", "UTF-16");
1344   if (ic == (iconv_t) -1)
1345     return NULL;
1346
1347   /* iconv(3) has an insane interface ... */
1348
1349   /* Mostly UTF-8 will be smaller, so this is a good initial guess. */
1350   size_t outalloc = len;
1351
1352  again:;
1353   size_t inlen = len;
1354   size_t outlen = outalloc;
1355   char *out = malloc (outlen + 1);
1356   if (out == NULL) {
1357     int err = errno;
1358     iconv_close (ic);
1359     errno = err;
1360     return NULL;
1361   }
1362   char *inp = input;
1363   char *outp = out;
1364
1365   size_t r = iconv (ic, &inp, &inlen, &outp, &outlen);
1366   if (r == (size_t) -1) {
1367     if (errno == E2BIG) {
1368       int err = errno;
1369       size_t prev = outalloc;
1370       /* Try again with a larger output buffer. */
1371       free (out);
1372       outalloc *= 2;
1373       if (outalloc < prev) {
1374         iconv_close (ic);
1375         errno = err;
1376         return NULL;
1377       }
1378       goto again;
1379     }
1380     else {
1381       /* Else some conversion failure, eg. EILSEQ, EINVAL. */
1382       int err = errno;
1383       iconv_close (ic);
1384       free (out);
1385       errno = err;
1386       return NULL;
1387     }
1388   }
1389
1390   *outp = '\0';
1391   iconv_close (ic);
1392
1393   return out;
1394 }
1395
1396 char *
1397 hivex_value_string (hive_h *h, hive_value_h value)
1398 {
1399   hive_type t;
1400   size_t len;
1401   char *data = hivex_value_value (h, value, &t, &len);
1402
1403   if (data == NULL)
1404     return NULL;
1405
1406   if (t != hive_t_string && t != hive_t_expand_string && t != hive_t_link) {
1407     free (data);
1408     errno = EINVAL;
1409     return NULL;
1410   }
1411
1412   /* Deal with the case where Windows has allocated a large buffer
1413    * full of random junk, and only the first few bytes of the buffer
1414    * contain a genuine UTF-16 string.
1415    *
1416    * In this case, iconv would try to process the junk bytes as UTF-16
1417    * and inevitably find an illegal sequence (EILSEQ).  Instead, stop
1418    * after we find the first \0\0.
1419    *
1420    * (Found by Hilko Bengen in a fresh Windows XP SOFTWARE hive).
1421    */
1422   size_t slen = utf16_string_len_in_bytes_max (data, len);
1423   if (slen < len)
1424     len = slen;
1425
1426   char *ret = windows_utf16_to_utf8 (data, len);
1427   free (data);
1428   if (ret == NULL)
1429     return NULL;
1430
1431   return ret;
1432 }
1433
1434 static void
1435 free_strings (char **argv)
1436 {
1437   if (argv) {
1438     size_t i;
1439
1440     for (i = 0; argv[i] != NULL; ++i)
1441       free (argv[i]);
1442     free (argv);
1443   }
1444 }
1445
1446 /* Get the length of a UTF-16 format string.  Handle the string as
1447  * pairs of bytes, looking for the first \0\0 pair.  Only read up to
1448  * 'len' maximum bytes.
1449  */
1450 static size_t
1451 utf16_string_len_in_bytes_max (const char *str, size_t len)
1452 {
1453   size_t ret = 0;
1454
1455   while (len >= 2 && (str[0] || str[1])) {
1456     str += 2;
1457     ret += 2;
1458     len -= 2;
1459   }
1460
1461   return ret;
1462 }
1463
1464 /* http://blogs.msdn.com/oldnewthing/archive/2009/10/08/9904646.aspx */
1465 char **
1466 hivex_value_multiple_strings (hive_h *h, hive_value_h value)
1467 {
1468   hive_type t;
1469   size_t len;
1470   char *data = hivex_value_value (h, value, &t, &len);
1471
1472   if (data == NULL)
1473     return NULL;
1474
1475   if (t != hive_t_multiple_strings) {
1476     free (data);
1477     errno = EINVAL;
1478     return NULL;
1479   }
1480
1481   size_t nr_strings = 0;
1482   char **ret = malloc ((1 + nr_strings) * sizeof (char *));
1483   if (ret == NULL) {
1484     free (data);
1485     return NULL;
1486   }
1487   ret[0] = NULL;
1488
1489   char *p = data;
1490   size_t plen;
1491
1492   while (p < data + len &&
1493          (plen = utf16_string_len_in_bytes_max (p, data + len - p)) > 0) {
1494     nr_strings++;
1495     char **ret2 = realloc (ret, (1 + nr_strings) * sizeof (char *));
1496     if (ret2 == NULL) {
1497       free_strings (ret);
1498       free (data);
1499       return NULL;
1500     }
1501     ret = ret2;
1502
1503     ret[nr_strings-1] = windows_utf16_to_utf8 (p, plen);
1504     ret[nr_strings] = NULL;
1505     if (ret[nr_strings-1] == NULL) {
1506       free_strings (ret);
1507       free (data);
1508       return NULL;
1509     }
1510
1511     p += plen + 2 /* skip over UTF-16 \0\0 at the end of this string */;
1512   }
1513
1514   free (data);
1515   return ret;
1516 }
1517
1518 int32_t
1519 hivex_value_dword (hive_h *h, hive_value_h value)
1520 {
1521   hive_type t;
1522   size_t len;
1523   char *data = hivex_value_value (h, value, &t, &len);
1524
1525   if (data == NULL)
1526     return -1;
1527
1528   if ((t != hive_t_dword && t != hive_t_dword_be) || len != 4) {
1529     free (data);
1530     errno = EINVAL;
1531     return -1;
1532   }
1533
1534   int32_t ret = *(int32_t*)data;
1535   free (data);
1536   if (t == hive_t_dword)        /* little endian */
1537     ret = le32toh (ret);
1538   else
1539     ret = be32toh (ret);
1540
1541   return ret;
1542 }
1543
1544 int64_t
1545 hivex_value_qword (hive_h *h, hive_value_h value)
1546 {
1547   hive_type t;
1548   size_t len;
1549   char *data = hivex_value_value (h, value, &t, &len);
1550
1551   if (data == NULL)
1552     return -1;
1553
1554   if (t != hive_t_qword || len != 8) {
1555     free (data);
1556     errno = EINVAL;
1557     return -1;
1558   }
1559
1560   int64_t ret = *(int64_t*)data;
1561   free (data);
1562   ret = le64toh (ret);          /* always little endian */
1563
1564   return ret;
1565 }
1566
1567 /*----------------------------------------------------------------------
1568  * Visiting.
1569  */
1570
1571 int
1572 hivex_visit (hive_h *h, const struct hivex_visitor *visitor, size_t len,
1573              void *opaque, int flags)
1574 {
1575   return hivex_visit_node (h, hivex_root (h), visitor, len, opaque, flags);
1576 }
1577
1578 static int hivex__visit_node (hive_h *h, hive_node_h node,
1579                               const struct hivex_visitor *vtor,
1580                               char *unvisited, void *opaque, int flags);
1581
1582 int
1583 hivex_visit_node (hive_h *h, hive_node_h node,
1584                   const struct hivex_visitor *visitor, size_t len, void *opaque,
1585                   int flags)
1586 {
1587   struct hivex_visitor vtor;
1588   memset (&vtor, 0, sizeof vtor);
1589
1590   /* Note that len might be larger *or smaller* than the expected size. */
1591   size_t copysize = len <= sizeof vtor ? len : sizeof vtor;
1592   memcpy (&vtor, visitor, copysize);
1593
1594   /* This bitmap records unvisited nodes, so we don't loop if the
1595    * registry contains cycles.
1596    */
1597   char *unvisited = malloc (1 + h->size / 32);
1598   if (unvisited == NULL)
1599     return -1;
1600   memcpy (unvisited, h->bitmap, 1 + h->size / 32);
1601
1602   int r = hivex__visit_node (h, node, &vtor, unvisited, opaque, flags);
1603   free (unvisited);
1604   return r;
1605 }
1606
1607 static int
1608 hivex__visit_node (hive_h *h, hive_node_h node,
1609                    const struct hivex_visitor *vtor, char *unvisited,
1610                    void *opaque, int flags)
1611 {
1612   int skip_bad = flags & HIVEX_VISIT_SKIP_BAD;
1613   char *name = NULL;
1614   hive_value_h *values = NULL;
1615   hive_node_h *children = NULL;
1616   char *key = NULL;
1617   char *str = NULL;
1618   char **strs = NULL;
1619   int i;
1620
1621   /* Return -1 on all callback errors.  However on internal errors,
1622    * check if skip_bad is set and suppress those errors if so.
1623    */
1624   int ret = -1;
1625
1626   if (!BITMAP_TST (unvisited, node)) {
1627     if (h->msglvl >= 2)
1628       fprintf (stderr, "hivex__visit_node: contains cycle:"
1629                " visited node 0x%zx already\n",
1630                node);
1631
1632     errno = ELOOP;
1633     return skip_bad ? 0 : -1;
1634   }
1635   BITMAP_CLR (unvisited, node);
1636
1637   name = hivex_node_name (h, node);
1638   if (!name) return skip_bad ? 0 : -1;
1639   if (vtor->node_start && vtor->node_start (h, opaque, node, name) == -1)
1640     goto error;
1641
1642   values = hivex_node_values (h, node);
1643   if (!values) {
1644     ret = skip_bad ? 0 : -1;
1645     goto error;
1646   }
1647
1648   for (i = 0; values[i] != 0; ++i) {
1649     hive_type t;
1650     size_t len;
1651
1652     if (hivex_value_type (h, values[i], &t, &len) == -1) {
1653       ret = skip_bad ? 0 : -1;
1654       goto error;
1655     }
1656
1657     key = hivex_value_key (h, values[i]);
1658     if (key == NULL) {
1659       ret = skip_bad ? 0 : -1;
1660       goto error;
1661     }
1662
1663     if (vtor->value_any) {
1664       str = hivex_value_value (h, values[i], &t, &len);
1665       if (str == NULL) {
1666         ret = skip_bad ? 0 : -1;
1667         goto error;
1668       }
1669       if (vtor->value_any (h, opaque, node, values[i], t, len, key, str) == -1)
1670         goto error;
1671       free (str); str = NULL;
1672     }
1673     else {
1674       switch (t) {
1675       case hive_t_none:
1676         str = hivex_value_value (h, values[i], &t, &len);
1677         if (str == NULL) {
1678           ret = skip_bad ? 0 : -1;
1679           goto error;
1680         }
1681         if (t != hive_t_none) {
1682           ret = skip_bad ? 0 : -1;
1683           goto error;
1684         }
1685         if (vtor->value_none &&
1686             vtor->value_none (h, opaque, node, values[i], t, len, key, str) == -1)
1687           goto error;
1688         free (str); str = NULL;
1689         break;
1690
1691       case hive_t_string:
1692       case hive_t_expand_string:
1693       case hive_t_link:
1694         str = hivex_value_string (h, values[i]);
1695         if (str == NULL) {
1696           if (errno != EILSEQ && errno != EINVAL) {
1697             ret = skip_bad ? 0 : -1;
1698             goto error;
1699           }
1700           if (vtor->value_string_invalid_utf16) {
1701             str = hivex_value_value (h, values[i], &t, &len);
1702             if (vtor->value_string_invalid_utf16 (h, opaque, node, values[i],
1703                                                   t, len, key, str) == -1)
1704               goto error;
1705             free (str); str = NULL;
1706           }
1707           break;
1708         }
1709         if (vtor->value_string &&
1710             vtor->value_string (h, opaque, node, values[i],
1711                                 t, len, key, str) == -1)
1712           goto error;
1713         free (str); str = NULL;
1714         break;
1715
1716       case hive_t_dword:
1717       case hive_t_dword_be: {
1718         int32_t i32 = hivex_value_dword (h, values[i]);
1719         if (vtor->value_dword &&
1720             vtor->value_dword (h, opaque, node, values[i],
1721                                t, len, key, i32) == -1)
1722           goto error;
1723         break;
1724       }
1725
1726       case hive_t_qword: {
1727         int64_t i64 = hivex_value_qword (h, values[i]);
1728         if (vtor->value_qword &&
1729             vtor->value_qword (h, opaque, node, values[i],
1730                                t, len, key, i64) == -1)
1731           goto error;
1732         break;
1733       }
1734
1735       case hive_t_binary:
1736         str = hivex_value_value (h, values[i], &t, &len);
1737         if (str == NULL) {
1738           ret = skip_bad ? 0 : -1;
1739           goto error;
1740         }
1741         if (t != hive_t_binary) {
1742           ret = skip_bad ? 0 : -1;
1743           goto error;
1744         }
1745         if (vtor->value_binary &&
1746             vtor->value_binary (h, opaque, node, values[i],
1747                                 t, len, key, str) == -1)
1748           goto error;
1749         free (str); str = NULL;
1750         break;
1751
1752       case hive_t_multiple_strings:
1753         strs = hivex_value_multiple_strings (h, values[i]);
1754         if (strs == NULL) {
1755           if (errno != EILSEQ && errno != EINVAL) {
1756             ret = skip_bad ? 0 : -1;
1757             goto error;
1758           }
1759           if (vtor->value_string_invalid_utf16) {
1760             str = hivex_value_value (h, values[i], &t, &len);
1761             if (vtor->value_string_invalid_utf16 (h, opaque, node, values[i],
1762                                                   t, len, key, str) == -1)
1763               goto error;
1764             free (str); str = NULL;
1765           }
1766           break;
1767         }
1768         if (vtor->value_multiple_strings &&
1769             vtor->value_multiple_strings (h, opaque, node, values[i],
1770                                           t, len, key, strs) == -1)
1771           goto error;
1772         free_strings (strs); strs = NULL;
1773         break;
1774
1775       case hive_t_resource_list:
1776       case hive_t_full_resource_description:
1777       case hive_t_resource_requirements_list:
1778       default:
1779         str = hivex_value_value (h, values[i], &t, &len);
1780         if (str == NULL) {
1781           ret = skip_bad ? 0 : -1;
1782           goto error;
1783         }
1784         if (vtor->value_other &&
1785             vtor->value_other (h, opaque, node, values[i],
1786                                t, len, key, str) == -1)
1787           goto error;
1788         free (str); str = NULL;
1789         break;
1790       }
1791     }
1792
1793     free (key); key = NULL;
1794   }
1795
1796   children = hivex_node_children (h, node);
1797   if (children == NULL) {
1798     ret = skip_bad ? 0 : -1;
1799     goto error;
1800   }
1801
1802   for (i = 0; children[i] != 0; ++i) {
1803     if (h->msglvl >= 2)
1804       fprintf (stderr, "hivex__visit_node: %s: visiting subkey %d (0x%zx)\n",
1805                name, i, children[i]);
1806
1807     if (hivex__visit_node (h, children[i], vtor, unvisited, opaque, flags) == -1)
1808       goto error;
1809   }
1810
1811   if (vtor->node_end && vtor->node_end (h, opaque, node, name) == -1)
1812     goto error;
1813
1814   ret = 0;
1815
1816  error:
1817   free (name);
1818   free (values);
1819   free (children);
1820   free (key);
1821   free (str);
1822   free_strings (strs);
1823   return ret;
1824 }
1825
1826 /*----------------------------------------------------------------------
1827  * Writing.
1828  */
1829
1830 /* Allocate an hbin (page), extending the malloc'd space if necessary,
1831  * and updating the hive handle fields (but NOT the hive disk header
1832  * -- the hive disk header is updated when we commit).  This function
1833  * also extends the bitmap if necessary.
1834  *
1835  * 'allocation_hint' is the size of the block allocation we would like
1836  * to make.  Normally registry blocks are very small (avg 50 bytes)
1837  * and are contained in standard-sized pages (4KB), but the registry
1838  * can support blocks which are larger than a standard page, in which
1839  * case it creates a page of 8KB, 12KB etc.
1840  *
1841  * Returns:
1842  * > 0 : offset of first usable byte of new page (after page header)
1843  * 0   : error (errno set)
1844  */
1845 static size_t
1846 allocate_page (hive_h *h, size_t allocation_hint)
1847 {
1848   /* In almost all cases this will be 1. */
1849   size_t nr_4k_pages =
1850     1 + (allocation_hint + sizeof (struct ntreg_hbin_page) - 1) / 4096;
1851   assert (nr_4k_pages >= 1);
1852
1853   /* 'extend' is the number of bytes to extend the file by.  Note that
1854    * hives found in the wild often contain slack between 'endpages'
1855    * and the actual end of the file, so we don't always need to make
1856    * the file larger.
1857    */
1858   ssize_t extend = h->endpages + nr_4k_pages * 4096 - h->size;
1859
1860   if (h->msglvl >= 2) {
1861     fprintf (stderr, "allocate_page: current endpages = 0x%zx,"
1862              " current size = 0x%zx\n",
1863              h->endpages, h->size);
1864     fprintf (stderr, "allocate_page: extending file by %zd bytes"
1865              " (<= 0 if no extension)\n",
1866              extend);
1867   }
1868
1869   if (extend > 0) {
1870     size_t oldsize = h->size;
1871     size_t newsize = h->size + extend;
1872     char *newaddr = realloc (h->addr, newsize);
1873     if (newaddr == NULL)
1874       return 0;
1875
1876     size_t oldbitmapsize = 1 + oldsize / 32;
1877     size_t newbitmapsize = 1 + newsize / 32;
1878     char *newbitmap = realloc (h->bitmap, newbitmapsize);
1879     if (newbitmap == NULL) {
1880       free (newaddr);
1881       return 0;
1882     }
1883
1884     h->addr = newaddr;
1885     h->size = newsize;
1886     h->bitmap = newbitmap;
1887
1888     memset (h->addr + oldsize, 0, newsize - oldsize);
1889     memset (h->bitmap + oldbitmapsize, 0, newbitmapsize - oldbitmapsize);
1890   }
1891
1892   size_t offset = h->endpages;
1893   h->endpages += nr_4k_pages * 4096;
1894
1895   if (h->msglvl >= 2)
1896     fprintf (stderr, "allocate_page: new endpages = 0x%zx, new size = 0x%zx\n",
1897              h->endpages, h->size);
1898
1899   /* Write the hbin header. */
1900   struct ntreg_hbin_page *page =
1901     (struct ntreg_hbin_page *) (h->addr + offset);
1902   page->magic[0] = 'h';
1903   page->magic[1] = 'b';
1904   page->magic[2] = 'i';
1905   page->magic[3] = 'n';
1906   page->offset_first = htole32 (offset - 0x1000);
1907   page->page_size = htole32 (nr_4k_pages * 4096);
1908   memset (page->unknown, 0, sizeof (page->unknown));
1909
1910   if (h->msglvl >= 2)
1911     fprintf (stderr, "allocate_page: new page at 0x%zx\n", offset);
1912
1913   /* Offset of first usable byte after the header. */
1914   return offset + sizeof (struct ntreg_hbin_page);
1915 }
1916
1917 /* Allocate a single block, first allocating an hbin (page) at the end
1918  * of the current file if necessary.  NB. To keep the implementation
1919  * simple and more likely to be correct, we do not reuse existing free
1920  * blocks.
1921  *
1922  * seg_len is the size of the block (this INCLUDES the block header).
1923  * The header of the block is initialized to -seg_len (negative to
1924  * indicate used).  id[2] is the block ID (type), eg. "nk" for nk-
1925  * record.  The block bitmap is updated to show this block as valid.
1926  * The rest of the contents of the block will be zero.
1927  *
1928  * **NB** Because allocate_block may reallocate the memory, all
1929  * pointers into the memory become potentially invalid.  I really
1930  * love writing in C, can't you tell?
1931  *
1932  * Returns:
1933  * > 0 : offset of new block
1934  * 0   : error (errno set)
1935  */
1936 static size_t
1937 allocate_block (hive_h *h, size_t seg_len, const char id[2])
1938 {
1939   if (!h->writable) {
1940     errno = EROFS;
1941     return 0;
1942   }
1943
1944   if (seg_len < 4) {
1945     /* The caller probably forgot to include the header.  Note that
1946      * value lists have no ID field, so seg_len == 4 would be possible
1947      * for them, albeit unusual.
1948      */
1949     if (h->msglvl >= 2)
1950       fprintf (stderr, "allocate_block: refusing too small allocation (%zu),"
1951                " returning ERANGE\n", seg_len);
1952     errno = ERANGE;
1953     return 0;
1954   }
1955
1956   /* Refuse really large allocations. */
1957   if (seg_len > HIVEX_MAX_ALLOCATION) {
1958     if (h->msglvl >= 2)
1959       fprintf (stderr, "allocate_block: refusing large allocation (%zu),"
1960                " returning ERANGE\n", seg_len);
1961     errno = ERANGE;
1962     return 0;
1963   }
1964
1965   /* Round up allocation to multiple of 8 bytes.  All blocks must be
1966    * on an 8 byte boundary.
1967    */
1968   seg_len = (seg_len + 7) & ~7;
1969
1970   /* Allocate a new page if necessary. */
1971   if (h->endblocks == 0 || h->endblocks + seg_len > h->endpages) {
1972     size_t newendblocks = allocate_page (h, seg_len);
1973     if (newendblocks == 0)
1974       return 0;
1975     h->endblocks = newendblocks;
1976   }
1977
1978   size_t offset = h->endblocks;
1979
1980   if (h->msglvl >= 2)
1981     fprintf (stderr, "allocate_block: new block at 0x%zx, size %zu\n",
1982              offset, seg_len);
1983
1984   struct ntreg_hbin_block *blockhdr =
1985     (struct ntreg_hbin_block *) (h->addr + offset);
1986
1987   memset (blockhdr, 0, seg_len);
1988
1989   blockhdr->seg_len = htole32 (- (int32_t) seg_len);
1990   if (id[0] && id[1] && seg_len >= sizeof (struct ntreg_hbin_block)) {
1991     blockhdr->id[0] = id[0];
1992     blockhdr->id[1] = id[1];
1993   }
1994
1995   BITMAP_SET (h->bitmap, offset);
1996
1997   h->endblocks += seg_len;
1998
1999   /* If there is space after the last block in the last page, then we
2000    * have to put a dummy free block header here to mark the rest of
2001    * the page as free.
2002    */
2003   ssize_t rem = h->endpages - h->endblocks;
2004   if (rem > 0) {
2005     if (h->msglvl >= 2)
2006       fprintf (stderr, "allocate_block: marking remainder of page free"
2007                " starting at 0x%zx, size %zd\n", h->endblocks, rem);
2008
2009     assert (rem >= 4);
2010
2011     blockhdr = (struct ntreg_hbin_block *) (h->addr + h->endblocks);
2012     blockhdr->seg_len = htole32 ((int32_t) rem);
2013   }
2014
2015   return offset;
2016 }
2017
2018 /* 'offset' must point to a valid, used block.  This function marks
2019  * the block unused (by updating the seg_len field) and invalidates
2020  * the bitmap.  It does NOT do this recursively, so to avoid creating
2021  * unreachable used blocks, callers may have to recurse over the hive
2022  * structures.  Also callers must ensure there are no references to
2023  * this block from other parts of the hive.
2024  */
2025 static void
2026 mark_block_unused (hive_h *h, size_t offset)
2027 {
2028   assert (h->writable);
2029   assert (IS_VALID_BLOCK (h, offset));
2030
2031   if (h->msglvl >= 2)
2032     fprintf (stderr, "mark_block_unused: marking 0x%zx unused\n", offset);
2033
2034   struct ntreg_hbin_block *blockhdr =
2035     (struct ntreg_hbin_block *) (h->addr + offset);
2036
2037   size_t seg_len = block_len (h, offset, NULL);
2038   blockhdr->seg_len = htole32 (seg_len);
2039
2040   BITMAP_CLR (h->bitmap, offset);
2041 }
2042
2043 /* Delete all existing values at this node. */
2044 static int
2045 delete_values (hive_h *h, hive_node_h node)
2046 {
2047   assert (h->writable);
2048
2049   hive_value_h *values;
2050   size_t *blocks;
2051   if (get_values (h, node, &values, &blocks) == -1)
2052     return -1;
2053
2054   size_t i;
2055   for (i = 0; blocks[i] != 0; ++i)
2056     mark_block_unused (h, blocks[i]);
2057
2058   free (blocks);
2059
2060   for (i = 0; values[i] != 0; ++i) {
2061     struct ntreg_vk_record *vk =
2062       (struct ntreg_vk_record *) (h->addr + values[i]);
2063
2064     size_t len;
2065     int is_inline;
2066     len = le32toh (vk->data_len);
2067     is_inline = !!(len & 0x80000000); /* top bit indicates is inline */
2068     len &= 0x7fffffff;
2069
2070     if (!is_inline) {           /* non-inline, so remove data block */
2071       size_t data_offset = le32toh (vk->data_offset);
2072       data_offset += 0x1000;
2073       mark_block_unused (h, data_offset);
2074     }
2075
2076     /* remove vk record */
2077     mark_block_unused (h, values[i]);
2078   }
2079
2080   free (values);
2081
2082   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
2083   nk->nr_values = htole32 (0);
2084   nk->vallist = htole32 (0xffffffff);
2085
2086   return 0;
2087 }
2088
2089 int
2090 hivex_commit (hive_h *h, const char *filename, int flags)
2091 {
2092   if (flags != 0) {
2093     errno = EINVAL;
2094     return -1;
2095   }
2096
2097   if (!h->writable) {
2098     errno = EROFS;
2099     return -1;
2100   }
2101
2102   filename = filename ? : h->filename;
2103   int fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
2104   if (fd == -1)
2105     return -1;
2106
2107   /* Update the header fields. */
2108   uint32_t sequence = le32toh (h->hdr->sequence1);
2109   sequence++;
2110   h->hdr->sequence1 = htole32 (sequence);
2111   h->hdr->sequence2 = htole32 (sequence);
2112   /* XXX Ought to update h->hdr->last_modified. */
2113   h->hdr->blocks = htole32 (h->endpages - 0x1000);
2114
2115   /* Recompute header checksum. */
2116   uint32_t sum = header_checksum (h);
2117   h->hdr->csum = htole32 (sum);
2118
2119   if (h->msglvl >= 2)
2120     fprintf (stderr, "hivex_commit: new header checksum: 0x%x\n", sum);
2121
2122   if (full_write (fd, h->addr, h->size) != h->size) {
2123     int err = errno;
2124     close (fd);
2125     errno = err;
2126     return -1;
2127   }
2128
2129   if (close (fd) == -1)
2130     return -1;
2131
2132   return 0;
2133 }
2134
2135 /* Calculate the hash for a lf or lh record offset.
2136  */
2137 static void
2138 calc_hash (const char *type, const char *name, char *ret)
2139 {
2140   size_t len = strlen (name);
2141
2142   if (STRPREFIX (type, "lf"))
2143     /* Old-style, not used in current registries. */
2144     memcpy (ret, name, len < 4 ? len : 4);
2145   else {
2146     /* New-style for lh-records. */
2147     size_t i, c;
2148     uint32_t h = 0;
2149     for (i = 0; i < len; ++i) {
2150       c = c_toupper (name[i]);
2151       h *= 37;
2152       h += c;
2153     }
2154     *((uint32_t *) ret) = htole32 (h);
2155   }
2156 }
2157
2158 /* Create a completely new lh-record containing just the single node. */
2159 static size_t
2160 new_lh_record (hive_h *h, const char *name, hive_node_h node)
2161 {
2162   static const char id[2] = { 'l', 'h' };
2163   size_t seg_len = sizeof (struct ntreg_lf_record);
2164   size_t offset = allocate_block (h, seg_len, id);
2165   if (offset == 0)
2166     return 0;
2167
2168   struct ntreg_lf_record *lh = (struct ntreg_lf_record *) (h->addr + offset);
2169   lh->nr_keys = htole16 (1);
2170   lh->keys[0].offset = htole32 (node - 0x1000);
2171   calc_hash ("lh", name, lh->keys[0].hash);
2172
2173   return offset;
2174 }
2175
2176 /* Insert node into existing lf/lh-record at position.
2177  * This allocates a new record and marks the old one as unused.
2178  */
2179 static size_t
2180 insert_lf_record (hive_h *h, size_t old_offs, size_t posn,
2181                   const char *name, hive_node_h node)
2182 {
2183   assert (IS_VALID_BLOCK (h, old_offs));
2184
2185   /* Work around C stupidity.
2186    * http://www.redhat.com/archives/libguestfs/2010-February/msg00056.html
2187    */
2188   int test = BLOCK_ID_EQ (h, old_offs, "lf") || BLOCK_ID_EQ (h, old_offs, "lh");
2189   assert (test);
2190
2191   struct ntreg_lf_record *old_lf =
2192     (struct ntreg_lf_record *) (h->addr + old_offs);
2193   size_t nr_keys = le16toh (old_lf->nr_keys);
2194
2195   nr_keys++; /* in new record ... */
2196
2197   size_t seg_len = sizeof (struct ntreg_lf_record) + (nr_keys-1) * 8;
2198
2199   /* Copy the old_lf->id in case it moves during allocate_block. */
2200   char id[2];
2201   memcpy (id, old_lf->id, sizeof id);
2202
2203   size_t new_offs = allocate_block (h, seg_len, id);
2204   if (new_offs == 0)
2205     return 0;
2206
2207   /* old_lf could have been invalidated by allocate_block. */
2208   old_lf = (struct ntreg_lf_record *) (h->addr + old_offs);
2209
2210   struct ntreg_lf_record *new_lf =
2211     (struct ntreg_lf_record *) (h->addr + new_offs);
2212   new_lf->nr_keys = htole16 (nr_keys);
2213
2214   /* Copy the keys until we reach posn, insert the new key there, then
2215    * copy the remaining keys.
2216    */
2217   size_t i;
2218   for (i = 0; i < posn; ++i)
2219     new_lf->keys[i] = old_lf->keys[i];
2220
2221   new_lf->keys[i].offset = htole32 (node - 0x1000);
2222   calc_hash (new_lf->id, name, new_lf->keys[i].hash);
2223
2224   for (i = posn+1; i < nr_keys; ++i)
2225     new_lf->keys[i] = old_lf->keys[i-1];
2226
2227   /* Old block is unused, return new block. */
2228   mark_block_unused (h, old_offs);
2229   return new_offs;
2230 }
2231
2232 /* Compare name with name in nk-record. */
2233 static int
2234 compare_name_with_nk_name (hive_h *h, const char *name, hive_node_h nk_offs)
2235 {
2236   assert (IS_VALID_BLOCK (h, nk_offs));
2237   assert (BLOCK_ID_EQ (h, nk_offs, "nk"));
2238
2239   /* Name in nk is not necessarily nul-terminated. */
2240   char *nname = hivex_node_name (h, nk_offs);
2241
2242   /* Unfortunately we don't have a way to return errors here. */
2243   if (!nname) {
2244     perror ("compare_name_with_nk_name");
2245     return 0;
2246   }
2247
2248   int r = strcasecmp (name, nname);
2249   free (nname);
2250
2251   return r;
2252 }
2253
2254 hive_node_h
2255 hivex_node_add_child (hive_h *h, hive_node_h parent, const char *name)
2256 {
2257   if (!h->writable) {
2258     errno = EROFS;
2259     return 0;
2260   }
2261
2262   if (!IS_VALID_BLOCK (h, parent) || !BLOCK_ID_EQ (h, parent, "nk")) {
2263     errno = EINVAL;
2264     return 0;
2265   }
2266
2267   if (name == NULL || strlen (name) == 0) {
2268     errno = EINVAL;
2269     return 0;
2270   }
2271
2272   if (hivex_node_get_child (h, parent, name) != 0) {
2273     errno = EEXIST;
2274     return 0;
2275   }
2276
2277   /* Create the new nk-record. */
2278   static const char nk_id[2] = { 'n', 'k' };
2279   size_t seg_len = sizeof (struct ntreg_nk_record) + strlen (name);
2280   hive_node_h node = allocate_block (h, seg_len, nk_id);
2281   if (node == 0)
2282     return 0;
2283
2284   if (h->msglvl >= 2)
2285     fprintf (stderr, "hivex_node_add_child: allocated new nk-record"
2286              " for child at 0x%zx\n", node);
2287
2288   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
2289   nk->flags = htole16 (0x0020); /* key is ASCII. */
2290   nk->parent = htole32 (parent - 0x1000);
2291   nk->subkey_lf = htole32 (0xffffffff);
2292   nk->subkey_lf_volatile = htole32 (0xffffffff);
2293   nk->vallist = htole32 (0xffffffff);
2294   nk->classname = htole32 (0xffffffff);
2295   nk->name_len = htole16 (strlen (name));
2296   strcpy (nk->name, name);
2297
2298   /* Inherit parent sk. */
2299   struct ntreg_nk_record *parent_nk =
2300     (struct ntreg_nk_record *) (h->addr + parent);
2301   size_t parent_sk_offset = le32toh (parent_nk->sk);
2302   parent_sk_offset += 0x1000;
2303   if (!IS_VALID_BLOCK (h, parent_sk_offset) ||
2304       !BLOCK_ID_EQ (h, parent_sk_offset, "sk")) {
2305     if (h->msglvl >= 2)
2306       fprintf (stderr, "hivex_node_add_child: returning EFAULT"
2307                " because parent sk is not a valid block (%zu)\n",
2308                parent_sk_offset);
2309     errno = EFAULT;
2310     return 0;
2311   }
2312   struct ntreg_sk_record *sk =
2313     (struct ntreg_sk_record *) (h->addr + parent_sk_offset);
2314   sk->refcount = htole32 (le32toh (sk->refcount) + 1);
2315   nk->sk = htole32 (parent_sk_offset - 0x1000);
2316
2317   /* Inherit parent timestamp. */
2318   nk->timestamp = parent_nk->timestamp;
2319
2320   /* What I found out the hard way (not documented anywhere): the
2321    * subkeys in lh-records must be kept sorted.  If you just add a
2322    * subkey in a non-sorted position (eg. just add it at the end) then
2323    * Windows won't see the subkey _and_ Windows will corrupt the hive
2324    * itself when it modifies or saves it.
2325    *
2326    * So use get_children() to get a list of intermediate
2327    * lf/lh-records.  get_children() returns these in reading order
2328    * (which is sorted), so we look for the lf/lh-records in sequence
2329    * until we find the key name just after the one we are inserting,
2330    * and we insert the subkey just before it.
2331    *
2332    * The only other case is the no-subkeys case, where we have to
2333    * create a brand new lh-record.
2334    */
2335   hive_node_h *unused;
2336   size_t *blocks;
2337
2338   if (get_children (h, parent, &unused, &blocks, 0) == -1)
2339     return 0;
2340   free (unused);
2341
2342   size_t i, j;
2343   size_t nr_subkeys_in_parent_nk = le32toh (parent_nk->nr_subkeys);
2344   if (nr_subkeys_in_parent_nk == 0) { /* No subkeys case. */
2345     /* Free up any existing intermediate blocks. */
2346     for (i = 0; blocks[i] != 0; ++i)
2347       mark_block_unused (h, blocks[i]);
2348     size_t lh_offs = new_lh_record (h, name, node);
2349     if (lh_offs == 0) {
2350       free (blocks);
2351       return 0;
2352     }
2353
2354     /* Recalculate pointers that could have been invalidated by
2355      * previous call to allocate_block (via new_lh_record).
2356      */
2357     nk = (struct ntreg_nk_record *) (h->addr + node);
2358     parent_nk = (struct ntreg_nk_record *) (h->addr + parent);
2359
2360     if (h->msglvl >= 2)
2361       fprintf (stderr, "hivex_node_add_child: no keys, allocated new"
2362                " lh-record at 0x%zx\n", lh_offs);
2363
2364     parent_nk->subkey_lf = htole32 (lh_offs - 0x1000);
2365   }
2366   else {                        /* Insert subkeys case. */
2367     size_t old_offs = 0, new_offs = 0;
2368     struct ntreg_lf_record *old_lf = NULL;
2369
2370     /* Find lf/lh key name just after the one we are inserting. */
2371     for (i = 0; blocks[i] != 0; ++i) {
2372       if (BLOCK_ID_EQ (h, blocks[i], "lf") ||
2373           BLOCK_ID_EQ (h, blocks[i], "lh")) {
2374         old_offs = blocks[i];
2375         old_lf = (struct ntreg_lf_record *) (h->addr + old_offs);
2376         for (j = 0; j < le16toh (old_lf->nr_keys); ++j) {
2377           hive_node_h nk_offs = le32toh (old_lf->keys[j].offset);
2378           nk_offs += 0x1000;
2379           if (compare_name_with_nk_name (h, name, nk_offs) < 0)
2380             goto insert_it;
2381         }
2382       }
2383     }
2384
2385     /* Insert it at the end.
2386      * old_offs points to the last lf record, set j.
2387      */
2388     assert (old_offs != 0);   /* should never happen if nr_subkeys > 0 */
2389     j = le16toh (old_lf->nr_keys);
2390
2391     /* Insert it. */
2392   insert_it:
2393     if (h->msglvl >= 2)
2394       fprintf (stderr, "hivex_node_add_child: insert key in existing"
2395                " lh-record at 0x%zx, posn %zu\n", old_offs, j);
2396
2397     new_offs = insert_lf_record (h, old_offs, j, name, node);
2398     if (new_offs == 0) {
2399       free (blocks);
2400       return 0;
2401     }
2402
2403     /* Recalculate pointers that could have been invalidated by
2404      * previous call to allocate_block (via insert_lf_record).
2405      */
2406     nk = (struct ntreg_nk_record *) (h->addr + node);
2407     parent_nk = (struct ntreg_nk_record *) (h->addr + parent);
2408
2409     if (h->msglvl >= 2)
2410       fprintf (stderr, "hivex_node_add_child: new lh-record at 0x%zx\n",
2411                new_offs);
2412
2413     /* If the lf/lh-record was directly referenced by the parent nk,
2414      * then update the parent nk.
2415      */
2416     if (le32toh (parent_nk->subkey_lf) + 0x1000 == old_offs)
2417       parent_nk->subkey_lf = htole32 (new_offs - 0x1000);
2418     /* Else we have to look for the intermediate ri-record and update
2419      * that in-place.
2420      */
2421     else {
2422       for (i = 0; blocks[i] != 0; ++i) {
2423         if (BLOCK_ID_EQ (h, blocks[i], "ri")) {
2424           struct ntreg_ri_record *ri =
2425             (struct ntreg_ri_record *) (h->addr + blocks[i]);
2426           for (j = 0; j < le16toh (ri->nr_offsets); ++j)
2427             if (le32toh (ri->offset[j] + 0x1000) == old_offs) {
2428               ri->offset[j] = htole32 (new_offs - 0x1000);
2429               goto found_it;
2430             }
2431         }
2432       }
2433
2434       /* Not found ..  This is an internal error. */
2435       if (h->msglvl >= 2)
2436         fprintf (stderr, "hivex_node_add_child: returning ENOTSUP"
2437                  " because could not find ri->lf link\n");
2438       errno = ENOTSUP;
2439       free (blocks);
2440       return 0;
2441
2442     found_it:
2443       ;
2444     }
2445   }
2446
2447   free (blocks);
2448
2449   /* Update nr_subkeys in parent nk. */
2450   nr_subkeys_in_parent_nk++;
2451   parent_nk->nr_subkeys = htole32 (nr_subkeys_in_parent_nk);
2452
2453   /* Update max_subkey_name_len in parent nk. */
2454   uint16_t max = le16toh (parent_nk->max_subkey_name_len);
2455   if (max < strlen (name) * 2)  /* *2 because "recoded" in UTF16-LE. */
2456     parent_nk->max_subkey_name_len = htole16 (strlen (name) * 2);
2457
2458   return node;
2459 }
2460
2461 /* Decrement the refcount of an sk-record, and if it reaches zero,
2462  * unlink it from the chain and delete it.
2463  */
2464 static int
2465 delete_sk (hive_h *h, size_t sk_offset)
2466 {
2467   if (!IS_VALID_BLOCK (h, sk_offset) || !BLOCK_ID_EQ (h, sk_offset, "sk")) {
2468     if (h->msglvl >= 2)
2469       fprintf (stderr, "delete_sk: not an sk record: 0x%zx\n", sk_offset);
2470     errno = EFAULT;
2471     return -1;
2472   }
2473
2474   struct ntreg_sk_record *sk = (struct ntreg_sk_record *) (h->addr + sk_offset);
2475
2476   if (sk->refcount == 0) {
2477     if (h->msglvl >= 2)
2478       fprintf (stderr, "delete_sk: sk record already has refcount 0: 0x%zx\n",
2479                sk_offset);
2480     errno = EINVAL;
2481     return -1;
2482   }
2483
2484   sk->refcount--;
2485
2486   if (sk->refcount == 0) {
2487     size_t sk_prev_offset = sk->sk_prev;
2488     sk_prev_offset += 0x1000;
2489
2490     size_t sk_next_offset = sk->sk_next;
2491     sk_next_offset += 0x1000;
2492
2493     /* Update sk_prev/sk_next SKs, unless they both point back to this
2494      * cell in which case we are deleting the last SK.
2495      */
2496     if (sk_prev_offset != sk_offset && sk_next_offset != sk_offset) {
2497       struct ntreg_sk_record *sk_prev =
2498         (struct ntreg_sk_record *) (h->addr + sk_prev_offset);
2499       struct ntreg_sk_record *sk_next =
2500         (struct ntreg_sk_record *) (h->addr + sk_next_offset);
2501
2502       sk_prev->sk_next = htole32 (sk_next_offset - 0x1000);
2503       sk_next->sk_prev = htole32 (sk_prev_offset - 0x1000);
2504     }
2505
2506     /* Refcount is zero so really delete this block. */
2507     mark_block_unused (h, sk_offset);
2508   }
2509
2510   return 0;
2511 }
2512
2513 /* Callback from hivex_node_delete_child which is called to delete a
2514  * node AFTER its subnodes have been visited.  The subnodes have been
2515  * deleted but we still have to delete any lf/lh/li/ri records and the
2516  * value list block and values, followed by deleting the node itself.
2517  */
2518 static int
2519 delete_node (hive_h *h, void *opaque, hive_node_h node, const char *name)
2520 {
2521   /* Get the intermediate blocks.  The subkeys have already been
2522    * deleted by this point, so tell get_children() not to check for
2523    * validity of the nk-records.
2524    */
2525   hive_node_h *unused;
2526   size_t *blocks;
2527   if (get_children (h, node, &unused, &blocks, GET_CHILDREN_NO_CHECK_NK) == -1)
2528     return -1;
2529   free (unused);
2530
2531   /* We don't care what's in these intermediate blocks, so we can just
2532    * delete them unconditionally.
2533    */
2534   size_t i;
2535   for (i = 0; blocks[i] != 0; ++i)
2536     mark_block_unused (h, blocks[i]);
2537
2538   free (blocks);
2539
2540   /* Delete the values in the node. */
2541   if (delete_values (h, node) == -1)
2542     return -1;
2543
2544   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
2545
2546   /* If the NK references an SK, delete it. */
2547   size_t sk_offs = le32toh (nk->sk);
2548   if (sk_offs != 0xffffffff) {
2549     sk_offs += 0x1000;
2550     if (delete_sk (h, sk_offs) == -1)
2551       return -1;
2552     nk->sk = htole32 (0xffffffff);
2553   }
2554
2555   /* If the NK references a classname, delete it. */
2556   size_t cl_offs = le32toh (nk->classname);
2557   if (cl_offs != 0xffffffff) {
2558     cl_offs += 0x1000;
2559     mark_block_unused (h, cl_offs);
2560     nk->classname = htole32 (0xffffffff);
2561   }
2562
2563   /* Delete the node itself. */
2564   mark_block_unused (h, node);
2565
2566   return 0;
2567 }
2568
2569 int
2570 hivex_node_delete_child (hive_h *h, hive_node_h node)
2571 {
2572   if (!h->writable) {
2573     errno = EROFS;
2574     return -1;
2575   }
2576
2577   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
2578     errno = EINVAL;
2579     return -1;
2580   }
2581
2582   if (node == hivex_root (h)) {
2583     if (h->msglvl >= 2)
2584       fprintf (stderr, "hivex_node_delete_child: cannot delete root node\n");
2585     errno = EINVAL;
2586     return -1;
2587   }
2588
2589   hive_node_h parent = hivex_node_parent (h, node);
2590   if (parent == 0)
2591     return -1;
2592
2593   /* Delete node and all its children and values recursively. */
2594   static const struct hivex_visitor visitor = { .node_end = delete_node };
2595   if (hivex_visit_node (h, node, &visitor, sizeof visitor, NULL, 0) == -1)
2596     return -1;
2597
2598   /* Delete the link from parent to child.  We need to find the lf/lh
2599    * record which contains the offset and remove the offset from that
2600    * record, then decrement the element count in that record, and
2601    * decrement the overall number of subkeys stored in the parent
2602    * node.
2603    */
2604   hive_node_h *unused;
2605   size_t *blocks;
2606   if (get_children (h, parent, &unused, &blocks, GET_CHILDREN_NO_CHECK_NK)== -1)
2607     return -1;
2608   free (unused);
2609
2610   size_t i, j;
2611   for (i = 0; blocks[i] != 0; ++i) {
2612     struct ntreg_hbin_block *block =
2613       (struct ntreg_hbin_block *) (h->addr + blocks[i]);
2614
2615     if (block->id[0] == 'l' && (block->id[1] == 'f' || block->id[1] == 'h')) {
2616       struct ntreg_lf_record *lf = (struct ntreg_lf_record *) block;
2617
2618       size_t nr_subkeys_in_lf = le16toh (lf->nr_keys);
2619
2620       for (j = 0; j < nr_subkeys_in_lf; ++j)
2621         if (le32toh (lf->keys[j].offset) + 0x1000 == node) {
2622           for (; j < nr_subkeys_in_lf - 1; ++j)
2623             memcpy (&lf->keys[j], &lf->keys[j+1], sizeof (lf->keys[j]));
2624           lf->nr_keys = htole16 (nr_subkeys_in_lf - 1);
2625           goto found;
2626         }
2627     }
2628   }
2629   if (h->msglvl >= 2)
2630     fprintf (stderr, "hivex_node_delete_child: could not find parent"
2631              " to child link\n");
2632   errno = ENOTSUP;
2633   return -1;
2634
2635  found:;
2636   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + parent);
2637   size_t nr_subkeys_in_nk = le32toh (nk->nr_subkeys);
2638   nk->nr_subkeys = htole32 (nr_subkeys_in_nk - 1);
2639
2640   if (h->msglvl >= 2)
2641     fprintf (stderr, "hivex_node_delete_child: updating nr_subkeys"
2642              " in parent 0x%zx to %zu\n", parent, nr_subkeys_in_nk);
2643
2644   return 0;
2645 }
2646
2647 int
2648 hivex_node_set_values (hive_h *h, hive_node_h node,
2649                        size_t nr_values, const hive_set_value *values,
2650                        int flags)
2651 {
2652   if (!h->writable) {
2653     errno = EROFS;
2654     return -1;
2655   }
2656
2657   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
2658     errno = EINVAL;
2659     return -1;
2660   }
2661
2662   /* Delete all existing values. */
2663   if (delete_values (h, node) == -1)
2664     return -1;
2665
2666   if (nr_values == 0)
2667     return 0;
2668
2669   /* Allocate value list node.  Value lists have no id field. */
2670   static const char nul_id[2] = { 0, 0 };
2671   size_t seg_len =
2672     sizeof (struct ntreg_value_list) + (nr_values - 1) * sizeof (uint32_t);
2673   size_t vallist_offs = allocate_block (h, seg_len, nul_id);
2674   if (vallist_offs == 0)
2675     return -1;
2676
2677   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
2678   nk->nr_values = htole32 (nr_values);
2679   nk->vallist = htole32 (vallist_offs - 0x1000);
2680
2681   struct ntreg_value_list *vallist =
2682     (struct ntreg_value_list *) (h->addr + vallist_offs);
2683
2684   size_t i;
2685   for (i = 0; i < nr_values; ++i) {
2686     /* Allocate vk record to store this (key, value) pair. */
2687     static const char vk_id[2] = { 'v', 'k' };
2688     seg_len = sizeof (struct ntreg_vk_record) + strlen (values[i].key);
2689     size_t vk_offs = allocate_block (h, seg_len, vk_id);
2690     if (vk_offs == 0)
2691       return -1;
2692
2693     /* Recalculate pointers that could have been invalidated by
2694      * previous call to allocate_block.
2695      */
2696     nk = (struct ntreg_nk_record *) (h->addr + node);
2697     vallist = (struct ntreg_value_list *) (h->addr + vallist_offs);
2698
2699     vallist->offset[i] = htole32 (vk_offs - 0x1000);
2700
2701     struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + vk_offs);
2702     size_t name_len = strlen (values[i].key);
2703     vk->name_len = htole16 (name_len);
2704     strcpy (vk->name, values[i].key);
2705     vk->data_type = htole32 (values[i].t);
2706     uint32_t len = values[i].len;
2707     if (len <= 4)               /* store it inline => set MSB flag */
2708       len |= 0x80000000;
2709     vk->data_len = htole32 (len);
2710     vk->flags = name_len == 0 ? 0 : 1;
2711
2712     if (values[i].len <= 4)     /* store it inline */
2713       memcpy (&vk->data_offset, values[i].value, values[i].len);
2714     else {
2715       size_t offs = allocate_block (h, values[i].len + 4, nul_id);
2716       if (offs == 0)
2717         return -1;
2718
2719       /* Recalculate pointers that could have been invalidated by
2720        * previous call to allocate_block.
2721        */
2722       nk = (struct ntreg_nk_record *) (h->addr + node);
2723       vallist = (struct ntreg_value_list *) (h->addr + vallist_offs);
2724       vk = (struct ntreg_vk_record *) (h->addr + vk_offs);
2725
2726       memcpy (h->addr + offs + 4, values[i].value, values[i].len);
2727       vk->data_offset = htole32 (offs - 0x1000);
2728     }
2729
2730     if (name_len * 2 > le32toh (nk->max_vk_name_len))
2731       /* * 2 for UTF16-LE "reencoding" */
2732       nk->max_vk_name_len = htole32 (name_len * 2);
2733     if (values[i].len > le32toh (nk->max_vk_data_len))
2734       nk->max_vk_data_len = htole32 (values[i].len);
2735   }
2736
2737   return 0;
2738 }
2739
2740 int
2741 hivex_node_set_value (hive_h *h, hive_node_h node,
2742                       const hive_set_value *val, int flags)
2743 {
2744   hive_value_h *prev_values = hivex_node_values (h, node);
2745   if (prev_values == NULL)
2746     return -1;
2747
2748   int retval = -1;
2749
2750   size_t nr_values = 0;
2751   for (hive_value_h *itr = prev_values; *itr != 0; ++itr)
2752     ++nr_values;
2753
2754   hive_set_value *values = malloc ((nr_values + 1) * (sizeof (hive_set_value)));
2755   if (values == NULL)
2756     goto leave_prev_values;
2757
2758   int alloc_ct = 0;
2759   int idx_of_val = -1;
2760   hive_value_h *prev_val;
2761   for (prev_val = prev_values; *prev_val != 0; ++prev_val) {
2762     size_t len;
2763     hive_type t;
2764
2765     hive_set_value *value = &values[prev_val - prev_values];
2766
2767     char *valval = hivex_value_value (h, *prev_val, &t, &len);
2768     if (valval == NULL) goto leave_partial;
2769
2770     ++alloc_ct;
2771     value->value = valval;
2772     value->t = t;
2773     value->len = len;
2774
2775     char *valkey = hivex_value_key (h, *prev_val);
2776     if (valkey == NULL) goto leave_partial;
2777
2778     ++alloc_ct;
2779     value->key = valkey;
2780
2781     if (STRCASEEQ (valkey, val->key))
2782       idx_of_val = prev_val - prev_values;
2783   }
2784
2785   if (idx_of_val > -1) {
2786     free (values[idx_of_val].key);
2787     free (values[idx_of_val].value);
2788   } else {
2789     idx_of_val = nr_values;
2790     ++nr_values;
2791   }
2792
2793   hive_set_value *value = &values[idx_of_val];
2794   *value = (hive_set_value){
2795     .key = strdup (val->key),
2796     .value = malloc (val->len),
2797     .len = val->len,
2798     .t = val->t
2799   };
2800
2801   if (value->key == NULL || value->value == NULL) goto leave_partial;
2802   memcpy (value->value, val->value, val->len);
2803
2804   retval = hivex_node_set_values (h, node, nr_values, values, 0);
2805
2806  leave_partial:
2807   for (int i = 0; i < alloc_ct; i += 2) {
2808     free (values[i / 2].value);
2809     if (i + 1 < alloc_ct && values[i / 2].key != NULL)
2810       free (values[i / 2].key);
2811   }
2812   free (values);
2813
2814  leave_prev_values:
2815   free (prev_values);
2816   return retval;
2817 }