]> wimlib.net Git - wimlib/blob - src/registry.c
registry: support long subkey lists
[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 http://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 } _packed_attribute;
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 } _packed_attribute;
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 } _packed_attribute;
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 } _packed_attribute;
103
104 /* Value list cell - contains a list of value references  */
105 struct value_list {
106         le32 size;
107         le32 vk_offsets[0];
108 } _packed_attribute;
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_SUBKEYS             65536
147 #define MAX_SUBKEY_LIST_LEVELS  5
148 #define MAX_SUBKEY_LISTS        4096
149
150 static enum hive_status
151 translate_wimlib_error(int ret)
152 {
153         if (likely(!ret))
154                 return HIVE_OK;
155         if (ret == WIMLIB_ERR_NOMEM)
156                 return HIVE_OUT_OF_MEMORY;
157         return HIVE_UNSUPPORTED;
158 }
159
160 /* Compare a UTF-16LE name with a key or value name in the registry.  The
161  * comparison is case insensitive.  */
162 static inline bool
163 names_equal(const utf16lechar *name, size_t name_nchars,
164             const void *disk_name, size_t disk_name_size,
165             bool compressed)
166 {
167         if (compressed) {
168                 /* ISO-8859-1 (LATIN1) on-disk  */
169                 const u8 *p = disk_name;
170                 if (disk_name_size != name_nchars)
171                         return false;
172                 for (size_t i = 0; i < name_nchars; i++)
173                         if (upcase[le16_to_cpu(name[i])] != upcase[p[i]])
174                                 return false;
175                 return true;
176         } else {
177                 /* UTF-16LE on disk  */
178                 disk_name_size /= 2;
179                 if (disk_name_size != name_nchars)
180                         return false;
181                 return !cmp_utf16le_strings(name, name_nchars,
182                                             disk_name, disk_name_size, true);
183         }
184 }
185
186 /* Get a pointer to a cell, with alignment and bounds checking.  Returns NULL if
187  * the requested information does not specify a properly aligned, sized, and
188  * in-use cell.  */
189 static const void *
190 get_cell_pointer(const struct regf *regf, le32 offset, size_t wanted_size)
191 {
192         u32 total = le32_to_cpu(regf->total_hbin_size);
193         u32 offs = le32_to_cpu(offset);
194         const struct cell *cell;
195         s32 actual_size;
196
197         if ((offs > total) || (offs & 7) || (wanted_size > total - offs))
198                 return NULL;
199
200         cell = (const struct cell *)&regf->hbin_area[offs];
201         actual_size = le32_to_cpu(cell->size);
202         if (actual_size >= 0) /* Cell not in use?  */
203                 return NULL;
204         if (wanted_size > -actual_size) /* Cell too small?  */
205                 return NULL;
206         return cell;
207 }
208
209 /* Revalidate the cell with its full length.  Returns true iff the cell is
210  * valid.  */
211 static bool
212 revalidate_cell(const struct regf *regf, le32 offset, size_t wanted_size)
213 {
214         return get_cell_pointer(regf, offset, wanted_size) != NULL;
215 }
216
217 struct subkey_iteration_stats {
218
219         /* The number of additional levels of descendent subkey lists that may
220          * be visited (currently, i.e. at this point in the iteration) before
221          * our safety limit of MAX_SUBKEY_LIST_LEVELS is reached  */
222         u32 levels_remaining;
223
224         /* The number of additional subkey lists that may be visited until our
225          * safety limit of MAX_SUBKEY_LISTS is reached  */
226         u32 subkey_lists_remaining;
227
228         /* The number of subkeys remaining to be found.  Since the number of
229          * subkeys is known from the parent nk cell, this should be 0 at the end
230          * of the iteration.  */
231         u32 subkeys_remaining;
232 };
233
234 typedef enum hive_status (*subkey_cb_t)(const struct nk *, void *);
235
236 static enum hive_status
237 iterate_subkeys_recursive(const struct regf *regf, le32 subkey_list_offset,
238                           subkey_cb_t cb, void *cb_ctx,
239                           struct subkey_iteration_stats *stats)
240 {
241         const struct subkey_list *list;
242         unsigned num_offsets;
243         size_t extra_size;
244         unsigned increment;
245         const le32 *p;
246         enum hive_status status;
247
248         if (stats->levels_remaining == 0 || stats->subkey_lists_remaining == 0)
249                 return HIVE_CORRUPT;
250
251         stats->subkey_lists_remaining--;
252
253         list = get_cell_pointer(regf, subkey_list_offset,
254                                 sizeof(struct subkey_list));
255         if (!list)
256                 return HIVE_CORRUPT;
257
258         num_offsets = le16_to_cpu(list->num_offsets);
259         extra_size = num_offsets * sizeof(list->elements[0]);
260         increment = 1;
261
262         if (list->base.magic == LF_MAGIC || list->base.magic == LH_MAGIC) {
263                 /* Hashes are included  */
264                 extra_size *= 2;
265                 increment = 2;
266         }
267
268         if (!revalidate_cell(regf, subkey_list_offset,
269                              sizeof(struct subkey_list) + extra_size))
270                 return HIVE_CORRUPT;
271
272         p = list->elements;
273
274         switch (list->base.magic) {
275         case LF_MAGIC:
276         case LH_MAGIC:
277         case LI_MAGIC:
278                 /* Children are subkeys  */
279                 if (stats->subkeys_remaining < num_offsets)
280                         return HIVE_CORRUPT;
281                 stats->subkeys_remaining -= num_offsets;
282                 while (num_offsets--) {
283                         const struct nk *sub_nk;
284
285                         sub_nk = get_cell_pointer(regf, *p, sizeof(struct nk));
286                         if (!sub_nk || sub_nk->base.magic != NK_MAGIC)
287                                 return HIVE_CORRUPT;
288
289                         if (!revalidate_cell(regf, *p, sizeof(struct nk) +
290                                                 le16_to_cpu(sub_nk->name_size)))
291                                 return HIVE_CORRUPT;
292
293                         status = (*cb)(sub_nk, cb_ctx);
294                         if (status != HIVE_OK)
295                                 return status;
296                         p += increment;
297                 }
298                 return HIVE_OK;
299         case RI_MAGIC:
300                 /* Children are subkey lists  */
301                 status = HIVE_OK;
302                 stats->levels_remaining--;
303                 while (num_offsets--) {
304                         status = iterate_subkeys_recursive(regf, *p++,
305                                                            cb, cb_ctx, stats);
306                         if (status != HIVE_OK)
307                                 break;
308                 }
309                 stats->levels_remaining++;
310                 return status;
311         default:
312                 return HIVE_UNSUPPORTED;
313         }
314 }
315
316 /* Call @cb on each subkey cell of the key @nk.  */
317 static enum hive_status
318 iterate_subkeys(const struct regf *regf, const struct nk *nk,
319                 subkey_cb_t cb, void *cb_ctx)
320 {
321         u32 num_subkeys = le32_to_cpu(nk->num_subkeys);
322         struct subkey_iteration_stats stats;
323         enum hive_status status;
324
325         if (num_subkeys == 0)
326                 return HIVE_OK;
327
328         if (num_subkeys > MAX_SUBKEYS)
329                 return HIVE_CORRUPT;
330
331         stats.levels_remaining = MAX_SUBKEY_LIST_LEVELS;
332         stats.subkey_lists_remaining = MAX_SUBKEY_LISTS;
333         stats.subkeys_remaining = num_subkeys;
334
335         status = iterate_subkeys_recursive(regf, nk->subkey_list_offset,
336                                            cb, cb_ctx, &stats);
337         if (stats.subkeys_remaining != 0 && status == HIVE_OK)
338                 status = HIVE_CORRUPT;
339         return status;
340 }
341
342 struct lookup_subkey_ctx {
343         const utf16lechar *key_name;
344         size_t key_name_nchars;
345         const struct nk *result;
346 };
347
348 static enum hive_status
349 lookup_subkey_cb(const struct nk *sub_nk, void *_ctx)
350 {
351         struct lookup_subkey_ctx *ctx = _ctx;
352
353         if (names_equal(ctx->key_name, ctx->key_name_nchars,
354                         sub_nk->name, le16_to_cpu(sub_nk->name_size),
355                         (sub_nk->flags & NK_COMPRESSED_NAME)))
356         {
357                 ctx->result = sub_nk;
358                 return HIVE_ITERATION_STOPPED;
359         }
360
361         return HIVE_OK;
362 }
363
364 /*
365  * Given a registry key cell @nk, look up the next component of the key
366  * *key_namep.  If found, return HIVE_OK, advance *key_namep past the key name
367  * component, and return the subkey cell in @sub_nk_ret.  Otherwise, return
368  * another HIVE_* error code.
369  */
370 static enum hive_status
371 lookup_subkey(const struct regf *regf, const utf16lechar **key_namep,
372               const struct nk *nk, const struct nk **sub_nk_ret)
373 {
374         const utf16lechar *key_name = *key_namep;
375         size_t key_name_nchars = 0;
376         struct lookup_subkey_ctx ctx;
377         enum hive_status status;
378
379         while (key_name[key_name_nchars] != cpu_to_le16('\0') &&
380                key_name[key_name_nchars] != cpu_to_le16('\\'))
381                 key_name_nchars++;
382
383         ctx.key_name = key_name;
384         ctx.key_name_nchars = key_name_nchars;
385         ctx.result = NULL;
386
387         status = iterate_subkeys(regf, nk, lookup_subkey_cb, &ctx);
388         if (!ctx.result) {
389                 if (status == HIVE_OK)
390                         status = HIVE_KEY_NOT_FOUND;
391                 return status;
392         }
393
394         key_name += key_name_nchars;
395         while (*key_name == cpu_to_le16('\\'))
396                 key_name++;
397         *key_namep = key_name;
398         *sub_nk_ret = ctx.result;
399         return HIVE_OK;
400 }
401
402 /* Find the nk cell for the key named @key_name in the registry hive @regf.  */
403 static enum hive_status
404 lookup_key(const struct regf *regf, const tchar *key_name,
405            const struct nk **nk_ret)
406 {
407         const struct nk *nk;
408         enum hive_status status;
409         const utf16lechar *key_uname, *key_unamep;
410
411         nk = get_cell_pointer(regf, regf->root_key_offset, sizeof(struct nk));
412         if (!nk || nk->base.magic != NK_MAGIC)
413                 return HIVE_CORRUPT;
414
415         status = translate_wimlib_error(tstr_get_utf16le(key_name, &key_uname));
416         if (status != HIVE_OK)
417                 return status;
418         key_unamep = key_uname;
419         while (*key_unamep) {
420                 status = lookup_subkey(regf, &key_unamep, nk, &nk);
421                 if (status != HIVE_OK)
422                         goto out;
423         }
424         *nk_ret = nk;
425         status = HIVE_OK;
426 out:
427         tstr_put_utf16le(key_uname);
428         return status;
429 }
430
431 /* Find the vk cell for the value named @value_name of the key named @key_name
432  * in the registry hive @regf.  */
433 static enum hive_status
434 lookup_value(const struct regf *regf, const tchar *key_name,
435              const tchar *value_name, const struct vk **vk_ret)
436 {
437         enum hive_status status;
438         const struct nk *nk;
439         size_t num_values;
440         const struct value_list *value_list;
441         const  utf16lechar *value_uname;
442         size_t value_uname_nchars;
443
444         /* Look up the nk cell for the key.  */
445         status = lookup_key(regf, key_name, &nk);
446         if (status != HIVE_OK)
447                 return status;
448
449         num_values = le32_to_cpu(nk->num_values);
450
451         if (num_values == 0) /* No values?  */
452                 return HIVE_VALUE_NOT_FOUND;
453
454         if (num_values > MAX_VALUES)
455                 return HIVE_CORRUPT;
456
457         value_list = get_cell_pointer(regf, nk->value_list_offset,
458                                       sizeof(struct value_list) +
459                                       (num_values *
460                                        sizeof(value_list->vk_offsets[0])));
461         if (!value_list)
462                 return HIVE_CORRUPT;
463
464         /* Look for the value in the value list.  */
465
466         status = translate_wimlib_error(
467                         tstr_get_utf16le_and_len(value_name, &value_uname,
468                                                  &value_uname_nchars));
469         if (status != HIVE_OK)
470                 return status;
471         value_uname_nchars /= 2;
472
473         for (size_t i = 0; i < num_values; i++) {
474                 const struct vk *vk;
475                 size_t name_size;
476
477                 status = HIVE_CORRUPT;
478                 vk = get_cell_pointer(regf, value_list->vk_offsets[i],
479                                       sizeof(struct vk));
480                 if (!vk || vk->base.magic != VK_MAGIC)
481                         goto out;
482
483                 name_size = le16_to_cpu(vk->name_size);
484
485                 if (!revalidate_cell(regf, value_list->vk_offsets[i],
486                                      sizeof(struct vk) + name_size))
487                         goto out;
488
489                 if (names_equal(value_uname, value_uname_nchars,
490                                 vk->name, name_size,
491                                  (vk->flags & VK_COMPRESSED_NAME)))
492                 {
493                         *vk_ret = vk;
494                         status = HIVE_OK;
495                         goto out;
496                 }
497         }
498
499         status = HIVE_VALUE_NOT_FOUND;
500 out:
501         tstr_put_utf16le(value_uname);
502         return status;
503 }
504
505 /*
506  * Retrieve the data of the value named @value_name of the key named @key_name
507  * in the registry hive @regf.  If the value was found, return HIVE_OK and
508  * return the data, its size, and its type in @data_ret, @data_size_ret, and
509  * @data_type_ret.  Otherwise, return another HIVE_* error code.
510  */
511 static enum hive_status
512 retrieve_value(const struct regf *regf, const tchar *key_name,
513                const tchar *value_name, void **data_ret,
514                size_t *data_size_ret, le32 *data_type_ret)
515 {
516         enum hive_status status;
517         const struct vk *vk;
518         size_t data_size;
519         bool is_inline;
520         const void *data;
521
522         /* Find the vk cell.  */
523         status = lookup_value(regf, key_name, value_name, &vk);
524         if (status != HIVE_OK)
525                 return status;
526
527         /* Extract the value data from the vk cell (for inline data) or from the
528          * data cell which it references (for non-inline data).  */
529
530         data_size = le32_to_cpu(vk->data_size);
531
532         is_inline = (data_size & 0x80000000);
533         data_size &= 0x7FFFFFFF;
534
535         if (data_size > 1048576)        /* Arbitrary limit */
536                 return HIVE_CORRUPT;
537
538         if (is_inline) {
539                 if (data_size > 4)
540                         return HIVE_CORRUPT;
541                 data = &vk->data_offset;
542         } else {
543                 const struct data_cell *data_cell;
544
545                 data_cell = get_cell_pointer(regf, vk->data_offset,
546                                              sizeof(struct data_cell));
547                 if (!data_cell)
548                         return HIVE_CORRUPT;
549
550                 if (!revalidate_cell(regf, vk->data_offset,
551                                      sizeof(struct data_cell) + data_size))
552                         return HIVE_UNSUPPORTED; /* Possibly a big data cell  */
553
554                 data = data_cell->data;
555         }
556
557         *data_ret = memdup(data, data_size);
558         if (!*data_ret)
559                 return HIVE_OUT_OF_MEMORY;
560         *data_size_ret = data_size;
561         *data_type_ret = vk->data_type;
562         return HIVE_OK;
563 }
564
565 /* Validate the registry hive file given in memory as @hive_mem and @hive_size.
566  * If valid, return HIVE_OK.  If invalid, return another HIVE_* error code.  */
567 enum hive_status
568 hive_validate(const void *hive_mem, size_t hive_size)
569 {
570         const struct regf *regf = hive_mem;
571
572         STATIC_ASSERT(sizeof(struct regf) == 4096);
573
574         if (hive_size < sizeof(struct regf))
575                 return HIVE_CORRUPT;
576
577         if (regf->magic != REGF_MAGIC || regf->major_version != REGF_MAJOR)
578                 return HIVE_UNSUPPORTED;
579
580         if (le32_to_cpu(regf->total_hbin_size) > hive_size - sizeof(struct regf))
581                 return HIVE_CORRUPT;
582
583         return HIVE_OK;
584 }
585
586 /* Get a string value from the registry hive file.  */
587 enum hive_status
588 hive_get_string(const struct regf *regf, const tchar *key_name,
589                 const tchar *value_name, tchar **value_ret)
590 {
591         void *data;
592         size_t data_size;
593         le32 data_type;
594         enum hive_status status;
595
596         /* Retrieve the raw value data.  */
597         status = retrieve_value(regf, key_name, value_name,
598                                 &data, &data_size, &data_type);
599         if (status != HIVE_OK)
600                 return status;
601
602         /* Interpret the data as a string, when possible.  */
603         switch (data_type) {
604         case REG_SZ:
605         case REG_MULTI_SZ:
606                 status = translate_wimlib_error(
607                         utf16le_to_tstr(data, data_size, value_ret, &data_size));
608                 break;
609         default:
610                 status = HIVE_VALUE_IS_WRONG_TYPE;
611                 break;
612         }
613         FREE(data);
614         return status;
615 }
616
617 /* Get a number value from the registry hive file.  */
618 enum hive_status
619 hive_get_number(const struct regf *regf, const tchar *key_name,
620                 const tchar *value_name, s64 *value_ret)
621 {
622         void *data;
623         size_t data_size;
624         le32 data_type;
625         enum hive_status status;
626
627         /* Retrieve the raw value data.  */
628         status = retrieve_value(regf, key_name, value_name,
629                                 &data, &data_size, &data_type);
630         if (status != HIVE_OK)
631                 return status;
632
633         /* Interpret the data as a number, when possible.  */
634         switch (data_type) {
635         case REG_DWORD_LITTLE_ENDIAN:
636                 if (data_size == 4) {
637                         *value_ret = le32_to_cpu(*(le32 *)data);
638                         status = HIVE_OK;
639                 } else {
640                         status = HIVE_CORRUPT;
641                 }
642                 break;
643         case REG_DWORD_BIG_ENDIAN:
644                 if (data_size == 4) {
645                         *value_ret = be32_to_cpu(*(be32 *)data);
646                         status = HIVE_OK;
647                 } else {
648                         status = HIVE_CORRUPT;
649                 }
650                 break;
651         case REG_QWORD_LITTLE_ENDIAN:
652                 if (data_size == 8) {
653                         *value_ret = le64_to_cpu(*(le64 *)data);
654                         status = HIVE_OK;
655                 } else {
656                         status = HIVE_CORRUPT;
657                 }
658                 break;
659         default:
660                 status = HIVE_VALUE_IS_WRONG_TYPE;
661                 break;
662         }
663
664         FREE(data);
665         return status;
666 }
667
668 static enum hive_status
669 append_subkey_name(const struct nk *sub_nk, void *_next_subkey_p)
670 {
671         size_t name_size = le16_to_cpu(sub_nk->name_size);
672         tchar *subkey;
673         tchar ***next_subkeyp = _next_subkey_p;
674
675         if (sub_nk->flags & NK_COMPRESSED_NAME) {
676                 subkey = MALLOC((name_size + 1) * sizeof(tchar));
677                 if (!subkey)
678                         return HIVE_OUT_OF_MEMORY;
679                 for (size_t i = 0; i < name_size; i++)
680                         subkey[i] = sub_nk->name[i];
681                 subkey[name_size] = '\0';
682         } else {
683                 size_t dummy;
684                 enum hive_status status;
685
686                 status = translate_wimlib_error(
687                         utf16le_to_tstr((utf16lechar *)sub_nk->name,
688                                         name_size, &subkey, &dummy));
689                 if (status != HIVE_OK)
690                         return status;
691         }
692
693         **next_subkeyp = subkey;
694         ++*next_subkeyp;
695         return HIVE_OK;
696 }
697
698 /* List the subkeys of the specified registry key.  */
699 enum hive_status
700 hive_list_subkeys(const struct regf *regf, const tchar *key_name,
701                   tchar ***subkeys_ret)
702 {
703         enum hive_status status;
704         const struct nk *nk;
705         tchar **subkeys;
706         tchar **next_subkey;
707
708         status = lookup_key(regf, key_name, &nk);
709         if (status != HIVE_OK)
710                 return status;
711
712         if (le32_to_cpu(nk->num_subkeys) > MAX_SUBKEYS)
713                 return HIVE_CORRUPT;
714
715         subkeys = CALLOC(le32_to_cpu(nk->num_subkeys) + 1, sizeof(subkeys[0]));
716         if (!subkeys)
717                 return HIVE_OUT_OF_MEMORY;
718
719         next_subkey = subkeys;
720         status = iterate_subkeys(regf, nk, append_subkey_name, &next_subkey);
721         if (status == HIVE_OK)
722                 *subkeys_ret = subkeys;
723         else
724                 hive_free_subkeys_list(subkeys);
725         return status;
726 }
727
728 void
729 hive_free_subkeys_list(tchar **subkeys)
730 {
731         for (tchar **p = subkeys; *p; p++)
732                 FREE(*p);
733         FREE(subkeys);
734 }
735
736 const char *
737 hive_status_to_string(enum hive_status status)
738 {
739         switch (status) {
740         case HIVE_OK:
741                 return "HIVE_OK";
742         case HIVE_CORRUPT:
743                 return "HIVE_CORRUPT";
744         case HIVE_UNSUPPORTED:
745                 return "HIVE_UNSUPPORTED";
746         case HIVE_KEY_NOT_FOUND:
747                 return "HIVE_KEY_NOT_FOUND";
748         case HIVE_VALUE_NOT_FOUND:
749                 return "HIVE_VALUE_NOT_FOUND";
750         case HIVE_VALUE_IS_WRONG_TYPE:
751                 return "HIVE_VALUE_IS_WRONG_TYPE";
752         case HIVE_OUT_OF_MEMORY:
753                 return "HIVE_OUT_OF_MEMORY";
754         case HIVE_ITERATION_STOPPED:
755                 return "HIVE_ITERATION_STOPPED";
756         }
757         return NULL;
758 }