source: src/reglookup.c @ 7

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

Fixed a bug in output.

Improved typing output.

Added type filter command line argument.

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