source: src/reglookup.c @ 4

Last change on this file since 4 was 4, checked in by tim, 19 years ago

Now handling MULTI_SZ types by printing a list of converted strings, rather
than a hex dump. (Still needs testing.)

Moved header comments of reglookup.c to doc/winntreg.txt.

Added copy of GPL2 as LICENSE.

  • Property svn:keywords set to Id
File size: 49.1 KB
Line 
1/*
2 * $Id: reglookup.c 4 2005-02-20 03:19:23Z tim $
3 *
4 * A utility to edit a Windows NT/2K etc registry file.
5 *
6 * This code was taken from Richard Sharpe''s editreg utility, in the
7 * Samba CVS tree.  It has since been simplified and turned into a
8 * strictly read-only utility.
9 *
10 * Copyright (C) 2005 Timothy D. Morgan
11 * Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; version 2 of the License.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
25 */
26 
27/*************************************************************************
28
29 A note from Richard Sharpe:
30  Many of the ideas in here come from other people and software.
31  I first looked in Wine in misc/registry.c and was also influenced by
32  http://www.wednesday.demon.co.uk/dosreg.html
33
34  Which seems to contain comments from someone else. I reproduce them here
35  incase the site above disappears. It actually comes from
36  http://home.eunet.no/~pnordahl/ntpasswd/WinReg.txt.
37 
38 NOTE: the comments he refers to have been moved to doc/winntreg.txt
39
40**************************************************************************/
41
42
43#include <stdio.h>
44#include <stdlib.h>
45#include <errno.h>
46#include <assert.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49#include <unistd.h>
50#include <sys/mman.h>
51#include <strings.h>
52#include <string.h>
53#include <fcntl.h>
54
55#define False 0
56#define True 1
57#define REG_KEY_LIST_SIZE 10
58
59/*
60 * Structures for dealing with the on-disk format of the registry
61 */
62
63#define IVAL(buf) ((unsigned int) \
64                   (unsigned int)*((unsigned char *)(buf)+3)<<24| \
65                   (unsigned int)*((unsigned char *)(buf)+2)<<16| \
66                   (unsigned int)*((unsigned char *)(buf)+1)<<8| \
67                   (unsigned int)*((unsigned char *)(buf)+0))
68
69#define SVAL(buf) ((unsigned short) \
70                   (unsigned short)*((unsigned char *)(buf)+1)<<8| \
71                   (unsigned short)*((unsigned char *)(buf)+0))
72
73#define CVAL(buf) ((unsigned char)*((unsigned char *)(buf)))
74
75#define SIVAL(buf, val) \
76            ((((unsigned char *)(buf))[0])=(unsigned char)((val)&0xFF),\
77             (((unsigned char *)(buf))[1])=(unsigned char)(((val)>>8)&0xFF),\
78             (((unsigned char *)(buf))[2])=(unsigned char)(((val)>>16)&0xFF),\
79             (((unsigned char *)(buf))[3])=(unsigned char)((val)>>24))
80
81#define SSVAL(buf, val) \
82  ((((unsigned char *)(buf))[0])=(unsigned char)((val)&0xFF),\
83   (((unsigned char *)(buf))[1])=(unsigned char)((val)>>8))
84
85static int verbose = 0;
86static int print_security = 0;
87static int full_print = 0;
88static const char *def_owner_sid_str = NULL;
89
90/*
91 * These definitions are for the in-memory registry structure.
92 * It is a tree structure that mimics what you see with tools like regedit
93 */
94
95/*
96 * DateTime struct for Windows
97 */
98
99typedef struct date_time_s {
100  unsigned int low, high;
101} NTTIME;
102
103/*
104 * Definition of a Key. It has a name, classname, date/time last modified,
105 * sub-keys, values, and a security descriptor
106 */
107
108#define REG_ROOT_KEY 1
109#define REG_SUB_KEY  2
110#define REG_SYM_LINK 3
111
112typedef struct key_sec_desc_s KEY_SEC_DESC;
113
114typedef struct reg_key_s {
115  char *name;         /* Name of the key                    */
116  char *class_name;
117  int type;           /* One of REG_ROOT_KEY or REG_SUB_KEY */
118  NTTIME last_mod; /* Time last modified                 */
119  struct reg_key_s *owner;
120  struct key_list_s *sub_keys;
121  struct val_list_s *values;
122  KEY_SEC_DESC *security;
123  unsigned int offset;  /* Offset of the record in the file */
124} REG_KEY;
125
126/*
127 * The KEY_LIST struct lists sub-keys.
128 */
129
130typedef struct key_list_s {
131  int key_count;
132  int max_keys;
133  REG_KEY *keys[1];
134} KEY_LIST;
135
136typedef struct val_key_s {
137  char *name;
138  int has_name;
139  int data_type;
140  int data_len;
141  void *data_blk;    /* Might want a separate block */
142} VAL_KEY;
143
144typedef struct val_list_s {
145  int val_count;
146  int max_vals;
147  VAL_KEY *vals[1];
148} VAL_LIST;
149
150#ifndef MAXSUBAUTHS
151#define MAXSUBAUTHS 15
152#endif
153
154typedef struct sid_s {
155  unsigned char ver, auths;
156  unsigned char auth[6];
157  unsigned int sub_auths[MAXSUBAUTHS];
158} sid_t;
159
160typedef struct ace_struct_s {
161  unsigned char type, flags;
162  unsigned int perms;   /* Perhaps a better def is in order */
163  sid_t *trustee;
164} ACE; 
165
166typedef struct acl_struct_s {
167  unsigned short rev, refcnt;
168  unsigned short num_aces;
169  ACE *aces[1];
170} ACL;
171
172typedef struct sec_desc_s {
173  unsigned int rev, type;
174  sid_t *owner, *group;
175  ACL *sacl, *dacl;
176} SEC_DESC;
177
178#define SEC_DESC_NON 0
179#define SEC_DESC_RES 1
180#define SEC_DESC_OCU 2
181#define SEC_DESC_NBK 3
182typedef struct sk_struct SK_HDR;
183struct key_sec_desc_s {
184  struct key_sec_desc_s *prev, *next;
185  int ref_cnt;
186  int state;
187  int offset;
188  SK_HDR *sk_hdr;     /* This means we must keep the registry in memory */
189  SEC_DESC *sec_desc;
190}; 
191
192/*
193 * All of the structures below actually have a four-byte length before them
194 * which always seems to be negative. The following macro retrieves that
195 * size as an integer
196 */
197
198#define BLK_SIZE(b) ((int)*(int *)(((int *)b)-1))
199
200typedef unsigned int DWORD;
201typedef unsigned short WORD;
202
203#define REG_REGF_ID 0x66676572
204
205typedef struct regf_block {
206  DWORD REGF_ID;     /* regf */
207  DWORD uk1;
208  DWORD uk2;
209  DWORD tim1, tim2;
210  DWORD uk3;             /* 1 */
211  DWORD uk4;             /* 3 */
212  DWORD uk5;             /* 0 */
213  DWORD uk6;             /* 1 */
214  DWORD first_key;       /* offset */
215  unsigned int dblk_size;
216  DWORD uk7[116];        /* 1 */
217  DWORD chksum;
218} REGF_HDR;
219
220typedef struct hbin_sub_struct {
221  DWORD dblocksize;
222  char data[1];
223} HBIN_SUB_HDR;
224
225#define REG_HBIN_ID 0x6E696268
226
227typedef struct hbin_struct {
228  DWORD HBIN_ID; /* hbin */
229  DWORD off_from_first;
230  DWORD off_to_next;
231  DWORD uk1;
232  DWORD uk2;
233  DWORD uk3;
234  DWORD uk4;
235  DWORD blk_size;
236  HBIN_SUB_HDR hbin_sub_hdr;
237} HBIN_HDR;
238
239#define REG_NK_ID 0x6B6E
240
241typedef struct nk_struct {
242  WORD NK_ID;
243  WORD type;
244  DWORD t1, t2;
245  DWORD uk1;
246  DWORD own_off;
247  DWORD subk_num;
248  DWORD uk2;
249  DWORD lf_off;
250  DWORD uk3;
251  DWORD val_cnt;
252  DWORD val_off;
253  DWORD sk_off;
254  DWORD clsnam_off;
255  DWORD unk4[4];
256  DWORD unk5;
257  WORD nam_len;
258  WORD clsnam_len;
259  char key_nam[1];  /* Actual length determined by nam_len */
260} NK_HDR;
261
262#define REG_SK_ID 0x6B73
263
264struct sk_struct {
265  WORD SK_ID;
266  WORD uk1;
267  DWORD prev_off;
268  DWORD next_off;
269  DWORD ref_cnt;
270  DWORD rec_size;
271  char sec_desc[1];
272};
273
274typedef struct ace_struct {
275    unsigned char type;
276    unsigned char flags;
277    unsigned short length;
278    unsigned int perms;
279    sid_t trustee;
280} REG_ACE;
281
282typedef struct acl_struct {
283  WORD rev;
284  WORD size;
285  DWORD num_aces;
286  REG_ACE *aces;   /* One or more ACEs */
287} REG_ACL;
288
289typedef struct sec_desc_rec {
290  WORD rev;
291  WORD type;
292  DWORD owner_off;
293  DWORD group_off;
294  DWORD sacl_off;
295  DWORD dacl_off;
296} REG_SEC_DESC;
297
298typedef struct hash_struct {
299  DWORD nk_off;
300  char hash[4];
301} HASH_REC;
302
303#define REG_LF_ID 0x666C
304
305typedef struct lf_struct {
306  WORD LF_ID;
307  WORD key_count;
308  struct hash_struct hr[1];  /* Array of hash records, depending on key_count */
309} LF_HDR;
310
311typedef DWORD VL_TYPE[1];  /* Value list is an array of vk rec offsets */
312
313#define REG_VK_ID 0x6B76
314
315typedef struct vk_struct {
316  WORD VK_ID;
317  WORD nam_len;
318  DWORD dat_len;    /* If top-bit set, offset contains the data */
319  DWORD dat_off;   
320  DWORD dat_type;
321  WORD flag;        /* =1, has name, else no name (=Default). */
322  WORD unk1;
323  char dat_name[1]; /* Name starts here ... */
324} VK_HDR;
325
326#define REG_TYPE_DELETE    -1
327#define REG_TYPE_NONE      0
328#define REG_TYPE_REGSZ     1
329#define REG_TYPE_EXPANDSZ  2
330#define REG_TYPE_BIN       3 
331#define REG_TYPE_DWORD     4
332#define REG_TYPE_MULTISZ   7
333
334typedef struct _val_str { 
335  unsigned int val;
336  const char * str;
337} VAL_STR;
338
339/* A map of sk offsets in the regf to KEY_SEC_DESCs for quick lookup etc */
340typedef struct sk_map_s {
341  int sk_off;
342  KEY_SEC_DESC *key_sec_desc;
343} SK_MAP;
344
345/*
346 * This structure keeps track of the output format of the registry
347 */
348#define REG_OUTBLK_HDR 1
349#define REG_OUTBLK_HBIN 2
350
351typedef struct hbin_blk_s {
352  int type, size;
353  struct hbin_blk_s *next;
354  char *data;                /* The data block                */
355  unsigned int file_offset;  /* Offset in file                */
356  unsigned int free_space;   /* Amount of free space in block */
357  unsigned int fsp_off;      /* Start of free space in block  */
358  int complete, stored;
359} HBIN_BLK;
360
361/*
362 * This structure keeps all the registry stuff in one place
363 */
364typedef struct regf_struct_s {
365  int reg_type;
366  char *regfile_name, *outfile_name;
367  int fd;
368  struct stat sbuf;
369  char *base;
370  int modified;
371  NTTIME last_mod_time;
372  REG_KEY *root;  /* Root of the tree for this file */
373  int sk_count, sk_map_size;
374  SK_MAP *sk_map;
375  const char *owner_sid_str;
376  SEC_DESC *def_sec_desc;
377  /*
378   * These next pointers point to the blocks used to contain the
379   * keys when we are preparing to write them to a file
380   */
381  HBIN_BLK *blk_head, *blk_tail, *free_space;
382} REGF;
383
384
385/* Function prototypes */
386
387static int nt_val_list_iterator(REGF *regf,  REG_KEY *key_tree, int bf, 
388                                char *path, int terminal, 
389                                const char* filter_prefix);
390static int nt_key_iterator(REGF *regf, REG_KEY *key_tree, int bf,
391                           const char *path, const char* filter_prefix);
392static REG_KEY *nt_find_key_by_name(REG_KEY *tree, char *key);
393static int print_key(const char *path, char *name, char *class_name, int root,
394                     int terminal, int vals, char* newline);
395static int print_val(const char *path, char *val_name, int val_type, 
396                     int data_len, void *data_blk, int terminal, int first, 
397                     int last);
398
399static
400int print_sec(SEC_DESC *sec_desc);
401
402unsigned int str_is_prefix(const char* p, const char* s)
403{
404  const char* cp;
405  const char* cs;
406 
407  cs = s;
408  for(cp=p; (*cp) != '\0'; cp++)
409  {
410    if((*cp)!=(*cs))
411      return 0;
412    cs++;
413  }
414
415  return 1;
416}
417
418
419/*
420 * Iterate over the keys, depth first, calling a function for each key
421 * and indicating if it is terminal or non-terminal and if it has values.
422 *
423 * In addition, for each value in the list, call a value list function
424 */
425
426static
427int nt_val_list_iterator(REGF *regf,  REG_KEY *key_tree, int bf, char *path,
428                         int terminal, const char* filter_prefix)
429{
430  int i;
431  VAL_LIST* val_list = key_tree->values;
432
433  if (str_is_prefix(filter_prefix, path))
434  { 
435    for (i=0; i<val_list->val_count; i++) 
436    {
437      /*XXX: print_key() is doing nothing right now, can probably be removed. */
438      if (!print_key(path, key_tree->name,
439                     key_tree->class_name,
440                     (key_tree->type == REG_ROOT_KEY),
441                     (key_tree->sub_keys == NULL),
442                     (key_tree->values?(key_tree->values->val_count):0),
443                     "\n") ||
444          !print_val(path, val_list->vals[i]->name,val_list->vals[i]->data_type,
445                     val_list->vals[i]->data_len, val_list->vals[i]->data_blk,
446                     terminal,
447                     (i == 0),
448                     (i == val_list->val_count)))
449      { return 0; }
450    }
451  }
452
453  return 1;
454}
455
456static
457int nt_key_list_iterator(REGF *regf, KEY_LIST *key_list, int bf, 
458                         const char *path, const char* filter_prefix)
459{
460  int i;
461
462  if (!key_list) 
463    return 1;
464
465  for (i=0; i < key_list->key_count; i++) 
466  {
467    if (!nt_key_iterator(regf, key_list->keys[i], bf, path, filter_prefix)) 
468      return 0;
469  }
470  return 1;
471}
472
473static
474int nt_key_iterator(REGF *regf, REG_KEY *key_tree, int bf, 
475                    const char *path, const char* filter_prefix)
476{
477  int path_len = strlen(path);
478  char *new_path;
479
480  if (!regf || !key_tree)
481    return -1;
482
483  /* List the key first, then the values, then the sub-keys */
484  /*printf("filter_prefix: %s, path: %s\n", filter_prefix, path);*/
485  if (str_is_prefix(filter_prefix, path))
486  {
487    /*XXX: print_key() is doing nothing right now, can probably be removed. */
488    if (!print_key(path, key_tree->name,
489                   key_tree->class_name,
490                   (key_tree->type == REG_ROOT_KEY),
491                   (key_tree->sub_keys == NULL),
492                   (key_tree->values?(key_tree->values->val_count):0),
493                   "\n"))
494    { return 0; }
495
496    /*
497     * If we have a security print routine, call it
498     * If the security print routine returns false, stop.
499     */
500    if (key_tree->security && !print_sec(key_tree->security->sec_desc))
501      return 0;
502  }
503
504  new_path = (char *)malloc(path_len + 1 + strlen(key_tree->name) + 1);
505  if (!new_path) 
506    return 0; /* Errors? */
507  new_path[0] = '\0';
508  strcat(new_path, path);
509  strcat(new_path, key_tree->name);
510  strcat(new_path, "\\");
511
512  /*
513   * Now, iterate through the values in the val_list
514   */
515  if (key_tree->values &&
516      !nt_val_list_iterator(regf, key_tree, bf, new_path, 
517                            (key_tree->values!=NULL), filter_prefix))
518  {
519    free(new_path);
520    return 0;
521  }
522
523  /*
524   * Now, iterate through the keys in the key list
525   */
526  if (key_tree->sub_keys && 
527      !nt_key_list_iterator(regf, key_tree->sub_keys, bf, 
528                            new_path, filter_prefix)) 
529  {
530    free(new_path);
531    return 0;
532  } 
533
534  free(new_path);
535  return 1;
536}
537
538
539/*
540 * Find key by name in a list ...
541 * Take the first component and search for that in the list
542 */
543static
544REG_KEY *nt_find_key_in_list_by_name(KEY_LIST *list, char *key)
545{
546  int i;
547  REG_KEY *res = NULL;
548
549  if (!list || !key || !*key) return NULL;
550
551  for (i = 0; i < list->key_count; i++)
552    if ((res = nt_find_key_by_name(list->keys[i], key)))
553      return res;
554 
555  return NULL;
556}
557
558
559/*
560 * Find key by name in a tree ... We will assume absolute names here, but we
561 * need the root of the tree ...
562 */
563static REG_KEY* nt_find_key_by_name(REG_KEY* tree, char* key)
564{
565  char* lname = NULL;
566  char* c1;
567  char* c2;
568  REG_KEY* tmp;
569
570  if (!tree || !key || !*key) 
571    return NULL;
572
573  lname = strdup(key);
574  if (!lname) 
575    return NULL;
576
577  /*
578   * Make sure that the first component is correct ...
579   */
580  c1 = lname;
581  c2 = strchr(c1, '\\');
582  if (c2) 
583  { /* Split here ... */
584    *c2 = 0;
585    c2++;
586  }
587 
588  if (strcmp(c1, tree->name) != 0) 
589  { 
590    if (lname)
591      free(lname);
592    return NULL;
593  }
594 
595  if (c2) 
596  {
597    tmp = nt_find_key_in_list_by_name(tree->sub_keys, c2);
598    free(lname);
599    return tmp;
600  }
601  else 
602  {
603    if (lname) 
604      free(lname);
605    return tree;
606  }
607
608  return NULL;
609}
610
611/* Make, delete keys */
612static
613int nt_delete_val_key(VAL_KEY *val_key)
614{
615
616  if (val_key) {
617    if (val_key->name) free(val_key->name);
618    if (val_key->data_blk) free(val_key->data_blk);
619    free(val_key);
620  };
621  return 1;
622}
623
624
625/*
626 * Add a key to the tree ... We walk down the components matching until
627 * we don't find any. There must be a match on the first component ...
628 * We return the key structure for the final component as that is
629 * often where we want to add values ...
630 */
631
632/*
633 * Convert a string of the form S-1-5-x[-y-z-r] to a SID
634 */
635/* MIGHT COME IN HANDY LATER.
636static
637int sid_string_to_sid(sid_t **sid, const char *sid_str)
638{
639  int i = 0;
640  unsigned int auth;
641  const char *lstr;
642
643  *sid = (sid_t *)malloc(sizeof(sid_t));
644  if (!*sid) return 0;
645
646  memset(*sid, 0, sizeof(sid_t));
647
648  if (strncmp(sid_str, "S-1-5", 5)) {
649    fprintf(stderr, "Does not conform to S-1-5...: %s\n", sid_str);
650    return 0;
651  }
652
653//We only allow strings of form S-1-5...
654
655  (*sid)->ver = 1;
656  (*sid)->auth[5] = 5;
657
658  lstr = sid_str + 5;
659
660  while (1)
661  {
662    if (!lstr || !lstr[0] || sscanf(lstr, "-%u", &auth) == 0)
663    {
664      if (i < 1)
665      {
666        fprintf(stderr, "Not of form -d-d...: %s, %u\n", lstr, i);
667        return 0;
668      }
669      (*sid)->auths=i;
670      return 1;
671    }
672
673    (*sid)->sub_auths[i] = auth;
674    i++;
675    lstr = strchr(lstr + 1, '-');
676  }
677
678  return 1;
679}
680*/
681
682
683/*
684 * We will implement inheritence that is based on what the parent's SEC_DESC
685 * says, but the Owner and Group SIDs can be overwridden from the command line
686 * and additional ACEs can be applied from the command line etc.
687 */
688static
689KEY_SEC_DESC *nt_inherit_security(REG_KEY *key)
690{
691
692  if (!key) return NULL;
693  return key->security;
694}
695
696/*
697 * Add a sub-key
698 */
699static
700REG_KEY *nt_add_reg_key_list(REGF *regf, REG_KEY *key, char * name, int create)
701{
702  int i;
703  REG_KEY *ret = NULL, *tmp = NULL;
704  KEY_LIST *list;
705  char *lname, *c1, *c2;
706
707  if (!key || !name || !*name) return NULL;
708 
709  list = key->sub_keys;
710  if (!list) { /* Create an empty list */
711
712    list = (KEY_LIST *)malloc(sizeof(KEY_LIST) + (REG_KEY_LIST_SIZE - 1) * sizeof(REG_KEY *));
713    list->key_count = 0;
714    list->max_keys = REG_KEY_LIST_SIZE;
715
716  }
717
718  lname = strdup(name);
719  if (!lname) return NULL;
720
721  c1 = lname;
722  c2 = strchr(c1, '\\');
723  if (c2) { /* Split here ... */
724    *c2 = 0;
725    c2++;
726  }
727
728  for (i = 0; i < list->key_count; i++) {
729    if (strcmp(list->keys[i]->name, c1) == 0) {
730      ret = nt_add_reg_key_list(regf, list->keys[i], c2, create);
731      free(lname);
732      return ret;
733    }
734  }
735
736  /*
737   * If we reach here we could not find the the first component
738   * so create it ...
739   */
740
741  if (list->key_count < list->max_keys){
742    list->key_count++;
743  }
744  else { /* Create more space in the list ... */
745    if (!(list = (KEY_LIST *)realloc(list, sizeof(KEY_LIST) + 
746                                     (list->max_keys + REG_KEY_LIST_SIZE - 1) 
747                                     * sizeof(REG_KEY *))))
748      goto error;
749
750    list->max_keys += REG_KEY_LIST_SIZE;
751    list->key_count++;
752  }
753
754  /*
755   * add the new key at the new slot
756   * FIXME: Sort the list someday
757   */
758
759  /*
760   * We want to create the key, and then do the rest
761   */
762
763  tmp = (REG_KEY *)malloc(sizeof(REG_KEY)); 
764
765  memset(tmp, 0, sizeof(REG_KEY));
766
767  tmp->name = strdup(c1);
768  if (!tmp->name) goto error;
769  tmp->owner = key;
770  tmp->type = REG_SUB_KEY;
771  /*
772   * Next, pull security from the parent, but override with
773   * anything passed in on the command line
774   */
775  tmp->security = nt_inherit_security(key);
776
777  list->keys[list->key_count - 1] = tmp;
778
779  if (c2) {
780    ret = nt_add_reg_key_list(regf, key, c2, True);
781  }
782
783  if (lname) free(lname);
784
785  return ret;
786
787 error:
788  if (tmp) free(tmp);
789  if (lname) free(lname);
790  return NULL;
791}
792
793
794/*
795 * Load and unload a registry file.
796 *
797 * Load, loads it into memory as a tree, while unload sealizes/flattens it
798 */
799
800/*
801 * Get the starting record for NT Registry file
802 */
803
804/*
805 * Where we keep all the regf stuff for one registry.
806 * This is the structure that we use to tie the in memory tree etc
807 * together. By keeping separate structs, we can operate on different
808 * registries at the same time.
809 * Currently, the SK_MAP is an array of mapping structure.
810 * Since we only need this on input and output, we fill in the structure
811 * as we go on input. On output, we know how many SK items we have, so
812 * we can allocate the structure as we need to.
813 * If you add stuff here that is dynamically allocated, add the
814 * appropriate free statements below.
815 */
816
817#define REGF_REGTYPE_NONE 0
818#define REGF_REGTYPE_NT   1
819#define REGF_REGTYPE_W9X  2
820
821#define TTTONTTIME(r, t1, t2) (r)->last_mod_time.low = (t1); \
822                              (r)->last_mod_time.high = (t2);
823
824#define REGF_HDR_BLKSIZ 0x1000
825
826#define OFF(f) ((f) + REGF_HDR_BLKSIZ + 4)
827#define LOCN(base, f) ((base) + OFF(f))
828
829const VAL_STR reg_type_names[] = {
830   { REG_TYPE_REGSZ,    "REG_SZ" },
831   { REG_TYPE_EXPANDSZ, "REG_EXPAND_SZ" },
832   { REG_TYPE_BIN,      "REG_BIN" },
833   { REG_TYPE_DWORD,    "REG_DWORD" },
834   { REG_TYPE_MULTISZ,  "REG_MULTI_SZ" },
835   { 0, NULL },
836};
837
838static
839const char *val_to_str(unsigned int val, const VAL_STR *val_array)
840{
841  int i = 0;
842
843  if (!val_array) return NULL;
844
845  while (val_array[i].val && val_array[i].str) {
846
847    if (val_array[i].val == val) return val_array[i].str;
848    i++;
849
850  }
851
852  return NULL;
853
854}
855
856/*
857 * Convert from UniCode to Ascii ... Does not take into account other lang
858 * Restrict by ascii_max if > 0
859 */
860static
861int uni_to_ascii(unsigned char *uni, unsigned char *ascii, int ascii_max, 
862                 int uni_max)
863{
864  int i = 0; 
865
866  while (i < ascii_max && (uni[i*2] || uni[i*2+1]))
867  {
868    if (uni_max > 0 && (i*2) >= uni_max) break;
869    ascii[i] = uni[i*2];
870    i++;
871  }
872  ascii[i] = '\0';
873
874  return i;
875}
876
877/*
878 * Convert a data value to a string for display
879 */
880static
881unsigned char* data_to_ascii(unsigned char *datap, int len, int type)
882{
883  unsigned char *asciip;
884  unsigned int i;
885  unsigned short num_nulls;
886  unsigned char* ascii;
887  unsigned char* cur_str;
888  unsigned int cur_str_len;
889  unsigned int ascii_max, cur_str_max;
890  unsigned int str_rem, cur_str_rem, alen;
891
892  switch (type) 
893  {
894  case REG_TYPE_REGSZ:
895    if (verbose)
896      fprintf(stderr, "Len: %d\n", len);
897
898    ascii_max = sizeof(char)*len;
899    ascii = malloc(ascii_max+4);
900    if(ascii == NULL)
901      return NULL;
902
903    /* FIXME. This has to be fixed. It has to be UNICODE */ 
904    uni_to_ascii(datap, ascii, len, ascii_max);
905    return ascii;
906    break;
907
908  case REG_TYPE_EXPANDSZ:
909    ascii_max = sizeof(char)*len;
910    ascii = malloc(ascii_max+2);
911    if(ascii == NULL)
912      return NULL;
913
914    uni_to_ascii(datap, ascii, len, ascii_max);
915    return ascii;
916    break;
917
918  case REG_TYPE_BIN:
919    ascii_max = sizeof(char)*len*3;
920    ascii = malloc(ascii_max+4);
921    if(ascii == NULL)
922      return NULL;
923
924    asciip = ascii;
925    for (i=0; (i<len)&&(i+1)*3<ascii_max; i++) { 
926      int str_rem = ascii_max - ((int)asciip - (int)ascii);
927      asciip += snprintf((char*)asciip, str_rem, "%02x", 
928                         *(unsigned char *)(datap+i));
929      if (i < len && str_rem > 0)
930        *asciip = ' '; asciip++;       
931    }
932    *asciip = '\0';
933    return ascii;
934    break;
935
936  case REG_TYPE_DWORD:
937    ascii_max = sizeof(char)*10;
938    ascii = malloc(ascii_max+1);
939    if(ascii == NULL)
940      return NULL;
941
942    if (*(int *)datap == 0)
943      snprintf((char*)ascii, ascii_max, "0");
944    else
945      snprintf((char*)ascii, ascii_max, "0x%x", *(int *)datap);
946    return ascii;
947    break;
948
949  case REG_TYPE_MULTISZ:
950    ascii_max = sizeof(char)*len*4;
951    cur_str_max = sizeof(char)*len+1;
952    cur_str = malloc(cur_str_max);
953    ascii = malloc(ascii_max+4);
954    if(ascii == NULL)
955      return NULL;
956
957    /* Reads until it reaches 4 consecutive NULLs,
958     * which is two nulls in unicode, or until it reaches len, or until we
959     * run out of buffer.  The latter should never happen, but we shouldn't
960     * trust our file to have the right lengths/delimiters.
961     */
962    asciip = ascii;
963    num_nulls = 0;
964    str_rem = ascii_max;
965    cur_str_rem = cur_str_max;
966    cur_str_len = 0;
967
968    *asciip = '"';
969    asciip +=1;
970   
971    for(i=0; (i < len) && str_rem > 0; i++)
972    {
973      *(cur_str+cur_str_len) = *(datap+i);
974      if(*(cur_str+cur_str_len) == 0)
975        num_nulls++;
976      else
977        num_nulls = 0;
978      cur_str_len++;
979
980      if(num_nulls == 2)
981      {
982        uni_to_ascii(cur_str, asciip, str_rem, 0);
983        alen = strlen((char*)asciip);
984        asciip += alen;
985        str_rem -= alen;
986        if(*(datap+i+1) == 0 && *(datap+i+2) == 0)
987          break;
988        else
989        {
990          alen = snprintf((char*)asciip, str_rem, "%s", "\" \"");
991          asciip += alen;
992          str_rem -= alen;
993          memset(cur_str, 0, cur_str_max);
994          cur_str_len = 0;
995          num_nulls = 0;
996          /* To eliminate leading nulls in subsequent strings. */
997          i++;
998        }
999      }
1000    }
1001    snprintf((char*)asciip, str_rem, "%s", "\"");
1002    return ascii;
1003    break;
1004
1005  default:
1006    return NULL;
1007    break;
1008  } 
1009
1010  return NULL;
1011}
1012
1013static
1014REG_KEY *nt_get_key_tree(REGF *regf, NK_HDR *nk_hdr, int size, REG_KEY *parent);
1015
1016static
1017int nt_set_regf_input_file(REGF *regf, char *filename)
1018{
1019  return ((regf->regfile_name = strdup(filename)) != NULL); 
1020}
1021
1022
1023/* Create a regf structure and init it */
1024
1025static
1026REGF *nt_create_regf(void)
1027{
1028  REGF *tmp = (REGF *)malloc(sizeof(REGF));
1029  if (!tmp) return tmp;
1030  memset(tmp, 0, sizeof(REGF));
1031  tmp->owner_sid_str = def_owner_sid_str;
1032  return tmp;
1033} 
1034
1035
1036/* Get the header of the registry. Return a pointer to the structure
1037 * If the mmap'd area has not been allocated, then mmap the input file
1038 */
1039static
1040REGF_HDR *nt_get_regf_hdr(REGF *regf)
1041{
1042  if (!regf)
1043    return NULL; /* What about errors */
1044
1045  if (!regf->regfile_name)
1046    return NULL; /* What about errors */
1047
1048  if (!regf->base) { /* Try to mmap etc the file */
1049
1050    if ((regf->fd = open(regf->regfile_name, O_RDONLY, 0000)) <0) {
1051      return NULL; /* What about errors? */
1052    }
1053
1054    if (fstat(regf->fd, &regf->sbuf) < 0) {
1055      return NULL;
1056    }
1057
1058    regf->base = mmap(0, regf->sbuf.st_size, PROT_READ, MAP_SHARED, regf->fd, 0);
1059
1060    if ((int)regf->base == 1) {
1061      fprintf(stderr, "Could not mmap file: %s, %s\n", regf->regfile_name,
1062              strerror(errno));
1063      return NULL;
1064    }
1065  }
1066
1067  /*
1068   * At this point, regf->base != NULL, and we should be able to read the
1069   * header
1070   */
1071
1072  assert(regf->base != NULL);
1073
1074  return (REGF_HDR *)regf->base;
1075}
1076
1077/*
1078 * Validate a regf header
1079 * For now, do nothing, but we should check the checksum
1080 */
1081static
1082int valid_regf_hdr(REGF_HDR *regf_hdr)
1083{
1084  if (!regf_hdr) return 0;
1085
1086  return 1;
1087}
1088
1089/*
1090 * Process an SK header ...
1091 * Every time we see a new one, add it to the map. Otherwise, just look it up.
1092 * We will do a simple linear search for the moment, since many KEYs have the
1093 * same security descriptor.
1094 * We allocate the map in increments of 10 entries.
1095 */
1096
1097/*
1098 * Create a new entry in the map, and increase the size of the map if needed
1099 */
1100static
1101SK_MAP *alloc_sk_map_entry(REGF *regf, KEY_SEC_DESC *tmp, int sk_off)
1102{
1103 if (!regf->sk_map) { /* Allocate a block of 10 */
1104    regf->sk_map = (SK_MAP *)malloc(sizeof(SK_MAP) * 10);
1105    if (!regf->sk_map) {
1106      free(tmp);
1107      return NULL;
1108    }
1109    regf->sk_map_size = 10;
1110    regf->sk_count = 1;
1111    (regf->sk_map)[0].sk_off = sk_off;
1112    (regf->sk_map)[0].key_sec_desc = tmp;
1113  }
1114  else { /* Simply allocate a new slot, unless we have to expand the list */ 
1115    int ndx = regf->sk_count;
1116    if (regf->sk_count >= regf->sk_map_size) {
1117      regf->sk_map = (SK_MAP *)realloc(regf->sk_map, 
1118                                       (regf->sk_map_size + 10)*sizeof(SK_MAP));
1119      if (!regf->sk_map) {
1120        free(tmp);
1121        return NULL;
1122      }
1123      /*
1124       * ndx already points at the first entry of the new block
1125       */
1126      regf->sk_map_size += 10;
1127    }
1128    (regf->sk_map)[ndx].sk_off = sk_off;
1129    (regf->sk_map)[ndx].key_sec_desc = tmp;
1130    regf->sk_count++;
1131  }
1132 return regf->sk_map;
1133}
1134
1135/*
1136 * Search for a KEY_SEC_DESC in the sk_map, but don't create one if not
1137 * found
1138 */
1139static
1140KEY_SEC_DESC *lookup_sec_key(SK_MAP *sk_map, int count, int sk_off)
1141{
1142  int i;
1143
1144  if (!sk_map) return NULL;
1145
1146  for (i = 0; i < count; i++) {
1147
1148    if (sk_map[i].sk_off == sk_off)
1149      return sk_map[i].key_sec_desc;
1150
1151  }
1152
1153  return NULL;
1154
1155}
1156
1157/*
1158 * Allocate a KEY_SEC_DESC if we can't find one in the map
1159 */
1160static
1161KEY_SEC_DESC *lookup_create_sec_key(REGF *regf, SK_MAP *sk_map, int sk_off)
1162{
1163  KEY_SEC_DESC *tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off);
1164
1165  if (tmp) {
1166    return tmp;
1167  }
1168  else { /* Allocate a new one */
1169    tmp = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC));
1170    if (!tmp) {
1171      return NULL;
1172    }
1173    memset(tmp, 0, sizeof(KEY_SEC_DESC)); /* Neatly sets offset to 0 */
1174    tmp->state = SEC_DESC_RES;
1175    if (!alloc_sk_map_entry(regf, tmp, sk_off)) {
1176      return NULL;
1177    }
1178    return tmp;
1179  }
1180}
1181
1182/*
1183 * Allocate storage and duplicate a SID
1184 * We could allocate the SID to be only the size needed, but I am too lazy.
1185 */
1186static
1187sid_t *dup_sid(sid_t *sid)
1188{
1189  sid_t *tmp = (sid_t *)malloc(sizeof(sid_t));
1190  int i;
1191 
1192  if (!tmp) return NULL;
1193  tmp->ver = sid->ver;
1194  tmp->auths = sid->auths;
1195  for (i=0; i<6; i++) {
1196    tmp->auth[i] = sid->auth[i];
1197  }
1198  for (i=0; i<tmp->auths&&i<MAXSUBAUTHS; i++) {
1199    tmp->sub_auths[i] = sid->sub_auths[i];
1200  }
1201  return tmp;
1202}
1203
1204/*
1205 * Allocate space for an ACE and duplicate the registry encoded one passed in
1206 */
1207static
1208ACE *dup_ace(REG_ACE *ace)
1209{
1210  ACE *tmp = NULL; 
1211
1212  tmp = (ACE *)malloc(sizeof(ACE));
1213
1214  if (!tmp) return NULL;
1215
1216  tmp->type = CVAL(&ace->type);
1217  tmp->flags = CVAL(&ace->flags);
1218  tmp->perms = IVAL(&ace->perms);
1219  tmp->trustee = dup_sid(&ace->trustee);
1220  return tmp;
1221}
1222
1223/*
1224 * Allocate space for an ACL and duplicate the registry encoded one passed in
1225 */
1226static
1227ACL *dup_acl(REG_ACL *acl)
1228{
1229  ACL *tmp = NULL;
1230  REG_ACE* ace;
1231  int i, num_aces;
1232
1233  num_aces = IVAL(&acl->num_aces);
1234
1235  tmp = (ACL *)malloc(sizeof(ACL) + (num_aces - 1)*sizeof(ACE *));
1236  if (!tmp) return NULL;
1237
1238  tmp->num_aces = num_aces;
1239  tmp->refcnt = 1;
1240  tmp->rev = SVAL(&acl->rev);
1241  if (verbose) fprintf(stdout, "ACL: refcnt: %u, rev: %u\n", tmp->refcnt, 
1242                       tmp->rev);
1243  ace = (REG_ACE *)&acl->aces;
1244  for (i=0; i<num_aces; i++) {
1245    tmp->aces[i] = dup_ace(ace);
1246    ace = (REG_ACE *)((char *)ace + SVAL(&ace->length));
1247    /* XXX: FIXME, should handle malloc errors */
1248  }
1249
1250  return tmp;
1251}
1252
1253static
1254SEC_DESC *process_sec_desc(REGF *regf, REG_SEC_DESC *sec_desc)
1255{
1256  SEC_DESC *tmp = NULL;
1257 
1258  tmp = (SEC_DESC *)malloc(sizeof(SEC_DESC));
1259
1260  if (!tmp) {
1261    return NULL;
1262  }
1263 
1264  tmp->rev = SVAL(&sec_desc->rev);
1265  tmp->type = SVAL(&sec_desc->type);
1266  if (verbose) fprintf(stdout, "SEC_DESC Rev: %0X, Type: %0X\n", 
1267                       tmp->rev, tmp->type);
1268  if (verbose) fprintf(stdout, "SEC_DESC Owner Off: %0X\n",
1269                       IVAL(&sec_desc->owner_off));
1270  if (verbose) fprintf(stdout, "SEC_DESC Group Off: %0X\n",
1271                       IVAL(&sec_desc->group_off));
1272  if (verbose) fprintf(stdout, "SEC_DESC DACL Off: %0X\n",
1273                       IVAL(&sec_desc->dacl_off));
1274  tmp->owner = dup_sid((sid_t *)((char *)sec_desc + IVAL(&sec_desc->owner_off)));
1275  if (!tmp->owner) {
1276    free(tmp);
1277    return NULL;
1278  }
1279  tmp->group = dup_sid((sid_t *)((char *)sec_desc + IVAL(&sec_desc->group_off)));
1280  if (!tmp->group) {
1281    free(tmp);
1282    return NULL;
1283  }
1284
1285  /* Now pick up the SACL and DACL */
1286
1287  if (sec_desc->sacl_off)
1288    tmp->sacl = dup_acl((REG_ACL *)((char *)sec_desc + IVAL(&sec_desc->sacl_off)));
1289  else
1290    tmp->sacl = NULL;
1291
1292  if (sec_desc->dacl_off)
1293    tmp->dacl = dup_acl((REG_ACL *)((char *)sec_desc + IVAL(&sec_desc->dacl_off)));
1294  else
1295    tmp->dacl = NULL;
1296
1297  return tmp;
1298}
1299
1300static
1301KEY_SEC_DESC *process_sk(REGF *regf, SK_HDR *sk_hdr, int sk_off, int size)
1302{
1303  KEY_SEC_DESC *tmp = NULL;
1304  int sk_next_off, sk_prev_off, sk_size;
1305  REG_SEC_DESC *sec_desc;
1306
1307  if (!sk_hdr) return NULL;
1308
1309  if (SVAL(&sk_hdr->SK_ID) != REG_SK_ID) {
1310    fprintf(stderr, "Unrecognized SK Header ID: %08X, %s\n", (int)sk_hdr,
1311            regf->regfile_name);
1312    return NULL;
1313  }
1314
1315  if (-size < (sk_size = IVAL(&sk_hdr->rec_size))) {
1316    fprintf(stderr, "Incorrect SK record size: %d vs %d. %s\n",
1317            -size, sk_size, regf->regfile_name);
1318    return NULL;
1319  }
1320
1321  /*
1322   * Now, we need to look up the SK Record in the map, and return it
1323   * Since the map contains the SK_OFF mapped to KEY_SEC_DESC, we can
1324   * use that
1325   */
1326
1327  if (regf->sk_map &&
1328      ((tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off)) != NULL)
1329      && (tmp->state == SEC_DESC_OCU)) {
1330    tmp->ref_cnt++;
1331    return tmp;
1332  }
1333
1334  /* Here, we have an item in the map that has been reserved, or tmp==NULL. */
1335
1336  assert(tmp == NULL || (tmp && tmp->state != SEC_DESC_NON));
1337
1338  /*
1339   * Now, allocate a KEY_SEC_DESC, and parse the structure here, and add the
1340   * new KEY_SEC_DESC to the mapping structure, since the offset supplied is
1341   * the actual offset of structure. The same offset will be used by
1342   * all future references to this structure
1343   * We could put all this unpleasantness in a function.
1344   */
1345
1346  if (!tmp) {
1347    tmp = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC));
1348    if (!tmp) return NULL;
1349    memset(tmp, 0, sizeof(KEY_SEC_DESC));
1350   
1351    /*
1352     * Allocate an entry in the SK_MAP ...
1353     * We don't need to free tmp, because that is done for us if the
1354     * sm_map entry can't be expanded when we need more space in the map.
1355     */
1356   
1357    if (!alloc_sk_map_entry(regf, tmp, sk_off)) {
1358      return NULL;
1359    }
1360  }
1361
1362  tmp->ref_cnt++;
1363  tmp->state = SEC_DESC_OCU;
1364
1365  /*
1366   * Now, process the actual sec desc and plug the values in
1367   */
1368
1369  sec_desc = (REG_SEC_DESC *)&sk_hdr->sec_desc[0];
1370  tmp->sec_desc = process_sec_desc(regf, sec_desc);
1371
1372  /*
1373   * Now forward and back links. Here we allocate an entry in the sk_map
1374   * if it does not exist, and mark it reserved
1375   */
1376
1377  sk_prev_off = IVAL(&sk_hdr->prev_off);
1378  tmp->prev = lookup_create_sec_key(regf, regf->sk_map, sk_prev_off);
1379  assert(tmp->prev != NULL);
1380  sk_next_off = IVAL(&sk_hdr->next_off);
1381  tmp->next = lookup_create_sec_key(regf, regf->sk_map, sk_next_off);
1382  assert(tmp->next != NULL);
1383
1384  return tmp;
1385}
1386
1387/*
1388 * Process a VK header and return a value
1389 */
1390static
1391VAL_KEY *process_vk(REGF *regf, VK_HDR *vk_hdr, int size)
1392{
1393  char val_name[1024];
1394  int nam_len, dat_len, flag, dat_type, dat_off, vk_id;
1395  const char *val_type;
1396  VAL_KEY *tmp = NULL; 
1397
1398  if (!vk_hdr) return NULL;
1399
1400  if ((vk_id = SVAL(&vk_hdr->VK_ID)) != REG_VK_ID) {
1401    fprintf(stderr, "Unrecognized VK header ID: %0X, block: %0X, %s\n",
1402            vk_id, (int)vk_hdr, regf->regfile_name);
1403    return NULL;
1404  }
1405
1406  nam_len = SVAL(&vk_hdr->nam_len);
1407  val_name[nam_len] = '\0';
1408  flag = SVAL(&vk_hdr->flag);
1409  dat_type = IVAL(&vk_hdr->dat_type);
1410  dat_len = IVAL(&vk_hdr->dat_len);  /* If top bit, offset contains data */
1411  dat_off = IVAL(&vk_hdr->dat_off);
1412
1413  tmp = (VAL_KEY *)malloc(sizeof(VAL_KEY));
1414  if (!tmp) {
1415    goto error;
1416  }
1417  memset(tmp, 0, sizeof(VAL_KEY));
1418  tmp->has_name = flag;
1419  tmp->data_type = dat_type;
1420
1421  if (flag & 0x01) {
1422    strncpy(val_name, vk_hdr->dat_name, nam_len);
1423    tmp->name = strdup(val_name);
1424    if (!tmp->name) {
1425      goto error;
1426    }
1427  }
1428  else
1429    strncpy(val_name, "<No Name>", 10);
1430
1431  /*
1432   * Allocate space and copy the data as a BLOB
1433   */
1434
1435  if (dat_len) {
1436   
1437    char *dtmp = (char *)malloc(dat_len&0x7FFFFFFF);
1438   
1439    if (!dtmp) {
1440      goto error;
1441    }
1442
1443    tmp->data_blk = dtmp;
1444
1445    if ((dat_len&0x80000000) == 0) 
1446    { /* The data is pointed to by the offset */
1447      char *dat_ptr = LOCN(regf->base, dat_off);
1448      /* XXX: replace with memcpy */
1449      bcopy(dat_ptr, dtmp, dat_len);
1450    }
1451    else { /* The data is in the offset or type */
1452      /*
1453       * FIXME.
1454       * Some registry files seem to have wierd fields. If top bit is set,
1455       * but len is 0, the type seems to be the value ...
1456       * Not sure how to handle this last type for the moment ...
1457       */
1458      dat_len = dat_len & 0x7FFFFFFF;
1459      /* XXX: replace with memcpy */
1460      bcopy(&dat_off, dtmp, dat_len);
1461    }
1462
1463    tmp->data_len = dat_len;
1464  }
1465
1466  val_type = val_to_str(dat_type, reg_type_names);
1467
1468  /*
1469   * We need to save the data area as well
1470   */
1471  if (verbose) 
1472    fprintf(stdout, "  %s : %s : \n", val_name, val_type);
1473
1474  return tmp;
1475
1476 error:
1477  if (tmp) nt_delete_val_key(tmp);
1478  return NULL;
1479
1480}
1481
1482/*
1483 * Process a VL Header and return a list of values
1484 */
1485static
1486VAL_LIST *process_vl(REGF *regf, VL_TYPE vl, int count, int size)
1487{
1488  int i, vk_off;
1489  VK_HDR *vk_hdr;
1490  VAL_LIST *tmp = NULL;
1491
1492  if (!vl) return NULL;
1493
1494  if (-size < (count+1)*sizeof(int)){
1495    fprintf(stderr, "Error in VL header format. Size less than space required. %d\n", -size);
1496    return NULL;
1497  }
1498
1499  tmp = (VAL_LIST *)malloc(sizeof(VAL_LIST) + (count - 1) * sizeof(VAL_KEY *));
1500  if (!tmp) {
1501    goto error;
1502  }
1503
1504  for (i=0; i<count; i++) {
1505    vk_off = IVAL(&vl[i]);
1506    vk_hdr = (VK_HDR *)LOCN(regf->base, vk_off);
1507    tmp->vals[i] = process_vk(regf, vk_hdr, BLK_SIZE(vk_hdr));
1508    if (!tmp->vals[i]){
1509      goto error;
1510    }
1511  }
1512
1513  tmp->val_count = count;
1514  tmp->max_vals = count;
1515
1516  return tmp;
1517
1518 error:
1519  /* XXX: FIXME, free the partially allocated structure */
1520  return NULL;
1521} 
1522
1523/*
1524 * Process an LF Header and return a list of sub-keys
1525 */
1526static
1527KEY_LIST *process_lf(REGF *regf, LF_HDR *lf_hdr, int size, REG_KEY *parent)
1528{
1529  int count, i, nk_off;
1530  unsigned int lf_id;
1531  KEY_LIST *tmp;
1532
1533  if (!lf_hdr) return NULL;
1534
1535  if ((lf_id = SVAL(&lf_hdr->LF_ID)) != REG_LF_ID) {
1536    fprintf(stderr, "Unrecognized LF Header format: %0X, Block: %0X, %s.\n",
1537            lf_id, (int)lf_hdr, regf->regfile_name);
1538    return NULL;
1539  }
1540
1541  assert(size < 0);
1542
1543  count = SVAL(&lf_hdr->key_count);
1544  if (verbose) 
1545    fprintf(stdout, "Key Count: %u\n", count);
1546  if (count <= 0) return NULL;
1547
1548  /* Now, we should allocate a KEY_LIST struct and fill it in ... */
1549
1550  tmp = (KEY_LIST *)malloc(sizeof(KEY_LIST) + (count - 1) * sizeof(REG_KEY *));
1551  if (!tmp) {
1552    goto error;
1553  }
1554
1555  tmp->key_count = count;
1556  tmp->max_keys = count;
1557
1558  for (i=0; i<count; i++) {
1559    NK_HDR *nk_hdr;
1560
1561    nk_off = IVAL(&lf_hdr->hr[i].nk_off);
1562    if (verbose) 
1563      fprintf(stdout, "NK Offset: %0X\n", nk_off);
1564    nk_hdr = (NK_HDR *)LOCN(regf->base, nk_off);
1565    tmp->keys[i] = nt_get_key_tree(regf, nk_hdr, BLK_SIZE(nk_hdr), parent);
1566    if (!tmp->keys[i]) {
1567      goto error;
1568    }
1569  }
1570
1571  return tmp;
1572
1573 error:
1574  /*if (tmp) nt_delete_key_list(tmp, False);*/
1575  return NULL;
1576}
1577
1578
1579/*
1580 * This routine is passed an NK_HDR pointer and retrieves the entire tree
1581 * from there down. It returns a REG_KEY *.
1582 */
1583static
1584REG_KEY *nt_get_key_tree(REGF *regf, NK_HDR *nk_hdr, int size, REG_KEY *parent)
1585{
1586  REG_KEY *tmp = NULL, *own;
1587  int name_len, clsname_len, lf_off, val_off, val_count, sk_off, own_off;
1588  unsigned int nk_id;
1589  LF_HDR *lf_hdr;
1590  VL_TYPE *vl;
1591  SK_HDR *sk_hdr;
1592  char key_name[1024];
1593  unsigned char cls_name[1024];
1594
1595  if (!nk_hdr) return NULL;
1596
1597  if ((nk_id = SVAL(&nk_hdr->NK_ID)) != REG_NK_ID) {
1598    fprintf(stderr, "Unrecognized NK Header format: %08X, Block: %0X. %s\n", 
1599            nk_id, (int)nk_hdr, regf->regfile_name);
1600    return NULL;
1601  }
1602
1603  assert(size < 0);
1604
1605  name_len = SVAL(&nk_hdr->nam_len);
1606  clsname_len = SVAL(&nk_hdr->clsnam_len);
1607
1608  /*
1609   * The value of -size should be ge
1610   * (sizeof(NK_HDR) - 1 + name_len)
1611   * The -1 accounts for the fact that we included the first byte of
1612   * the name in the structure. clsname_len is the length of the thing
1613   * pointed to by clsnam_off
1614   */
1615
1616  if (-size < (sizeof(NK_HDR) - 1 + name_len)) {
1617    fprintf(stderr, "Incorrect NK_HDR size: %d, %0X\n", -size, (int)nk_hdr);
1618    fprintf(stderr, "Sizeof NK_HDR: %d, name_len %d, clsname_len %d\n",
1619            sizeof(NK_HDR), name_len, clsname_len);
1620    /*return NULL;*/
1621  }
1622
1623  if (verbose) fprintf(stdout, "NK HDR: Name len: %d, class name len: %d\n", 
1624                       name_len, clsname_len);
1625
1626  /* Fish out the key name and process the LF list */
1627
1628  assert(name_len < sizeof(key_name));
1629
1630  /* Allocate the key struct now */
1631  tmp = (REG_KEY *)malloc(sizeof(REG_KEY));
1632  if (!tmp) return tmp;
1633  memset(tmp, 0, sizeof(REG_KEY));
1634
1635  tmp->type = (SVAL(&nk_hdr->type)==0x2C?REG_ROOT_KEY:REG_SUB_KEY);
1636 
1637  strncpy(key_name, nk_hdr->key_nam, name_len);
1638  key_name[name_len] = '\0';
1639
1640  if (verbose) fprintf(stdout, "Key name: %s\n", key_name);
1641
1642  tmp->name = strdup(key_name);
1643  if (!tmp->name) {
1644    goto error;
1645  }
1646
1647  /*
1648   * Fish out the class name, it is in UNICODE, while the key name is
1649   * ASCII :-)
1650   */
1651
1652  if (clsname_len) 
1653  { /* Just print in Ascii for now */
1654    unsigned char *clsnamep;
1655    unsigned int clsnam_off;
1656
1657    clsnam_off = IVAL(&nk_hdr->clsnam_off);
1658    clsnamep = (unsigned char*)LOCN(regf->base, clsnam_off);
1659    if (verbose) fprintf(stdout, "Class Name Offset: %0X\n", clsnam_off);
1660 
1661    memset(cls_name, 0, clsname_len);
1662    uni_to_ascii(clsnamep, cls_name, sizeof(cls_name), clsname_len);
1663   
1664    /*
1665     * I am keeping class name as an ascii string for the moment.
1666     * That means it needs to be converted on output.
1667     * It will also piss off people who need Unicode/UTF-8 strings. Sorry.
1668     * XXX: FIXME
1669     */
1670    tmp->class_name = strdup((char*)cls_name);
1671    if (!tmp->class_name) {
1672      goto error;
1673    }
1674
1675    if (verbose) fprintf(stdout, "  Class Name: %s\n", cls_name);
1676
1677  }
1678
1679  /*
1680   * Process the owner offset ...
1681   */
1682  own_off = IVAL(&nk_hdr->own_off);
1683  own = (REG_KEY *)LOCN(regf->base, own_off);
1684  if (verbose) 
1685    fprintf(stdout, "Owner Offset: %0X\n", own_off);
1686
1687  if (verbose) 
1688    fprintf(stdout, "  Owner locn: %0X, Our locn: %0X\n", 
1689                       (unsigned int)own, (unsigned int)nk_hdr);
1690
1691  /*
1692   * We should verify that the owner field is correct ...
1693   * for now, we don't worry ...
1694   */
1695  tmp->owner = parent;
1696
1697  /*
1698   * If there are any values, process them here
1699   */
1700
1701  val_count = IVAL(&nk_hdr->val_cnt);
1702  if (verbose) 
1703    fprintf(stdout, "Val Count: %d\n", val_count);
1704  if (val_count) 
1705  {
1706    val_off = IVAL(&nk_hdr->val_off);
1707    vl = (VL_TYPE *)LOCN(regf->base, val_off);
1708    if (verbose) 
1709      fprintf(stdout, "Val List Offset: %0X\n", val_off);
1710
1711    tmp->values = process_vl(regf, *vl, val_count, BLK_SIZE(vl));
1712    if (!tmp->values) {
1713      goto error;
1714    }
1715
1716  }
1717
1718  /*
1719   * Also handle the SK header ...
1720   */
1721
1722  sk_off = IVAL(&nk_hdr->sk_off);
1723  sk_hdr = (SK_HDR *)LOCN(regf->base, sk_off);
1724  if (verbose) 
1725    fprintf(stdout, "SK Offset: %0X\n", sk_off);
1726
1727  if (sk_off != -1) {
1728
1729    tmp->security = process_sk(regf, sk_hdr, sk_off, BLK_SIZE(sk_hdr));
1730
1731  } 
1732
1733  lf_off = IVAL(&nk_hdr->lf_off);
1734  if (verbose) 
1735    fprintf(stdout, "SubKey list offset: %0X\n", lf_off);
1736
1737  /*
1738   * No more subkeys if lf_off == -1
1739   */
1740  if (lf_off != -1) 
1741  {
1742    lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off);
1743   
1744    tmp->sub_keys = process_lf(regf, lf_hdr, BLK_SIZE(lf_hdr), tmp);
1745    if (!tmp->sub_keys)
1746      goto error;
1747  }
1748
1749  return tmp;
1750
1751 error:
1752  /*if (tmp) nt_delete_reg_key(tmp, False);*/
1753  return NULL;
1754}
1755
1756static
1757int nt_load_registry(REGF *regf)
1758{
1759  REGF_HDR *regf_hdr;
1760  unsigned int regf_id, hbin_id;
1761  HBIN_HDR *hbin_hdr;
1762  NK_HDR *first_key;
1763
1764  /* Get the header */
1765
1766  if ((regf_hdr = nt_get_regf_hdr(regf)) == NULL) {
1767    return -1;
1768  }
1769
1770  /* Now process that header and start to read the rest in */
1771
1772  if ((regf_id = IVAL(&regf_hdr->REGF_ID)) != REG_REGF_ID) {
1773    fprintf(stderr, "Unrecognized NT registry header id: %0X, %s\n",
1774            regf_id, regf->regfile_name);
1775    return -1;
1776  }
1777
1778  /*
1779   * Validate the header ...
1780   */
1781  if (!valid_regf_hdr(regf_hdr)) {
1782    fprintf(stderr, "Registry file header does not validate: %s\n",
1783            regf->regfile_name);
1784    return -1;
1785  }
1786
1787  /* Update the last mod date, and then go get the first NK record and on */
1788
1789  TTTONTTIME(regf, IVAL(&regf_hdr->tim1), IVAL(&regf_hdr->tim2));
1790
1791  /*
1792   * The hbin hdr seems to be just uninteresting garbage. Check that
1793   * it is there, but that is all.
1794   */
1795
1796  hbin_hdr = (HBIN_HDR *)(regf->base + REGF_HDR_BLKSIZ);
1797
1798  if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID)) != REG_HBIN_ID) {
1799    fprintf(stderr, "Unrecognized registry hbin hdr ID: %0X, %s\n", 
1800            hbin_id, regf->regfile_name);
1801    return -1;
1802  } 
1803
1804  /*
1805   * Get a pointer to the first key from the hreg_hdr
1806   */
1807
1808  if (verbose) 
1809    fprintf(stdout, "First Key: %0X\n", IVAL(&regf_hdr->first_key));
1810
1811  first_key = (NK_HDR *)LOCN(regf->base, IVAL(&regf_hdr->first_key));
1812  if (verbose) fprintf(stdout, "First Key Offset: %0X\n", 
1813                       IVAL(&regf_hdr->first_key));
1814
1815  if (verbose) fprintf(stdout, "Data Block Size: %d\n",
1816                       IVAL(&regf_hdr->dblk_size));
1817
1818  if (verbose) fprintf(stdout, "Offset to next hbin block: %0X\n",
1819                       IVAL(&hbin_hdr->off_to_next));
1820
1821  if (verbose) fprintf(stdout, "HBIN block size: %0X\n",
1822                       IVAL(&hbin_hdr->blk_size));
1823
1824  /*
1825   * Now, get the registry tree by processing that NK recursively
1826   */
1827
1828  regf->root = nt_get_key_tree(regf, first_key, BLK_SIZE(first_key), NULL);
1829
1830  assert(regf->root != NULL);
1831
1832  /*
1833   * Unmap the registry file, as we might want to read in another
1834   * tree etc.
1835   */
1836
1837  if (regf->base) munmap(regf->base, regf->sbuf.st_size);
1838  regf->base = NULL;
1839  close(regf->fd);    /* Ignore the error :-) */
1840
1841  return 1;
1842}
1843
1844
1845/*
1846 * Routines to parse a REGEDIT4 file
1847 *
1848 * The file consists of:
1849 *
1850 * REGEDIT4
1851 * \[[-]key-path\]\n
1852 * <value-spec>*
1853 *
1854 * Format:
1855 * [cmd:]name=type:value
1856 *
1857 * cmd = a|d|c|add|delete|change|as|ds|cs
1858 *
1859 * There can be more than one key-path and value-spec.
1860 *
1861 * Since we want to support more than one type of file format, we
1862 * construct a command-file structure that keeps info about the command file
1863 */
1864
1865#define FMT_UNREC -1
1866#define FMT_REGEDIT4 0
1867#define FMT_EDITREG1_1 1
1868
1869#define FMT_STRING_REGEDIT4 "REGEDIT4"
1870#define FMT_STRING_EDITREG1_0 "EDITREG1.0"
1871
1872#define CMD_NONE     0
1873#define CMD_ADD_KEY  1
1874#define CMD_DEL_KEY  2
1875
1876#define CMD_KEY 1
1877#define CMD_VAL 2
1878
1879typedef struct val_spec_list {
1880  struct val_spec_list *next;
1881  char *name;
1882  int type;
1883  char *val;    /* Kept as a char string, really? */
1884} VAL_SPEC_LIST;
1885
1886typedef struct command_s {
1887  int cmd;
1888  char *key;
1889  int val_count;
1890  VAL_SPEC_LIST *val_spec_list, *val_spec_last;
1891} CMD;
1892
1893typedef struct cmd_line {
1894  int len, line_len;
1895  char *line;
1896} CMD_LINE;
1897
1898
1899
1900#define INIT_ALLOC 10
1901
1902
1903/* prints a key */
1904static
1905int print_key(const char *path, char *name, char *class_name, int root, 
1906              int terminal, int vals, char* newline)
1907{
1908  if (full_print)
1909    fprintf(stdout, "%s%s\\%s", path, name, newline);
1910
1911  return 1;
1912}
1913
1914/*
1915 * Sec Desc print functions
1916 */
1917static
1918void print_type(unsigned char type)
1919{
1920  switch (type) {
1921  case 0x00:
1922    fprintf(stdout, "    ALLOW");
1923    break;
1924  case 0x01:
1925    fprintf(stdout, "     DENY");
1926    break;
1927  case 0x02:
1928    fprintf(stdout, "    AUDIT");
1929    break;
1930  case 0x03:
1931    fprintf(stdout, "    ALARM");
1932    break;
1933  case 0x04:
1934    fprintf(stdout, "ALLOW CPD");
1935    break;
1936  case 0x05:
1937    fprintf(stdout, "OBJ ALLOW");
1938    break;
1939  case 0x06:
1940    fprintf(stdout, " OBJ DENY");
1941    break;
1942  default:
1943    fprintf(stdout, "  UNKNOWN");
1944    break;
1945  }
1946}
1947
1948static
1949void print_flags(unsigned char flags)
1950{
1951  char flg_output[21];
1952  int some = 0;
1953
1954  flg_output[0] = 0;
1955  if (!flags) {
1956    fprintf(stdout, "         ");
1957    return;
1958  }
1959  if (flags & 0x01) {
1960    if (some) strcat(flg_output, ",");
1961    some = 1;
1962    strcat(flg_output, "OI");
1963  }
1964  if (flags & 0x02) {
1965    if (some) strcat(flg_output, ",");
1966    some = 1;
1967    strcat(flg_output, "CI");
1968  }
1969  if (flags & 0x04) {
1970    if (some) strcat(flg_output, ",");
1971    some = 1;
1972    strcat(flg_output, "NP");
1973  }
1974  if (flags & 0x08) {
1975    if (some) strcat(flg_output, ",");
1976    some = 1;
1977    strcat(flg_output, "IO");
1978  }
1979  if (flags & 0x10) {
1980    if (some) strcat(flg_output, ",");
1981    some = 1;
1982    strcat(flg_output, "IA");
1983  }
1984  if (flags == 0xF) {
1985    if (some) strcat(flg_output, ",");
1986    some = 1;
1987    strcat(flg_output, "VI");
1988  }
1989  fprintf(stdout, " %s", flg_output);
1990}
1991
1992static
1993void print_perms(int perms)
1994{
1995  fprintf(stdout, " %8X", perms);
1996}
1997
1998static
1999void print_sid(sid_t *sid)
2000{
2001  int i, comps = sid->auths;
2002  fprintf(stdout, "S-%u-%u", sid->ver, sid->auth[5]);
2003
2004  for (i = 0; i < comps; i++) 
2005    fprintf(stdout, "-%u", sid->sub_auths[i]);
2006
2007  /*fprintf(stdout, "\n");*/
2008}
2009
2010static
2011void print_acl(ACL *acl, const char *prefix)
2012{
2013  int i;
2014
2015  for (i = 0; i < acl->num_aces; i++) {
2016    fprintf(stdout, ";;%s", prefix);
2017    print_type(acl->aces[i]->type);
2018    print_flags(acl->aces[i]->flags);
2019    print_perms(acl->aces[i]->perms);
2020    fprintf(stdout, " ");
2021    print_sid(acl->aces[i]->trustee);
2022  }
2023}
2024
2025static
2026int print_sec(SEC_DESC *sec_desc)
2027{
2028  if (!print_security) return 1;
2029  fprintf(stdout, ";;  SECURITY\n");
2030  fprintf(stdout, ";;   Owner: ");
2031  print_sid(sec_desc->owner);
2032  fprintf(stdout, ";;   Group: ");
2033  print_sid(sec_desc->group);
2034  if (sec_desc->sacl) {
2035    fprintf(stdout, ";;    SACL:\n");
2036    print_acl(sec_desc->sacl, " ");
2037  }
2038  if (sec_desc->dacl) {
2039    fprintf(stdout, ";;    DACL:\n");
2040    print_acl(sec_desc->dacl, " ");
2041  }
2042  return 1;
2043}
2044
2045/*
2046 * Value print function here ...
2047 */
2048static
2049int print_val(const char *path, char *val_name, int val_type, int data_len, 
2050              void *data_blk, int terminal, int first, int last)
2051{
2052  unsigned char* data_asc;
2053 
2054  if(!val_name)
2055    val_name = "<No Name>";
2056
2057  fprintf(stdout, "%s", path);
2058  data_asc = data_to_ascii((unsigned char *)data_blk, data_len, val_type);
2059  fprintf(stdout, "%s:%s=%s\n", val_name, val_to_str(val_type, reg_type_names),
2060          data_asc);
2061 
2062  free(data_asc);
2063  return 1;
2064}
2065
2066static
2067void usage(void)
2068{
2069  fprintf(stderr, "Usage: readreg [-f<filterprefix>] [-v] [-p] [-k] [-s]"
2070          "<registryfile>\n");
2071  fprintf(stderr, "Version: 0.1\n\n");
2072  fprintf(stderr, "\n\t-v\t sets verbose mode");
2073  fprintf(stderr, "\n\t-f\t a simple prefix filter.");
2074  fprintf(stderr, "\n\t-s\t prints security descriptors");
2075  fprintf(stderr, "\n");
2076}
2077
2078
2079int main(int argc, char *argv[])
2080{
2081  REGF *regf;
2082  extern char *optarg;
2083  extern int optind;
2084  int opt; 
2085  int regf_opt = 1;
2086  char* filter_prefix = "";
2087
2088  if (argc < 2)
2089  {
2090    usage();
2091    exit(1);
2092  }
2093 
2094  /*
2095   * Now, process the arguments
2096   */
2097
2098  while ((opt = getopt(argc, argv, "svkf:o:c:")) != EOF)
2099  {
2100    switch (opt)
2101    {
2102    case 'f':
2103      /*full_print = 1;*/
2104      filter_prefix = strdup(optarg);
2105      regf_opt++;
2106      break;
2107
2108    case 's':
2109      print_security++;
2110      full_print++;
2111      regf_opt++;
2112      break;
2113
2114    case 'v':
2115      verbose++;
2116      regf_opt++;
2117      break;
2118
2119    case 'k':
2120      regf_opt++;
2121      break;
2122
2123    default:
2124      usage();
2125      exit(1);
2126      break;
2127    }
2128  }
2129
2130  /*
2131   * We only want to complain about the lack of a default owner SID if
2132   * we need one. This approximates that need
2133   */
2134  if (!def_owner_sid_str) {
2135    def_owner_sid_str = "S-1-5-21-1-2-3-4";
2136    if (verbose)
2137      fprintf(stderr, "Warning, default owner SID not set. Setting to %s\n",
2138              def_owner_sid_str);
2139  }
2140
2141  if ((regf = nt_create_regf()) == NULL) 
2142  {
2143    fprintf(stderr, "Could not create registry object: %s\n", strerror(errno));
2144    exit(2);
2145  }
2146
2147  if (regf_opt < argc) 
2148  { /* We have a registry file */
2149    if (!nt_set_regf_input_file(regf, argv[regf_opt])) 
2150    {
2151      fprintf(stderr, "Could not set name of registry file: %s, %s\n", 
2152              argv[regf_opt], strerror(errno));
2153      exit(3);
2154    }
2155
2156    /* Now, open it, and bring it into memory :-) */
2157    if (nt_load_registry(regf) < 0) 
2158    {
2159      fprintf(stderr, "Could not load registry: %s\n", argv[1]);
2160      exit(4);
2161    }
2162  }
2163
2164  /*
2165   * At this point, we should have a registry in memory and should be able
2166   * to iterate over it.
2167   */
2168  nt_key_iterator(regf, regf->root, 0, "", filter_prefix);
2169
2170  return 0;
2171}
Note: See TracBrowser for help on using the repository browser.