]> wimlib.net Git - wimlib/blob - src/registry.c
Implement setting of Windows-specific XML information
[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 /* LF (or LH) cell - contains a list of subkey references.  LF and LH cells are
90  * the same except they use different hashing algorithms.  But this
91  * implementation doesn't yet make use of the hashes anyway.  */
92 struct lf {
93 #define LF_MAGIC        cpu_to_le16(0x666C)     /* "lf" */
94 #define LH_MAGIC        cpu_to_le16(0x686C)     /* "lh" */
95         struct cell base;
96         le16 num_subkeys;
97         struct {
98                 le32 offset;
99                 le32 subkey_name_hash;
100         } subkeys[0];
101 } _packed_attribute;
102
103 /* Value list cell - contains a list of value references  */
104 struct value_list {
105         le32 size;
106         le32 vk_offsets[0];
107 } _packed_attribute;
108
109 /* VK cell - contains a value's data, or a reference to it  */
110 struct vk {
111         struct cell base;
112         le16 name_size;
113         le32 data_size;
114         le32 data_offset;
115 #define REG_NONE                        cpu_to_le32(0x00000000)
116 #define REG_SZ                          cpu_to_le32(0x00000001)
117 #define REG_EXPAND_SZ                   cpu_to_le32(0x00000002)
118 #define REG_BINARY                      cpu_to_le32(0x00000003)
119 #define REG_DWORD                       cpu_to_le32(0x00000004)
120 #define REG_DWORD_LITTLE_ENDIAN         cpu_to_le32(0x00000004)
121 #define REG_DWORD_BIG_ENDIAN            cpu_to_le32(0x00000005)
122 #define REG_LINK                        cpu_to_le32(0x00000006)
123 #define REG_MULTI_SZ                    cpu_to_le32(0x00000007)
124 #define REG_RESOURCE_LIST               cpu_to_le32(0x00000008)
125 #define REG_FULL_RESOURCE_DESCRIPTOR    cpu_to_le32(0x00000009)
126 #define REG_RESOURCE_REQUIREMENTS_LIST  cpu_to_le32(0x0000000A)
127 #define REG_QWORD                       cpu_to_le32(0x0000000B)
128 #define REG_QWORD_LITTLE_ENDIAN         cpu_to_le32(0x0000000B)
129         le32 data_type;
130 #define VK_COMPRESSED_NAME              cpu_to_le16(0x0001)
131         le16 flags;
132         le16 unknown_0x16;
133         char name[0];
134 };
135
136 /* Data cell - contains a value's data  */
137 struct data_cell {
138         le32 size;
139         u8 data[0];
140 };
141
142 static enum hive_status
143 translate_wimlib_error(int ret)
144 {
145         if (likely(!ret))
146                 return HIVE_OK;
147         if (ret == WIMLIB_ERR_NOMEM)
148                 return HIVE_OUT_OF_MEMORY;
149         return HIVE_UNSUPPORTED;
150 }
151
152 /* Compare a UTF-16LE name with a key or value name in the registry.  The
153  * comparison is case insensitive.  */
154 static inline bool
155 names_equal(const utf16lechar *name, size_t name_nchars,
156             const void *disk_name, size_t disk_name_size,
157             bool compressed)
158 {
159         if (compressed) {
160                 /* ISO-8859-1 (LATIN1) on-disk  */
161                 const u8 *p = disk_name;
162                 if (disk_name_size != name_nchars)
163                         return false;
164                 for (size_t i = 0; i < name_nchars; i++)
165                         if (upcase[le16_to_cpu(name[i])] != upcase[p[i]])
166                                 return false;
167                 return true;
168         } else {
169                 /* UTF-16LE on disk  */
170                 disk_name_size /= 2;
171                 if (disk_name_size != name_nchars)
172                         return false;
173                 return !cmp_utf16le_strings(name, name_nchars,
174                                             disk_name, disk_name_size, true);
175         }
176 }
177
178 /* Get a pointer to a cell, with alignment and bounds checking.  Returns NULL if
179  * the requested information does not specify a properly aligned, sized, and
180  * in-use cell.  */
181 static const void *
182 get_cell_pointer(const struct regf *regf, le32 offset, size_t wanted_size)
183 {
184         u32 total = le32_to_cpu(regf->total_hbin_size);
185         u32 offs = le32_to_cpu(offset);
186         const struct cell *cell;
187         s32 actual_size;
188
189         if ((offs > total) || (offs & 7) || (wanted_size > total - offs))
190                 return NULL;
191
192         cell = (const struct cell *)&regf->hbin_area[offs];
193         actual_size = le32_to_cpu(cell->size);
194         if (actual_size >= 0) /* Cell not in use?  */
195                 return NULL;
196         if (wanted_size > -actual_size) /* Cell too small?  */
197                 return NULL;
198         return cell;
199 }
200
201 /* Revalidate the cell with its full length.  Returns true iff the cell is
202  * valid.  */
203 static bool
204 revalidate_cell(const struct regf *regf, le32 offset, size_t wanted_size)
205 {
206         return get_cell_pointer(regf, offset, wanted_size) != NULL;
207 }
208
209 /*
210  * Given a registry key cell @nk, look up the next component of the key
211  * *key_namep.  If found, return HIVE_OK, advance *key_namep past the key name
212  * component, and return the subkey cell in @sub_nk_ret.  Otherwise, return
213  * another HIVE_* error code.
214  */
215 static enum hive_status
216 lookup_subkey(const struct regf *regf, const utf16lechar **key_namep,
217               const struct nk *nk, const struct nk **sub_nk_ret)
218 {
219         const utf16lechar *key_name = *key_namep;
220         size_t key_name_nchars = 0;
221         size_t num_subkeys;
222         const struct cell *subkey_list;
223
224         for (const utf16lechar *p = key_name;
225              *p && *p != cpu_to_le16('\\'); p++)
226                 key_name_nchars++;
227
228         num_subkeys = le32_to_cpu(nk->num_subkeys);
229
230         if (num_subkeys == 0) /* No subkeys?  */
231                 return HIVE_KEY_NOT_FOUND;
232
233         if (num_subkeys > 65536) /* Arbitrary limit */
234                 return HIVE_CORRUPT;
235
236         /* Find the subkey list cell.  */
237         subkey_list = get_cell_pointer(regf, nk->subkey_list_offset,
238                                        sizeof(struct cell));
239         if (!subkey_list)
240                 return HIVE_CORRUPT;
241
242         if (subkey_list->magic == LF_MAGIC || subkey_list->magic == LH_MAGIC) {
243                 const struct lf *lf;
244
245                 /* Handle LF and LH subkey lists.  */
246
247                 lf = get_cell_pointer(regf, nk->subkey_list_offset,
248                                       sizeof(struct lf) +
249                                       (num_subkeys * sizeof(lf->subkeys[0])));
250                 if (!lf)
251                         return HIVE_CORRUPT;
252
253                 /* Look for the subkey in the subkey list.  */
254                 for (size_t i = 0; i < num_subkeys; i++) {
255                         const struct nk *sub_nk;
256                         size_t name_size;
257
258                         sub_nk = get_cell_pointer(regf, lf->subkeys[i].offset,
259                                                   sizeof(struct nk));
260                         if (!sub_nk)
261                                 return HIVE_CORRUPT;
262
263                         name_size = le16_to_cpu(sub_nk->name_size);
264
265                         if (!revalidate_cell(regf, lf->subkeys[i].offset,
266                                              sizeof(struct nk) + name_size))
267                                 return HIVE_CORRUPT;
268
269                         if (names_equal(key_name, key_name_nchars,
270                                         sub_nk->name, name_size,
271                                         (sub_nk->flags & NK_COMPRESSED_NAME)))
272                         {
273                                 key_name += key_name_nchars;
274                                 while (*key_name == cpu_to_le16('\\'))
275                                         key_name++;
276                                 *key_namep = key_name;
277                                 *sub_nk_ret = sub_nk;
278                                 return HIVE_OK;
279                         }
280                 }
281                 return HIVE_KEY_NOT_FOUND;
282         }
283
284         return HIVE_UNSUPPORTED;
285 }
286
287 /* Find the nk cell for the key named @key_name in the registry hive @regf.  */
288 static enum hive_status
289 lookup_key(const struct regf *regf, const tchar *key_name,
290            const struct nk **nk_ret)
291 {
292         const struct nk *nk;
293         enum hive_status status;
294         const utf16lechar *key_uname, *key_unamep;
295
296         nk = get_cell_pointer(regf, regf->root_key_offset, sizeof(struct nk));
297         if (!nk)
298                 return HIVE_CORRUPT;
299
300         status = translate_wimlib_error(tstr_get_utf16le(key_name, &key_uname));
301         if (status != HIVE_OK)
302                 return status;
303         key_unamep = key_uname;
304         while (*key_unamep) {
305                 status = lookup_subkey(regf, &key_unamep, nk, &nk);
306                 if (status != HIVE_OK)
307                         goto out;
308         }
309         *nk_ret = nk;
310         status = HIVE_OK;
311 out:
312         tstr_put_utf16le(key_uname);
313         return status;
314 }
315
316 /* Find the vk cell for the value named @value_name of the key named @key_name
317  * in the registry hive @regf.  */
318 static enum hive_status
319 lookup_value(const struct regf *regf, const tchar *key_name,
320              const tchar *value_name, const struct vk **vk_ret)
321 {
322         enum hive_status status;
323         const struct nk *nk;
324         size_t num_values;
325         const struct value_list *value_list;
326         const  utf16lechar *value_uname;
327         size_t value_uname_nchars;
328
329         /* Look up the nk cell for the key.  */
330         status = lookup_key(regf, key_name, &nk);
331         if (status != HIVE_OK)
332                 return status;
333
334         num_values = le32_to_cpu(nk->num_values);
335
336         if (num_values == 0) /* No values?  */
337                 return HIVE_VALUE_NOT_FOUND;
338
339         if (num_values > 65536) /* Arbitrary limit */
340                 return HIVE_CORRUPT;
341
342         value_list = get_cell_pointer(regf, nk->value_list_offset,
343                                       sizeof(struct value_list) +
344                                       (num_values *
345                                        sizeof(value_list->vk_offsets[0])));
346         if (!value_list)
347                 return HIVE_CORRUPT;
348
349         /* Look for the value in the value list.  */
350
351         status = translate_wimlib_error(
352                         tstr_get_utf16le_and_len(value_name, &value_uname,
353                                                  &value_uname_nchars));
354         if (status != HIVE_OK)
355                 return status;
356         value_uname_nchars /= 2;
357
358         for (size_t i = 0; i < num_values; i++) {
359                 const struct vk *vk;
360                 size_t name_size;
361
362                 status = HIVE_CORRUPT;
363                 vk = get_cell_pointer(regf, value_list->vk_offsets[i],
364                                       sizeof(struct vk));
365                 if (!vk)
366                         goto out;
367
368                 name_size = le16_to_cpu(vk->name_size);
369
370                 if (!revalidate_cell(regf, value_list->vk_offsets[i],
371                                      sizeof(struct vk) + name_size))
372                         goto out;
373
374                 if (names_equal(value_uname, value_uname_nchars,
375                                 vk->name, name_size,
376                                  (vk->flags & VK_COMPRESSED_NAME)))
377                 {
378                         *vk_ret = vk;
379                         status = HIVE_OK;
380                         goto out;
381                 }
382         }
383
384         status = HIVE_VALUE_NOT_FOUND;
385 out:
386         tstr_put_utf16le(value_uname);
387         return status;
388 }
389
390 /*
391  * Retrieve the data of the value named @value_name of the key named @key_name
392  * in the registry hive @regf.  If the value was found, return HIVE_OK and
393  * return the data, its size, and its type in @data_ret, @data_size_ret, and
394  * @data_type_ret.  Otherwise, return another HIVE_* error code.
395  */
396 static enum hive_status
397 retrieve_value(const struct regf *regf, const tchar *key_name,
398                const tchar *value_name, void **data_ret,
399                size_t *data_size_ret, le32 *data_type_ret)
400 {
401         enum hive_status status;
402         const struct vk *vk;
403         size_t data_size;
404         bool is_inline;
405         const void *data;
406
407         /* Find the vk cell.  */
408         status = lookup_value(regf, key_name, value_name, &vk);
409         if (status != HIVE_OK)
410                 return status;
411
412         /* Extract the value data from the vk cell (for inline data) or from the
413          * data cell which it references (for non-inline data).  */
414
415         data_size = le32_to_cpu(vk->data_size);
416
417         is_inline = (data_size & 0x80000000);
418         data_size &= 0x7FFFFFFF;
419
420         if (data_size > 1048576)        /* Arbitrary limit */
421                 return HIVE_CORRUPT;
422
423         if (is_inline) {
424                 if (data_size > 4)
425                         return HIVE_CORRUPT;
426                 data = &vk->data_offset;
427         } else {
428                 const struct data_cell *data_cell;
429
430                 data_cell = get_cell_pointer(regf, vk->data_offset,
431                                              sizeof(struct data_cell));
432                 if (!data_cell)
433                         return HIVE_CORRUPT;
434
435                 if (!revalidate_cell(regf, vk->data_offset,
436                                      sizeof(struct data_cell) + data_size))
437                         return HIVE_UNSUPPORTED; /* Possibly a big data cell  */
438
439                 data = data_cell->data;
440         }
441
442         *data_ret = memdup(data, data_size);
443         if (!*data_ret)
444                 return HIVE_OUT_OF_MEMORY;
445         *data_size_ret = data_size;
446         *data_type_ret = vk->data_type;
447         return HIVE_OK;
448 }
449
450 /* Validate the registry hive file given in memory as @hive_mem and @hive_size.
451  * If valid, return HIVE_OK.  If invalid, return another HIVE_* error code.  */
452 enum hive_status
453 hive_validate(const void *hive_mem, size_t hive_size)
454 {
455         const struct regf *regf = hive_mem;
456
457         STATIC_ASSERT(sizeof(struct regf) == 4096);
458
459         if (hive_size < sizeof(struct regf))
460                 return HIVE_CORRUPT;
461
462         if (regf->magic != REGF_MAGIC || regf->major_version != REGF_MAJOR)
463                 return HIVE_UNSUPPORTED;
464
465         if (le32_to_cpu(regf->total_hbin_size) > hive_size - sizeof(struct regf))
466                 return HIVE_CORRUPT;
467
468         return HIVE_OK;
469 }
470
471 /* Get a string value from the registry hive file.  */
472 enum hive_status
473 hive_get_string(const struct regf *regf, const tchar *key_name,
474                 const tchar *value_name, tchar **value_ret)
475 {
476         void *data;
477         size_t data_size;
478         le32 data_type;
479         enum hive_status status;
480
481         /* Retrieve the raw value data.  */
482         status = retrieve_value(regf, key_name, value_name,
483                                 &data, &data_size, &data_type);
484         if (status != HIVE_OK)
485                 return status;
486
487         /* Interpret the data as a string, when possible.  */
488         switch (data_type) {
489         case REG_SZ:
490         case REG_MULTI_SZ:
491                 status = translate_wimlib_error(
492                         utf16le_to_tstr(data, data_size, value_ret, &data_size));
493                 break;
494         default:
495                 status = HIVE_VALUE_IS_WRONG_TYPE;
496                 break;
497         }
498         FREE(data);
499         return status;
500 }
501
502 /* Get a number value from the registry hive file.  */
503 enum hive_status
504 hive_get_number(const struct regf *regf, const tchar *key_name,
505                 const tchar *value_name, s64 *value_ret)
506 {
507         void *data;
508         size_t data_size;
509         le32 data_type;
510         enum hive_status status;
511
512         /* Retrieve the raw value data.  */
513         status = retrieve_value(regf, key_name, value_name,
514                                 &data, &data_size, &data_type);
515         if (status != HIVE_OK)
516                 return status;
517
518         /* Interpret the data as a number, when possible.  */
519         switch (data_type) {
520         case REG_DWORD_LITTLE_ENDIAN:
521                 if (data_size == 4) {
522                         *value_ret = le32_to_cpu(*(le32 *)data);
523                         status = HIVE_OK;
524                 } else {
525                         status = HIVE_CORRUPT;
526                 }
527                 break;
528         case REG_DWORD_BIG_ENDIAN:
529                 if (data_size == 4) {
530                         *value_ret = be32_to_cpu(*(be32 *)data);
531                         status = HIVE_OK;
532                 } else {
533                         status = HIVE_CORRUPT;
534                 }
535                 break;
536         case REG_QWORD_LITTLE_ENDIAN:
537                 if (data_size == 8) {
538                         *value_ret = le64_to_cpu(*(le64 *)data);
539                         status = HIVE_OK;
540                 } else {
541                         status = HIVE_CORRUPT;
542                 }
543                 break;
544         default:
545                 status = HIVE_VALUE_IS_WRONG_TYPE;
546                 break;
547         }
548
549         FREE(data);
550         return status;
551 }
552
553 /* List the subkeys of the specified registry key.  */
554 enum hive_status
555 hive_list_subkeys(const struct regf *regf, const tchar *key_name,
556                   tchar ***subkeys_ret)
557 {
558         enum hive_status status;
559         const struct nk *nk;
560         size_t num_subkeys;
561         const struct cell *subkey_list;
562         tchar **subkeys;
563
564         /* Look up the nk cell for the key.  */
565         status = lookup_key(regf, key_name, &nk);
566         if (status != HIVE_OK)
567                 return status;
568
569         num_subkeys = le32_to_cpu(nk->num_subkeys);
570
571         if (num_subkeys > 65536) /* Arbitrary limit */
572                 return HIVE_CORRUPT;
573
574         /* Prepare the array of subkey names to return.  */
575         subkeys = CALLOC(num_subkeys + 1, sizeof(subkeys[0]));
576         if (!subkeys)
577                 return HIVE_OUT_OF_MEMORY;
578         *subkeys_ret = subkeys;
579
580         /* No subkeys?  */
581         if (num_subkeys == 0)
582                 return HIVE_OK;
583
584         /* Find the subkey list cell.  */
585         status = HIVE_CORRUPT;
586         subkey_list = get_cell_pointer(regf, nk->subkey_list_offset,
587                                        sizeof(struct cell));
588         if (!subkey_list)
589                 goto err;
590
591         if (subkey_list->magic == LF_MAGIC || subkey_list->magic == LH_MAGIC) {
592                 const struct lf *lf;
593
594                 /* Handle LF and LH subkey lists.  */
595
596                 status = HIVE_CORRUPT;
597                 lf = get_cell_pointer(regf, nk->subkey_list_offset,
598                                       sizeof(struct lf) +
599                                       (num_subkeys * sizeof(lf->subkeys[0])));
600                 if (!lf)
601                         goto err;
602
603                 /* Iterate through the subkey list and gather the subkey names.
604                  */
605                 for (size_t i = 0; i < num_subkeys; i++) {
606                         const struct nk *sub_nk;
607                         size_t name_size;
608                         tchar *subkey;
609                         size_t dummy;
610
611                         status = HIVE_CORRUPT;
612                         sub_nk = get_cell_pointer(regf, lf->subkeys[i].offset,
613                                                   sizeof(struct nk));
614                         if (!sub_nk)
615                                 goto err;
616
617                         name_size = le16_to_cpu(sub_nk->name_size);
618
619                         if (!revalidate_cell(regf, lf->subkeys[i].offset,
620                                              sizeof(struct nk) + name_size))
621                                 goto err;
622
623                         if (sub_nk->flags & NK_COMPRESSED_NAME) {
624                                 status = HIVE_OUT_OF_MEMORY;
625                                 subkey = MALLOC((name_size + 1) * sizeof(tchar));
626                                 if (!subkey)
627                                         goto err;
628                                 for (size_t j = 0; j < name_size; j++)
629                                         subkey[j] = sub_nk->name[j];
630                                 subkey[name_size] = '\0';
631                         } else {
632                                 status = translate_wimlib_error(
633                                         utf16le_to_tstr((utf16lechar *)sub_nk->name,
634                                                         name_size, &subkey, &dummy));
635                                 if (status != HIVE_OK)
636                                         goto err;
637                         }
638                         subkeys[i] = subkey;
639                 }
640                 return HIVE_OK;
641         }
642
643         status = HIVE_UNSUPPORTED;
644 err:
645         hive_free_subkeys_list(subkeys);
646         return status;
647 }
648
649 void
650 hive_free_subkeys_list(tchar **subkeys)
651 {
652         for (tchar **p = subkeys; *p; p++)
653                 FREE(*p);
654         FREE(subkeys);
655 }
656
657 const char *
658 hive_status_to_string(enum hive_status status)
659 {
660         switch (status) {
661         case HIVE_OK:
662                 return "HIVE_OK";
663         case HIVE_CORRUPT:
664                 return "HIVE_CORRUPT";
665         case HIVE_UNSUPPORTED:
666                 return "HIVE_UNSUPPORTED";
667         case HIVE_KEY_NOT_FOUND:
668                 return "HIVE_KEY_NOT_FOUND";
669         case HIVE_VALUE_NOT_FOUND:
670                 return "HIVE_VALUE_NOT_FOUND";
671         case HIVE_VALUE_IS_WRONG_TYPE:
672                 return "HIVE_VALUE_IS_WRONG_TYPE";
673         case HIVE_OUT_OF_MEMORY:
674                 return "HIVE_OUT_OF_MEMORY";
675         }
676         return NULL;
677 }