source: trunk/include/regfi.h @ 139

Last change on this file since 139 was 139, checked in by tim, 15 years ago

rewrote subkey list parsing code to include more organized recursion and parsing as well as improved sanity checking

  • Property svn:keywords set to Id
File size: 15.9 KB
Line 
1/*
2 * Branched from Samba project Subversion repository, version #6903:
3 *   http://viewcvs.samba.org/cgi-bin/viewcvs.cgi/trunk/source/include/regfio.h?rev=6903&view=auto
4 *
5 * Windows NT (and later) registry parsing library
6 *
7 * Copyright (C) 2005-2009 Timothy D. Morgan
8 * Copyright (C) 2005 Gerald (Jerry) Carter
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 3 of the License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * $Id: regfi.h 139 2009-02-09 03:06:16Z tim $
24 */
25
26/************************************************************
27 * Most of this information was obtained from
28 * http://www.wednesday.demon.co.uk/dosreg.html
29 * Thanks Nigel!
30 ***********************************************************/
31
32#ifndef _REGFI_H
33#define _REGFI_H
34
35#include <stdlib.h>
36#include <stdio.h>
37#include <stdbool.h>
38#include <stdarg.h>
39#include <string.h>
40#include <errno.h>
41#include <time.h>
42#include <fcntl.h>
43#include <sys/stat.h>
44#include <sys/types.h>
45#include <unistd.h>
46#include <assert.h>
47
48#include "smb_deps.h"
49#include "winsec.h"
50#include "void_stack.h"
51#include "range_list.h"
52#include "lru_cache.h"
53
54/******************************************************************************/
55
56/* regfi library error message types */
57#define REGFI_MSG_INFO  0x0001
58#define REGFI_MSG_WARN  0x0004
59#define REGFI_MSG_ERROR 0x0010
60
61/* Registry data types */
62#define REG_NONE                       0
63#define REG_SZ                         1
64#define REG_EXPAND_SZ                  2
65#define REG_BINARY                     3
66#define REG_DWORD                      4
67#define REG_DWORD_LE                   4  /* DWORD, little endian */
68#define REG_DWORD_BE                   5  /* DWORD, big endian */
69#define REG_LINK                       6
70#define REG_MULTI_SZ                   7
71#define REG_RESOURCE_LIST              8
72#define REG_FULL_RESOURCE_DESCRIPTOR   9
73#define REG_RESOURCE_REQUIREMENTS_LIST 10
74#define REG_QWORD                      11 /* 64-bit little endian */
75/* XXX: Has MS defined a REG_QWORD_BE? */
76/* Not a real type in the registry */
77#define REG_KEY                    0x7FFFFFFF
78
79#define REGFI_REGF_SIZE            0x1000 /* "regf" header block size */
80#define REGFI_HBIN_ALLOC           0x1000 /* Minimum allocation unit for HBINs */
81#define REGFI_MAX_DEPTH            512
82#define REGFI_OFFSET_NONE          0xffffffff
83
84/* XXX: This is totally arbitrary right now. */
85#define REGFI_MAX_SUBKEY_DEPTH     255   
86
87/* Header sizes and magic number lengths for various records */
88#define REGFI_REGF_MAGIC_SIZE      4
89#define REGFI_HBIN_MAGIC_SIZE      4
90#define REGFI_CELL_MAGIC_SIZE      2
91#define REGFI_HBIN_HEADER_SIZE     0x20
92#define REGFI_NK_MIN_LENGTH        0x4C
93#define REGFI_VK_MIN_LENGTH        0x14
94#define REGFI_SK_MIN_LENGTH        0x14
95#define REGFI_SUBKEY_LIST_MIN_LEN  0x4
96
97
98/* Constants used for validation */
99/* XXX: Can we add clock resolution validation as well as range?  It has
100 *      been reported that Windows timestamps are never more than a
101 *      certain granularity (250ms?), which could be used to help
102 *      eliminate false positives.  Would need to validate this and
103 *      perhaps conservatively implement a check.
104 */
105 /* Minimum time is Jan 1, 1990 00:00:00 */
106#define REGFI_MTIME_MIN_HIGH       0x01B41E6D
107#define REGFI_MTIME_MIN_LOW        0x26F98000
108 /* Maximum time is Jan 1, 2290 00:00:00
109  * (We hope no one is using Windows by then...)
110  */
111#define REGFI_MTIME_MAX_HIGH       0x03047543
112#define REGFI_MTIME_MAX_LOW        0xC80A4000
113
114
115/* Flags for the vk records */
116#define REGFI_VK_FLAG_NAME_PRESENT 0x0001
117#define REGFI_VK_DATA_IN_OFFSET    0x80000000
118#define REGFI_VK_MAX_DATA_LENGTH   1024*1024
119
120
121/* NK record types */
122/* XXX: This is starting to look like this is a flags field. 
123 *      Need to decipher the meaning of each flag.
124 */
125#define REGFI_NK_TYPE_LINKKEY      0x0010
126#define REGFI_NK_TYPE_NORMALKEY    0x0020
127 /* XXX: Unknown key type that shows up in Vista registries */
128#define REGFI_NK_TYPE_UNKNOWN1     0x1020
129 /* XXX: Unknown key types that shows up in W2K3 registries */
130#define REGFI_NK_TYPE_UNKNOWN2     0x4020
131#define REGFI_NK_TYPE_UNKNOWN3     0x0000  /* XXX: This type seems to have UTF-16 names!!! */
132#define REGFI_NK_TYPE_ROOTKEY1     0x002c
133 /* XXX: Unknown root key type that shows up in Vista registries */
134#define REGFI_NK_TYPE_ROOTKEY2     0x00ac
135
136#if 0
137/* Initial hypothesis of NK flags: */
138#define REGFI_NK_FLAG_LINK         0x0010
139/* The name will be in ASCII if this next bit is set, otherwise UTF-16LE */
140#define REGFI_NK_FLAG_ASCIINAME    0x0020
141/* These next two combine to form the "c" on both known root key types */
142#define REGFI_NK_FLAG_ROOT1        0x0008
143#define REGFI_NK_FLAG_ROOT2        0x0004
144/* These next two show up on normal-seeming keys in Vista and W2K3 registries */
145#define REGFI_NK_FLAG_UNKNOWN1     0x4000
146#define REGFI_NK_FLAG_UNKNOWN2     0x1000
147/* This next one shows up on root keys in some Vista "software" registries */
148#define REGFI_NK_FLAG_UNKNOWN3     0x0080
149#endif
150
151
152
153/* HBIN block */
154typedef struct _regfi_hbin
155{
156  uint32 file_off;       /* my offset in the registry file */
157  uint32 ref_count;      /* how many active records are pointing to this
158                          * block (not used currently)
159                          */
160 
161  uint32 first_hbin_off; /* offset from first hbin block */
162  uint32 block_size;     /* block size of this block
163                          * Should be a multiple of 4096 (0x1000)
164                          */
165  uint32 next_block;     /* relative offset to next block. 
166                          * NOTE: This value may be unreliable!
167                          */
168
169  uint8 magic[REGFI_HBIN_MAGIC_SIZE]; /* "hbin" */
170} REGFI_HBIN;
171
172
173/* Subkey List -- list of key offsets and hashed names for consistency */
174typedef struct 
175{
176  /* Virtual offset of NK record or additional subkey list,
177   * depending on this list's type.
178   */
179  uint32 offset;
180
181  uint32 hash;
182} REGFI_SUBKEY_LIST_ELEM;
183
184
185typedef struct 
186{
187  /* Real offset of this record's cell in the file */
188  uint32 offset;
189
190  uint32 cell_size;
191 
192  /* Number of immediate children */
193  uint32 num_children; 
194
195  /* Total number of keys referenced by this list and it's children */
196  uint32 num_keys;     
197
198  REGFI_SUBKEY_LIST_ELEM* elements;
199  uint8 magic[REGFI_CELL_MAGIC_SIZE];
200
201  /* Set if the magic indicates this subkey list points to child subkey lists */
202  bool recursive_type; 
203} REGFI_SUBKEY_LIST;
204
205
206/* Key Value */
207typedef struct 
208{
209  uint32 offset;        /* Real offset of this record's cell in the file */
210  uint32 cell_size;     /* ((start_offset - end_offset) & 0xfffffff8) */
211
212  REGFI_HBIN* hbin;     /* pointer to HBIN record (in memory) containing
213                         * this nk record
214                         */
215  uint8* data;
216  uint16 name_length;
217  char*  valuename;
218  uint32 hbin_off;      /* offset from beginning of this hbin block */
219 
220  uint32 data_size;
221  uint32 data_off;      /* offset of data cell (virtual) */
222  uint32 type;
223  uint8  magic[REGFI_CELL_MAGIC_SIZE];
224  uint16 flag;
225  uint16 unknown1;
226  bool data_in_offset;
227} REGFI_VK_REC;
228
229
230/* Key Security */
231struct _regfi_sk_rec;
232
233typedef struct _regfi_sk_rec
234{
235  uint32 offset;        /* Real file offset of this record */
236  uint32 cell_size;     /* ((start_offset - end_offset) & 0xfffffff8) */
237
238  WINSEC_DESC* sec_desc;
239  uint32 hbin_off;      /* offset from beginning of this hbin block */
240 
241  uint32 sk_off;        /* offset parsed from NK record used as a key
242                         * to lookup reference to this SK record
243                         */
244 
245  uint32 prev_sk_off;
246  uint32 next_sk_off;
247  uint32 ref_count;
248  uint32 desc_size;     /* size of security descriptor */
249  uint16 unknown_tag;
250  uint8  magic[REGFI_CELL_MAGIC_SIZE];
251} REGFI_SK_REC;
252
253
254/* Key Name */
255typedef struct
256{
257  uint32 offset;        /* Real offset of this record's cell in the file */
258  uint32 cell_size;     /* Actual or estimated length of the cell. 
259                         * Always in multiples of 8.
260                         */
261
262  /* link in the other records here */
263  REGFI_VK_REC** values;
264  REGFI_SUBKEY_LIST* subkeys;
265 
266  /* header information */
267  uint16 key_type;
268  uint8  magic[REGFI_CELL_MAGIC_SIZE];
269  NTTIME mtime;
270  uint16 name_length;
271  uint16 classname_length;
272  char* classname;
273  char* keyname;
274  uint32 parent_off;                /* pointer to parent key */
275  uint32 classname_off;
276 
277  /* max lengths */
278  uint32 max_bytes_subkeyname;      /* max subkey name * 2 */
279  uint32 max_bytes_subkeyclassname; /* max subkey classname length (as if) */
280  uint32 max_bytes_valuename;       /* max valuename * 2 */
281  uint32 max_bytes_value;           /* max value data size */
282 
283  /* unknowns */
284  uint32 unknown1;
285  uint32 unknown2;
286  uint32 unknown3;
287  uint32 unk_index;                 /* nigel says run time index ? */
288 
289  /* children */
290  uint32 num_subkeys;
291  uint32 subkeys_off;   /* offset of subkey list that points to NK records */
292  uint32 num_values;
293  uint32 values_off;    /* value lists which point to VK records */
294  uint32 sk_off;        /* offset to SK record */
295} REGFI_NK_REC;
296
297
298
299/* REGF block */
300typedef struct 
301{
302  /* Run-time information */
303  /************************/
304  /* file descriptor */
305  int fd;
306
307  /* For sanity checking (not part of the registry header) */
308  uint32 file_length;
309
310  /* Metadata about hbins */
311  range_list* hbins;
312
313  /* Error/warning/info messages returned by lower layer functions */
314  char* last_message;
315
316  /* Mask for error message types that will be stored. */
317  uint16 msg_mask;
318
319
320  /* Data parsed from file header */
321  /********************************/
322  uint8  magic[REGFI_REGF_MAGIC_SIZE];/* "regf" */
323  NTTIME mtime;
324  uint32 data_offset;           /* offset to record in the first (or any?)
325                                 * hbin block
326                                 */
327  uint32 last_block;            /* offset to last hbin block in file */
328
329  uint32 checksum;              /* Stored checksum. */
330  uint32 computed_checksum;     /* Our own calculation of the checksum.
331                                 * (XOR of bytes 0x0000 - 0x01FB)
332                                 */
333 
334  /* unknown data structure values */
335  uint32 unknown1;
336  uint32 unknown2;
337  uint32 unknown3;
338  uint32 unknown4;
339  uint32 unknown5;
340  uint32 unknown6;
341  uint32 unknown7;
342} REGFI_FILE;
343
344
345
346typedef struct 
347{
348  REGFI_FILE* f;
349  void_stack* key_positions;
350  lru_cache* sk_recs;
351  REGFI_NK_REC* cur_key;
352  uint32 cur_subkey;
353  uint32 cur_value;
354} REGFI_ITERATOR;
355
356
357typedef struct 
358{
359  /* XXX: Should probably eliminate the storage of keys here
360   *      once key caching is implemented.
361   */
362  REGFI_NK_REC* nk;
363  uint32 cur_subkey;
364  /* We could store a cur_value here as well, but didn't see
365   * the use in it right now.
366   */
367} REGFI_ITER_POSITION;
368
369
370/******************************************************************************/
371/*                         Main iterator API                                  */
372/******************************************************************************/
373REGFI_FILE*           regfi_open(const char* filename);
374int                   regfi_close(REGFI_FILE* r);
375
376/* regfi_get_messages: Get errors, warnings, and/or verbose information
377 *                     relating to processing of the given registry file.
378 *
379 * Arguments:
380 *   file     -- the structure for the registry file
381 *
382 * Returns:
383 *   A newly allocated char* which must be free()d by the caller.
384 */
385char*                 regfi_get_messages(REGFI_FILE* file);
386void                  regfi_set_message_mask(REGFI_FILE* file, uint16 mask);
387
388REGFI_ITERATOR*       regfi_iterator_new(REGFI_FILE* fh);
389void                  regfi_iterator_free(REGFI_ITERATOR* i);
390bool                  regfi_iterator_down(REGFI_ITERATOR* i);
391bool                  regfi_iterator_up(REGFI_ITERATOR* i);
392bool                  regfi_iterator_to_root(REGFI_ITERATOR* i);
393
394bool                  regfi_iterator_find_subkey(REGFI_ITERATOR* i, 
395                                                 const char* subkey_name);
396bool                  regfi_iterator_walk_path(REGFI_ITERATOR* i, 
397                                               const char** path);
398const REGFI_NK_REC*   regfi_iterator_cur_key(REGFI_ITERATOR* i);
399const REGFI_SK_REC*   regfi_iterator_cur_sk(REGFI_ITERATOR* i);
400const REGFI_NK_REC*   regfi_iterator_first_subkey(REGFI_ITERATOR* i);
401const REGFI_NK_REC*   regfi_iterator_cur_subkey(REGFI_ITERATOR* i);
402const REGFI_NK_REC*   regfi_iterator_next_subkey(REGFI_ITERATOR* i);
403
404bool                  regfi_iterator_find_value(REGFI_ITERATOR* i, 
405                                                const char* value_name);
406const REGFI_VK_REC*   regfi_iterator_first_value(REGFI_ITERATOR* i);
407const REGFI_VK_REC*   regfi_iterator_cur_value(REGFI_ITERATOR* i);
408const REGFI_VK_REC*   regfi_iterator_next_value(REGFI_ITERATOR* i);
409
410
411/********************************************************/
412/* Middle-layer structure caching, loading, and linking */
413/********************************************************/
414REGFI_HBIN*           regfi_lookup_hbin(REGFI_FILE* file, uint32 offset);
415REGFI_NK_REC*         regfi_load_key(REGFI_FILE* file, uint32 offset, 
416                                     bool strict);
417REGFI_SUBKEY_LIST*    regfi_load_subkeylist(REGFI_FILE* file, uint32 offset, 
418                                            uint32 num_keys, uint32 max_size, 
419                                            bool strict);
420REGFI_VK_REC**        regfi_load_valuelist(REGFI_FILE* file, uint32 offset, 
421                                           uint32 num_values, uint32 max_size, 
422                                           bool strict);
423
424/************************************/
425/*  Low-layer data structure access */
426/************************************/
427REGFI_FILE*           regfi_parse_regf(int fd, bool strict);
428REGFI_HBIN*           regfi_parse_hbin(REGFI_FILE* file, uint32 offset, 
429                                       bool strict);
430
431
432/* regfi_parse_nk: Parses an NK record.
433 *
434 * Arguments:
435 *   f        -- the registry file structure
436 *   offset   -- the offset of the cell (not the record) to be parsed.
437 *   max_size -- the maximum size the NK cell could be. (for validation)
438 *   strict   -- if true, rejects any malformed records.  Otherwise,
439 *               tries to minimally validate integrity.
440 * Returns:
441 *   A newly allocated NK record structure, or NULL on failure.
442 */
443REGFI_NK_REC*         regfi_parse_nk(REGFI_FILE* file, uint32 offset, 
444                                     uint32 max_size, bool strict);
445
446REGFI_SUBKEY_LIST*    regfi_parse_subkeylist(REGFI_FILE* file, uint32 offset,
447                                             uint32 max_size, bool strict);
448
449REGFI_VK_REC*         regfi_parse_vk(REGFI_FILE* file, uint32 offset, 
450                                     uint32 max_size, bool strict);
451
452uint8*                regfi_parse_data(REGFI_FILE* file, uint32 offset, 
453                                       uint32 length, uint32 max_size, 
454                                       bool strict);
455
456REGFI_SK_REC*         regfi_parse_sk(REGFI_FILE* file, uint32 offset, 
457                                     uint32 max_size, bool strict);
458
459range_list*           regfi_parse_unalloc_cells(REGFI_FILE* file);
460
461bool                  regfi_parse_cell(int fd, uint32 offset, 
462                                       uint8* hdr, uint32 hdr_len,
463                                       uint32* cell_length, bool* unalloc);
464
465char*                 regfi_parse_classname(REGFI_FILE* file, uint32 offset,
466                                            uint16* name_length, 
467                                            uint32 max_size, bool strict);
468
469
470/************************************/
471/*    Private Functions             */
472/************************************/
473REGFI_NK_REC*         regfi_rootkey(REGFI_FILE* file);
474void                  regfi_key_free(REGFI_NK_REC* nk);
475void                  regfi_subkeylist_free(REGFI_SUBKEY_LIST* list);
476uint32                regfi_read(int fd, uint8* buf, uint32* length);
477
478const char*           regfi_type_val2str(unsigned int val);
479int                   regfi_type_str2val(const char* str);
480
481char*                 regfi_get_sacl(WINSEC_DESC* sec_desc);
482char*                 regfi_get_dacl(WINSEC_DESC* sec_desc);
483char*                 regfi_get_owner(WINSEC_DESC* sec_desc);
484char*                 regfi_get_group(WINSEC_DESC* sec_desc);
485
486REGFI_SUBKEY_LIST*    regfi_merge_subkeylists(uint16 num_lists, 
487                                              REGFI_SUBKEY_LIST** lists,
488                                              bool strict);
489REGFI_SUBKEY_LIST*    regfi_load_subkeylist_aux(REGFI_FILE* file, uint32 offset,
490                                                uint32 max_size, bool strict,
491                                                uint8 depth_left);
492void                  regfi_add_message(REGFI_FILE* file, uint16 msg_type, 
493                                        const char* fmt, ...);
494#endif  /* _REGFI_H */
Note: See TracBrowser for help on using the repository browser.