source: releases/release-0.1/src/reglookup.c@ 293

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

moved project under trunk. (I am a subversion newbie.)

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