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