source: releases/0.9.0/src/reglookup.c@ 293

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

fixed minor path/type filter bug in reglookup
misc code cleanups

  • Property svn:keywords set to Id
File size: 15.6 KB
Line 
1/*
2 * A utility to read a Windows NT/2K/XP/2K3 registry file, using
3 * Gerald Carter''s regfio interface.
4 *
5 * Copyright (C) 2005-2008 Timothy D. Morgan
6 * Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 3 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * $Id: reglookup.c 121 2008-08-09 17:22:26Z tim $
22 */
23
24
25#include <stdlib.h>
26#include <sysexits.h>
27#include <stdio.h>
28#include <string.h>
29#include <strings.h>
30#include <time.h>
31#include "../include/regfi.h"
32#include "../include/void_stack.h"
33
34/* Globals, influenced by command line parameters */
35bool print_verbose = false;
36bool print_security = false;
37bool print_header = true;
38bool path_filter_enabled = false;
39bool type_filter_enabled = false;
40char* path_filter = NULL;
41int type_filter;
42char* registry_file = NULL;
43
44/* Other globals */
45REGF_FILE* f;
46
47
48/* XXX: A hack to share some functions with reglookup-recover.c.
49 * Should move these into a properly library at some point.
50 */
51#include "common.c"
52
53
54void printValue(const REGF_VK_REC* vk, char* prefix)
55{
56 char* quoted_value = NULL;
57 char* quoted_name = NULL;
58 char* conv_error = NULL;
59 const char* str_type = NULL;
60 uint32 size = vk->data_size;
61
62 /* Microsoft's documentation indicates that "available memory" is
63 * the limit on value sizes. Annoying. We limit it to 1M which
64 * should rarely be exceeded, unless the file is corrupt or
65 * malicious. For more info, see:
66 * http://msdn2.microsoft.com/en-us/library/ms724872.aspx
67 */
68 if(size > VK_MAX_DATA_LENGTH)
69 {
70 fprintf(stderr, "WARNING: value data size %d larger than "
71 "%d, truncating...\n", size, VK_MAX_DATA_LENGTH);
72 size = VK_MAX_DATA_LENGTH;
73 }
74
75 quoted_name = quote_string(vk->valuename, key_special_chars);
76 if (quoted_name == NULL)
77 { /* Value names are NULL when we're looking at the "(default)" value.
78 * Currently we just return a 0-length string to try an eliminate
79 * ambiguity with a literal "(default)" value. The data type of a line
80 * in the output allows one to differentiate between the parent key and
81 * this value.
82 */
83 quoted_name = malloc(1*sizeof(char));
84 if(quoted_name == NULL)
85 bailOut(EX_OSERR, "ERROR: Could not allocate sufficient memory.\n");
86 quoted_name[0] = '\0';
87 }
88
89 quoted_value = data_to_ascii(vk->data, size, vk->type, &conv_error);
90 if(quoted_value == NULL)
91 {
92 if(conv_error == NULL)
93 fprintf(stderr, "WARNING: Could not quote value for '%s/%s'. "
94 "Memory allocation failure likely.\n", prefix, quoted_name);
95 else if(print_verbose)
96 fprintf(stderr, "WARNING: Could not quote value for '%s/%s'. "
97 "Returned error: %s\n", prefix, quoted_name, conv_error);
98 }
99 /* XXX: should these always be printed? */
100 else if(conv_error != NULL && print_verbose)
101 fprintf(stderr, "VERBOSE: While quoting value for '%s/%s', "
102 "warning returned: %s\n", prefix, quoted_name, conv_error);
103
104 str_type = regfi_type_val2str(vk->type);
105 if(print_security)
106 {
107 if(str_type == NULL)
108 printf("%s/%s,0x%.8X,%s,,,,,\n", prefix, quoted_name,
109 vk->type, quoted_value);
110 else
111 printf("%s/%s,%s,%s,,,,,\n", prefix, quoted_name,
112 str_type, quoted_value);
113 }
114 else
115 {
116 if(str_type == NULL)
117 printf("%s/%s,0x%.8X,%s,\n", prefix, quoted_name,
118 vk->type, quoted_value);
119 else
120 printf("%s/%s,%s,%s,\n", prefix, quoted_name,
121 str_type, quoted_value);
122 }
123
124 if(quoted_value != NULL)
125 free(quoted_value);
126 if(quoted_name != NULL)
127 free(quoted_name);
128 if(conv_error != NULL)
129 free(conv_error);
130}
131
132
133
134/* XXX: Each chunk must be unquoted after it is split out.
135 * Quoting syntax may need to be standardized and pushed into the API
136 * to deal with this issue and others.
137 */
138char** splitPath(const char* s)
139{
140 char** ret_val;
141 const char* cur = s;
142 char* next = NULL;
143 char* copy;
144 uint32 ret_cur = 0;
145
146 ret_val = (char**)malloc((REGF_MAX_DEPTH+1+1)*sizeof(char**));
147 if (ret_val == NULL)
148 return NULL;
149 ret_val[0] = NULL;
150
151 /* We return a well-formed, 0-length, path even when input is icky. */
152 if (s == NULL)
153 return ret_val;
154
155 while((next = strchr(cur, '/')) != NULL)
156 {
157 if ((next-cur) > 0)
158 {
159 copy = (char*)malloc((next-cur+1)*sizeof(char));
160 if(copy == NULL)
161 bailOut(EX_OSERR, "ERROR: Memory allocation problem.\n");
162
163 memcpy(copy, cur, next-cur);
164 copy[next-cur] = '\0';
165 ret_val[ret_cur++] = copy;
166 if(ret_cur < (REGF_MAX_DEPTH+1+1))
167 ret_val[ret_cur] = NULL;
168 else
169 bailOut(EX_DATAERR, "ERROR: Registry maximum depth exceeded.\n");
170 }
171 cur = next+1;
172 }
173
174 /* Grab last element, if path doesn't end in '/'. */
175 if(strlen(cur) > 0)
176 {
177 copy = strdup(cur);
178 ret_val[ret_cur++] = copy;
179 if(ret_cur < (REGF_MAX_DEPTH+1+1))
180 ret_val[ret_cur] = NULL;
181 else
182 bailOut(EX_DATAERR, "ERROR: Registry maximum depth exceeded.\n");
183 }
184
185 return ret_val;
186}
187
188
189void freePath(char** path)
190{
191 uint32 i;
192
193 if(path == NULL)
194 return;
195
196 for(i=0; path[i] != NULL; i++)
197 free(path[i]);
198
199 free(path);
200}
201
202
203/* Returns a quoted path from an iterator's stack */
204/* XXX: Some way should be found to integrate this into regfi's API
205 * The problem is that the escaping is sorta reglookup-specific.
206 */
207char* iter2Path(REGFI_ITERATOR* i)
208{
209 const REGFI_ITER_POSITION* cur;
210 uint32 buf_left = 127;
211 uint32 buf_len = buf_left+1;
212 uint32 name_len = 0;
213 uint32 grow_amt;
214 char* buf;
215 char* new_buf;
216 char* name;
217 const char* cur_name;
218 void_stack_iterator* iter;
219
220 buf = (char*)malloc((buf_len)*sizeof(char));
221 if (buf == NULL)
222 return NULL;
223 buf[0] = '\0';
224
225 iter = void_stack_iterator_new(i->key_positions);
226 if (iter == NULL)
227 {
228 free(buf);
229 return NULL;
230 }
231
232 /* skip root element */
233 if(void_stack_size(i->key_positions) < 1)
234 {
235 buf[0] = '/';
236 buf[1] = '\0';
237 return buf;
238 }
239 cur = void_stack_iterator_next(iter);
240
241 do
242 {
243 cur = void_stack_iterator_next(iter);
244 if (cur == NULL)
245 cur_name = i->cur_key->keyname;
246 else
247 cur_name = cur->nk->keyname;
248
249 buf[buf_len-buf_left-1] = '/';
250 buf_left -= 1;
251 name = quote_string(cur_name, key_special_chars);
252 name_len = strlen(name);
253 if(name_len+1 > buf_left)
254 {
255 grow_amt = (uint32)(buf_len/2);
256 buf_len += name_len+1+grow_amt-buf_left;
257 if((new_buf = realloc(buf, buf_len)) == NULL)
258 {
259 free(buf);
260 free(iter);
261 return NULL;
262 }
263 buf = new_buf;
264 buf_left = grow_amt + name_len + 1;
265 }
266 strncpy(buf+(buf_len-buf_left-1), name, name_len);
267 buf_left -= name_len;
268 buf[buf_len-buf_left-1] = '\0';
269 free(name);
270 } while(cur != NULL);
271
272 return buf;
273}
274
275
276void printValueList(REGFI_ITERATOR* i, char* prefix)
277{
278 const REGF_VK_REC* value;
279
280 value = regfi_iterator_first_value(i);
281 while(value != NULL)
282 {
283 if(!type_filter_enabled || (value->type == type_filter))
284 printValue(value, prefix);
285 value = regfi_iterator_next_value(i);
286 }
287}
288
289
290void printKey(REGFI_ITERATOR* i, char* full_path)
291{
292 static char empty_str[1] = "";
293 char* owner = NULL;
294 char* group = NULL;
295 char* sacl = NULL;
296 char* dacl = NULL;
297 char mtime[20];
298 time_t tmp_time[1];
299 struct tm* tmp_time_s = NULL;
300 const REGF_SK_REC* sk;
301 const REGF_NK_REC* k = regfi_iterator_cur_key(i);
302
303 *tmp_time = nt_time_to_unix(&k->mtime);
304 tmp_time_s = gmtime(tmp_time);
305 strftime(mtime, sizeof(mtime), "%Y-%m-%d %H:%M:%S", tmp_time_s);
306
307 if(print_security && (sk=regfi_iterator_cur_sk(i)))
308 {
309 owner = regfi_get_owner(sk->sec_desc);
310 group = regfi_get_group(sk->sec_desc);
311 sacl = regfi_get_sacl(sk->sec_desc);
312 dacl = regfi_get_dacl(sk->sec_desc);
313 if(owner == NULL)
314 owner = empty_str;
315 if(group == NULL)
316 group = empty_str;
317 if(sacl == NULL)
318 sacl = empty_str;
319 if(dacl == NULL)
320 dacl = empty_str;
321
322 printf("%s,KEY,,%s,%s,%s,%s,%s\n", full_path, mtime,
323 owner, group, sacl, dacl);
324
325 if(owner != empty_str)
326 free(owner);
327 if(group != empty_str)
328 free(group);
329 if(sacl != empty_str)
330 free(sacl);
331 if(dacl != empty_str)
332 free(dacl);
333 }
334 else
335 printf("%s,KEY,,%s\n", full_path, mtime);
336}
337
338
339void printKeyTree(REGFI_ITERATOR* iter)
340{
341 const REGF_NK_REC* root = NULL;
342 const REGF_NK_REC* cur = NULL;
343 const REGF_NK_REC* sub = NULL;
344 char* path = NULL;
345 int key_type = regfi_type_str2val("KEY");
346 bool print_this = true;
347
348 root = cur = regfi_iterator_cur_key(iter);
349 sub = regfi_iterator_first_subkey(iter);
350
351 if(root == NULL)
352 bailOut(EX_DATAERR, "ERROR: root cannot be NULL.\n");
353
354 do
355 {
356 if(print_this)
357 {
358 path = iter2Path(iter);
359 if(path == NULL)
360 bailOut(EX_OSERR, "ERROR: Could not construct iterator's path.\n");
361
362 if(!type_filter_enabled || (key_type == type_filter))
363 printKey(iter, path);
364 if(!type_filter_enabled || (key_type != type_filter))
365 printValueList(iter, path);
366
367 free(path);
368 }
369
370 if(sub == NULL)
371 {
372 if(cur != root)
373 {
374 /* We're done with this sub-tree, going up and hitting other branches. */
375 if(!regfi_iterator_up(iter))
376 bailOut(EX_DATAERR, "ERROR: could not traverse iterator upward.\n");
377
378 cur = regfi_iterator_cur_key(iter);
379 if(cur == NULL)
380 bailOut(EX_DATAERR, "ERROR: unexpected NULL for key.\n");
381
382 sub = regfi_iterator_next_subkey(iter);
383 }
384 print_this = false;
385 }
386 else
387 { /* We have unexplored sub-keys.
388 * Let's move down and print this first sub-tree out.
389 */
390 if(!regfi_iterator_down(iter))
391 bailOut(EX_DATAERR, "ERROR: could not traverse iterator downward.\n");
392
393 cur = sub;
394 sub = regfi_iterator_first_subkey(iter);
395 print_this = true;
396 }
397 } while(!((cur == root) && (sub == NULL)));
398
399 if(print_verbose)
400 fprintf(stderr, "VERBOSE: Finished printing key tree.\n");
401}
402
403
404/* XXX: what if there is BOTH a value AND a key with that name?? */
405/*
406 * Returns 0 if path was not found.
407 * Returns 1 if path was found as value.
408 * Returns 2 if path was found as key.
409 * Returns less than 0 on other error.
410 */
411int retrievePath(REGFI_ITERATOR* iter, char** path)
412{
413 const REGF_VK_REC* value;
414 char* tmp_path_joined;
415 const char** tmp_path;
416 uint32 i;
417
418 if(path == NULL)
419 return -1;
420
421 /* One extra for any value at the end, and one more for NULL */
422 tmp_path = (const char**)malloc(sizeof(const char**)*(REGF_MAX_DEPTH+1+1));
423 if(tmp_path == NULL)
424 return -2;
425
426 /* Strip any potential value name at end of path */
427 for(i=0;
428 (path[i] != NULL) && (path[i+1] != NULL)
429 && (i < REGF_MAX_DEPTH+1+1);
430 i++)
431 tmp_path[i] = path[i];
432
433 tmp_path[i] = NULL;
434
435 if(print_verbose)
436 fprintf(stderr, "VERBOSE: Attempting to retrieve specified path: %s\n",
437 path_filter);
438
439 /* Special check for '/' path filter */
440 if(path[0] == NULL)
441 {
442 if(print_verbose)
443 fprintf(stderr, "VERBOSE: Found final path element as root key.\n");
444 return 2;
445 }
446
447 if(!regfi_iterator_walk_path(iter, tmp_path))
448 {
449 free(tmp_path);
450 return 0;
451 }
452
453 if(regfi_iterator_find_value(iter, path[i]))
454 {
455 if(print_verbose)
456 fprintf(stderr, "VERBOSE: Found final path element as value.\n");
457
458 value = regfi_iterator_cur_value(iter);
459 tmp_path_joined = iter2Path(iter);
460
461 if((value == NULL) || (tmp_path_joined == NULL))
462 bailOut(EX_OSERR, "ERROR: Unexpected error before printValue.\n");
463
464 if(!type_filter_enabled || (value->type == type_filter))
465 printValue(value, tmp_path_joined);
466
467 free(tmp_path);
468 free(tmp_path_joined);
469 return 1;
470 }
471 else if(regfi_iterator_find_subkey(iter, path[i]))
472 {
473 if(print_verbose)
474 fprintf(stderr, "VERBOSE: Found final path element as key.\n");
475
476 if(!regfi_iterator_down(iter))
477 bailOut(EX_DATAERR, "ERROR: Unexpected error on traversing path filter key.\n");
478
479 return 2;
480 }
481
482 if(print_verbose)
483 fprintf(stderr, "VERBOSE: Could not find last element of path.\n");
484
485 return 0;
486}
487
488
489static void usage(void)
490{
491 fprintf(stderr, "Usage: reglookup [-v] [-s]"
492 " [-p <PATH_FILTER>] [-t <TYPE_FILTER>]"
493 " <REGISTRY_FILE>\n");
494 fprintf(stderr, "Version: %s\n", REGLOOKUP_VERSION);
495 fprintf(stderr, "Options:\n");
496 fprintf(stderr, "\t-v\t sets verbose mode.\n");
497 fprintf(stderr, "\t-h\t enables header row. (default)\n");
498 fprintf(stderr, "\t-H\t disables header row.\n");
499 fprintf(stderr, "\t-s\t enables security descriptor output.\n");
500 fprintf(stderr, "\t-S\t disables security descriptor output. (default)\n");
501 fprintf(stderr, "\t-p\t restrict output to elements below this path.\n");
502 fprintf(stderr, "\t-t\t restrict results to this specific data type.\n");
503 fprintf(stderr, "\n");
504}
505
506
507int main(int argc, char** argv)
508{
509 char** path = NULL;
510 REGFI_ITERATOR* iter;
511 int retr_path_ret;
512 uint32 argi, arge;
513
514 /* Process command line arguments */
515 if(argc < 2)
516 {
517 usage();
518 bailOut(EX_USAGE, "ERROR: Requires at least one argument.\n");
519 }
520
521 arge = argc-1;
522 for(argi = 1; argi < arge; argi++)
523 {
524 if (strcmp("-p", argv[argi]) == 0)
525 {
526 if(++argi >= arge)
527 {
528 usage();
529 bailOut(EX_USAGE, "ERROR: '-p' option requires parameter.\n");
530 }
531 if((path_filter = strdup(argv[argi])) == NULL)
532 bailOut(EX_OSERR, "ERROR: Memory allocation problem.\n");
533
534 path_filter_enabled = true;
535 }
536 else if (strcmp("-t", argv[argi]) == 0)
537 {
538 if(++argi >= arge)
539 {
540 usage();
541 bailOut(EX_USAGE, "ERROR: '-t' option requires parameter.\n");
542 }
543 if((type_filter = regfi_type_str2val(argv[argi])) < 0)
544 {
545 fprintf(stderr, "ERROR: Invalid type specified: %s.\n", argv[argi]);
546 bailOut(EX_USAGE, "");
547 }
548 type_filter_enabled = true;
549 }
550 else if (strcmp("-h", argv[argi]) == 0)
551 print_header = true;
552 else if (strcmp("-H", argv[argi]) == 0)
553 print_header = false;
554 else if (strcmp("-s", argv[argi]) == 0)
555 print_security = true;
556 else if (strcmp("-S", argv[argi]) == 0)
557 print_security = false;
558 else if (strcmp("-v", argv[argi]) == 0)
559 print_verbose = true;
560 else
561 {
562 usage();
563 fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
564 bailOut(EX_USAGE, "");
565 }
566 }
567 if((registry_file = strdup(argv[argi])) == NULL)
568 bailOut(EX_OSERR, "ERROR: Memory allocation problem.\n");
569
570 f = regfi_open(registry_file);
571 if(f == NULL)
572 {
573 fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
574 bailOut(EX_NOINPUT, "");
575 }
576
577 iter = regfi_iterator_new(f);
578 if(iter == NULL)
579 bailOut(EX_OSERR, "ERROR: Couldn't create registry iterator.\n");
580
581 if(print_header)
582 {
583 if(print_security)
584 printf("PATH,TYPE,VALUE,MTIME,OWNER,GROUP,SACL,DACL\n");
585 else
586 printf("PATH,TYPE,VALUE,MTIME\n");
587 }
588
589 if(path_filter_enabled && path_filter != NULL)
590 path = splitPath(path_filter);
591
592 if(path != NULL)
593 {
594 retr_path_ret = retrievePath(iter, path);
595 freePath(path);
596
597 if(retr_path_ret == 0)
598 fprintf(stderr, "WARNING: specified path not found.\n");
599 else if (retr_path_ret == 2)
600 printKeyTree(iter);
601 else if(retr_path_ret < 0)
602 {
603 fprintf(stderr, "ERROR: retrievePath() returned %d.\n",
604 retr_path_ret);
605 bailOut(EX_DATAERR,"ERROR: Unknown error occurred in retrieving path.\n");
606 }
607 }
608 else
609 printKeyTree(iter);
610
611 regfi_iterator_free(iter);
612 regfi_close(f);
613
614 return 0;
615}
Note: See TracBrowser for help on using the repository browser.