]> wimlib.net Git - wimlib/blob - src/registry.c
Add a clang-format file
[wimlib] / src / registry.c
1 /*
2  * registry.c
3  *
4  * Extract information from Windows NT registry hives.
5  */
6
7 /*
8  * Copyright (C) 2016 Eric Biggers
9  *
10  * This file is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU Lesser General Public License as published by the Free
12  * Software Foundation; either version 3 of the License, or (at your option) any
13  * later version.
14  *
15  * This file is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this file; if not, see https://www.gnu.org/licenses/.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include <string.h>
29
30 #include "wimlib/encoding.h"
31 #include "wimlib/endianness.h"
32 #include "wimlib/error.h"
33 #include "wimlib/registry.h"
34 #include "wimlib/util.h"
35
36 /* Registry hive file header  */
37 struct regf {
38 #define REGF_MAGIC              cpu_to_le32(0x66676572) /* "regf" */
39         le32 magic;
40         le32 f1[4];
41 #define REGF_MAJOR              cpu_to_le32(1)
42         le32 major_version;
43         le32 minor_version;
44         le32 f2[2];
45         le32 root_key_offset;           /* Offset, in hbin area, to root nk  */
46         le32 total_hbin_size;           /* Total size of all hbins  */
47         le32 f3[1013];
48         u8 hbin_area[0];                /* Start of hbin area  */
49 } __attribute__((packed));
50
51
52 /* Cell header  */
53 struct cell {
54         /* The cell size in bytes, negated for in-use cells  */
55         le32 size;
56
57         /* Magic characters which identify the cell type  */
58         le16 magic;
59 } __attribute__((packed));
60
61 /* NK cell - represents a registry key  */
62 struct nk {
63 #define NK_MAGIC                cpu_to_le16(0x6B6E)     /* "nk" */
64         struct cell base;
65 #define NK_COMPRESSED_NAME      cpu_to_le16(0x0020)
66         le16 flags;
67         le64 unknown_0x08;
68         le32 unknown_0x10;
69         le32 parent_offset;
70         le32 num_subkeys;
71         le32 unknown_0x1C;
72         le32 subkey_list_offset;
73         le32 unknown_0x24;
74         le32 num_values;
75         le32 value_list_offset;
76         le32 unknown_0x30;
77         le32 unknown_0x34;
78         le16 unknown_0x38;
79         le16 unknown_0x3A;
80         le32 unknown_0x3C;
81         le32 unknown_0x40;
82         le32 unknown_0x44;
83         le32 unknown_0x48;
84         le16 name_size;
85         le16 unknown_0x4E;
86         char name[0];
87 } __attribute__((packed));
88
89 /* Subkey list cell.  There are four types.  LF, LH, and LI cells reference
90  * subkey NK cells directly, while RI cells reference other subkey lists.  All
91  * contain a count followed by that many 32-bit offsets.  But LF and LH cells
92  * contain a 32-bit hash along with each offset, while LI and RI cells only
93  * contain offsets.  */
94 struct subkey_list {
95 #define LF_MAGIC        cpu_to_le16(0x666C)     /* "lf" */
96 #define LH_MAGIC        cpu_to_le16(0x686C)     /* "lh" */
97 #define LI_MAGIC        cpu_to_le16(0x696C)     /* "li" */
98 #define RI_MAGIC        cpu_to_le16(0x6972)     /* "ri" */
99         struct cell base;
100         le16 num_offsets;
101         le32 elements[0];
102 } __attribute__((packed));
103
104 /* Value list cell - contains a list of value references  */
105 struct value_list {
106         le32 size;
107         le32 vk_offsets[0];
108 } __attribute__((packed));
109
110 /* VK cell - contains a value's data, or a reference to it  */
111 struct vk {
112 #define VK_MAGIC                        cpu_to_le16(0x6B76)
113         struct cell base;
114         le16 name_size;
115         le32 data_size;
116         le32 data_offset;
117 #define REG_NONE                        cpu_to_le32(0)
118 #define REG_SZ                          cpu_to_le32(1)
119 #define REG_EXPAND_SZ                   cpu_to_le32(2)
120 #define REG_BINARY                      cpu_to_le32(3)
121 #define REG_DWORD                       cpu_to_le32(4)
122 #define REG_DWORD_LITTLE_ENDIAN         cpu_to_le32(4)
123 #define REG_DWORD_BIG_ENDIAN            cpu_to_le32(5)
124 #define REG_LINK                        cpu_to_le32(6)
125 #define REG_MULTI_SZ                    cpu_to_le32(7)
126 #define REG_RESOURCE_LIST               cpu_to_le32(8)
127 #define REG_FULL_RESOURCE_DESCRIPTOR    cpu_to_le32(9)
128 #define REG_RESOURCE_REQUIREMENTS_LIST  cpu_to_le32(10)
129 #define REG_QWORD                       cpu_to_le32(11)
130 #define REG_QWORD_LITTLE_ENDIAN         cpu_to_le32(11)
131         le32 data_type;
132 #define VK_COMPRESSED_NAME              cpu_to_le16(0x0001)
133         le16 flags;
134         le16 unknown_0x16;
135         char name[0];
136 };
137
138 /* Data cell - contains a value's data  */
139 struct data_cell {
140         le32 size;
141         u8 data[0];
142 };
143
144 /* Arbitrary limits for safety  */
145 #define MAX_VALUES              65536
146 #define MAX_VALUE_SIZE          1048576
147 #define MAX_SUBKEYS             65536
148 #define MAX_SUBKEY_LIST_LEVELS  5
149 #define MAX_SUBKEY_LISTS        4096
150
151 static enum hive_status
152 translate_wimlib_error(int ret)
153 {
154         if (likely(!ret))
155                 return HIVE_OK;
156         if (ret == WIMLIB_ERR_NOMEM)
157                 return HIVE_OUT_OF_MEMORY;
158         return HIVE_UNSUPPORTED;
159 }
160
161 /* Compare a UTF-16LE name with a key or value name in the registry.  The
162  * comparison is case insensitive.  */
163 static inline bool
164 names_equal(const utf16lechar *name, size_t name_nchars,
165             const void *disk_name, size_t disk_name_size,
166             bool compressed)
167 {
168         if (compressed) {
169                 /* ISO-8859-1 (LATIN1) on-disk  */
170                 const u8 *p = disk_name;
171                 if (disk_name_size != name_nchars)
172                         return false;
173                 for (size_t i = 0; i < name_nchars; i++)
174                         if (upcase[le16_to_cpu(name[i])] != upcase[p[i]])
175                                 return false;
176                 return true;
177         } else {
178                 /* UTF-16LE on disk  */
179                 disk_name_size /= 2;
180                 if (disk_name_size != name_nchars)
181                         return false;
182                 return !cmp_utf16le_strings(name, name_nchars,
183                                             disk_name, disk_name_size, true);
184         }
185 }
186
187 /* Get a pointer to a cell, with alignment and bounds checking.  Returns NULL if
188  * the requested information does not specify a properly aligned, sized, and
189  * in-use cell.  */
190 static const void *
191 get_cell_pointer(const struct regf *regf, le32 offset, size_t wanted_size)
192 {
193         u32 total = le32_to_cpu(regf->total_hbin_size);
194         u32 offs = le32_to_cpu(offset);
195         const struct cell *cell;
196         u32 actual_size;
197
198         if ((offs > total) || (offs & 7) || (wanted_size > total - offs))
199                 return NULL;
200
201         cell = (const struct cell *)&regf->hbin_area[offs];
202         actual_size = -le32_to_cpu(cell->size);
203         if (actual_size > INT32_MAX) /* Cell unused, or size was INT32_MIN?  */
204                 return NULL;
205         if (wanted_size > actual_size) /* Cell too small?  */
206                 return NULL;
207         return cell;
208 }
209
210 /* Revalidate the cell with its full length.  Returns true iff the cell is
211  * valid.  */
212 static bool
213 revalidate_cell(const struct regf *regf, le32 offset, size_t wanted_size)
214 {
215         return get_cell_pointer(regf, offset, wanted_size) != NULL;
216 }
217
218 struct subkey_iteration_stats {
219
220         /* The number of additional levels of descendent subkey lists that may
221          * be visited (currently, i.e. at this point in the iteration) before
222          * our safety limit of MAX_SUBKEY_LIST_LEVELS is reached  */
223         u32 levels_remaining;
224
225         /* The number of additional subkey lists that may be visited until our
226          * safety limit of MAX_SUBKEY_LISTS is reached  */
227         u32 subkey_lists_remaining;
228
229         /* The number of subkeys remaining to be found.  Since the number of
230          * subkeys is known from the parent nk cell, this should be 0 at the end
231          * of the iteration.  */
232         u32 subkeys_remaining;
233 };
234
235 typedef enum hive_status (*subkey_cb_t)(const struct nk *, void *);
236
237 static enum hive_status
238 iterate_subkeys_recursive(const struct regf *regf, le32 subkey_list_offset,
239                           subkey_cb_t cb, void *cb_ctx,
240                           struct subkey_iteration_stats *stats)
241 {
242         const struct subkey_list *list;
243         unsigned num_offsets;
244         size_t extra_size;
245         unsigned increment;
246         size_t i = 0;
247         enum hive_status status;
248
249         if (stats->levels_remaining == 0 || stats->subkey_lists_remaining == 0)
250                 return HIVE_CORRUPT;
251
252         stats->subkey_lists_remaining--;
253
254         list = get_cell_pointer(regf, subkey_list_offset,
255                                 sizeof(struct subkey_list));
256         if (!list)
257                 return HIVE_CORRUPT;
258
259         num_offsets = le16_to_cpu(list->num_offsets);
260         extra_size = num_offsets * sizeof(list->elements[0]);
261         increment = 1;
262
263         if (list->base.magic == LF_MAGIC || list->base.magic == LH_MAGIC) {
264                 /* Hashes are included  */
265                 extra_size *= 2;
266                 increment = 2;
267         }
268
269         if (!revalidate_cell(regf, subkey_list_offset,
270                              sizeof(struct subkey_list) + extra_size))
271                 return HIVE_CORRUPT;
272
273         switch (list->base.magic) {
274         case LF_MAGIC:
275         case LH_MAGIC:
276         case LI_MAGIC:
277                 /* Children are subkeys  */
278                 if (stats->subkeys_remaining < num_offsets)
279                         return HIVE_CORRUPT;
280                 stats->subkeys_remaining -= num_offsets;
281                 while (num_offsets--) {
282                         const struct nk *sub_nk;
283
284                         sub_nk = get_cell_pointer(regf, list->elements[i],
285                                                   sizeof(struct nk));
286                         if (!sub_nk || sub_nk->base.magic != NK_MAGIC)
287                                 return HIVE_CORRUPT;
288
289                         if (!revalidate_cell(regf, list->elements[i],
290                                              sizeof(struct nk) +
291                                                 le16_to_cpu(sub_nk->name_size)))
292                                 return HIVE_CORRUPT;
293
294                         status = (*cb)(sub_nk, cb_ctx);
295                         if (status != HIVE_OK)
296                                 return status;
297                         i += increment;
298                 }
299                 return HIVE_OK;
300         case RI_MAGIC:
301                 /* Children are subkey lists  */
302                 status = HIVE_OK;
303                 stats->levels_remaining--;
304                 while (num_offsets--) {
305                         status = iterate_subkeys_recursive(regf,
306                                                 list->elements[i++],
307                                                 cb, cb_ctx, stats);
308                         if (status != HIVE_OK)
309                                 break;
310                 }
311                 stats->levels_remaining++;
312                 return status;
313         default:
314                 return HIVE_UNSUPPORTED;
315         }
316 }
317
318 /* Call @cb on each subkey cell of the key @nk.  */
319 static enum hive_status
320 iterate_subkeys(const struct regf *regf, const struct nk *nk,
321                 subkey_cb_t cb, void *cb_ctx)
322 {
323         u32 num_subkeys = le32_to_cpu(nk->num_subkeys);
324         struct subkey_iteration_stats stats;
325         enum hive_status status;
326
327         if (num_subkeys == 0)
328                 return HIVE_OK;
329
330         if (num_subkeys > MAX_SUBKEYS)
331                 return HIVE_CORRUPT;
332
333         stats.levels_remaining = MAX_SUBKEY_LIST_LEVELS;
334         stats.subkey_lists_remaining = MAX_SUBKEY_LISTS;
335         stats.subkeys_remaining = num_subkeys;
336
337         status = iterate_subkeys_recursive(regf, nk->subkey_list_offset,
338                                            cb, cb_ctx, &stats);
339         if (stats.subkeys_remaining != 0 && status == HIVE_OK)
340                 status = HIVE_CORRUPT;
341         return status;
342 }
343
344 struct lookup_subkey_ctx {
345         const utf16lechar *key_name;
346         size_t key_name_nchars;
347         const struct nk *result;
348 };
349
350 static enum hive_status
351 lookup_subkey_cb(const struct nk *sub_nk, void *_ctx)
352 {
353         struct lookup_subkey_ctx *ctx = _ctx;
354
355         if (names_equal(ctx->key_name, ctx->key_name_nchars,
356                         sub_nk->name, le16_to_cpu(sub_nk->name_size),
357                         (sub_nk->flags & NK_COMPRESSED_NAME) != 0))
358         {
359                 ctx->result = sub_nk;
360                 return HIVE_ITERATION_STOPPED;
361         }
362
363         return HIVE_OK;
364 }
365
366 /*
367  * Given a registry key cell @nk, look up the next component of the key
368  * *key_namep.  If found, return HIVE_OK, advance *key_namep past the key name
369  * component, and return the subkey cell in @sub_nk_ret.  Otherwise, return
370  * another HIVE_* error code.
371  */
372 static enum hive_status
373 lookup_subkey(const struct regf *regf, const utf16lechar **key_namep,
374               const struct nk *nk, const struct nk **sub_nk_ret)
375 {
376         const utf16lechar *key_name = *key_namep;
377         size_t key_name_nchars = 0;
378         struct lookup_subkey_ctx ctx;
379         enum hive_status status;
380
381         while (key_name[key_name_nchars] != cpu_to_le16('\0') &&
382                key_name[key_name_nchars] != cpu_to_le16('\\'))
383                 key_name_nchars++;
384
385         ctx.key_name = key_name;
386         ctx.key_name_nchars = key_name_nchars;
387         ctx.result = NULL;
388
389         status = iterate_subkeys(regf, nk, lookup_subkey_cb, &ctx);
390         if (!ctx.result) {
391                 if (status == HIVE_OK)
392                         status = HIVE_KEY_NOT_FOUND;
393                 return status;
394         }
395
396         key_name += key_name_nchars;
397         while (*key_name == cpu_to_le16('\\'))
398                 key_name++;
399         *key_namep = key_name;
400         *sub_nk_ret = ctx.result;
401         return HIVE_OK;
402 }
403
404 /* Find the nk cell for the key named @key_name in the registry hive @regf.  */
405 static enum hive_status
406 lookup_key(const struct regf *regf, const tchar *key_name,
407            const struct nk **nk_ret)
408 {
409         const struct nk *nk;
410         enum hive_status status;
411         const utf16lechar *key_uname, *key_unamep;
412
413         nk = get_cell_pointer(regf, regf->root_key_offset, sizeof(struct nk));
414         if (!nk || nk->base.magic != NK_MAGIC)
415                 return HIVE_CORRUPT;
416
417         status = translate_wimlib_error(tstr_get_utf16le(key_name, &key_uname));
418         if (status != HIVE_OK)
419                 return status;
420         key_unamep = key_uname;
421         while (*key_unamep) {
422                 status = lookup_subkey(regf, &key_unamep, nk, &nk);
423                 if (status != HIVE_OK)
424                         goto out;
425         }
426         *nk_ret = nk;
427         status = HIVE_OK;
428 out:
429         tstr_put_utf16le(key_uname);
430         return status;
431 }
432
433 /* Find the vk cell for the value named @value_name of the key named @key_name
434  * in the registry hive @regf.  */
435 static enum hive_status
436 lookup_value(const struct regf *regf, const tchar *key_name,
437              const tchar *value_name, const struct vk **vk_ret)
438 {
439         enum hive_status status;
440         const struct nk *nk;
441         size_t num_values;
442         const struct value_list *value_list;
443         const  utf16lechar *value_uname;
444         size_t value_uname_nchars;
445
446         /* Look up the nk cell for the key.  */
447         status = lookup_key(regf, key_name, &nk);
448         if (status != HIVE_OK)
449                 return status;
450
451         num_values = le32_to_cpu(nk->num_values);
452
453         if (num_values == 0) /* No values?  */
454                 return HIVE_VALUE_NOT_FOUND;
455
456         if (num_values > MAX_VALUES)
457                 return HIVE_CORRUPT;
458
459         value_list = get_cell_pointer(regf, nk->value_list_offset,
460                                       sizeof(struct value_list) +
461                                       (num_values *
462                                        sizeof(value_list->vk_offsets[0])));
463         if (!value_list)
464                 return HIVE_CORRUPT;
465
466         /* Look for the value in the value list.  */
467
468         status = translate_wimlib_error(
469                         tstr_get_utf16le_and_len(value_name, &value_uname,
470                                                  &value_uname_nchars));
471         if (status != HIVE_OK)
472                 return status;
473         value_uname_nchars /= 2;
474
475         for (size_t i = 0; i < num_values; i++) {
476                 const struct vk *vk;
477                 size_t name_size;
478
479                 status = HIVE_CORRUPT;
480                 vk = get_cell_pointer(regf, value_list->vk_offsets[i],
481                                       sizeof(struct vk));
482                 if (!vk || vk->base.magic != VK_MAGIC)
483                         goto out;
484
485                 name_size = le16_to_cpu(vk->name_size);
486
487                 if (!revalidate_cell(regf, value_list->vk_offsets[i],
488                                      sizeof(struct vk) + name_size))
489                         goto out;
490
491                 if (names_equal(value_uname, value_uname_nchars,
492                                 vk->name, name_size,
493                                 (vk->flags & VK_COMPRESSED_NAME) != 0))
494                 {
495                         *vk_ret = vk;
496                         status = HIVE_OK;
497                         goto out;
498                 }
499         }
500
501         status = HIVE_VALUE_NOT_FOUND;
502 out:
503         tstr_put_utf16le(value_uname);
504         return status;
505 }
506
507 /*
508  * Retrieve the data of the value named @value_name of the key named @key_name
509  * in the registry hive @regf.  If the value was found, return HIVE_OK and
510  * return the data, its size, and its type in @data_ret, @data_size_ret, and
511  * @data_type_ret.  Otherwise, return another HIVE_* error code.
512  */
513 static enum hive_status
514 retrieve_value(const struct regf *regf, const tchar *key_name,
515                const tchar *value_name, void **data_ret,
516                size_t *data_size_ret, le32 *data_type_ret)
517 {
518         enum hive_status status;
519         const struct vk *vk;
520         size_t data_size;
521         bool is_inline;
522         const void *data;
523
524         /* Find the vk cell.  */
525         status = lookup_value(regf, key_name, value_name, &vk);
526         if (status != HIVE_OK)
527                 return status;
528
529         /* Extract the value data from the vk cell (for inline data) or from the
530          * data cell which it references (for non-inline data).  */
531
532         data_size = le32_to_cpu(vk->data_size);
533
534         is_inline = (data_size & 0x80000000);
535         data_size &= 0x7FFFFFFF;
536
537         if (data_size > MAX_VALUE_SIZE)
538                 return HIVE_CORRUPT;
539
540         if (is_inline) {
541                 if (data_size > 4)
542                         return HIVE_CORRUPT;
543                 data = &vk->data_offset;
544         } else {
545                 const struct data_cell *data_cell;
546
547                 data_cell = get_cell_pointer(regf, vk->data_offset,
548                                              sizeof(struct data_cell));
549                 if (!data_cell)
550                         return HIVE_CORRUPT;
551
552                 if (!revalidate_cell(regf, vk->data_offset,
553                                      sizeof(struct data_cell) + data_size))
554                         return HIVE_UNSUPPORTED; /* Possibly a big data cell  */
555
556                 data = data_cell->data;
557         }
558
559         *data_ret = memdup(data, data_size);
560         if (!*data_ret)
561                 return HIVE_OUT_OF_MEMORY;
562         *data_size_ret = data_size;
563         *data_type_ret = vk->data_type;
564         return HIVE_OK;
565 }
566
567 /* Validate the registry hive file given in memory as @hive_mem and @hive_size.
568  * If valid, return HIVE_OK.  If invalid, return another HIVE_* error code.  */
569 enum hive_status
570 hive_validate(const void *hive_mem, size_t hive_size)
571 {
572         const struct regf *regf = hive_mem;
573
574         STATIC_ASSERT(sizeof(struct regf) == 4096);
575
576         if (hive_size < sizeof(struct regf))
577                 return HIVE_CORRUPT;
578
579         if (regf->magic != REGF_MAGIC || regf->major_version != REGF_MAJOR)
580                 return HIVE_UNSUPPORTED;
581
582         if (le32_to_cpu(regf->total_hbin_size) > hive_size - sizeof(struct regf))
583                 return HIVE_CORRUPT;
584
585         return HIVE_OK;
586 }
587
588 /* Get a string value from the registry hive file.  */
589 enum hive_status
590 hive_get_string(const struct regf *regf, const tchar *key_name,
591                 const tchar *value_name, tchar **value_ret)
592 {
593         void *data;
594         size_t data_size;
595         le32 data_type;
596         enum hive_status status;
597
598         /* Retrieve the raw value data.  */
599         status = retrieve_value(regf, key_name, value_name,
600                                 &data, &data_size, &data_type);
601         if (status != HIVE_OK)
602                 return status;
603
604         /* Interpret the data as a string, when possible.  */
605         switch (data_type) {
606         case REG_SZ:
607         case REG_MULTI_SZ:
608                 status = translate_wimlib_error(
609                         utf16le_to_tstr(data, data_size, value_ret, &data_size));
610                 break;
611         default:
612                 status = HIVE_VALUE_IS_WRONG_TYPE;
613                 break;
614         }
615         FREE(data);
616         return status;
617 }
618
619 /* Get a number value from the registry hive file.  */
620 enum hive_status
621 hive_get_number(const struct regf *regf, const tchar *key_name,
622                 const tchar *value_name, s64 *value_ret)
623 {
624         void *data;
625         size_t data_size;
626         le32 data_type;
627         enum hive_status status;
628
629         /* Retrieve the raw value data.  */
630         status = retrieve_value(regf, key_name, value_name,
631                                 &data, &data_size, &data_type);
632         if (status != HIVE_OK)
633                 return status;
634
635         /* Interpret the data as a number, when possible.  */
636         switch (data_type) {
637         case REG_DWORD_LITTLE_ENDIAN:
638                 if (data_size == 4) {
639                         *value_ret = le32_to_cpu(*(le32 *)data);
640                         status = HIVE_OK;
641                 } else {
642                         status = HIVE_CORRUPT;
643                 }
644                 break;
645         case REG_DWORD_BIG_ENDIAN:
646                 if (data_size == 4) {
647                         *value_ret = be32_to_cpu(*(be32 *)data);
648                         status = HIVE_OK;
649                 } else {
650                         status = HIVE_CORRUPT;
651                 }
652                 break;
653         case REG_QWORD_LITTLE_ENDIAN:
654                 if (data_size == 8) {
655                         *value_ret = le64_to_cpu(*(le64 *)data);
656                         status = HIVE_OK;
657                 } else {
658                         status = HIVE_CORRUPT;
659                 }
660                 break;
661         default:
662                 status = HIVE_VALUE_IS_WRONG_TYPE;
663                 break;
664         }
665
666         FREE(data);
667         return status;
668 }
669
670 static enum hive_status
671 append_subkey_name(const struct nk *sub_nk, void *_next_subkey_p)
672 {
673         size_t name_size = le16_to_cpu(sub_nk->name_size);
674         tchar *subkey;
675         tchar ***next_subkeyp = _next_subkey_p;
676
677         if (sub_nk->flags & NK_COMPRESSED_NAME) {
678                 subkey = MALLOC((name_size + 1) * sizeof(tchar));
679                 if (!subkey)
680                         return HIVE_OUT_OF_MEMORY;
681                 for (size_t i = 0; i < name_size; i++)
682                         subkey[i] = sub_nk->name[i];
683                 subkey[name_size] = '\0';
684         } else {
685                 enum hive_status status;
686
687                 status = translate_wimlib_error(
688                         utf16le_to_tstr((utf16lechar *)sub_nk->name,
689                                         name_size, &subkey, NULL));
690                 if (status != HIVE_OK)
691                         return status;
692         }
693
694         **next_subkeyp = subkey;
695         ++*next_subkeyp;
696         return HIVE_OK;
697 }
698
699 /* List the subkeys of the specified registry key.  */
700 enum hive_status
701 hive_list_subkeys(const struct regf *regf, const tchar *key_name,
702                   tchar ***subkeys_ret)
703 {
704         enum hive_status status;
705         const struct nk *nk;
706         tchar **subkeys;
707         tchar **next_subkey;
708
709         status = lookup_key(regf, key_name, &nk);
710         if (status != HIVE_OK)
711                 return status;
712
713         if (le32_to_cpu(nk->num_subkeys) > MAX_SUBKEYS)
714                 return HIVE_CORRUPT;
715
716         subkeys = CALLOC(le32_to_cpu(nk->num_subkeys) + 1, sizeof(subkeys[0]));
717         if (!subkeys)
718                 return HIVE_OUT_OF_MEMORY;
719
720         next_subkey = subkeys;
721         status = iterate_subkeys(regf, nk, append_subkey_name, &next_subkey);
722         if (status == HIVE_OK)
723                 *subkeys_ret = subkeys;
724         else
725                 hive_free_subkeys_list(subkeys);
726         return status;
727 }
728
729 void
730 hive_free_subkeys_list(tchar **subkeys)
731 {
732         for (tchar **p = subkeys; *p; p++)
733                 FREE(*p);
734         FREE(subkeys);
735 }
736
737 const char *
738 hive_status_to_string(enum hive_status status)
739 {
740         switch (status) {
741         case HIVE_OK:
742                 return "HIVE_OK";
743         case HIVE_CORRUPT:
744                 return "HIVE_CORRUPT";
745         case HIVE_UNSUPPORTED:
746                 return "HIVE_UNSUPPORTED";
747         case HIVE_KEY_NOT_FOUND:
748                 return "HIVE_KEY_NOT_FOUND";
749         case HIVE_VALUE_NOT_FOUND:
750                 return "HIVE_VALUE_NOT_FOUND";
751         case HIVE_VALUE_IS_WRONG_TYPE:
752                 return "HIVE_VALUE_IS_WRONG_TYPE";
753         case HIVE_OUT_OF_MEMORY:
754                 return "HIVE_OUT_OF_MEMORY";
755         case HIVE_ITERATION_STOPPED:
756                 return "HIVE_ITERATION_STOPPED";
757         }
758         return NULL;
759 }