source: src/reglookup.c @ 6

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

Updated MULTI_SZ output. Strings are now '|' delimited and quoted.

  • Property svn:keywords set to Id
File size: 50.1 KB
Line 
1/*
2 * $Id: reglookup.c 6 2005-02-21 03:35:41Z 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/* Returns a newly malloc()ed string which contains original string,
420 * except for non-printable or special characters are quoted in hex
421 * with the syntax '\xQQ' where QQ is the hex ascii value of the quoted
422 * character.
423 */
424static
425char* quote_string(const char* str, char* special)
426{
427  unsigned int i;
428  unsigned int num_written=0;
429  unsigned int len = strlen(str);
430  unsigned int out_len = sizeof(char)*len+1;
431  char* ret_val = malloc(out_len);
432  if(ret_val == NULL)
433    return NULL;
434
435  for(i=0; i<len; i++)
436  {
437    if(str[i] < 32 || str[i] > 126 || strchr(special, str[i]) != NULL)
438    {
439      out_len += 3;
440      ret_val = realloc(ret_val, out_len);
441      if(ret_val == NULL)
442        break;
443      num_written += snprintf(ret_val+num_written, out_len-num_written,
444                              "\\x%.2X", str[i]);
445    }
446    else
447      ret_val[num_written++] = str[i];
448  }
449  ret_val[num_written] = '\0';
450
451  return ret_val;
452}
453
454
455/*
456 * Iterate over the keys, depth first, calling a function for each key
457 * and indicating if it is terminal or non-terminal and if it has values.
458 *
459 * In addition, for each value in the list, call a value list function
460 */
461
462static
463int nt_val_list_iterator(REGF *regf,  REG_KEY *key_tree, int bf, char *path,
464                         int terminal, const char* filter_prefix)
465{
466  int i;
467  VAL_LIST* val_list = key_tree->values;
468
469  if (str_is_prefix(filter_prefix, path))
470  { 
471    for (i=0; i<val_list->val_count; i++) 
472    {
473      /*XXX: print_key() is doing nothing right now, can probably be removed. */
474      if (!print_key(path, key_tree->name,
475                     key_tree->class_name,
476                     (key_tree->type == REG_ROOT_KEY),
477                     (key_tree->sub_keys == NULL),
478                     (key_tree->values?(key_tree->values->val_count):0),
479                     "\n") ||
480          !print_val(path, val_list->vals[i]->name,val_list->vals[i]->data_type,
481                     val_list->vals[i]->data_len, val_list->vals[i]->data_blk,
482                     terminal,
483                     (i == 0),
484                     (i == val_list->val_count)))
485      { return 0; }
486    }
487  }
488
489  return 1;
490}
491
492static
493int nt_key_list_iterator(REGF *regf, KEY_LIST *key_list, int bf, 
494                         const char *path, const char* filter_prefix)
495{
496  int i;
497
498  if (!key_list) 
499    return 1;
500
501  for (i=0; i < key_list->key_count; i++) 
502  {
503    if (!nt_key_iterator(regf, key_list->keys[i], bf, path, filter_prefix)) 
504      return 0;
505  }
506  return 1;
507}
508
509static
510int nt_key_iterator(REGF *regf, REG_KEY *key_tree, int bf, 
511                    const char *path, const char* filter_prefix)
512{
513  int path_len = strlen(path);
514  char *new_path;
515
516  if (!regf || !key_tree)
517    return -1;
518
519  /* List the key first, then the values, then the sub-keys */
520  /*printf("filter_prefix: %s, path: %s\n", filter_prefix, path);*/
521  if (str_is_prefix(filter_prefix, path))
522  {
523    /*XXX: print_key() is doing nothing right now, can probably be removed. */
524    if (!print_key(path, key_tree->name,
525                   key_tree->class_name,
526                   (key_tree->type == REG_ROOT_KEY),
527                   (key_tree->sub_keys == NULL),
528                   (key_tree->values?(key_tree->values->val_count):0),
529                   "\n"))
530    { return 0; }
531
532    /*
533     * If we have a security print routine, call it
534     * If the security print routine returns false, stop.
535     */
536    if (key_tree->security && !print_sec(key_tree->security->sec_desc))
537      return 0;
538  }
539
540  new_path = (char *)malloc(path_len + 1 + strlen(key_tree->name) + 1);
541  if (!new_path) 
542    return 0; /* Errors? */
543  new_path[0] = '\0';
544  strcat(new_path, path);
545  strcat(new_path, key_tree->name);
546  strcat(new_path, "\\");
547
548  /*
549   * Now, iterate through the values in the val_list
550   */
551  if (key_tree->values &&
552      !nt_val_list_iterator(regf, key_tree, bf, new_path, 
553                            (key_tree->values!=NULL), filter_prefix))
554  {
555    free(new_path);
556    return 0;
557  }
558
559  /*
560   * Now, iterate through the keys in the key list
561   */
562  if (key_tree->sub_keys && 
563      !nt_key_list_iterator(regf, key_tree->sub_keys, bf, 
564                            new_path, filter_prefix)) 
565  {
566    free(new_path);
567    return 0;
568  } 
569
570  free(new_path);
571  return 1;
572}
573
574
575/*
576 * Find key by name in a list ...
577 * Take the first component and search for that in the list
578 */
579static
580REG_KEY *nt_find_key_in_list_by_name(KEY_LIST *list, char *key)
581{
582  int i;
583  REG_KEY *res = NULL;
584
585  if (!list || !key || !*key) return NULL;
586
587  for (i = 0; i < list->key_count; i++)
588    if ((res = nt_find_key_by_name(list->keys[i], key)))
589      return res;
590 
591  return NULL;
592}
593
594
595/*
596 * Find key by name in a tree ... We will assume absolute names here, but we
597 * need the root of the tree ...
598 */
599static REG_KEY* nt_find_key_by_name(REG_KEY* tree, char* key)
600{
601  char* lname = NULL;
602  char* c1;
603  char* c2;
604  REG_KEY* tmp;
605
606  if (!tree || !key || !*key) 
607    return NULL;
608
609  lname = strdup(key);
610  if (!lname) 
611    return NULL;
612
613  /*
614   * Make sure that the first component is correct ...
615   */
616  c1 = lname;
617  c2 = strchr(c1, '\\');
618  if (c2) 
619  { /* Split here ... */
620    *c2 = 0;
621    c2++;
622  }
623 
624  if (strcmp(c1, tree->name) != 0) 
625  { 
626    if (lname)
627      free(lname);
628    return NULL;
629  }
630 
631  if (c2) 
632  {
633    tmp = nt_find_key_in_list_by_name(tree->sub_keys, c2);
634    free(lname);
635    return tmp;
636  }
637  else 
638  {
639    if (lname) 
640      free(lname);
641    return tree;
642  }
643
644  return NULL;
645}
646
647/* Make, delete keys */
648static
649int nt_delete_val_key(VAL_KEY *val_key)
650{
651
652  if (val_key) {
653    if (val_key->name) free(val_key->name);
654    if (val_key->data_blk) free(val_key->data_blk);
655    free(val_key);
656  };
657  return 1;
658}
659
660
661/*
662 * Add a key to the tree ... We walk down the components matching until
663 * we don't find any. There must be a match on the first component ...
664 * We return the key structure for the final component as that is
665 * often where we want to add values ...
666 */
667
668/*
669 * Convert a string of the form S-1-5-x[-y-z-r] to a SID
670 */
671/* MIGHT COME IN HANDY LATER.
672static
673int sid_string_to_sid(sid_t **sid, const char *sid_str)
674{
675  int i = 0;
676  unsigned int auth;
677  const char *lstr;
678
679  *sid = (sid_t *)malloc(sizeof(sid_t));
680  if (!*sid) return 0;
681
682  memset(*sid, 0, sizeof(sid_t));
683
684  if (strncmp(sid_str, "S-1-5", 5)) {
685    fprintf(stderr, "Does not conform to S-1-5...: %s\n", sid_str);
686    return 0;
687  }
688
689//We only allow strings of form S-1-5...
690
691  (*sid)->ver = 1;
692  (*sid)->auth[5] = 5;
693
694  lstr = sid_str + 5;
695
696  while (1)
697  {
698    if (!lstr || !lstr[0] || sscanf(lstr, "-%u", &auth) == 0)
699    {
700      if (i < 1)
701      {
702        fprintf(stderr, "Not of form -d-d...: %s, %u\n", lstr, i);
703        return 0;
704      }
705      (*sid)->auths=i;
706      return 1;
707    }
708
709    (*sid)->sub_auths[i] = auth;
710    i++;
711    lstr = strchr(lstr + 1, '-');
712  }
713
714  return 1;
715}
716*/
717
718
719/*
720 * We will implement inheritence that is based on what the parent's SEC_DESC
721 * says, but the Owner and Group SIDs can be overwridden from the command line
722 * and additional ACEs can be applied from the command line etc.
723 */
724static
725KEY_SEC_DESC *nt_inherit_security(REG_KEY *key)
726{
727
728  if (!key) return NULL;
729  return key->security;
730}
731
732/*
733 * Add a sub-key
734 */
735static
736REG_KEY *nt_add_reg_key_list(REGF *regf, REG_KEY *key, char * name, int create)
737{
738  int i;
739  REG_KEY *ret = NULL, *tmp = NULL;
740  KEY_LIST *list;
741  char *lname, *c1, *c2;
742
743  if (!key || !name || !*name) return NULL;
744 
745  list = key->sub_keys;
746  if (!list) { /* Create an empty list */
747
748    list = (KEY_LIST *)malloc(sizeof(KEY_LIST) + (REG_KEY_LIST_SIZE - 1) * sizeof(REG_KEY *));
749    list->key_count = 0;
750    list->max_keys = REG_KEY_LIST_SIZE;
751
752  }
753
754  lname = strdup(name);
755  if (!lname) return NULL;
756
757  c1 = lname;
758  c2 = strchr(c1, '\\');
759  if (c2) { /* Split here ... */
760    *c2 = 0;
761    c2++;
762  }
763
764  for (i = 0; i < list->key_count; i++) {
765    if (strcmp(list->keys[i]->name, c1) == 0) {
766      ret = nt_add_reg_key_list(regf, list->keys[i], c2, create);
767      free(lname);
768      return ret;
769    }
770  }
771
772  /*
773   * If we reach here we could not find the the first component
774   * so create it ...
775   */
776
777  if (list->key_count < list->max_keys){
778    list->key_count++;
779  }
780  else { /* Create more space in the list ... */
781    if (!(list = (KEY_LIST *)realloc(list, sizeof(KEY_LIST) + 
782                                     (list->max_keys + REG_KEY_LIST_SIZE - 1) 
783                                     * sizeof(REG_KEY *))))
784      goto error;
785
786    list->max_keys += REG_KEY_LIST_SIZE;
787    list->key_count++;
788  }
789
790  /*
791   * add the new key at the new slot
792   * FIXME: Sort the list someday
793   */
794
795  /*
796   * We want to create the key, and then do the rest
797   */
798
799  tmp = (REG_KEY *)malloc(sizeof(REG_KEY)); 
800
801  memset(tmp, 0, sizeof(REG_KEY));
802
803  tmp->name = strdup(c1);
804  if (!tmp->name) goto error;
805  tmp->owner = key;
806  tmp->type = REG_SUB_KEY;
807  /*
808   * Next, pull security from the parent, but override with
809   * anything passed in on the command line
810   */
811  tmp->security = nt_inherit_security(key);
812
813  list->keys[list->key_count - 1] = tmp;
814
815  if (c2) {
816    ret = nt_add_reg_key_list(regf, key, c2, True);
817  }
818
819  if (lname) free(lname);
820
821  return ret;
822
823 error:
824  if (tmp) free(tmp);
825  if (lname) free(lname);
826  return NULL;
827}
828
829
830/*
831 * Load and unload a registry file.
832 *
833 * Load, loads it into memory as a tree, while unload sealizes/flattens it
834 */
835
836/*
837 * Get the starting record for NT Registry file
838 */
839
840/*
841 * Where we keep all the regf stuff for one registry.
842 * This is the structure that we use to tie the in memory tree etc
843 * together. By keeping separate structs, we can operate on different
844 * registries at the same time.
845 * Currently, the SK_MAP is an array of mapping structure.
846 * Since we only need this on input and output, we fill in the structure
847 * as we go on input. On output, we know how many SK items we have, so
848 * we can allocate the structure as we need to.
849 * If you add stuff here that is dynamically allocated, add the
850 * appropriate free statements below.
851 */
852
853#define REGF_REGTYPE_NONE 0
854#define REGF_REGTYPE_NT   1
855#define REGF_REGTYPE_W9X  2
856
857#define TTTONTTIME(r, t1, t2) (r)->last_mod_time.low = (t1); \
858                              (r)->last_mod_time.high = (t2);
859
860#define REGF_HDR_BLKSIZ 0x1000
861
862#define OFF(f) ((f) + REGF_HDR_BLKSIZ + 4)
863#define LOCN(base, f) ((base) + OFF(f))
864
865const VAL_STR reg_type_names[] = {
866   { REG_TYPE_REGSZ,    "REG_SZ" },
867   { REG_TYPE_EXPANDSZ, "REG_EXPAND_SZ" },
868   { REG_TYPE_BIN,      "REG_BIN" },
869   { REG_TYPE_DWORD,    "REG_DWORD" },
870   { REG_TYPE_MULTISZ,  "REG_MULTI_SZ" },
871   { 0, NULL },
872};
873
874static
875const char *val_to_str(unsigned int val, const VAL_STR *val_array)
876{
877  int i = 0;
878
879  if (!val_array) return NULL;
880
881  while (val_array[i].val && val_array[i].str) {
882
883    if (val_array[i].val == val) return val_array[i].str;
884    i++;
885
886  }
887
888  return NULL;
889
890}
891
892/*
893 * Convert from UniCode to Ascii ... Does not take into account other lang
894 * Restrict by ascii_max if > 0
895 */
896static
897int uni_to_ascii(unsigned char *uni, unsigned char *ascii, int ascii_max, 
898                 int uni_max)
899{
900  int i = 0; 
901
902  while (i < ascii_max && (uni[i*2] || uni[i*2+1]))
903  {
904    if (uni_max > 0 && (i*2) >= uni_max) break;
905    ascii[i] = uni[i*2];
906    i++;
907  }
908  ascii[i] = '\0';
909
910  return i;
911}
912
913/*
914 * Convert a data value to a string for display
915 */
916static
917unsigned char* data_to_ascii(unsigned char *datap, int len, int type)
918{
919  unsigned char *asciip;
920  unsigned int i;
921  unsigned short num_nulls;
922  unsigned char* ascii;
923  unsigned char* cur_str;
924  unsigned char* cur_ascii;
925  char* cur_quoted;
926  unsigned int cur_str_len;
927  unsigned int ascii_max, cur_str_max;
928  unsigned int str_rem, cur_str_rem, alen;
929
930  switch (type) 
931  {
932  case REG_TYPE_REGSZ:
933    if (verbose)
934      fprintf(stderr, "Len: %d\n", len);
935
936    ascii_max = sizeof(char)*len;
937    ascii = malloc(ascii_max+4);
938    if(ascii == NULL)
939      return NULL;
940
941    /* FIXME. This has to be fixed. It has to be UNICODE */ 
942    uni_to_ascii(datap, ascii, len, ascii_max);
943    return ascii;
944    break;
945
946  case REG_TYPE_EXPANDSZ:
947    ascii_max = sizeof(char)*len;
948    ascii = malloc(ascii_max+2);
949    if(ascii == NULL)
950      return NULL;
951
952    uni_to_ascii(datap, ascii, len, ascii_max);
953    return ascii;
954    break;
955
956  case REG_TYPE_BIN:
957    ascii_max = sizeof(char)*len*3;
958    ascii = malloc(ascii_max+4);
959    if(ascii == NULL)
960      return NULL;
961
962    asciip = ascii;
963    for (i=0; (i<len)&&(i+1)*3<ascii_max; i++) { 
964      int str_rem = ascii_max - ((int)asciip - (int)ascii);
965      asciip += snprintf((char*)asciip, str_rem, "%02x", 
966                         *(unsigned char *)(datap+i));
967      if (i < len && str_rem > 0)
968        *asciip = ' '; asciip++;       
969    }
970    *asciip = '\0';
971    return ascii;
972    break;
973
974  case REG_TYPE_DWORD:
975    ascii_max = sizeof(char)*10;
976    ascii = malloc(ascii_max+1);
977    if(ascii == NULL)
978      return NULL;
979
980    if (*(int *)datap == 0)
981      snprintf((char*)ascii, ascii_max, "0");
982    else
983      snprintf((char*)ascii, ascii_max, "0x%x", *(int *)datap);
984    return ascii;
985    break;
986
987  case REG_TYPE_MULTISZ:
988    ascii_max = sizeof(char)*len*4;
989    cur_str_max = sizeof(char)*len+1;
990    cur_str = malloc(cur_str_max);
991    cur_ascii = malloc(cur_str_max);
992    ascii = malloc(ascii_max+4);
993    if(ascii == NULL)
994      return NULL;
995
996    /* Reads until it reaches 4 consecutive NULLs,
997     * which is two nulls in unicode, or until it reaches len, or until we
998     * run out of buffer.  The latter should never happen, but we shouldn't
999     * trust our file to have the right lengths/delimiters.
1000     */
1001    asciip = ascii;
1002    num_nulls = 0;
1003    str_rem = ascii_max;
1004    cur_str_rem = cur_str_max;
1005    cur_str_len = 0;
1006
1007    for(i=0; (i < len) && str_rem > 0; i++)
1008    {
1009      *(cur_str+cur_str_len) = *(datap+i);
1010      if(*(cur_str+cur_str_len) == 0)
1011        num_nulls++;
1012      else
1013        num_nulls = 0;
1014      cur_str_len++;
1015
1016      if(num_nulls == 2)
1017      {
1018        uni_to_ascii(cur_str, cur_ascii, cur_str_max, 0);
1019        cur_quoted = quote_string((char*)cur_ascii, "|");
1020        alen = snprintf((char*)asciip, str_rem, "%s", cur_quoted);
1021        asciip += alen;
1022        str_rem -= alen;
1023        free(cur_quoted);
1024
1025        if(*(datap+i+1) == 0 && *(datap+i+2) == 0)
1026          break;
1027        else
1028        {
1029          alen = snprintf((char*)asciip, str_rem, "%c", '|');
1030          asciip += alen;
1031          str_rem -= alen;
1032          memset(cur_str, 0, cur_str_max);
1033          cur_str_len = 0;
1034          num_nulls = 0;
1035          /* To eliminate leading nulls in subsequent strings. */
1036          i++;
1037        }
1038      }
1039    }
1040    *asciip = 0;
1041    return ascii;
1042    break;
1043
1044  default:
1045    return NULL;
1046    break;
1047  } 
1048
1049  return NULL;
1050}
1051
1052static
1053REG_KEY *nt_get_key_tree(REGF *regf, NK_HDR *nk_hdr, int size, REG_KEY *parent);
1054
1055static
1056int nt_set_regf_input_file(REGF *regf, char *filename)
1057{
1058  return ((regf->regfile_name = strdup(filename)) != NULL); 
1059}
1060
1061
1062/* Create a regf structure and init it */
1063
1064static
1065REGF *nt_create_regf(void)
1066{
1067  REGF *tmp = (REGF *)malloc(sizeof(REGF));
1068  if (!tmp) return tmp;
1069  memset(tmp, 0, sizeof(REGF));
1070  tmp->owner_sid_str = def_owner_sid_str;
1071  return tmp;
1072} 
1073
1074
1075/* Get the header of the registry. Return a pointer to the structure
1076 * If the mmap'd area has not been allocated, then mmap the input file
1077 */
1078static
1079REGF_HDR *nt_get_regf_hdr(REGF *regf)
1080{
1081  if (!regf)
1082    return NULL; /* What about errors */
1083
1084  if (!regf->regfile_name)
1085    return NULL; /* What about errors */
1086
1087  if (!regf->base) { /* Try to mmap etc the file */
1088
1089    if ((regf->fd = open(regf->regfile_name, O_RDONLY, 0000)) <0) {
1090      return NULL; /* What about errors? */
1091    }
1092
1093    if (fstat(regf->fd, &regf->sbuf) < 0) {
1094      return NULL;
1095    }
1096
1097    regf->base = mmap(0, regf->sbuf.st_size, PROT_READ, MAP_SHARED, regf->fd, 0);
1098
1099    if ((int)regf->base == 1) {
1100      fprintf(stderr, "Could not mmap file: %s, %s\n", regf->regfile_name,
1101              strerror(errno));
1102      return NULL;
1103    }
1104  }
1105
1106  /*
1107   * At this point, regf->base != NULL, and we should be able to read the
1108   * header
1109   */
1110
1111  assert(regf->base != NULL);
1112
1113  return (REGF_HDR *)regf->base;
1114}
1115
1116/*
1117 * Validate a regf header
1118 * For now, do nothing, but we should check the checksum
1119 */
1120static
1121int valid_regf_hdr(REGF_HDR *regf_hdr)
1122{
1123  if (!regf_hdr) return 0;
1124
1125  return 1;
1126}
1127
1128/*
1129 * Process an SK header ...
1130 * Every time we see a new one, add it to the map. Otherwise, just look it up.
1131 * We will do a simple linear search for the moment, since many KEYs have the
1132 * same security descriptor.
1133 * We allocate the map in increments of 10 entries.
1134 */
1135
1136/*
1137 * Create a new entry in the map, and increase the size of the map if needed
1138 */
1139static
1140SK_MAP *alloc_sk_map_entry(REGF *regf, KEY_SEC_DESC *tmp, int sk_off)
1141{
1142 if (!regf->sk_map) { /* Allocate a block of 10 */
1143    regf->sk_map = (SK_MAP *)malloc(sizeof(SK_MAP) * 10);
1144    if (!regf->sk_map) {
1145      free(tmp);
1146      return NULL;
1147    }
1148    regf->sk_map_size = 10;
1149    regf->sk_count = 1;
1150    (regf->sk_map)[0].sk_off = sk_off;
1151    (regf->sk_map)[0].key_sec_desc = tmp;
1152  }
1153  else { /* Simply allocate a new slot, unless we have to expand the list */ 
1154    int ndx = regf->sk_count;
1155    if (regf->sk_count >= regf->sk_map_size) {
1156      regf->sk_map = (SK_MAP *)realloc(regf->sk_map, 
1157                                       (regf->sk_map_size + 10)*sizeof(SK_MAP));
1158      if (!regf->sk_map) {
1159        free(tmp);
1160        return NULL;
1161      }
1162      /*
1163       * ndx already points at the first entry of the new block
1164       */
1165      regf->sk_map_size += 10;
1166    }
1167    (regf->sk_map)[ndx].sk_off = sk_off;
1168    (regf->sk_map)[ndx].key_sec_desc = tmp;
1169    regf->sk_count++;
1170  }
1171 return regf->sk_map;
1172}
1173
1174/*
1175 * Search for a KEY_SEC_DESC in the sk_map, but don't create one if not
1176 * found
1177 */
1178static
1179KEY_SEC_DESC *lookup_sec_key(SK_MAP *sk_map, int count, int sk_off)
1180{
1181  int i;
1182
1183  if (!sk_map) return NULL;
1184
1185  for (i = 0; i < count; i++) {
1186
1187    if (sk_map[i].sk_off == sk_off)
1188      return sk_map[i].key_sec_desc;
1189
1190  }
1191
1192  return NULL;
1193
1194}
1195
1196/*
1197 * Allocate a KEY_SEC_DESC if we can't find one in the map
1198 */
1199static
1200KEY_SEC_DESC *lookup_create_sec_key(REGF *regf, SK_MAP *sk_map, int sk_off)
1201{
1202  KEY_SEC_DESC *tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off);
1203
1204  if (tmp) {
1205    return tmp;
1206  }
1207  else { /* Allocate a new one */
1208    tmp = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC));
1209    if (!tmp) {
1210      return NULL;
1211    }
1212    memset(tmp, 0, sizeof(KEY_SEC_DESC)); /* Neatly sets offset to 0 */
1213    tmp->state = SEC_DESC_RES;
1214    if (!alloc_sk_map_entry(regf, tmp, sk_off)) {
1215      return NULL;
1216    }
1217    return tmp;
1218  }
1219}
1220
1221/*
1222 * Allocate storage and duplicate a SID
1223 * We could allocate the SID to be only the size needed, but I am too lazy.
1224 */
1225static
1226sid_t *dup_sid(sid_t *sid)
1227{
1228  sid_t *tmp = (sid_t *)malloc(sizeof(sid_t));
1229  int i;
1230 
1231  if (!tmp) return NULL;
1232  tmp->ver = sid->ver;
1233  tmp->auths = sid->auths;
1234  for (i=0; i<6; i++) {
1235    tmp->auth[i] = sid->auth[i];
1236  }
1237  for (i=0; i<tmp->auths&&i<MAXSUBAUTHS; i++) {
1238    tmp->sub_auths[i] = sid->sub_auths[i];
1239  }
1240  return tmp;
1241}
1242
1243/*
1244 * Allocate space for an ACE and duplicate the registry encoded one passed in
1245 */
1246static
1247ACE *dup_ace(REG_ACE *ace)
1248{
1249  ACE *tmp = NULL; 
1250
1251  tmp = (ACE *)malloc(sizeof(ACE));
1252
1253  if (!tmp) return NULL;
1254
1255  tmp->type = CVAL(&ace->type);
1256  tmp->flags = CVAL(&ace->flags);
1257  tmp->perms = IVAL(&ace->perms);
1258  tmp->trustee = dup_sid(&ace->trustee);
1259  return tmp;
1260}
1261
1262/*
1263 * Allocate space for an ACL and duplicate the registry encoded one passed in
1264 */
1265static
1266ACL *dup_acl(REG_ACL *acl)
1267{
1268  ACL *tmp = NULL;
1269  REG_ACE* ace;
1270  int i, num_aces;
1271
1272  num_aces = IVAL(&acl->num_aces);
1273
1274  tmp = (ACL *)malloc(sizeof(ACL) + (num_aces - 1)*sizeof(ACE *));
1275  if (!tmp) return NULL;
1276
1277  tmp->num_aces = num_aces;
1278  tmp->refcnt = 1;
1279  tmp->rev = SVAL(&acl->rev);
1280  if (verbose) fprintf(stdout, "ACL: refcnt: %u, rev: %u\n", tmp->refcnt, 
1281                       tmp->rev);
1282  ace = (REG_ACE *)&acl->aces;
1283  for (i=0; i<num_aces; i++) {
1284    tmp->aces[i] = dup_ace(ace);
1285    ace = (REG_ACE *)((char *)ace + SVAL(&ace->length));
1286    /* XXX: FIXME, should handle malloc errors */
1287  }
1288
1289  return tmp;
1290}
1291
1292static
1293SEC_DESC *process_sec_desc(REGF *regf, REG_SEC_DESC *sec_desc)
1294{
1295  SEC_DESC *tmp = NULL;
1296 
1297  tmp = (SEC_DESC *)malloc(sizeof(SEC_DESC));
1298
1299  if (!tmp) {
1300    return NULL;
1301  }
1302 
1303  tmp->rev = SVAL(&sec_desc->rev);
1304  tmp->type = SVAL(&sec_desc->type);
1305  if (verbose) fprintf(stdout, "SEC_DESC Rev: %0X, Type: %0X\n", 
1306                       tmp->rev, tmp->type);
1307  if (verbose) fprintf(stdout, "SEC_DESC Owner Off: %0X\n",
1308                       IVAL(&sec_desc->owner_off));
1309  if (verbose) fprintf(stdout, "SEC_DESC Group Off: %0X\n",
1310                       IVAL(&sec_desc->group_off));
1311  if (verbose) fprintf(stdout, "SEC_DESC DACL Off: %0X\n",
1312                       IVAL(&sec_desc->dacl_off));
1313  tmp->owner = dup_sid((sid_t *)((char *)sec_desc + IVAL(&sec_desc->owner_off)));
1314  if (!tmp->owner) {
1315    free(tmp);
1316    return NULL;
1317  }
1318  tmp->group = dup_sid((sid_t *)((char *)sec_desc + IVAL(&sec_desc->group_off)));
1319  if (!tmp->group) {
1320    free(tmp);
1321    return NULL;
1322  }
1323
1324  /* Now pick up the SACL and DACL */
1325
1326  if (sec_desc->sacl_off)
1327    tmp->sacl = dup_acl((REG_ACL *)((char *)sec_desc + IVAL(&sec_desc->sacl_off)));
1328  else
1329    tmp->sacl = NULL;
1330
1331  if (sec_desc->dacl_off)
1332    tmp->dacl = dup_acl((REG_ACL *)((char *)sec_desc + IVAL(&sec_desc->dacl_off)));
1333  else
1334    tmp->dacl = NULL;
1335
1336  return tmp;
1337}
1338
1339static
1340KEY_SEC_DESC *process_sk(REGF *regf, SK_HDR *sk_hdr, int sk_off, int size)
1341{
1342  KEY_SEC_DESC *tmp = NULL;
1343  int sk_next_off, sk_prev_off, sk_size;
1344  REG_SEC_DESC *sec_desc;
1345
1346  if (!sk_hdr) return NULL;
1347
1348  if (SVAL(&sk_hdr->SK_ID) != REG_SK_ID) {
1349    fprintf(stderr, "Unrecognized SK Header ID: %08X, %s\n", (int)sk_hdr,
1350            regf->regfile_name);
1351    return NULL;
1352  }
1353
1354  if (-size < (sk_size = IVAL(&sk_hdr->rec_size))) {
1355    fprintf(stderr, "Incorrect SK record size: %d vs %d. %s\n",
1356            -size, sk_size, regf->regfile_name);
1357    return NULL;
1358  }
1359
1360  /*
1361   * Now, we need to look up the SK Record in the map, and return it
1362   * Since the map contains the SK_OFF mapped to KEY_SEC_DESC, we can
1363   * use that
1364   */
1365
1366  if (regf->sk_map &&
1367      ((tmp = lookup_sec_key(regf->sk_map, regf->sk_count, sk_off)) != NULL)
1368      && (tmp->state == SEC_DESC_OCU)) {
1369    tmp->ref_cnt++;
1370    return tmp;
1371  }
1372
1373  /* Here, we have an item in the map that has been reserved, or tmp==NULL. */
1374
1375  assert(tmp == NULL || (tmp && tmp->state != SEC_DESC_NON));
1376
1377  /*
1378   * Now, allocate a KEY_SEC_DESC, and parse the structure here, and add the
1379   * new KEY_SEC_DESC to the mapping structure, since the offset supplied is
1380   * the actual offset of structure. The same offset will be used by
1381   * all future references to this structure
1382   * We could put all this unpleasantness in a function.
1383   */
1384
1385  if (!tmp) {
1386    tmp = (KEY_SEC_DESC *)malloc(sizeof(KEY_SEC_DESC));
1387    if (!tmp) return NULL;
1388    memset(tmp, 0, sizeof(KEY_SEC_DESC));
1389   
1390    /*
1391     * Allocate an entry in the SK_MAP ...
1392     * We don't need to free tmp, because that is done for us if the
1393     * sm_map entry can't be expanded when we need more space in the map.
1394     */
1395   
1396    if (!alloc_sk_map_entry(regf, tmp, sk_off)) {
1397      return NULL;
1398    }
1399  }
1400
1401  tmp->ref_cnt++;
1402  tmp->state = SEC_DESC_OCU;
1403
1404  /*
1405   * Now, process the actual sec desc and plug the values in
1406   */
1407
1408  sec_desc = (REG_SEC_DESC *)&sk_hdr->sec_desc[0];
1409  tmp->sec_desc = process_sec_desc(regf, sec_desc);
1410
1411  /*
1412   * Now forward and back links. Here we allocate an entry in the sk_map
1413   * if it does not exist, and mark it reserved
1414   */
1415
1416  sk_prev_off = IVAL(&sk_hdr->prev_off);
1417  tmp->prev = lookup_create_sec_key(regf, regf->sk_map, sk_prev_off);
1418  assert(tmp->prev != NULL);
1419  sk_next_off = IVAL(&sk_hdr->next_off);
1420  tmp->next = lookup_create_sec_key(regf, regf->sk_map, sk_next_off);
1421  assert(tmp->next != NULL);
1422
1423  return tmp;
1424}
1425
1426/*
1427 * Process a VK header and return a value
1428 */
1429static
1430VAL_KEY *process_vk(REGF *regf, VK_HDR *vk_hdr, int size)
1431{
1432  char val_name[1024];
1433  int nam_len, dat_len, flag, dat_type, dat_off, vk_id;
1434  const char *val_type;
1435  VAL_KEY *tmp = NULL; 
1436
1437  if (!vk_hdr) return NULL;
1438
1439  if ((vk_id = SVAL(&vk_hdr->VK_ID)) != REG_VK_ID) {
1440    fprintf(stderr, "Unrecognized VK header ID: %0X, block: %0X, %s\n",
1441            vk_id, (int)vk_hdr, regf->regfile_name);
1442    return NULL;
1443  }
1444
1445  nam_len = SVAL(&vk_hdr->nam_len);
1446  val_name[nam_len] = '\0';
1447  flag = SVAL(&vk_hdr->flag);
1448  dat_type = IVAL(&vk_hdr->dat_type);
1449  dat_len = IVAL(&vk_hdr->dat_len);  /* If top bit, offset contains data */
1450  dat_off = IVAL(&vk_hdr->dat_off);
1451
1452  tmp = (VAL_KEY *)malloc(sizeof(VAL_KEY));
1453  if (!tmp) {
1454    goto error;
1455  }
1456  memset(tmp, 0, sizeof(VAL_KEY));
1457  tmp->has_name = flag;
1458  tmp->data_type = dat_type;
1459
1460  if (flag & 0x01) {
1461    strncpy(val_name, vk_hdr->dat_name, nam_len);
1462    tmp->name = strdup(val_name);
1463    if (!tmp->name) {
1464      goto error;
1465    }
1466  }
1467  else
1468    strncpy(val_name, "<No Name>", 10);
1469
1470  /*
1471   * Allocate space and copy the data as a BLOB
1472   */
1473
1474  if (dat_len) {
1475   
1476    char *dtmp = (char *)malloc(dat_len&0x7FFFFFFF);
1477   
1478    if (!dtmp) {
1479      goto error;
1480    }
1481
1482    tmp->data_blk = dtmp;
1483
1484    if ((dat_len&0x80000000) == 0) 
1485    { /* The data is pointed to by the offset */
1486      char *dat_ptr = LOCN(regf->base, dat_off);
1487      /* XXX: replace with memcpy */
1488      bcopy(dat_ptr, dtmp, dat_len);
1489    }
1490    else { /* The data is in the offset or type */
1491      /*
1492       * FIXME.
1493       * Some registry files seem to have wierd fields. If top bit is set,
1494       * but len is 0, the type seems to be the value ...
1495       * Not sure how to handle this last type for the moment ...
1496       */
1497      dat_len = dat_len & 0x7FFFFFFF;
1498      /* XXX: replace with memcpy */
1499      bcopy(&dat_off, dtmp, dat_len);
1500    }
1501
1502    tmp->data_len = dat_len;
1503  }
1504
1505  val_type = val_to_str(dat_type, reg_type_names);
1506
1507  /*
1508   * We need to save the data area as well
1509   */
1510  if (verbose) 
1511    fprintf(stdout, "  %s : %s : \n", val_name, val_type);
1512
1513  return tmp;
1514
1515 error:
1516  if (tmp) nt_delete_val_key(tmp);
1517  return NULL;
1518
1519}
1520
1521/*
1522 * Process a VL Header and return a list of values
1523 */
1524static
1525VAL_LIST *process_vl(REGF *regf, VL_TYPE vl, int count, int size)
1526{
1527  int i, vk_off;
1528  VK_HDR *vk_hdr;
1529  VAL_LIST *tmp = NULL;
1530
1531  if (!vl) return NULL;
1532
1533  if (-size < (count+1)*sizeof(int)){
1534    fprintf(stderr, "Error in VL header format. Size less than space required. %d\n", -size);
1535    return NULL;
1536  }
1537
1538  tmp = (VAL_LIST *)malloc(sizeof(VAL_LIST) + (count - 1) * sizeof(VAL_KEY *));
1539  if (!tmp) {
1540    goto error;
1541  }
1542
1543  for (i=0; i<count; i++) {
1544    vk_off = IVAL(&vl[i]);
1545    vk_hdr = (VK_HDR *)LOCN(regf->base, vk_off);
1546    tmp->vals[i] = process_vk(regf, vk_hdr, BLK_SIZE(vk_hdr));
1547    if (!tmp->vals[i]){
1548      goto error;
1549    }
1550  }
1551
1552  tmp->val_count = count;
1553  tmp->max_vals = count;
1554
1555  return tmp;
1556
1557 error:
1558  /* XXX: FIXME, free the partially allocated structure */
1559  return NULL;
1560} 
1561
1562/*
1563 * Process an LF Header and return a list of sub-keys
1564 */
1565static
1566KEY_LIST *process_lf(REGF *regf, LF_HDR *lf_hdr, int size, REG_KEY *parent)
1567{
1568  int count, i, nk_off;
1569  unsigned int lf_id;
1570  KEY_LIST *tmp;
1571
1572  if (!lf_hdr) return NULL;
1573
1574  if ((lf_id = SVAL(&lf_hdr->LF_ID)) != REG_LF_ID) {
1575    fprintf(stderr, "Unrecognized LF Header format: %0X, Block: %0X, %s.\n",
1576            lf_id, (int)lf_hdr, regf->regfile_name);
1577    return NULL;
1578  }
1579
1580  assert(size < 0);
1581
1582  count = SVAL(&lf_hdr->key_count);
1583  if (verbose) 
1584    fprintf(stdout, "Key Count: %u\n", count);
1585  if (count <= 0) return NULL;
1586
1587  /* Now, we should allocate a KEY_LIST struct and fill it in ... */
1588
1589  tmp = (KEY_LIST *)malloc(sizeof(KEY_LIST) + (count - 1) * sizeof(REG_KEY *));
1590  if (!tmp) {
1591    goto error;
1592  }
1593
1594  tmp->key_count = count;
1595  tmp->max_keys = count;
1596
1597  for (i=0; i<count; i++) {
1598    NK_HDR *nk_hdr;
1599
1600    nk_off = IVAL(&lf_hdr->hr[i].nk_off);
1601    if (verbose) 
1602      fprintf(stdout, "NK Offset: %0X\n", nk_off);
1603    nk_hdr = (NK_HDR *)LOCN(regf->base, nk_off);
1604    tmp->keys[i] = nt_get_key_tree(regf, nk_hdr, BLK_SIZE(nk_hdr), parent);
1605    if (!tmp->keys[i]) {
1606      goto error;
1607    }
1608  }
1609
1610  return tmp;
1611
1612 error:
1613  /*if (tmp) nt_delete_key_list(tmp, False);*/
1614  return NULL;
1615}
1616
1617
1618/*
1619 * This routine is passed an NK_HDR pointer and retrieves the entire tree
1620 * from there down. It returns a REG_KEY *.
1621 */
1622static
1623REG_KEY *nt_get_key_tree(REGF *regf, NK_HDR *nk_hdr, int size, REG_KEY *parent)
1624{
1625  REG_KEY *tmp = NULL, *own;
1626  int name_len, clsname_len, lf_off, val_off, val_count, sk_off, own_off;
1627  unsigned int nk_id;
1628  LF_HDR *lf_hdr;
1629  VL_TYPE *vl;
1630  SK_HDR *sk_hdr;
1631  char key_name[1024];
1632  unsigned char cls_name[1024];
1633
1634  if (!nk_hdr) return NULL;
1635
1636  if ((nk_id = SVAL(&nk_hdr->NK_ID)) != REG_NK_ID) {
1637    fprintf(stderr, "Unrecognized NK Header format: %08X, Block: %0X. %s\n", 
1638            nk_id, (int)nk_hdr, regf->regfile_name);
1639    return NULL;
1640  }
1641
1642  assert(size < 0);
1643
1644  name_len = SVAL(&nk_hdr->nam_len);
1645  clsname_len = SVAL(&nk_hdr->clsnam_len);
1646
1647  /*
1648   * The value of -size should be ge
1649   * (sizeof(NK_HDR) - 1 + name_len)
1650   * The -1 accounts for the fact that we included the first byte of
1651   * the name in the structure. clsname_len is the length of the thing
1652   * pointed to by clsnam_off
1653   */
1654
1655  if (-size < (sizeof(NK_HDR) - 1 + name_len)) {
1656    fprintf(stderr, "Incorrect NK_HDR size: %d, %0X\n", -size, (int)nk_hdr);
1657    fprintf(stderr, "Sizeof NK_HDR: %d, name_len %d, clsname_len %d\n",
1658            sizeof(NK_HDR), name_len, clsname_len);
1659    /*return NULL;*/
1660  }
1661
1662  if (verbose) fprintf(stdout, "NK HDR: Name len: %d, class name len: %d\n", 
1663                       name_len, clsname_len);
1664
1665  /* Fish out the key name and process the LF list */
1666
1667  assert(name_len < sizeof(key_name));
1668
1669  /* Allocate the key struct now */
1670  tmp = (REG_KEY *)malloc(sizeof(REG_KEY));
1671  if (!tmp) return tmp;
1672  memset(tmp, 0, sizeof(REG_KEY));
1673
1674  tmp->type = (SVAL(&nk_hdr->type)==0x2C?REG_ROOT_KEY:REG_SUB_KEY);
1675 
1676  strncpy(key_name, nk_hdr->key_nam, name_len);
1677  key_name[name_len] = '\0';
1678
1679  if (verbose) fprintf(stdout, "Key name: %s\n", key_name);
1680
1681  tmp->name = strdup(key_name);
1682  if (!tmp->name) {
1683    goto error;
1684  }
1685
1686  /*
1687   * Fish out the class name, it is in UNICODE, while the key name is
1688   * ASCII :-)
1689   */
1690
1691  if (clsname_len) 
1692  { /* Just print in Ascii for now */
1693    unsigned char *clsnamep;
1694    unsigned int clsnam_off;
1695
1696    clsnam_off = IVAL(&nk_hdr->clsnam_off);
1697    clsnamep = (unsigned char*)LOCN(regf->base, clsnam_off);
1698    if (verbose) fprintf(stdout, "Class Name Offset: %0X\n", clsnam_off);
1699 
1700    memset(cls_name, 0, clsname_len);
1701    uni_to_ascii(clsnamep, cls_name, sizeof(cls_name), clsname_len);
1702   
1703    /*
1704     * I am keeping class name as an ascii string for the moment.
1705     * That means it needs to be converted on output.
1706     * It will also piss off people who need Unicode/UTF-8 strings. Sorry.
1707     * XXX: FIXME
1708     */
1709    tmp->class_name = strdup((char*)cls_name);
1710    if (!tmp->class_name) {
1711      goto error;
1712    }
1713
1714    if (verbose) fprintf(stdout, "  Class Name: %s\n", cls_name);
1715
1716  }
1717
1718  /*
1719   * Process the owner offset ...
1720   */
1721  own_off = IVAL(&nk_hdr->own_off);
1722  own = (REG_KEY *)LOCN(regf->base, own_off);
1723  if (verbose) 
1724    fprintf(stdout, "Owner Offset: %0X\n", own_off);
1725
1726  if (verbose) 
1727    fprintf(stdout, "  Owner locn: %0X, Our locn: %0X\n", 
1728                       (unsigned int)own, (unsigned int)nk_hdr);
1729
1730  /*
1731   * We should verify that the owner field is correct ...
1732   * for now, we don't worry ...
1733   */
1734  tmp->owner = parent;
1735
1736  /*
1737   * If there are any values, process them here
1738   */
1739
1740  val_count = IVAL(&nk_hdr->val_cnt);
1741  if (verbose) 
1742    fprintf(stdout, "Val Count: %d\n", val_count);
1743  if (val_count) 
1744  {
1745    val_off = IVAL(&nk_hdr->val_off);
1746    vl = (VL_TYPE *)LOCN(regf->base, val_off);
1747    if (verbose) 
1748      fprintf(stdout, "Val List Offset: %0X\n", val_off);
1749
1750    tmp->values = process_vl(regf, *vl, val_count, BLK_SIZE(vl));
1751    if (!tmp->values) {
1752      goto error;
1753    }
1754
1755  }
1756
1757  /*
1758   * Also handle the SK header ...
1759   */
1760
1761  sk_off = IVAL(&nk_hdr->sk_off);
1762  sk_hdr = (SK_HDR *)LOCN(regf->base, sk_off);
1763  if (verbose) 
1764    fprintf(stdout, "SK Offset: %0X\n", sk_off);
1765
1766  if (sk_off != -1) {
1767
1768    tmp->security = process_sk(regf, sk_hdr, sk_off, BLK_SIZE(sk_hdr));
1769
1770  } 
1771
1772  lf_off = IVAL(&nk_hdr->lf_off);
1773  if (verbose) 
1774    fprintf(stdout, "SubKey list offset: %0X\n", lf_off);
1775
1776  /*
1777   * No more subkeys if lf_off == -1
1778   */
1779  if (lf_off != -1) 
1780  {
1781    lf_hdr = (LF_HDR *)LOCN(regf->base, lf_off);
1782   
1783    tmp->sub_keys = process_lf(regf, lf_hdr, BLK_SIZE(lf_hdr), tmp);
1784    if (!tmp->sub_keys)
1785      goto error;
1786  }
1787
1788  return tmp;
1789
1790 error:
1791  /*if (tmp) nt_delete_reg_key(tmp, False);*/
1792  return NULL;
1793}
1794
1795static
1796int nt_load_registry(REGF *regf)
1797{
1798  REGF_HDR *regf_hdr;
1799  unsigned int regf_id, hbin_id;
1800  HBIN_HDR *hbin_hdr;
1801  NK_HDR *first_key;
1802
1803  /* Get the header */
1804
1805  if ((regf_hdr = nt_get_regf_hdr(regf)) == NULL) {
1806    return -1;
1807  }
1808
1809  /* Now process that header and start to read the rest in */
1810
1811  if ((regf_id = IVAL(&regf_hdr->REGF_ID)) != REG_REGF_ID) {
1812    fprintf(stderr, "Unrecognized NT registry header id: %0X, %s\n",
1813            regf_id, regf->regfile_name);
1814    return -1;
1815  }
1816
1817  /*
1818   * Validate the header ...
1819   */
1820  if (!valid_regf_hdr(regf_hdr)) {
1821    fprintf(stderr, "Registry file header does not validate: %s\n",
1822            regf->regfile_name);
1823    return -1;
1824  }
1825
1826  /* Update the last mod date, and then go get the first NK record and on */
1827
1828  TTTONTTIME(regf, IVAL(&regf_hdr->tim1), IVAL(&regf_hdr->tim2));
1829
1830  /*
1831   * The hbin hdr seems to be just uninteresting garbage. Check that
1832   * it is there, but that is all.
1833   */
1834
1835  hbin_hdr = (HBIN_HDR *)(regf->base + REGF_HDR_BLKSIZ);
1836
1837  if ((hbin_id = IVAL(&hbin_hdr->HBIN_ID)) != REG_HBIN_ID) {
1838    fprintf(stderr, "Unrecognized registry hbin hdr ID: %0X, %s\n", 
1839            hbin_id, regf->regfile_name);
1840    return -1;
1841  } 
1842
1843  /*
1844   * Get a pointer to the first key from the hreg_hdr
1845   */
1846
1847  if (verbose) 
1848    fprintf(stdout, "First Key: %0X\n", IVAL(&regf_hdr->first_key));
1849
1850  first_key = (NK_HDR *)LOCN(regf->base, IVAL(&regf_hdr->first_key));
1851  if (verbose) fprintf(stdout, "First Key Offset: %0X\n", 
1852                       IVAL(&regf_hdr->first_key));
1853
1854  if (verbose) fprintf(stdout, "Data Block Size: %d\n",
1855                       IVAL(&regf_hdr->dblk_size));
1856
1857  if (verbose) fprintf(stdout, "Offset to next hbin block: %0X\n",
1858                       IVAL(&hbin_hdr->off_to_next));
1859
1860  if (verbose) fprintf(stdout, "HBIN block size: %0X\n",
1861                       IVAL(&hbin_hdr->blk_size));
1862
1863  /*
1864   * Now, get the registry tree by processing that NK recursively
1865   */
1866
1867  regf->root = nt_get_key_tree(regf, first_key, BLK_SIZE(first_key), NULL);
1868
1869  assert(regf->root != NULL);
1870
1871  /*
1872   * Unmap the registry file, as we might want to read in another
1873   * tree etc.
1874   */
1875
1876  if (regf->base) munmap(regf->base, regf->sbuf.st_size);
1877  regf->base = NULL;
1878  close(regf->fd);    /* Ignore the error :-) */
1879
1880  return 1;
1881}
1882
1883
1884/*
1885 * Routines to parse a REGEDIT4 file
1886 *
1887 * The file consists of:
1888 *
1889 * REGEDIT4
1890 * \[[-]key-path\]\n
1891 * <value-spec>*
1892 *
1893 * Format:
1894 * [cmd:]name=type:value
1895 *
1896 * cmd = a|d|c|add|delete|change|as|ds|cs
1897 *
1898 * There can be more than one key-path and value-spec.
1899 *
1900 * Since we want to support more than one type of file format, we
1901 * construct a command-file structure that keeps info about the command file
1902 */
1903
1904#define FMT_UNREC -1
1905#define FMT_REGEDIT4 0
1906#define FMT_EDITREG1_1 1
1907
1908#define FMT_STRING_REGEDIT4 "REGEDIT4"
1909#define FMT_STRING_EDITREG1_0 "EDITREG1.0"
1910
1911#define CMD_NONE     0
1912#define CMD_ADD_KEY  1
1913#define CMD_DEL_KEY  2
1914
1915#define CMD_KEY 1
1916#define CMD_VAL 2
1917
1918typedef struct val_spec_list {
1919  struct val_spec_list *next;
1920  char *name;
1921  int type;
1922  char *val;    /* Kept as a char string, really? */
1923} VAL_SPEC_LIST;
1924
1925typedef struct command_s {
1926  int cmd;
1927  char *key;
1928  int val_count;
1929  VAL_SPEC_LIST *val_spec_list, *val_spec_last;
1930} CMD;
1931
1932typedef struct cmd_line {
1933  int len, line_len;
1934  char *line;
1935} CMD_LINE;
1936
1937
1938
1939#define INIT_ALLOC 10
1940
1941
1942/* prints a key */
1943static
1944int print_key(const char *path, char *name, char *class_name, int root, 
1945              int terminal, int vals, char* newline)
1946{
1947  if (full_print)
1948    fprintf(stdout, "%s%s\\%s", path, name, newline);
1949
1950  return 1;
1951}
1952
1953/*
1954 * Sec Desc print functions
1955 */
1956static
1957void print_type(unsigned char type)
1958{
1959  switch (type) {
1960  case 0x00:
1961    fprintf(stdout, "    ALLOW");
1962    break;
1963  case 0x01:
1964    fprintf(stdout, "     DENY");
1965    break;
1966  case 0x02:
1967    fprintf(stdout, "    AUDIT");
1968    break;
1969  case 0x03:
1970    fprintf(stdout, "    ALARM");
1971    break;
1972  case 0x04:
1973    fprintf(stdout, "ALLOW CPD");
1974    break;
1975  case 0x05:
1976    fprintf(stdout, "OBJ ALLOW");
1977    break;
1978  case 0x06:
1979    fprintf(stdout, " OBJ DENY");
1980    break;
1981  default:
1982    fprintf(stdout, "  UNKNOWN");
1983    break;
1984  }
1985}
1986
1987static
1988void print_flags(unsigned char flags)
1989{
1990  char flg_output[21];
1991  int some = 0;
1992
1993  flg_output[0] = 0;
1994  if (!flags) {
1995    fprintf(stdout, "         ");
1996    return;
1997  }
1998  if (flags & 0x01) {
1999    if (some) strcat(flg_output, ",");
2000    some = 1;
2001    strcat(flg_output, "OI");
2002  }
2003  if (flags & 0x02) {
2004    if (some) strcat(flg_output, ",");
2005    some = 1;
2006    strcat(flg_output, "CI");
2007  }
2008  if (flags & 0x04) {
2009    if (some) strcat(flg_output, ",");
2010    some = 1;
2011    strcat(flg_output, "NP");
2012  }
2013  if (flags & 0x08) {
2014    if (some) strcat(flg_output, ",");
2015    some = 1;
2016    strcat(flg_output, "IO");
2017  }
2018  if (flags & 0x10) {
2019    if (some) strcat(flg_output, ",");
2020    some = 1;
2021    strcat(flg_output, "IA");
2022  }
2023  if (flags == 0xF) {
2024    if (some) strcat(flg_output, ",");
2025    some = 1;
2026    strcat(flg_output, "VI");
2027  }
2028  fprintf(stdout, " %s", flg_output);
2029}
2030
2031static
2032void print_perms(int perms)
2033{
2034  fprintf(stdout, " %8X", perms);
2035}
2036
2037static
2038void print_sid(sid_t *sid)
2039{
2040  int i, comps = sid->auths;
2041  fprintf(stdout, "S-%u-%u", sid->ver, sid->auth[5]);
2042
2043  for (i = 0; i < comps; i++) 
2044    fprintf(stdout, "-%u", sid->sub_auths[i]);
2045
2046  /*fprintf(stdout, "\n");*/
2047}
2048
2049static
2050void print_acl(ACL *acl, const char *prefix)
2051{
2052  int i;
2053
2054  for (i = 0; i < acl->num_aces; i++) {
2055    fprintf(stdout, ";;%s", prefix);
2056    print_type(acl->aces[i]->type);
2057    print_flags(acl->aces[i]->flags);
2058    print_perms(acl->aces[i]->perms);
2059    fprintf(stdout, " ");
2060    print_sid(acl->aces[i]->trustee);
2061  }
2062}
2063
2064static
2065int print_sec(SEC_DESC *sec_desc)
2066{
2067  if (!print_security) return 1;
2068  fprintf(stdout, ";;  SECURITY\n");
2069  fprintf(stdout, ";;   Owner: ");
2070  print_sid(sec_desc->owner);
2071  fprintf(stdout, ";;   Group: ");
2072  print_sid(sec_desc->group);
2073  if (sec_desc->sacl) {
2074    fprintf(stdout, ";;    SACL:\n");
2075    print_acl(sec_desc->sacl, " ");
2076  }
2077  if (sec_desc->dacl) {
2078    fprintf(stdout, ";;    DACL:\n");
2079    print_acl(sec_desc->dacl, " ");
2080  }
2081  return 1;
2082}
2083
2084/*
2085 * Value print function here ...
2086 */
2087static
2088int print_val(const char *path, char *val_name, int val_type, int data_len, 
2089              void *data_blk, int terminal, int first, int last)
2090{
2091  unsigned char* data_asc;
2092 
2093  if(!val_name)
2094    val_name = "<No Name>";
2095
2096  fprintf(stdout, "%s", path);
2097  data_asc = data_to_ascii((unsigned char *)data_blk, data_len, val_type);
2098  fprintf(stdout, "%s:%s=%s\n", val_name, val_to_str(val_type, reg_type_names),
2099          data_asc);
2100 
2101  free(data_asc);
2102  return 1;
2103}
2104
2105static
2106void usage(void)
2107{
2108  fprintf(stderr, "Usage: readreg [-f<filterprefix>] [-v] [-p] [-k] [-s]"
2109          "<registryfile>\n");
2110  fprintf(stderr, "Version: 0.1\n\n");
2111  fprintf(stderr, "\n\t-v\t sets verbose mode");
2112  fprintf(stderr, "\n\t-f\t a simple prefix filter.");
2113  fprintf(stderr, "\n\t-s\t prints security descriptors");
2114  fprintf(stderr, "\n");
2115}
2116
2117
2118int main(int argc, char *argv[])
2119{
2120  REGF *regf;
2121  extern char *optarg;
2122  extern int optind;
2123  int opt; 
2124  int regf_opt = 1;
2125  char* filter_prefix = "";
2126
2127  if (argc < 2)
2128  {
2129    usage();
2130    exit(1);
2131  }
2132 
2133  /*
2134   * Now, process the arguments
2135   */
2136
2137  while ((opt = getopt(argc, argv, "svkf:o:c:")) != EOF)
2138  {
2139    switch (opt)
2140    {
2141    case 'f':
2142      /*full_print = 1;*/
2143      filter_prefix = strdup(optarg);
2144      regf_opt++;
2145      break;
2146
2147    case 's':
2148      print_security++;
2149      full_print++;
2150      regf_opt++;
2151      break;
2152
2153    case 'v':
2154      verbose++;
2155      regf_opt++;
2156      break;
2157
2158    case 'k':
2159      regf_opt++;
2160      break;
2161
2162    default:
2163      usage();
2164      exit(1);
2165      break;
2166    }
2167  }
2168
2169  /*
2170   * We only want to complain about the lack of a default owner SID if
2171   * we need one. This approximates that need
2172   */
2173  if (!def_owner_sid_str) {
2174    def_owner_sid_str = "S-1-5-21-1-2-3-4";
2175    if (verbose)
2176      fprintf(stderr, "Warning, default owner SID not set. Setting to %s\n",
2177              def_owner_sid_str);
2178  }
2179
2180  if ((regf = nt_create_regf()) == NULL) 
2181  {
2182    fprintf(stderr, "Could not create registry object: %s\n", strerror(errno));
2183    exit(2);
2184  }
2185
2186  if (regf_opt < argc) 
2187  { /* We have a registry file */
2188    if (!nt_set_regf_input_file(regf, argv[regf_opt])) 
2189    {
2190      fprintf(stderr, "Could not set name of registry file: %s, %s\n", 
2191              argv[regf_opt], strerror(errno));
2192      exit(3);
2193    }
2194
2195    /* Now, open it, and bring it into memory :-) */
2196    if (nt_load_registry(regf) < 0) 
2197    {
2198      fprintf(stderr, "Could not load registry: %s\n", argv[1]);
2199      exit(4);
2200    }
2201  }
2202
2203  /*
2204   * At this point, we should have a registry in memory and should be able
2205   * to iterate over it.
2206   */
2207  nt_key_iterator(regf, regf->root, 0, "", filter_prefix);
2208
2209  return 0;
2210}
Note: See TracBrowser for help on using the repository browser.