source: src/reglookup.c @ 1

Last change on this file since 1 was 1, checked in by tim, 20 years ago

imported initial version of project, based on previous work.

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