3063c456f9fddd2e425cce809c39acff9f12c0a3
[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 size_t
589 hivex_node_struct_length (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 0;
594   }
595
596   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
597   size_t name_len = le16toh (nk->name_len);
598   /* -1 to avoid double-counting the first name character */
599   size_t ret = name_len + sizeof (struct ntreg_nk_record) - 1;
600   int used;
601   size_t seg_len = block_len (h, node, &used);
602   if (ret > seg_len) {
603     if (h->msglvl >= 2)
604       fprintf (stderr, "hivex_node_struct_length: returning EFAULT because"
605                " node name is too long (%zu, %zu)\n", name_len, seg_len);
606     errno = EFAULT;
607     return 0;
608   }
609   return ret;
610 }
611
612 char *
613 hivex_node_name (hive_h *h, hive_node_h node)
614 {
615   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
616     errno = EINVAL;
617     return NULL;
618   }
619
620   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
621
622   /* AFAIK the node name is always plain ASCII, so no conversion
623    * to UTF-8 is necessary.  However we do need to nul-terminate
624    * the string.
625    */
626
627   /* nk->name_len is unsigned, 16 bit, so this is safe ...  However
628    * we have to make sure the length doesn't exceed the block length.
629    */
630   size_t len = le16toh (nk->name_len);
631   size_t seg_len = block_len (h, node, NULL);
632   if (sizeof (struct ntreg_nk_record) + len - 1 > seg_len) {
633     if (h->msglvl >= 2)
634       fprintf (stderr, "hivex_node_name: returning EFAULT because node name"
635                " is too long (%zu, %zu)\n",
636               len, seg_len);
637     errno = EFAULT;
638     return NULL;
639   }
640
641   char *ret = malloc (len + 1);
642   if (ret == NULL)
643     return NULL;
644   memcpy (ret, nk->name, len);
645   ret[len] = '\0';
646   return ret;
647 }
648
649 static int64_t
650 timestamp_check (hive_h *h, hive_node_h node, int64_t timestamp)
651 {
652   if (timestamp < 0) {
653     if (h->msglvl >= 2)
654       fprintf (stderr, "hivex: timestamp_check: "
655                "negative time reported at %zu: %" PRIi64 "\n",
656                node, timestamp);
657     errno = EINVAL;
658     return -1;
659   }
660
661   return timestamp;
662 }
663
664 int64_t
665 hivex_last_modified (hive_h *h)
666 {
667   return timestamp_check (h, 0, h->last_modified);
668 }
669
670 int64_t
671 hivex_node_timestamp (hive_h *h, hive_node_h node)
672 {
673   int64_t ret;
674
675   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
676     errno = EINVAL;
677     return -1;
678   }
679
680   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
681
682   ret = le64toh (nk->timestamp);
683   return timestamp_check (h, node, ret);
684 }
685
686 #if 0
687 /* I think the documentation for the sk and classname fields in the nk
688  * record is wrong, or else the offset field is in the wrong place.
689  * Otherwise this makes no sense.  Disabled this for now -- it's not
690  * useful for reading the registry anyway.
691  */
692
693 hive_security_h
694 hivex_node_security (hive_h *h, hive_node_h node)
695 {
696   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
697     errno = EINVAL;
698     return 0;
699   }
700
701   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
702
703   hive_node_h ret = le32toh (nk->sk);
704   ret += 0x1000;
705   if (!IS_VALID_BLOCK (h, ret)) {
706     errno = EFAULT;
707     return 0;
708   }
709   return ret;
710 }
711
712 hive_classname_h
713 hivex_node_classname (hive_h *h, hive_node_h node)
714 {
715   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
716     errno = EINVAL;
717     return 0;
718   }
719
720   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
721
722   hive_node_h ret = le32toh (nk->classname);
723   ret += 0x1000;
724   if (!IS_VALID_BLOCK (h, ret)) {
725     errno = EFAULT;
726     return 0;
727   }
728   return ret;
729 }
730 #endif
731
732 /* Structure for returning 0-terminated lists of offsets (nodes,
733  * values, etc).
734  */
735 struct offset_list {
736   size_t *offsets;
737   size_t len;
738   size_t alloc;
739 };
740
741 static void
742 init_offset_list (struct offset_list *list)
743 {
744   list->len = 0;
745   list->alloc = 0;
746   list->offsets = NULL;
747 }
748
749 #define INIT_OFFSET_LIST(name) \
750   struct offset_list name; \
751   init_offset_list (&name)
752
753 /* Preallocates the offset_list, but doesn't make the contents longer. */
754 static int
755 grow_offset_list (struct offset_list *list, size_t alloc)
756 {
757   assert (alloc >= list->len);
758   size_t *p = realloc (list->offsets, alloc * sizeof (size_t));
759   if (p == NULL)
760     return -1;
761   list->offsets = p;
762   list->alloc = alloc;
763   return 0;
764 }
765
766 static int
767 add_to_offset_list (struct offset_list *list, size_t offset)
768 {
769   if (list->len >= list->alloc) {
770     if (grow_offset_list (list, list->alloc ? list->alloc * 2 : 4) == -1)
771       return -1;
772   }
773   list->offsets[list->len] = offset;
774   list->len++;
775   return 0;
776 }
777
778 static void
779 free_offset_list (struct offset_list *list)
780 {
781   free (list->offsets);
782 }
783
784 static size_t *
785 return_offset_list (struct offset_list *list)
786 {
787   if (add_to_offset_list (list, 0) == -1)
788     return NULL;
789   return list->offsets;         /* caller frees */
790 }
791
792 /* Iterate over children, returning child nodes and intermediate blocks. */
793 #define GET_CHILDREN_NO_CHECK_NK 1
794
795 static int
796 get_children (hive_h *h, hive_node_h node,
797               hive_node_h **children_ret, size_t **blocks_ret,
798               int flags)
799 {
800   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
801     errno = EINVAL;
802     return -1;
803   }
804
805   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
806
807   size_t nr_subkeys_in_nk = le32toh (nk->nr_subkeys);
808
809   INIT_OFFSET_LIST (children);
810   INIT_OFFSET_LIST (blocks);
811
812   /* Deal with the common "no subkeys" case quickly. */
813   if (nr_subkeys_in_nk == 0)
814     goto ok;
815
816   /* Arbitrarily limit the number of subkeys we will ever deal with. */
817   if (nr_subkeys_in_nk > HIVEX_MAX_SUBKEYS) {
818     if (h->msglvl >= 2)
819       fprintf (stderr, "hivex: get_children: returning ERANGE because "
820                "nr_subkeys_in_nk > HIVEX_MAX_SUBKEYS (%zu > %d)\n",
821                nr_subkeys_in_nk, HIVEX_MAX_SUBKEYS);
822     errno = ERANGE;
823     goto error;
824   }
825
826   /* Preallocate space for the children. */
827   if (grow_offset_list (&children, nr_subkeys_in_nk) == -1)
828     goto error;
829
830   /* The subkey_lf field can point either to an lf-record, which is
831    * the common case, or if there are lots of subkeys, to an
832    * ri-record.
833    */
834   size_t subkey_lf = le32toh (nk->subkey_lf);
835   subkey_lf += 0x1000;
836   if (!IS_VALID_BLOCK (h, subkey_lf)) {
837     if (h->msglvl >= 2)
838       fprintf (stderr, "hivex_node_children: returning EFAULT"
839                " because subkey_lf is not a valid block (0x%zx)\n",
840                subkey_lf);
841     errno = EFAULT;
842     goto error;
843   }
844
845   if (add_to_offset_list (&blocks, subkey_lf) == -1)
846     goto error;
847
848   struct ntreg_hbin_block *block =
849     (struct ntreg_hbin_block *) (h->addr + subkey_lf);
850
851   /* Points to lf-record?  (Note, also "lh" but that is basically the
852    * same as "lf" as far as we are concerned here).
853    */
854   if (block->id[0] == 'l' && (block->id[1] == 'f' || block->id[1] == 'h')) {
855     struct ntreg_lf_record *lf = (struct ntreg_lf_record *) block;
856
857     /* Check number of subkeys in the nk-record matches number of subkeys
858      * in the lf-record.
859      */
860     size_t nr_subkeys_in_lf = le16toh (lf->nr_keys);
861
862     if (h->msglvl >= 2)
863       fprintf (stderr, "hivex_node_children: nr_subkeys_in_nk = %zu,"
864                " nr_subkeys_in_lf = %zu\n",
865                nr_subkeys_in_nk, nr_subkeys_in_lf);
866
867     if (nr_subkeys_in_nk != nr_subkeys_in_lf) {
868       errno = ENOTSUP;
869       goto error;
870     }
871
872     size_t len = block_len (h, subkey_lf, NULL);
873     if (8 + nr_subkeys_in_lf * 8 > len) {
874       if (h->msglvl >= 2)
875         fprintf (stderr, "hivex_node_children: returning EFAULT"
876                  " because too many subkeys (%zu, %zu)\n",
877                  nr_subkeys_in_lf, len);
878       errno = EFAULT;
879       goto error;
880     }
881
882     size_t i;
883     for (i = 0; i < nr_subkeys_in_lf; ++i) {
884       hive_node_h subkey = le32toh (lf->keys[i].offset);
885       subkey += 0x1000;
886       if (!(flags & GET_CHILDREN_NO_CHECK_NK)) {
887         if (!IS_VALID_BLOCK (h, subkey)) {
888           if (h->msglvl >= 2)
889             fprintf (stderr, "hivex_node_children: returning EFAULT"
890                      " because subkey is not a valid block (0x%zx)\n",
891                      subkey);
892           errno = EFAULT;
893           goto error;
894         }
895       }
896       if (add_to_offset_list (&children, subkey) == -1)
897         goto error;
898     }
899     goto ok;
900   }
901   /* Points to ri-record? */
902   else if (block->id[0] == 'r' && block->id[1] == 'i') {
903     struct ntreg_ri_record *ri = (struct ntreg_ri_record *) block;
904
905     size_t nr_offsets = le16toh (ri->nr_offsets);
906
907     /* Count total number of children. */
908     size_t i, count = 0;
909     for (i = 0; i < nr_offsets; ++i) {
910       hive_node_h offset = le32toh (ri->offset[i]);
911       offset += 0x1000;
912       if (!IS_VALID_BLOCK (h, offset)) {
913         if (h->msglvl >= 2)
914           fprintf (stderr, "hivex_node_children: returning EFAULT"
915                    " because ri-offset is not a valid block (0x%zx)\n",
916                    offset);
917         errno = EFAULT;
918         goto error;
919       }
920       if (!BLOCK_ID_EQ (h, offset, "lf") && !BLOCK_ID_EQ (h, offset, "lh")) {
921         if (h->msglvl >= 2)
922           fprintf (stderr, "get_children: returning ENOTSUP"
923                    " because ri-record offset does not point to lf/lh (0x%zx)\n",
924                    offset);
925         errno = ENOTSUP;
926         goto error;
927       }
928
929       if (add_to_offset_list (&blocks, offset) == -1)
930         goto error;
931
932       struct ntreg_lf_record *lf =
933         (struct ntreg_lf_record *) (h->addr + offset);
934
935       count += le16toh (lf->nr_keys);
936     }
937
938     if (h->msglvl >= 2)
939       fprintf (stderr, "hivex_node_children: nr_subkeys_in_nk = %zu,"
940                " counted = %zu\n",
941                nr_subkeys_in_nk, count);
942
943     if (nr_subkeys_in_nk != count) {
944       errno = ENOTSUP;
945       goto error;
946     }
947
948     /* Copy list of children.  Note nr_subkeys_in_nk is limited to
949      * something reasonable above.
950      */
951     for (i = 0; i < nr_offsets; ++i) {
952       hive_node_h offset = le32toh (ri->offset[i]);
953       offset += 0x1000;
954       if (!IS_VALID_BLOCK (h, offset)) {
955         if (h->msglvl >= 2)
956           fprintf (stderr, "hivex_node_children: returning EFAULT"
957                    " because ri-offset is not a valid block (0x%zx)\n",
958                    offset);
959         errno = EFAULT;
960         goto error;
961       }
962       if (!BLOCK_ID_EQ (h, offset, "lf") && !BLOCK_ID_EQ (h, offset, "lh")) {
963         if (h->msglvl >= 2)
964           fprintf (stderr, "get_children: returning ENOTSUP"
965                    " because ri-record offset does not point to lf/lh (0x%zx)\n",
966                    offset);
967         errno = ENOTSUP;
968         goto error;
969       }
970
971       struct ntreg_lf_record *lf =
972         (struct ntreg_lf_record *) (h->addr + offset);
973
974       size_t j;
975       for (j = 0; j < le16toh (lf->nr_keys); ++j) {
976         hive_node_h subkey = le32toh (lf->keys[j].offset);
977         subkey += 0x1000;
978         if (!(flags & GET_CHILDREN_NO_CHECK_NK)) {
979           if (!IS_VALID_BLOCK (h, subkey)) {
980             if (h->msglvl >= 2)
981               fprintf (stderr, "hivex_node_children: returning EFAULT"
982                        " because indirect subkey is not a valid block (0x%zx)\n",
983                        subkey);
984             errno = EFAULT;
985             goto error;
986           }
987         }
988         if (add_to_offset_list (&children, subkey) == -1)
989           goto error;
990       }
991     }
992     goto ok;
993   }
994   /* else not supported, set errno and fall through */
995   if (h->msglvl >= 2)
996     fprintf (stderr, "get_children: returning ENOTSUP"
997              " because subkey block is not lf/lh/ri (0x%zx, %d, %d)\n",
998              subkey_lf, block->id[0], block->id[1]);
999   errno = ENOTSUP;
1000  error:
1001   free_offset_list (&children);
1002   free_offset_list (&blocks);
1003   return -1;
1004
1005  ok:
1006   *children_ret = return_offset_list (&children);
1007   *blocks_ret = return_offset_list (&blocks);
1008   if (!*children_ret || !*blocks_ret)
1009     goto error;
1010   return 0;
1011 }
1012
1013 hive_node_h *
1014 hivex_node_children (hive_h *h, hive_node_h node)
1015 {
1016   hive_node_h *children;
1017   size_t *blocks;
1018
1019   if (get_children (h, node, &children, &blocks, 0) == -1)
1020     return NULL;
1021
1022   free (blocks);
1023   return children;
1024 }
1025
1026 /* Very inefficient, but at least having a separate API call
1027  * allows us to make it more efficient in future.
1028  */
1029 hive_node_h
1030 hivex_node_get_child (hive_h *h, hive_node_h node, const char *nname)
1031 {
1032   hive_node_h *children = NULL;
1033   char *name = NULL;
1034   hive_node_h ret = 0;
1035
1036   children = hivex_node_children (h, node);
1037   if (!children) goto error;
1038
1039   size_t i;
1040   for (i = 0; children[i] != 0; ++i) {
1041     name = hivex_node_name (h, children[i]);
1042     if (!name) goto error;
1043     if (STRCASEEQ (name, nname)) {
1044       ret = children[i];
1045       break;
1046     }
1047     free (name); name = NULL;
1048   }
1049
1050  error:
1051   free (children);
1052   free (name);
1053   return ret;
1054 }
1055
1056 hive_node_h
1057 hivex_node_parent (hive_h *h, hive_node_h node)
1058 {
1059   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
1060     errno = EINVAL;
1061     return 0;
1062   }
1063
1064   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
1065
1066   hive_node_h ret = le32toh (nk->parent);
1067   ret += 0x1000;
1068   if (!IS_VALID_BLOCK (h, ret)) {
1069     if (h->msglvl >= 2)
1070       fprintf (stderr, "hivex_node_parent: returning EFAULT"
1071                " because parent is not a valid block (0x%zx)\n",
1072               ret);
1073     errno = EFAULT;
1074     return 0;
1075   }
1076   return ret;
1077 }
1078
1079 static int
1080 get_values (hive_h *h, hive_node_h node,
1081             hive_value_h **values_ret, size_t **blocks_ret)
1082 {
1083   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
1084     errno = EINVAL;
1085     return -1;
1086   }
1087
1088   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
1089
1090   size_t nr_values = le32toh (nk->nr_values);
1091
1092   if (h->msglvl >= 2)
1093     fprintf (stderr, "hivex_node_values: nr_values = %zu\n", nr_values);
1094
1095   INIT_OFFSET_LIST (values);
1096   INIT_OFFSET_LIST (blocks);
1097
1098   /* Deal with the common "no values" case quickly. */
1099   if (nr_values == 0)
1100     goto ok;
1101
1102   /* Arbitrarily limit the number of values we will ever deal with. */
1103   if (nr_values > HIVEX_MAX_VALUES) {
1104     if (h->msglvl >= 2)
1105       fprintf (stderr, "hivex: get_values: returning ERANGE"
1106                " because nr_values > HIVEX_MAX_VALUES (%zu > %d)\n",
1107                nr_values, HIVEX_MAX_VALUES);
1108     errno = ERANGE;
1109     goto error;
1110   }
1111
1112   /* Preallocate space for the values. */
1113   if (grow_offset_list (&values, nr_values) == -1)
1114     goto error;
1115
1116   /* Get the value list and check it looks reasonable. */
1117   size_t vlist_offset = le32toh (nk->vallist);
1118   vlist_offset += 0x1000;
1119   if (!IS_VALID_BLOCK (h, vlist_offset)) {
1120     if (h->msglvl >= 2)
1121       fprintf (stderr, "hivex_node_values: returning EFAULT"
1122                " because value list is not a valid block (0x%zx)\n",
1123                vlist_offset);
1124     errno = EFAULT;
1125     goto error;
1126   }
1127
1128   if (add_to_offset_list (&blocks, vlist_offset) == -1)
1129     goto error;
1130
1131   struct ntreg_value_list *vlist =
1132     (struct ntreg_value_list *) (h->addr + vlist_offset);
1133
1134   size_t len = block_len (h, vlist_offset, NULL);
1135   if (4 + nr_values * 4 > len) {
1136     if (h->msglvl >= 2)
1137       fprintf (stderr, "hivex_node_values: returning EFAULT"
1138                " because value list is too long (%zu, %zu)\n",
1139                nr_values, len);
1140     errno = EFAULT;
1141     goto error;
1142   }
1143
1144   size_t i;
1145   for (i = 0; i < nr_values; ++i) {
1146     hive_node_h value = le32toh (vlist->offset[i]);
1147     value += 0x1000;
1148     if (!IS_VALID_BLOCK (h, value)) {
1149       if (h->msglvl >= 2)
1150         fprintf (stderr, "hivex_node_values: returning EFAULT"
1151                  " because value is not a valid block (0x%zx)\n",
1152                  value);
1153       errno = EFAULT;
1154       goto error;
1155     }
1156     if (add_to_offset_list (&values, value) == -1)
1157       goto error;
1158   }
1159
1160  ok:
1161   *values_ret = return_offset_list (&values);
1162   *blocks_ret = return_offset_list (&blocks);
1163   if (!*values_ret || !*blocks_ret)
1164     goto error;
1165   return 0;
1166
1167  error:
1168   free_offset_list (&values);
1169   free_offset_list (&blocks);
1170   return -1;
1171 }
1172
1173 hive_value_h *
1174 hivex_node_values (hive_h *h, hive_node_h node)
1175 {
1176   hive_value_h *values;
1177   size_t *blocks;
1178
1179   if (get_values (h, node, &values, &blocks) == -1)
1180     return NULL;
1181
1182   free (blocks);
1183   return values;
1184 }
1185
1186 /* Very inefficient, but at least having a separate API call
1187  * allows us to make it more efficient in future.
1188  */
1189 hive_value_h
1190 hivex_node_get_value (hive_h *h, hive_node_h node, const char *key)
1191 {
1192   hive_value_h *values = NULL;
1193   char *name = NULL;
1194   hive_value_h ret = 0;
1195
1196   values = hivex_node_values (h, node);
1197   if (!values) goto error;
1198
1199   size_t i;
1200   for (i = 0; values[i] != 0; ++i) {
1201     name = hivex_value_key (h, values[i]);
1202     if (!name) goto error;
1203     if (STRCASEEQ (name, key)) {
1204       ret = values[i];
1205       break;
1206     }
1207     free (name); name = NULL;
1208   }
1209
1210  error:
1211   free (values);
1212   free (name);
1213   return ret;
1214 }
1215
1216 size_t
1217 hivex_value_struct_length (hive_h *h, hive_value_h value)
1218 {
1219   size_t key_len;
1220
1221   errno = 0;
1222   key_len = hivex_value_key_len (h, value);
1223   if (key_len == 0 && errno != 0)
1224     return 0;
1225
1226   /* -1 to avoid double-counting the first name character */
1227   return key_len + sizeof (struct ntreg_vk_record) - 1;
1228 }
1229
1230 size_t
1231 hivex_value_key_len (hive_h *h, hive_value_h value)
1232 {
1233   if (!IS_VALID_BLOCK (h, value) || !BLOCK_ID_EQ (h, value, "vk")) {
1234     errno = EINVAL;
1235     return 0;
1236   }
1237
1238   struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + value);
1239
1240   /* vk->name_len is unsigned, 16 bit, so this is safe ...  However
1241    * we have to make sure the length doesn't exceed the block length.
1242    */
1243   size_t ret = le16toh (vk->name_len);
1244   size_t seg_len = block_len (h, value, NULL);
1245   if (sizeof (struct ntreg_vk_record) + ret - 1 > seg_len) {
1246     if (h->msglvl >= 2)
1247       fprintf (stderr, "hivex_value_key_len: returning EFAULT"
1248                " because key length is too long (%zu, %zu)\n",
1249                ret, seg_len);
1250     errno = EFAULT;
1251     return 0;
1252   }
1253   return ret;
1254 }
1255
1256 char *
1257 hivex_value_key (hive_h *h, hive_value_h value)
1258 {
1259   if (!IS_VALID_BLOCK (h, value) || !BLOCK_ID_EQ (h, value, "vk")) {
1260     errno = EINVAL;
1261     return 0;
1262   }
1263
1264   struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + value);
1265
1266   /* AFAIK the key is always plain ASCII, so no conversion to UTF-8 is
1267    * necessary.  However we do need to nul-terminate the string.
1268    */
1269   errno = 0;
1270   size_t len = hivex_value_key_len (h, value);
1271   if (len == 0 && errno != 0)
1272     return NULL;
1273
1274   char *ret = malloc (len + 1);
1275   if (ret == NULL)
1276     return NULL;
1277   memcpy (ret, vk->name, len);
1278   ret[len] = '\0';
1279   return ret;
1280 }
1281
1282 int
1283 hivex_value_type (hive_h *h, hive_value_h value, hive_type *t, size_t *len)
1284 {
1285   if (!IS_VALID_BLOCK (h, value) || !BLOCK_ID_EQ (h, value, "vk")) {
1286     errno = EINVAL;
1287     return -1;
1288   }
1289
1290   struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + value);
1291
1292   if (t)
1293     *t = le32toh (vk->data_type);
1294
1295   if (len) {
1296     *len = le32toh (vk->data_len);
1297     *len &= 0x7fffffff;         /* top bit indicates if data is stored inline */
1298   }
1299
1300   return 0;
1301 }
1302
1303 char *
1304 hivex_value_value (hive_h *h, hive_value_h value,
1305                    hive_type *t_rtn, size_t *len_rtn)
1306 {
1307   if (!IS_VALID_BLOCK (h, value) || !BLOCK_ID_EQ (h, value, "vk")) {
1308     errno = EINVAL;
1309     return NULL;
1310   }
1311
1312   struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + value);
1313
1314   hive_type t;
1315   size_t len;
1316   int is_inline;
1317
1318   t = le32toh (vk->data_type);
1319
1320   len = le32toh (vk->data_len);
1321   is_inline = !!(len & 0x80000000);
1322   len &= 0x7fffffff;
1323
1324   if (h->msglvl >= 2)
1325     fprintf (stderr, "hivex_value_value: value=0x%zx, t=%d, len=%zu, inline=%d\n",
1326              value, t, len, is_inline);
1327
1328   if (t_rtn)
1329     *t_rtn = t;
1330   if (len_rtn)
1331     *len_rtn = len;
1332
1333   if (is_inline && len > 4) {
1334     errno = ENOTSUP;
1335     return NULL;
1336   }
1337
1338   /* Arbitrarily limit the length that we will read. */
1339   if (len > HIVEX_MAX_VALUE_LEN) {
1340     if (h->msglvl >= 2)
1341       fprintf (stderr, "hivex_value_value: returning ERANGE because data "
1342                "length > HIVEX_MAX_VALUE_LEN (%zu > %d)\n",
1343                len, HIVEX_MAX_SUBKEYS);
1344     errno = ERANGE;
1345     return NULL;
1346   }
1347
1348   char *ret = malloc (len);
1349   if (ret == NULL)
1350     return NULL;
1351
1352   if (is_inline) {
1353     memcpy (ret, (char *) &vk->data_offset, len);
1354     return ret;
1355   }
1356
1357   size_t data_offset = le32toh (vk->data_offset);
1358   data_offset += 0x1000;
1359   if (!IS_VALID_BLOCK (h, data_offset)) {
1360     if (h->msglvl >= 2)
1361       fprintf (stderr, "hivex_value_value: returning EFAULT because data "
1362                "offset is not a valid block (0x%zx)\n",
1363                data_offset);
1364     errno = EFAULT;
1365     free (ret);
1366     return NULL;
1367   }
1368
1369   /* Check that the declared size isn't larger than the block its in.
1370    *
1371    * XXX Some apparently valid registries are seen to have this,
1372    * so turn this into a warning and substitute the smaller length
1373    * instead.
1374    */
1375   size_t blen = block_len (h, data_offset, NULL);
1376   if (len > blen - 4 /* subtract 4 for block header */) {
1377     if (h->msglvl >= 2)
1378       fprintf (stderr, "hivex_value_value: warning: declared data length "
1379                "is longer than the block it is in "
1380                "(data 0x%zx, data len %zu, block len %zu)\n",
1381                data_offset, len, blen);
1382     len = blen - 4;
1383
1384     /* Return the smaller length to the caller too. */
1385     if (len_rtn)
1386       *len_rtn = len;
1387   }
1388
1389   char *data = h->addr + data_offset + 4;
1390   memcpy (ret, data, len);
1391   return ret;
1392 }
1393
1394 static char *
1395 windows_utf16_to_utf8 (/* const */ char *input, size_t len)
1396 {
1397   iconv_t ic = iconv_open ("UTF-8", "UTF-16");
1398   if (ic == (iconv_t) -1)
1399     return NULL;
1400
1401   /* iconv(3) has an insane interface ... */
1402
1403   /* Mostly UTF-8 will be smaller, so this is a good initial guess. */
1404   size_t outalloc = len;
1405
1406  again:;
1407   size_t inlen = len;
1408   size_t outlen = outalloc;
1409   char *out = malloc (outlen + 1);
1410   if (out == NULL) {
1411     int err = errno;
1412     iconv_close (ic);
1413     errno = err;
1414     return NULL;
1415   }
1416   char *inp = input;
1417   char *outp = out;
1418
1419   size_t r = iconv (ic, &inp, &inlen, &outp, &outlen);
1420   if (r == (size_t) -1) {
1421     if (errno == E2BIG) {
1422       int err = errno;
1423       size_t prev = outalloc;
1424       /* Try again with a larger output buffer. */
1425       free (out);
1426       outalloc *= 2;
1427       if (outalloc < prev) {
1428         iconv_close (ic);
1429         errno = err;
1430         return NULL;
1431       }
1432       goto again;
1433     }
1434     else {
1435       /* Else some conversion failure, eg. EILSEQ, EINVAL. */
1436       int err = errno;
1437       iconv_close (ic);
1438       free (out);
1439       errno = err;
1440       return NULL;
1441     }
1442   }
1443
1444   *outp = '\0';
1445   iconv_close (ic);
1446
1447   return out;
1448 }
1449
1450 char *
1451 hivex_value_string (hive_h *h, hive_value_h value)
1452 {
1453   hive_type t;
1454   size_t len;
1455   char *data = hivex_value_value (h, value, &t, &len);
1456
1457   if (data == NULL)
1458     return NULL;
1459
1460   if (t != hive_t_string && t != hive_t_expand_string && t != hive_t_link) {
1461     free (data);
1462     errno = EINVAL;
1463     return NULL;
1464   }
1465
1466   /* Deal with the case where Windows has allocated a large buffer
1467    * full of random junk, and only the first few bytes of the buffer
1468    * contain a genuine UTF-16 string.
1469    *
1470    * In this case, iconv would try to process the junk bytes as UTF-16
1471    * and inevitably find an illegal sequence (EILSEQ).  Instead, stop
1472    * after we find the first \0\0.
1473    *
1474    * (Found by Hilko Bengen in a fresh Windows XP SOFTWARE hive).
1475    */
1476   size_t slen = utf16_string_len_in_bytes_max (data, len);
1477   if (slen < len)
1478     len = slen;
1479
1480   char *ret = windows_utf16_to_utf8 (data, len);
1481   free (data);
1482   if (ret == NULL)
1483     return NULL;
1484
1485   return ret;
1486 }
1487
1488 static void
1489 free_strings (char **argv)
1490 {
1491   if (argv) {
1492     size_t i;
1493
1494     for (i = 0; argv[i] != NULL; ++i)
1495       free (argv[i]);
1496     free (argv);
1497   }
1498 }
1499
1500 /* Get the length of a UTF-16 format string.  Handle the string as
1501  * pairs of bytes, looking for the first \0\0 pair.  Only read up to
1502  * 'len' maximum bytes.
1503  */
1504 static size_t
1505 utf16_string_len_in_bytes_max (const char *str, size_t len)
1506 {
1507   size_t ret = 0;
1508
1509   while (len >= 2 && (str[0] || str[1])) {
1510     str += 2;
1511     ret += 2;
1512     len -= 2;
1513   }
1514
1515   return ret;
1516 }
1517
1518 /* http://blogs.msdn.com/oldnewthing/archive/2009/10/08/9904646.aspx */
1519 char **
1520 hivex_value_multiple_strings (hive_h *h, hive_value_h value)
1521 {
1522   hive_type t;
1523   size_t len;
1524   char *data = hivex_value_value (h, value, &t, &len);
1525
1526   if (data == NULL)
1527     return NULL;
1528
1529   if (t != hive_t_multiple_strings) {
1530     free (data);
1531     errno = EINVAL;
1532     return NULL;
1533   }
1534
1535   size_t nr_strings = 0;
1536   char **ret = malloc ((1 + nr_strings) * sizeof (char *));
1537   if (ret == NULL) {
1538     free (data);
1539     return NULL;
1540   }
1541   ret[0] = NULL;
1542
1543   char *p = data;
1544   size_t plen;
1545
1546   while (p < data + len &&
1547          (plen = utf16_string_len_in_bytes_max (p, data + len - p)) > 0) {
1548     nr_strings++;
1549     char **ret2 = realloc (ret, (1 + nr_strings) * sizeof (char *));
1550     if (ret2 == NULL) {
1551       free_strings (ret);
1552       free (data);
1553       return NULL;
1554     }
1555     ret = ret2;
1556
1557     ret[nr_strings-1] = windows_utf16_to_utf8 (p, plen);
1558     ret[nr_strings] = NULL;
1559     if (ret[nr_strings-1] == NULL) {
1560       free_strings (ret);
1561       free (data);
1562       return NULL;
1563     }
1564
1565     p += plen + 2 /* skip over UTF-16 \0\0 at the end of this string */;
1566   }
1567
1568   free (data);
1569   return ret;
1570 }
1571
1572 int32_t
1573 hivex_value_dword (hive_h *h, hive_value_h value)
1574 {
1575   hive_type t;
1576   size_t len;
1577   char *data = hivex_value_value (h, value, &t, &len);
1578
1579   if (data == NULL)
1580     return -1;
1581
1582   if ((t != hive_t_dword && t != hive_t_dword_be) || len != 4) {
1583     free (data);
1584     errno = EINVAL;
1585     return -1;
1586   }
1587
1588   int32_t ret = *(int32_t*)data;
1589   free (data);
1590   if (t == hive_t_dword)        /* little endian */
1591     ret = le32toh (ret);
1592   else
1593     ret = be32toh (ret);
1594
1595   return ret;
1596 }
1597
1598 int64_t
1599 hivex_value_qword (hive_h *h, hive_value_h value)
1600 {
1601   hive_type t;
1602   size_t len;
1603   char *data = hivex_value_value (h, value, &t, &len);
1604
1605   if (data == NULL)
1606     return -1;
1607
1608   if (t != hive_t_qword || len != 8) {
1609     free (data);
1610     errno = EINVAL;
1611     return -1;
1612   }
1613
1614   int64_t ret = *(int64_t*)data;
1615   free (data);
1616   ret = le64toh (ret);          /* always little endian */
1617
1618   return ret;
1619 }
1620
1621 /*----------------------------------------------------------------------
1622  * Visiting.
1623  */
1624
1625 int
1626 hivex_visit (hive_h *h, const struct hivex_visitor *visitor, size_t len,
1627              void *opaque, int flags)
1628 {
1629   return hivex_visit_node (h, hivex_root (h), visitor, len, opaque, flags);
1630 }
1631
1632 static int hivex__visit_node (hive_h *h, hive_node_h node,
1633                               const struct hivex_visitor *vtor,
1634                               char *unvisited, void *opaque, int flags);
1635
1636 int
1637 hivex_visit_node (hive_h *h, hive_node_h node,
1638                   const struct hivex_visitor *visitor, size_t len, void *opaque,
1639                   int flags)
1640 {
1641   struct hivex_visitor vtor;
1642   memset (&vtor, 0, sizeof vtor);
1643
1644   /* Note that len might be larger *or smaller* than the expected size. */
1645   size_t copysize = len <= sizeof vtor ? len : sizeof vtor;
1646   memcpy (&vtor, visitor, copysize);
1647
1648   /* This bitmap records unvisited nodes, so we don't loop if the
1649    * registry contains cycles.
1650    */
1651   char *unvisited = malloc (1 + h->size / 32);
1652   if (unvisited == NULL)
1653     return -1;
1654   memcpy (unvisited, h->bitmap, 1 + h->size / 32);
1655
1656   int r = hivex__visit_node (h, node, &vtor, unvisited, opaque, flags);
1657   free (unvisited);
1658   return r;
1659 }
1660
1661 static int
1662 hivex__visit_node (hive_h *h, hive_node_h node,
1663                    const struct hivex_visitor *vtor, char *unvisited,
1664                    void *opaque, int flags)
1665 {
1666   int skip_bad = flags & HIVEX_VISIT_SKIP_BAD;
1667   char *name = NULL;
1668   hive_value_h *values = NULL;
1669   hive_node_h *children = NULL;
1670   char *key = NULL;
1671   char *str = NULL;
1672   char **strs = NULL;
1673   int i;
1674
1675   /* Return -1 on all callback errors.  However on internal errors,
1676    * check if skip_bad is set and suppress those errors if so.
1677    */
1678   int ret = -1;
1679
1680   if (!BITMAP_TST (unvisited, node)) {
1681     if (h->msglvl >= 2)
1682       fprintf (stderr, "hivex__visit_node: contains cycle:"
1683                " visited node 0x%zx already\n",
1684                node);
1685
1686     errno = ELOOP;
1687     return skip_bad ? 0 : -1;
1688   }
1689   BITMAP_CLR (unvisited, node);
1690
1691   name = hivex_node_name (h, node);
1692   if (!name) return skip_bad ? 0 : -1;
1693   if (vtor->node_start && vtor->node_start (h, opaque, node, name) == -1)
1694     goto error;
1695
1696   values = hivex_node_values (h, node);
1697   if (!values) {
1698     ret = skip_bad ? 0 : -1;
1699     goto error;
1700   }
1701
1702   for (i = 0; values[i] != 0; ++i) {
1703     hive_type t;
1704     size_t len;
1705
1706     if (hivex_value_type (h, values[i], &t, &len) == -1) {
1707       ret = skip_bad ? 0 : -1;
1708       goto error;
1709     }
1710
1711     key = hivex_value_key (h, values[i]);
1712     if (key == NULL) {
1713       ret = skip_bad ? 0 : -1;
1714       goto error;
1715     }
1716
1717     if (vtor->value_any) {
1718       str = hivex_value_value (h, values[i], &t, &len);
1719       if (str == NULL) {
1720         ret = skip_bad ? 0 : -1;
1721         goto error;
1722       }
1723       if (vtor->value_any (h, opaque, node, values[i], t, len, key, str) == -1)
1724         goto error;
1725       free (str); str = NULL;
1726     }
1727     else {
1728       switch (t) {
1729       case hive_t_none:
1730         str = hivex_value_value (h, values[i], &t, &len);
1731         if (str == NULL) {
1732           ret = skip_bad ? 0 : -1;
1733           goto error;
1734         }
1735         if (t != hive_t_none) {
1736           ret = skip_bad ? 0 : -1;
1737           goto error;
1738         }
1739         if (vtor->value_none &&
1740             vtor->value_none (h, opaque, node, values[i], t, len, key, str) == -1)
1741           goto error;
1742         free (str); str = NULL;
1743         break;
1744
1745       case hive_t_string:
1746       case hive_t_expand_string:
1747       case hive_t_link:
1748         str = hivex_value_string (h, values[i]);
1749         if (str == NULL) {
1750           if (errno != EILSEQ && errno != EINVAL) {
1751             ret = skip_bad ? 0 : -1;
1752             goto error;
1753           }
1754           if (vtor->value_string_invalid_utf16) {
1755             str = hivex_value_value (h, values[i], &t, &len);
1756             if (vtor->value_string_invalid_utf16 (h, opaque, node, values[i],
1757                                                   t, len, key, str) == -1)
1758               goto error;
1759             free (str); str = NULL;
1760           }
1761           break;
1762         }
1763         if (vtor->value_string &&
1764             vtor->value_string (h, opaque, node, values[i],
1765                                 t, len, key, str) == -1)
1766           goto error;
1767         free (str); str = NULL;
1768         break;
1769
1770       case hive_t_dword:
1771       case hive_t_dword_be: {
1772         int32_t i32 = hivex_value_dword (h, values[i]);
1773         if (vtor->value_dword &&
1774             vtor->value_dword (h, opaque, node, values[i],
1775                                t, len, key, i32) == -1)
1776           goto error;
1777         break;
1778       }
1779
1780       case hive_t_qword: {
1781         int64_t i64 = hivex_value_qword (h, values[i]);
1782         if (vtor->value_qword &&
1783             vtor->value_qword (h, opaque, node, values[i],
1784                                t, len, key, i64) == -1)
1785           goto error;
1786         break;
1787       }
1788
1789       case hive_t_binary:
1790         str = hivex_value_value (h, values[i], &t, &len);
1791         if (str == NULL) {
1792           ret = skip_bad ? 0 : -1;
1793           goto error;
1794         }
1795         if (t != hive_t_binary) {
1796           ret = skip_bad ? 0 : -1;
1797           goto error;
1798         }
1799         if (vtor->value_binary &&
1800             vtor->value_binary (h, opaque, node, values[i],
1801                                 t, len, key, str) == -1)
1802           goto error;
1803         free (str); str = NULL;
1804         break;
1805
1806       case hive_t_multiple_strings:
1807         strs = hivex_value_multiple_strings (h, values[i]);
1808         if (strs == NULL) {
1809           if (errno != EILSEQ && errno != EINVAL) {
1810             ret = skip_bad ? 0 : -1;
1811             goto error;
1812           }
1813           if (vtor->value_string_invalid_utf16) {
1814             str = hivex_value_value (h, values[i], &t, &len);
1815             if (vtor->value_string_invalid_utf16 (h, opaque, node, values[i],
1816                                                   t, len, key, str) == -1)
1817               goto error;
1818             free (str); str = NULL;
1819           }
1820           break;
1821         }
1822         if (vtor->value_multiple_strings &&
1823             vtor->value_multiple_strings (h, opaque, node, values[i],
1824                                           t, len, key, strs) == -1)
1825           goto error;
1826         free_strings (strs); strs = NULL;
1827         break;
1828
1829       case hive_t_resource_list:
1830       case hive_t_full_resource_description:
1831       case hive_t_resource_requirements_list:
1832       default:
1833         str = hivex_value_value (h, values[i], &t, &len);
1834         if (str == NULL) {
1835           ret = skip_bad ? 0 : -1;
1836           goto error;
1837         }
1838         if (vtor->value_other &&
1839             vtor->value_other (h, opaque, node, values[i],
1840                                t, len, key, str) == -1)
1841           goto error;
1842         free (str); str = NULL;
1843         break;
1844       }
1845     }
1846
1847     free (key); key = NULL;
1848   }
1849
1850   children = hivex_node_children (h, node);
1851   if (children == NULL) {
1852     ret = skip_bad ? 0 : -1;
1853     goto error;
1854   }
1855
1856   for (i = 0; children[i] != 0; ++i) {
1857     if (h->msglvl >= 2)
1858       fprintf (stderr, "hivex__visit_node: %s: visiting subkey %d (0x%zx)\n",
1859                name, i, children[i]);
1860
1861     if (hivex__visit_node (h, children[i], vtor, unvisited, opaque, flags) == -1)
1862       goto error;
1863   }
1864
1865   if (vtor->node_end && vtor->node_end (h, opaque, node, name) == -1)
1866     goto error;
1867
1868   ret = 0;
1869
1870  error:
1871   free (name);
1872   free (values);
1873   free (children);
1874   free (key);
1875   free (str);
1876   free_strings (strs);
1877   return ret;
1878 }
1879
1880 /*----------------------------------------------------------------------
1881  * Writing.
1882  */
1883
1884 /* Allocate an hbin (page), extending the malloc'd space if necessary,
1885  * and updating the hive handle fields (but NOT the hive disk header
1886  * -- the hive disk header is updated when we commit).  This function
1887  * also extends the bitmap if necessary.
1888  *
1889  * 'allocation_hint' is the size of the block allocation we would like
1890  * to make.  Normally registry blocks are very small (avg 50 bytes)
1891  * and are contained in standard-sized pages (4KB), but the registry
1892  * can support blocks which are larger than a standard page, in which
1893  * case it creates a page of 8KB, 12KB etc.
1894  *
1895  * Returns:
1896  * > 0 : offset of first usable byte of new page (after page header)
1897  * 0   : error (errno set)
1898  */
1899 static size_t
1900 allocate_page (hive_h *h, size_t allocation_hint)
1901 {
1902   /* In almost all cases this will be 1. */
1903   size_t nr_4k_pages =
1904     1 + (allocation_hint + sizeof (struct ntreg_hbin_page) - 1) / 4096;
1905   assert (nr_4k_pages >= 1);
1906
1907   /* 'extend' is the number of bytes to extend the file by.  Note that
1908    * hives found in the wild often contain slack between 'endpages'
1909    * and the actual end of the file, so we don't always need to make
1910    * the file larger.
1911    */
1912   ssize_t extend = h->endpages + nr_4k_pages * 4096 - h->size;
1913
1914   if (h->msglvl >= 2) {
1915     fprintf (stderr, "allocate_page: current endpages = 0x%zx,"
1916              " current size = 0x%zx\n",
1917              h->endpages, h->size);
1918     fprintf (stderr, "allocate_page: extending file by %zd bytes"
1919              " (<= 0 if no extension)\n",
1920              extend);
1921   }
1922
1923   if (extend > 0) {
1924     size_t oldsize = h->size;
1925     size_t newsize = h->size + extend;
1926     char *newaddr = realloc (h->addr, newsize);
1927     if (newaddr == NULL)
1928       return 0;
1929
1930     size_t oldbitmapsize = 1 + oldsize / 32;
1931     size_t newbitmapsize = 1 + newsize / 32;
1932     char *newbitmap = realloc (h->bitmap, newbitmapsize);
1933     if (newbitmap == NULL) {
1934       free (newaddr);
1935       return 0;
1936     }
1937
1938     h->addr = newaddr;
1939     h->size = newsize;
1940     h->bitmap = newbitmap;
1941
1942     memset (h->addr + oldsize, 0, newsize - oldsize);
1943     memset (h->bitmap + oldbitmapsize, 0, newbitmapsize - oldbitmapsize);
1944   }
1945
1946   size_t offset = h->endpages;
1947   h->endpages += nr_4k_pages * 4096;
1948
1949   if (h->msglvl >= 2)
1950     fprintf (stderr, "allocate_page: new endpages = 0x%zx, new size = 0x%zx\n",
1951              h->endpages, h->size);
1952
1953   /* Write the hbin header. */
1954   struct ntreg_hbin_page *page =
1955     (struct ntreg_hbin_page *) (h->addr + offset);
1956   page->magic[0] = 'h';
1957   page->magic[1] = 'b';
1958   page->magic[2] = 'i';
1959   page->magic[3] = 'n';
1960   page->offset_first = htole32 (offset - 0x1000);
1961   page->page_size = htole32 (nr_4k_pages * 4096);
1962   memset (page->unknown, 0, sizeof (page->unknown));
1963
1964   if (h->msglvl >= 2)
1965     fprintf (stderr, "allocate_page: new page at 0x%zx\n", offset);
1966
1967   /* Offset of first usable byte after the header. */
1968   return offset + sizeof (struct ntreg_hbin_page);
1969 }
1970
1971 /* Allocate a single block, first allocating an hbin (page) at the end
1972  * of the current file if necessary.  NB. To keep the implementation
1973  * simple and more likely to be correct, we do not reuse existing free
1974  * blocks.
1975  *
1976  * seg_len is the size of the block (this INCLUDES the block header).
1977  * The header of the block is initialized to -seg_len (negative to
1978  * indicate used).  id[2] is the block ID (type), eg. "nk" for nk-
1979  * record.  The block bitmap is updated to show this block as valid.
1980  * The rest of the contents of the block will be zero.
1981  *
1982  * **NB** Because allocate_block may reallocate the memory, all
1983  * pointers into the memory become potentially invalid.  I really
1984  * love writing in C, can't you tell?
1985  *
1986  * Returns:
1987  * > 0 : offset of new block
1988  * 0   : error (errno set)
1989  */
1990 static size_t
1991 allocate_block (hive_h *h, size_t seg_len, const char id[2])
1992 {
1993   if (!h->writable) {
1994     errno = EROFS;
1995     return 0;
1996   }
1997
1998   if (seg_len < 4) {
1999     /* The caller probably forgot to include the header.  Note that
2000      * value lists have no ID field, so seg_len == 4 would be possible
2001      * for them, albeit unusual.
2002      */
2003     if (h->msglvl >= 2)
2004       fprintf (stderr, "allocate_block: refusing too small allocation (%zu),"
2005                " returning ERANGE\n", seg_len);
2006     errno = ERANGE;
2007     return 0;
2008   }
2009
2010   /* Refuse really large allocations. */
2011   if (seg_len > HIVEX_MAX_ALLOCATION) {
2012     if (h->msglvl >= 2)
2013       fprintf (stderr, "allocate_block: refusing large allocation (%zu),"
2014                " returning ERANGE\n", seg_len);
2015     errno = ERANGE;
2016     return 0;
2017   }
2018
2019   /* Round up allocation to multiple of 8 bytes.  All blocks must be
2020    * on an 8 byte boundary.
2021    */
2022   seg_len = (seg_len + 7) & ~7;
2023
2024   /* Allocate a new page if necessary. */
2025   if (h->endblocks == 0 || h->endblocks + seg_len > h->endpages) {
2026     size_t newendblocks = allocate_page (h, seg_len);
2027     if (newendblocks == 0)
2028       return 0;
2029     h->endblocks = newendblocks;
2030   }
2031
2032   size_t offset = h->endblocks;
2033
2034   if (h->msglvl >= 2)
2035     fprintf (stderr, "allocate_block: new block at 0x%zx, size %zu\n",
2036              offset, seg_len);
2037
2038   struct ntreg_hbin_block *blockhdr =
2039     (struct ntreg_hbin_block *) (h->addr + offset);
2040
2041   memset (blockhdr, 0, seg_len);
2042
2043   blockhdr->seg_len = htole32 (- (int32_t) seg_len);
2044   if (id[0] && id[1] && seg_len >= sizeof (struct ntreg_hbin_block)) {
2045     blockhdr->id[0] = id[0];
2046     blockhdr->id[1] = id[1];
2047   }
2048
2049   BITMAP_SET (h->bitmap, offset);
2050
2051   h->endblocks += seg_len;
2052
2053   /* If there is space after the last block in the last page, then we
2054    * have to put a dummy free block header here to mark the rest of
2055    * the page as free.
2056    */
2057   ssize_t rem = h->endpages - h->endblocks;
2058   if (rem > 0) {
2059     if (h->msglvl >= 2)
2060       fprintf (stderr, "allocate_block: marking remainder of page free"
2061                " starting at 0x%zx, size %zd\n", h->endblocks, rem);
2062
2063     assert (rem >= 4);
2064
2065     blockhdr = (struct ntreg_hbin_block *) (h->addr + h->endblocks);
2066     blockhdr->seg_len = htole32 ((int32_t) rem);
2067   }
2068
2069   return offset;
2070 }
2071
2072 /* 'offset' must point to a valid, used block.  This function marks
2073  * the block unused (by updating the seg_len field) and invalidates
2074  * the bitmap.  It does NOT do this recursively, so to avoid creating
2075  * unreachable used blocks, callers may have to recurse over the hive
2076  * structures.  Also callers must ensure there are no references to
2077  * this block from other parts of the hive.
2078  */
2079 static void
2080 mark_block_unused (hive_h *h, size_t offset)
2081 {
2082   assert (h->writable);
2083   assert (IS_VALID_BLOCK (h, offset));
2084
2085   if (h->msglvl >= 2)
2086     fprintf (stderr, "mark_block_unused: marking 0x%zx unused\n", offset);
2087
2088   struct ntreg_hbin_block *blockhdr =
2089     (struct ntreg_hbin_block *) (h->addr + offset);
2090
2091   size_t seg_len = block_len (h, offset, NULL);
2092   blockhdr->seg_len = htole32 (seg_len);
2093
2094   BITMAP_CLR (h->bitmap, offset);
2095 }
2096
2097 /* Delete all existing values at this node. */
2098 static int
2099 delete_values (hive_h *h, hive_node_h node)
2100 {
2101   assert (h->writable);
2102
2103   hive_value_h *values;
2104   size_t *blocks;
2105   if (get_values (h, node, &values, &blocks) == -1)
2106     return -1;
2107
2108   size_t i;
2109   for (i = 0; blocks[i] != 0; ++i)
2110     mark_block_unused (h, blocks[i]);
2111
2112   free (blocks);
2113
2114   for (i = 0; values[i] != 0; ++i) {
2115     struct ntreg_vk_record *vk =
2116       (struct ntreg_vk_record *) (h->addr + values[i]);
2117
2118     size_t len;
2119     int is_inline;
2120     len = le32toh (vk->data_len);
2121     is_inline = !!(len & 0x80000000); /* top bit indicates is inline */
2122     len &= 0x7fffffff;
2123
2124     if (!is_inline) {           /* non-inline, so remove data block */
2125       size_t data_offset = le32toh (vk->data_offset);
2126       data_offset += 0x1000;
2127       mark_block_unused (h, data_offset);
2128     }
2129
2130     /* remove vk record */
2131     mark_block_unused (h, values[i]);
2132   }
2133
2134   free (values);
2135
2136   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
2137   nk->nr_values = htole32 (0);
2138   nk->vallist = htole32 (0xffffffff);
2139
2140   return 0;
2141 }
2142
2143 int
2144 hivex_commit (hive_h *h, const char *filename, int flags)
2145 {
2146   if (flags != 0) {
2147     errno = EINVAL;
2148     return -1;
2149   }
2150
2151   if (!h->writable) {
2152     errno = EROFS;
2153     return -1;
2154   }
2155
2156   filename = filename ? : h->filename;
2157   int fd = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0666);
2158   if (fd == -1)
2159     return -1;
2160
2161   /* Update the header fields. */
2162   uint32_t sequence = le32toh (h->hdr->sequence1);
2163   sequence++;
2164   h->hdr->sequence1 = htole32 (sequence);
2165   h->hdr->sequence2 = htole32 (sequence);
2166   /* XXX Ought to update h->hdr->last_modified. */
2167   h->hdr->blocks = htole32 (h->endpages - 0x1000);
2168
2169   /* Recompute header checksum. */
2170   uint32_t sum = header_checksum (h);
2171   h->hdr->csum = htole32 (sum);
2172
2173   if (h->msglvl >= 2)
2174     fprintf (stderr, "hivex_commit: new header checksum: 0x%x\n", sum);
2175
2176   if (full_write (fd, h->addr, h->size) != h->size) {
2177     int err = errno;
2178     close (fd);
2179     errno = err;
2180     return -1;
2181   }
2182
2183   if (close (fd) == -1)
2184     return -1;
2185
2186   return 0;
2187 }
2188
2189 /* Calculate the hash for a lf or lh record offset.
2190  */
2191 static void
2192 calc_hash (const char *type, const char *name, char *ret)
2193 {
2194   size_t len = strlen (name);
2195
2196   if (STRPREFIX (type, "lf"))
2197     /* Old-style, not used in current registries. */
2198     memcpy (ret, name, len < 4 ? len : 4);
2199   else {
2200     /* New-style for lh-records. */
2201     size_t i, c;
2202     uint32_t h = 0;
2203     for (i = 0; i < len; ++i) {
2204       c = c_toupper (name[i]);
2205       h *= 37;
2206       h += c;
2207     }
2208     *((uint32_t *) ret) = htole32 (h);
2209   }
2210 }
2211
2212 /* Create a completely new lh-record containing just the single node. */
2213 static size_t
2214 new_lh_record (hive_h *h, const char *name, hive_node_h node)
2215 {
2216   static const char id[2] = { 'l', 'h' };
2217   size_t seg_len = sizeof (struct ntreg_lf_record);
2218   size_t offset = allocate_block (h, seg_len, id);
2219   if (offset == 0)
2220     return 0;
2221
2222   struct ntreg_lf_record *lh = (struct ntreg_lf_record *) (h->addr + offset);
2223   lh->nr_keys = htole16 (1);
2224   lh->keys[0].offset = htole32 (node - 0x1000);
2225   calc_hash ("lh", name, lh->keys[0].hash);
2226
2227   return offset;
2228 }
2229
2230 /* Insert node into existing lf/lh-record at position.
2231  * This allocates a new record and marks the old one as unused.
2232  */
2233 static size_t
2234 insert_lf_record (hive_h *h, size_t old_offs, size_t posn,
2235                   const char *name, hive_node_h node)
2236 {
2237   assert (IS_VALID_BLOCK (h, old_offs));
2238
2239   /* Work around C stupidity.
2240    * http://www.redhat.com/archives/libguestfs/2010-February/msg00056.html
2241    */
2242   int test = BLOCK_ID_EQ (h, old_offs, "lf") || BLOCK_ID_EQ (h, old_offs, "lh");
2243   assert (test);
2244
2245   struct ntreg_lf_record *old_lf =
2246     (struct ntreg_lf_record *) (h->addr + old_offs);
2247   size_t nr_keys = le16toh (old_lf->nr_keys);
2248
2249   nr_keys++; /* in new record ... */
2250
2251   size_t seg_len = sizeof (struct ntreg_lf_record) + (nr_keys-1) * 8;
2252
2253   /* Copy the old_lf->id in case it moves during allocate_block. */
2254   char id[2];
2255   memcpy (id, old_lf->id, sizeof id);
2256
2257   size_t new_offs = allocate_block (h, seg_len, id);
2258   if (new_offs == 0)
2259     return 0;
2260
2261   /* old_lf could have been invalidated by allocate_block. */
2262   old_lf = (struct ntreg_lf_record *) (h->addr + old_offs);
2263
2264   struct ntreg_lf_record *new_lf =
2265     (struct ntreg_lf_record *) (h->addr + new_offs);
2266   new_lf->nr_keys = htole16 (nr_keys);
2267
2268   /* Copy the keys until we reach posn, insert the new key there, then
2269    * copy the remaining keys.
2270    */
2271   size_t i;
2272   for (i = 0; i < posn; ++i)
2273     new_lf->keys[i] = old_lf->keys[i];
2274
2275   new_lf->keys[i].offset = htole32 (node - 0x1000);
2276   calc_hash (new_lf->id, name, new_lf->keys[i].hash);
2277
2278   for (i = posn+1; i < nr_keys; ++i)
2279     new_lf->keys[i] = old_lf->keys[i-1];
2280
2281   /* Old block is unused, return new block. */
2282   mark_block_unused (h, old_offs);
2283   return new_offs;
2284 }
2285
2286 /* Compare name with name in nk-record. */
2287 static int
2288 compare_name_with_nk_name (hive_h *h, const char *name, hive_node_h nk_offs)
2289 {
2290   assert (IS_VALID_BLOCK (h, nk_offs));
2291   assert (BLOCK_ID_EQ (h, nk_offs, "nk"));
2292
2293   /* Name in nk is not necessarily nul-terminated. */
2294   char *nname = hivex_node_name (h, nk_offs);
2295
2296   /* Unfortunately we don't have a way to return errors here. */
2297   if (!nname) {
2298     perror ("compare_name_with_nk_name");
2299     return 0;
2300   }
2301
2302   int r = strcasecmp (name, nname);
2303   free (nname);
2304
2305   return r;
2306 }
2307
2308 hive_node_h
2309 hivex_node_add_child (hive_h *h, hive_node_h parent, const char *name)
2310 {
2311   if (!h->writable) {
2312     errno = EROFS;
2313     return 0;
2314   }
2315
2316   if (!IS_VALID_BLOCK (h, parent) || !BLOCK_ID_EQ (h, parent, "nk")) {
2317     errno = EINVAL;
2318     return 0;
2319   }
2320
2321   if (name == NULL || strlen (name) == 0) {
2322     errno = EINVAL;
2323     return 0;
2324   }
2325
2326   if (hivex_node_get_child (h, parent, name) != 0) {
2327     errno = EEXIST;
2328     return 0;
2329   }
2330
2331   /* Create the new nk-record. */
2332   static const char nk_id[2] = { 'n', 'k' };
2333   size_t seg_len = sizeof (struct ntreg_nk_record) + strlen (name);
2334   hive_node_h node = allocate_block (h, seg_len, nk_id);
2335   if (node == 0)
2336     return 0;
2337
2338   if (h->msglvl >= 2)
2339     fprintf (stderr, "hivex_node_add_child: allocated new nk-record"
2340              " for child at 0x%zx\n", node);
2341
2342   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
2343   nk->flags = htole16 (0x0020); /* key is ASCII. */
2344   nk->parent = htole32 (parent - 0x1000);
2345   nk->subkey_lf = htole32 (0xffffffff);
2346   nk->subkey_lf_volatile = htole32 (0xffffffff);
2347   nk->vallist = htole32 (0xffffffff);
2348   nk->classname = htole32 (0xffffffff);
2349   nk->name_len = htole16 (strlen (name));
2350   strcpy (nk->name, name);
2351
2352   /* Inherit parent sk. */
2353   struct ntreg_nk_record *parent_nk =
2354     (struct ntreg_nk_record *) (h->addr + parent);
2355   size_t parent_sk_offset = le32toh (parent_nk->sk);
2356   parent_sk_offset += 0x1000;
2357   if (!IS_VALID_BLOCK (h, parent_sk_offset) ||
2358       !BLOCK_ID_EQ (h, parent_sk_offset, "sk")) {
2359     if (h->msglvl >= 2)
2360       fprintf (stderr, "hivex_node_add_child: returning EFAULT"
2361                " because parent sk is not a valid block (%zu)\n",
2362                parent_sk_offset);
2363     errno = EFAULT;
2364     return 0;
2365   }
2366   struct ntreg_sk_record *sk =
2367     (struct ntreg_sk_record *) (h->addr + parent_sk_offset);
2368   sk->refcount = htole32 (le32toh (sk->refcount) + 1);
2369   nk->sk = htole32 (parent_sk_offset - 0x1000);
2370
2371   /* Inherit parent timestamp. */
2372   nk->timestamp = parent_nk->timestamp;
2373
2374   /* What I found out the hard way (not documented anywhere): the
2375    * subkeys in lh-records must be kept sorted.  If you just add a
2376    * subkey in a non-sorted position (eg. just add it at the end) then
2377    * Windows won't see the subkey _and_ Windows will corrupt the hive
2378    * itself when it modifies or saves it.
2379    *
2380    * So use get_children() to get a list of intermediate
2381    * lf/lh-records.  get_children() returns these in reading order
2382    * (which is sorted), so we look for the lf/lh-records in sequence
2383    * until we find the key name just after the one we are inserting,
2384    * and we insert the subkey just before it.
2385    *
2386    * The only other case is the no-subkeys case, where we have to
2387    * create a brand new lh-record.
2388    */
2389   hive_node_h *unused;
2390   size_t *blocks;
2391
2392   if (get_children (h, parent, &unused, &blocks, 0) == -1)
2393     return 0;
2394   free (unused);
2395
2396   size_t i, j;
2397   size_t nr_subkeys_in_parent_nk = le32toh (parent_nk->nr_subkeys);
2398   if (nr_subkeys_in_parent_nk == 0) { /* No subkeys case. */
2399     /* Free up any existing intermediate blocks. */
2400     for (i = 0; blocks[i] != 0; ++i)
2401       mark_block_unused (h, blocks[i]);
2402     size_t lh_offs = new_lh_record (h, name, node);
2403     if (lh_offs == 0) {
2404       free (blocks);
2405       return 0;
2406     }
2407
2408     /* Recalculate pointers that could have been invalidated by
2409      * previous call to allocate_block (via new_lh_record).
2410      */
2411     nk = (struct ntreg_nk_record *) (h->addr + node);
2412     parent_nk = (struct ntreg_nk_record *) (h->addr + parent);
2413
2414     if (h->msglvl >= 2)
2415       fprintf (stderr, "hivex_node_add_child: no keys, allocated new"
2416                " lh-record at 0x%zx\n", lh_offs);
2417
2418     parent_nk->subkey_lf = htole32 (lh_offs - 0x1000);
2419   }
2420   else {                        /* Insert subkeys case. */
2421     size_t old_offs = 0, new_offs = 0;
2422     struct ntreg_lf_record *old_lf = NULL;
2423
2424     /* Find lf/lh key name just after the one we are inserting. */
2425     for (i = 0; blocks[i] != 0; ++i) {
2426       if (BLOCK_ID_EQ (h, blocks[i], "lf") ||
2427           BLOCK_ID_EQ (h, blocks[i], "lh")) {
2428         old_offs = blocks[i];
2429         old_lf = (struct ntreg_lf_record *) (h->addr + old_offs);
2430         for (j = 0; j < le16toh (old_lf->nr_keys); ++j) {
2431           hive_node_h nk_offs = le32toh (old_lf->keys[j].offset);
2432           nk_offs += 0x1000;
2433           if (compare_name_with_nk_name (h, name, nk_offs) < 0)
2434             goto insert_it;
2435         }
2436       }
2437     }
2438
2439     /* Insert it at the end.
2440      * old_offs points to the last lf record, set j.
2441      */
2442     assert (old_offs != 0);   /* should never happen if nr_subkeys > 0 */
2443     j = le16toh (old_lf->nr_keys);
2444
2445     /* Insert it. */
2446   insert_it:
2447     if (h->msglvl >= 2)
2448       fprintf (stderr, "hivex_node_add_child: insert key in existing"
2449                " lh-record at 0x%zx, posn %zu\n", old_offs, j);
2450
2451     new_offs = insert_lf_record (h, old_offs, j, name, node);
2452     if (new_offs == 0) {
2453       free (blocks);
2454       return 0;
2455     }
2456
2457     /* Recalculate pointers that could have been invalidated by
2458      * previous call to allocate_block (via insert_lf_record).
2459      */
2460     nk = (struct ntreg_nk_record *) (h->addr + node);
2461     parent_nk = (struct ntreg_nk_record *) (h->addr + parent);
2462
2463     if (h->msglvl >= 2)
2464       fprintf (stderr, "hivex_node_add_child: new lh-record at 0x%zx\n",
2465                new_offs);
2466
2467     /* If the lf/lh-record was directly referenced by the parent nk,
2468      * then update the parent nk.
2469      */
2470     if (le32toh (parent_nk->subkey_lf) + 0x1000 == old_offs)
2471       parent_nk->subkey_lf = htole32 (new_offs - 0x1000);
2472     /* Else we have to look for the intermediate ri-record and update
2473      * that in-place.
2474      */
2475     else {
2476       for (i = 0; blocks[i] != 0; ++i) {
2477         if (BLOCK_ID_EQ (h, blocks[i], "ri")) {
2478           struct ntreg_ri_record *ri =
2479             (struct ntreg_ri_record *) (h->addr + blocks[i]);
2480           for (j = 0; j < le16toh (ri->nr_offsets); ++j)
2481             if (le32toh (ri->offset[j] + 0x1000) == old_offs) {
2482               ri->offset[j] = htole32 (new_offs - 0x1000);
2483               goto found_it;
2484             }
2485         }
2486       }
2487
2488       /* Not found ..  This is an internal error. */
2489       if (h->msglvl >= 2)
2490         fprintf (stderr, "hivex_node_add_child: returning ENOTSUP"
2491                  " because could not find ri->lf link\n");
2492       errno = ENOTSUP;
2493       free (blocks);
2494       return 0;
2495
2496     found_it:
2497       ;
2498     }
2499   }
2500
2501   free (blocks);
2502
2503   /* Update nr_subkeys in parent nk. */
2504   nr_subkeys_in_parent_nk++;
2505   parent_nk->nr_subkeys = htole32 (nr_subkeys_in_parent_nk);
2506
2507   /* Update max_subkey_name_len in parent nk. */
2508   uint16_t max = le16toh (parent_nk->max_subkey_name_len);
2509   if (max < strlen (name) * 2)  /* *2 because "recoded" in UTF16-LE. */
2510     parent_nk->max_subkey_name_len = htole16 (strlen (name) * 2);
2511
2512   return node;
2513 }
2514
2515 /* Decrement the refcount of an sk-record, and if it reaches zero,
2516  * unlink it from the chain and delete it.
2517  */
2518 static int
2519 delete_sk (hive_h *h, size_t sk_offset)
2520 {
2521   if (!IS_VALID_BLOCK (h, sk_offset) || !BLOCK_ID_EQ (h, sk_offset, "sk")) {
2522     if (h->msglvl >= 2)
2523       fprintf (stderr, "delete_sk: not an sk record: 0x%zx\n", sk_offset);
2524     errno = EFAULT;
2525     return -1;
2526   }
2527
2528   struct ntreg_sk_record *sk = (struct ntreg_sk_record *) (h->addr + sk_offset);
2529
2530   if (sk->refcount == 0) {
2531     if (h->msglvl >= 2)
2532       fprintf (stderr, "delete_sk: sk record already has refcount 0: 0x%zx\n",
2533                sk_offset);
2534     errno = EINVAL;
2535     return -1;
2536   }
2537
2538   sk->refcount--;
2539
2540   if (sk->refcount == 0) {
2541     size_t sk_prev_offset = sk->sk_prev;
2542     sk_prev_offset += 0x1000;
2543
2544     size_t sk_next_offset = sk->sk_next;
2545     sk_next_offset += 0x1000;
2546
2547     /* Update sk_prev/sk_next SKs, unless they both point back to this
2548      * cell in which case we are deleting the last SK.
2549      */
2550     if (sk_prev_offset != sk_offset && sk_next_offset != sk_offset) {
2551       struct ntreg_sk_record *sk_prev =
2552         (struct ntreg_sk_record *) (h->addr + sk_prev_offset);
2553       struct ntreg_sk_record *sk_next =
2554         (struct ntreg_sk_record *) (h->addr + sk_next_offset);
2555
2556       sk_prev->sk_next = htole32 (sk_next_offset - 0x1000);
2557       sk_next->sk_prev = htole32 (sk_prev_offset - 0x1000);
2558     }
2559
2560     /* Refcount is zero so really delete this block. */
2561     mark_block_unused (h, sk_offset);
2562   }
2563
2564   return 0;
2565 }
2566
2567 /* Callback from hivex_node_delete_child which is called to delete a
2568  * node AFTER its subnodes have been visited.  The subnodes have been
2569  * deleted but we still have to delete any lf/lh/li/ri records and the
2570  * value list block and values, followed by deleting the node itself.
2571  */
2572 static int
2573 delete_node (hive_h *h, void *opaque, hive_node_h node, const char *name)
2574 {
2575   /* Get the intermediate blocks.  The subkeys have already been
2576    * deleted by this point, so tell get_children() not to check for
2577    * validity of the nk-records.
2578    */
2579   hive_node_h *unused;
2580   size_t *blocks;
2581   if (get_children (h, node, &unused, &blocks, GET_CHILDREN_NO_CHECK_NK) == -1)
2582     return -1;
2583   free (unused);
2584
2585   /* We don't care what's in these intermediate blocks, so we can just
2586    * delete them unconditionally.
2587    */
2588   size_t i;
2589   for (i = 0; blocks[i] != 0; ++i)
2590     mark_block_unused (h, blocks[i]);
2591
2592   free (blocks);
2593
2594   /* Delete the values in the node. */
2595   if (delete_values (h, node) == -1)
2596     return -1;
2597
2598   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
2599
2600   /* If the NK references an SK, delete it. */
2601   size_t sk_offs = le32toh (nk->sk);
2602   if (sk_offs != 0xffffffff) {
2603     sk_offs += 0x1000;
2604     if (delete_sk (h, sk_offs) == -1)
2605       return -1;
2606     nk->sk = htole32 (0xffffffff);
2607   }
2608
2609   /* If the NK references a classname, delete it. */
2610   size_t cl_offs = le32toh (nk->classname);
2611   if (cl_offs != 0xffffffff) {
2612     cl_offs += 0x1000;
2613     mark_block_unused (h, cl_offs);
2614     nk->classname = htole32 (0xffffffff);
2615   }
2616
2617   /* Delete the node itself. */
2618   mark_block_unused (h, node);
2619
2620   return 0;
2621 }
2622
2623 int
2624 hivex_node_delete_child (hive_h *h, hive_node_h node)
2625 {
2626   if (!h->writable) {
2627     errno = EROFS;
2628     return -1;
2629   }
2630
2631   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
2632     errno = EINVAL;
2633     return -1;
2634   }
2635
2636   if (node == hivex_root (h)) {
2637     if (h->msglvl >= 2)
2638       fprintf (stderr, "hivex_node_delete_child: cannot delete root node\n");
2639     errno = EINVAL;
2640     return -1;
2641   }
2642
2643   hive_node_h parent = hivex_node_parent (h, node);
2644   if (parent == 0)
2645     return -1;
2646
2647   /* Delete node and all its children and values recursively. */
2648   static const struct hivex_visitor visitor = { .node_end = delete_node };
2649   if (hivex_visit_node (h, node, &visitor, sizeof visitor, NULL, 0) == -1)
2650     return -1;
2651
2652   /* Delete the link from parent to child.  We need to find the lf/lh
2653    * record which contains the offset and remove the offset from that
2654    * record, then decrement the element count in that record, and
2655    * decrement the overall number of subkeys stored in the parent
2656    * node.
2657    */
2658   hive_node_h *unused;
2659   size_t *blocks;
2660   if (get_children (h, parent, &unused, &blocks, GET_CHILDREN_NO_CHECK_NK)== -1)
2661     return -1;
2662   free (unused);
2663
2664   size_t i, j;
2665   for (i = 0; blocks[i] != 0; ++i) {
2666     struct ntreg_hbin_block *block =
2667       (struct ntreg_hbin_block *) (h->addr + blocks[i]);
2668
2669     if (block->id[0] == 'l' && (block->id[1] == 'f' || block->id[1] == 'h')) {
2670       struct ntreg_lf_record *lf = (struct ntreg_lf_record *) block;
2671
2672       size_t nr_subkeys_in_lf = le16toh (lf->nr_keys);
2673
2674       for (j = 0; j < nr_subkeys_in_lf; ++j)
2675         if (le32toh (lf->keys[j].offset) + 0x1000 == node) {
2676           for (; j < nr_subkeys_in_lf - 1; ++j)
2677             memcpy (&lf->keys[j], &lf->keys[j+1], sizeof (lf->keys[j]));
2678           lf->nr_keys = htole16 (nr_subkeys_in_lf - 1);
2679           goto found;
2680         }
2681     }
2682   }
2683   if (h->msglvl >= 2)
2684     fprintf (stderr, "hivex_node_delete_child: could not find parent"
2685              " to child link\n");
2686   errno = ENOTSUP;
2687   return -1;
2688
2689  found:;
2690   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + parent);
2691   size_t nr_subkeys_in_nk = le32toh (nk->nr_subkeys);
2692   nk->nr_subkeys = htole32 (nr_subkeys_in_nk - 1);
2693
2694   if (h->msglvl >= 2)
2695     fprintf (stderr, "hivex_node_delete_child: updating nr_subkeys"
2696              " in parent 0x%zx to %zu\n", parent, nr_subkeys_in_nk);
2697
2698   return 0;
2699 }
2700
2701 int
2702 hivex_node_set_values (hive_h *h, hive_node_h node,
2703                        size_t nr_values, const hive_set_value *values,
2704                        int flags)
2705 {
2706   if (!h->writable) {
2707     errno = EROFS;
2708     return -1;
2709   }
2710
2711   if (!IS_VALID_BLOCK (h, node) || !BLOCK_ID_EQ (h, node, "nk")) {
2712     errno = EINVAL;
2713     return -1;
2714   }
2715
2716   /* Delete all existing values. */
2717   if (delete_values (h, node) == -1)
2718     return -1;
2719
2720   if (nr_values == 0)
2721     return 0;
2722
2723   /* Allocate value list node.  Value lists have no id field. */
2724   static const char nul_id[2] = { 0, 0 };
2725   size_t seg_len =
2726     sizeof (struct ntreg_value_list) + (nr_values - 1) * sizeof (uint32_t);
2727   size_t vallist_offs = allocate_block (h, seg_len, nul_id);
2728   if (vallist_offs == 0)
2729     return -1;
2730
2731   struct ntreg_nk_record *nk = (struct ntreg_nk_record *) (h->addr + node);
2732   nk->nr_values = htole32 (nr_values);
2733   nk->vallist = htole32 (vallist_offs - 0x1000);
2734
2735   struct ntreg_value_list *vallist =
2736     (struct ntreg_value_list *) (h->addr + vallist_offs);
2737
2738   size_t i;
2739   for (i = 0; i < nr_values; ++i) {
2740     /* Allocate vk record to store this (key, value) pair. */
2741     static const char vk_id[2] = { 'v', 'k' };
2742     seg_len = sizeof (struct ntreg_vk_record) + strlen (values[i].key);
2743     size_t vk_offs = allocate_block (h, seg_len, vk_id);
2744     if (vk_offs == 0)
2745       return -1;
2746
2747     /* Recalculate pointers that could have been invalidated by
2748      * previous call to allocate_block.
2749      */
2750     nk = (struct ntreg_nk_record *) (h->addr + node);
2751     vallist = (struct ntreg_value_list *) (h->addr + vallist_offs);
2752
2753     vallist->offset[i] = htole32 (vk_offs - 0x1000);
2754
2755     struct ntreg_vk_record *vk = (struct ntreg_vk_record *) (h->addr + vk_offs);
2756     size_t name_len = strlen (values[i].key);
2757     vk->name_len = htole16 (name_len);
2758     strcpy (vk->name, values[i].key);
2759     vk->data_type = htole32 (values[i].t);
2760     uint32_t len = values[i].len;
2761     if (len <= 4)               /* store it inline => set MSB flag */
2762       len |= 0x80000000;
2763     vk->data_len = htole32 (len);
2764     vk->flags = name_len == 0 ? 0 : 1;
2765
2766     if (values[i].len <= 4)     /* store it inline */
2767       memcpy (&vk->data_offset, values[i].value, values[i].len);
2768     else {
2769       size_t offs = allocate_block (h, values[i].len + 4, nul_id);
2770       if (offs == 0)
2771         return -1;
2772
2773       /* Recalculate pointers that could have been invalidated by
2774        * previous call to allocate_block.
2775        */
2776       nk = (struct ntreg_nk_record *) (h->addr + node);
2777       vallist = (struct ntreg_value_list *) (h->addr + vallist_offs);
2778       vk = (struct ntreg_vk_record *) (h->addr + vk_offs);
2779
2780       memcpy (h->addr + offs + 4, values[i].value, values[i].len);
2781       vk->data_offset = htole32 (offs - 0x1000);
2782     }
2783
2784     if (name_len * 2 > le32toh (nk->max_vk_name_len))
2785       /* * 2 for UTF16-LE "reencoding" */
2786       nk->max_vk_name_len = htole32 (name_len * 2);
2787     if (values[i].len > le32toh (nk->max_vk_data_len))
2788       nk->max_vk_data_len = htole32 (values[i].len);
2789   }
2790
2791   return 0;
2792 }
2793
2794 int
2795 hivex_node_set_value (hive_h *h, hive_node_h node,
2796                       const hive_set_value *val, int flags)
2797 {
2798   hive_value_h *prev_values = hivex_node_values (h, node);
2799   if (prev_values == NULL)
2800     return -1;
2801
2802   int retval = -1;
2803
2804   size_t nr_values = 0;
2805   for (hive_value_h *itr = prev_values; *itr != 0; ++itr)
2806     ++nr_values;
2807
2808   hive_set_value *values = malloc ((nr_values + 1) * (sizeof (hive_set_value)));
2809   if (values == NULL)
2810     goto leave_prev_values;
2811
2812   int alloc_ct = 0;
2813   int idx_of_val = -1;
2814   hive_value_h *prev_val;
2815   for (prev_val = prev_values; *prev_val != 0; ++prev_val) {
2816     size_t len;
2817     hive_type t;
2818
2819     hive_set_value *value = &values[prev_val - prev_values];
2820
2821     char *valval = hivex_value_value (h, *prev_val, &t, &len);
2822     if (valval == NULL) goto leave_partial;
2823
2824     ++alloc_ct;
2825     value->value = valval;
2826     value->t = t;
2827     value->len = len;
2828
2829     char *valkey = hivex_value_key (h, *prev_val);
2830     if (valkey == NULL) goto leave_partial;
2831
2832     ++alloc_ct;
2833     value->key = valkey;
2834
2835     if (STRCASEEQ (valkey, val->key))
2836       idx_of_val = prev_val - prev_values;
2837   }
2838
2839   if (idx_of_val > -1) {
2840     free (values[idx_of_val].key);
2841     free (values[idx_of_val].value);
2842   } else {
2843     idx_of_val = nr_values;
2844     ++nr_values;
2845   }
2846
2847   hive_set_value *value = &values[idx_of_val];
2848   *value = (hive_set_value){
2849     .key = strdup (val->key),
2850     .value = malloc (val->len),
2851     .len = val->len,
2852     .t = val->t
2853   };
2854
2855   if (value->key == NULL || value->value == NULL) goto leave_partial;
2856   memcpy (value->value, val->value, val->len);
2857
2858   retval = hivex_node_set_values (h, node, nr_values, values, 0);
2859
2860  leave_partial:
2861   for (int i = 0; i < alloc_ct; i += 2) {
2862     free (values[i / 2].value);
2863     if (i + 1 < alloc_ct && values[i / 2].key != NULL)
2864       free (values[i / 2].key);
2865   }
2866   free (values);
2867
2868  leave_prev_values:
2869   free (prev_values);
2870   return retval;
2871 }