source: releases/0.3.0/src/reglookup.c@ 218

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

Added QWORD type support.

  • Property svn:keywords set to Id
File size: 24.0 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-2006 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 2 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 72 2006-07-30 20:09:07Z tim $
22 */
23
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <strings.h>
29#include <time.h>
30#include <iconv.h>
31#include "../include/regfio.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 */
45const char* key_special_chars = ",\"\\/";
46const char* subfield_special_chars = ",\"\\|";
47const char* common_special_chars = ",\"\\";
48
49iconv_t conv_desc;
50
51
52void bailOut(int code, char* message)
53{
54 fprintf(stderr, message);
55 exit(code);
56}
57
58
59/* Returns a newly malloc()ed string which contains original buffer,
60 * except for non-printable or special characters are quoted in hex
61 * with the syntax '\xQQ' where QQ is the hex ascii value of the quoted
62 * character. A null terminator is added, since only ascii, not binary,
63 * is returned.
64 */
65static char* quote_buffer(const unsigned char* str,
66 unsigned int len, const char* special)
67{
68 unsigned int i, added_len;
69 unsigned int num_written = 0;
70
71 unsigned int buf_len = sizeof(char)*(len+1);
72 char* ret_val = malloc(buf_len);
73 char* tmp_buf;
74
75 if(ret_val == NULL)
76 return NULL;
77
78 for(i=0; i<len; i++)
79 {
80 if(buf_len <= (num_written+5))
81 {
82 /* Expand the buffer by the memory consumption rate seen so far
83 * times the amount of input left to process. The expansion is bounded
84 * below by a minimum safety increase, and above by the maximum possible
85 * output string length. This should minimize both the number of
86 * reallocs() and the amount of wasted memory.
87 */
88 added_len = (len-i)*num_written/(i+1);
89 if((buf_len+added_len) > (len*4+1))
90 buf_len = len*4+1;
91 else
92 {
93 if (added_len < 5)
94 buf_len += 5;
95 else
96 buf_len += added_len;
97 }
98
99 tmp_buf = realloc(ret_val, buf_len);
100 if(tmp_buf == NULL)
101 {
102 free(ret_val);
103 return NULL;
104 }
105 ret_val = tmp_buf;
106 }
107
108 if(str[i] < 32 || str[i] > 126 || strchr(special, str[i]) != NULL)
109 {
110 num_written += snprintf(ret_val + num_written, buf_len - num_written,
111 "\\x%.2X", str[i]);
112 }
113 else
114 ret_val[num_written++] = str[i];
115 }
116 ret_val[num_written] = '\0';
117
118 return ret_val;
119}
120
121
122/* Returns a newly malloc()ed string which contains original string,
123 * except for non-printable or special characters are quoted in hex
124 * with the syntax '\xQQ' where QQ is the hex ascii value of the quoted
125 * character.
126 */
127static char* quote_string(const char* str, const char* special)
128{
129 unsigned int len;
130
131 if(str == NULL)
132 return NULL;
133
134 len = strlen(str);
135 return quote_buffer((const unsigned char*)str, len, special);
136}
137
138
139/*
140 * Convert from UTF-16LE to ASCII. Accepts a Unicode buffer, uni, and
141 * it's length, uni_max. Writes ASCII to the buffer ascii, whose size
142 * is ascii_max. Writes at most (ascii_max-1) bytes to ascii, and null
143 * terminates the string. Returns the length of the string stored in
144 * ascii. On error, returns a negative errno code.
145 */
146static int uni_to_ascii(unsigned char* uni, char* ascii,
147 unsigned int uni_max, unsigned int ascii_max)
148{
149 char* inbuf = (char*)uni;
150 char* outbuf = ascii;
151 size_t in_len = (size_t)uni_max;
152 size_t out_len = (size_t)(ascii_max-1);
153 int ret;
154
155 /* Set up conversion descriptor. */
156 conv_desc = iconv_open("US-ASCII", "UTF-16LE");
157
158 ret = iconv(conv_desc, &inbuf, &in_len, &outbuf, &out_len);
159 if(ret == -1)
160 {
161 iconv_close(conv_desc);
162 return -errno;
163 }
164 *outbuf = '\0';
165
166 iconv_close(conv_desc);
167 return strlen(ascii);
168}
169
170
171/*
172 * Convert a data value to a string for display. Returns NULL on error,
173 * and the string to display if there is no error, or a non-fatal
174 * error. On any error (fatal or non-fatal) occurs, (*error_msg) will
175 * be set to a newly allocated string, containing an error message. If
176 * a memory allocation failure occurs while generating the error
177 * message, both the return value and (*error_msg) will be NULL. It
178 * is the responsibility of the caller to free both a non-NULL return
179 * value, and a non-NULL (*error_msg).
180 */
181static char* data_to_ascii(unsigned char *datap, int len, int type,
182 char** error_msg)
183{
184 char* asciip;
185 char* ascii;
186 unsigned char* cur_str;
187 char* cur_ascii;
188 char* cur_quoted;
189 char* tmp_err;
190 const char* str_type;
191 unsigned int i;
192 unsigned int cur_str_len;
193 unsigned int ascii_max, cur_str_max;
194 unsigned int str_rem, cur_str_rem, alen;
195 int ret_err;
196 unsigned short num_nulls;
197
198 *error_msg = NULL;
199
200 switch (type)
201 {
202 case REG_SZ:
203 case REG_EXPAND_SZ:
204 /* REG_LINK is a symbolic link, stored as a unicode string. */
205 case REG_LINK:
206 ascii_max = sizeof(char)*(len+1);
207 ascii = malloc(ascii_max);
208 if(ascii == NULL)
209 return NULL;
210
211 /* Sometimes values have binary stored in them. If the unicode
212 * conversion fails, just quote it raw.
213 */
214 ret_err = uni_to_ascii(datap, ascii, len, ascii_max);
215 if(ret_err < 0)
216 {
217 tmp_err = strerror(-ret_err);
218 str_type = regfio_type_val2str(type);
219 *error_msg = (char*)malloc(65+strlen(str_type)+strlen(tmp_err)+1);
220 if(*error_msg == NULL)
221 {
222 free(ascii);
223 return NULL;
224 }
225 sprintf(*error_msg, "Unicode conversion failed on %s field; "
226 "printing as binary. Error: %s", str_type, tmp_err);
227
228 cur_quoted = quote_buffer(datap, len, common_special_chars);
229 }
230 else
231 cur_quoted = quote_string(ascii, common_special_chars);
232 free(ascii);
233 if(cur_quoted == NULL)
234 {
235 *error_msg = (char*)malloc(27+1);
236 if(*error_msg != NULL)
237 strcpy(*error_msg, "Buffer could not be quoted.");
238 }
239 return cur_quoted;
240 break;
241
242 case REG_DWORD:
243 ascii_max = sizeof(char)*(8+2+1);
244 ascii = malloc(ascii_max);
245 if(ascii == NULL)
246 return NULL;
247
248 snprintf(ascii, ascii_max, "0x%.2X%.2X%.2X%.2X",
249 datap[0], datap[1], datap[2], datap[3]);
250 return ascii;
251 break;
252
253 case REG_DWORD_BE:
254 ascii_max = sizeof(char)*(8+2+1);
255 ascii = malloc(ascii_max);
256 if(ascii == NULL)
257 return NULL;
258
259 snprintf(ascii, ascii_max, "0x%.2X%.2X%.2X%.2X",
260 datap[3], datap[2], datap[1], datap[0]);
261 return ascii;
262 break;
263
264 case REG_QWORD:
265 ascii_max = sizeof(char)*(16+2+1);
266 ascii = malloc(ascii_max);
267 if(ascii == NULL)
268 return NULL;
269
270 snprintf(ascii, ascii_max, "0x%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X",
271 datap[7], datap[6], datap[5], datap[4],
272 datap[3], datap[2], datap[1], datap[0]);
273 return ascii;
274 break;
275
276
277 /* XXX: this MULTI_SZ parser is pretty inefficient. Should be
278 * redone with fewer malloc calls and better string concatenation.
279 */
280 case REG_MULTI_SZ:
281 ascii_max = sizeof(char)*(len*4+1);
282 cur_str_max = sizeof(char)*(len+1);
283 cur_str = malloc(cur_str_max);
284 cur_ascii = malloc(cur_str_max);
285 ascii = malloc(ascii_max);
286 if(ascii == NULL || cur_str == NULL || cur_ascii == NULL)
287 return NULL;
288
289 /* Reads until it reaches 4 consecutive NULLs,
290 * which is two nulls in unicode, or until it reaches len, or until we
291 * run out of buffer. The latter should never happen, but we shouldn't
292 * trust our file to have the right lengths/delimiters.
293 */
294 asciip = ascii;
295 num_nulls = 0;
296 str_rem = ascii_max;
297 cur_str_rem = cur_str_max;
298 cur_str_len = 0;
299
300 for(i=0; (i < len) && str_rem > 0; i++)
301 {
302 *(cur_str+cur_str_len) = *(datap+i);
303 if(*(cur_str+cur_str_len) == 0)
304 num_nulls++;
305 else
306 num_nulls = 0;
307 cur_str_len++;
308
309 if(num_nulls == 2)
310 {
311 ret_err = uni_to_ascii(cur_str, cur_ascii, cur_str_len-1, cur_str_max);
312 if(ret_err < 0)
313 {
314 /* XXX: should every sub-field error be enumerated? */
315 if(*error_msg == NULL)
316 {
317 tmp_err = strerror(-ret_err);
318 *error_msg = (char*)malloc(90+strlen(tmp_err)+1);
319 if(*error_msg == NULL)
320 {
321 free(cur_str);
322 free(cur_ascii);
323 free(ascii);
324 return NULL;
325 }
326 sprintf(*error_msg, "Unicode conversion failed on at least one "
327 "MULTI_SZ sub-field; printing as binary. Error: %s",
328 tmp_err);
329 }
330 cur_quoted = quote_buffer(cur_str, cur_str_len-1,
331 subfield_special_chars);
332 }
333 else
334 cur_quoted = quote_string(cur_ascii, subfield_special_chars);
335
336 alen = snprintf(asciip, str_rem, "%s", cur_quoted);
337 asciip += alen;
338 str_rem -= alen;
339 free(cur_quoted);
340
341 if(*(datap+i+1) == 0 && *(datap+i+2) == 0)
342 break;
343 else
344 {
345 if(str_rem > 0)
346 {
347 asciip[0] = '|';
348 asciip[1] = '\0';
349 asciip++;
350 str_rem--;
351 }
352 memset(cur_str, 0, cur_str_max);
353 cur_str_len = 0;
354 num_nulls = 0;
355 /* To eliminate leading nulls in subsequent strings. */
356 i++;
357 }
358 }
359 }
360 *asciip = 0;
361 free(cur_str);
362 free(cur_ascii);
363 return ascii;
364 break;
365
366 /* XXX: Dont know what to do with these yet, just print as binary... */
367 case REG_NONE:
368 case REG_RESOURCE_LIST:
369 case REG_FULL_RESOURCE_DESCRIPTOR:
370 case REG_RESOURCE_REQUIREMENTS_LIST:
371
372 case REG_BINARY:
373 return quote_buffer(datap, len, common_special_chars);
374 break;
375 }
376
377
378 /* Invalid type */
379 *error_msg = (char*)malloc(33+11+1);
380 if(*error_msg != NULL)
381 sprintf(*error_msg, "Unrecognized registry data type: %d", type);
382
383 return NULL;
384}
385
386
387void_stack* path2Stack(const char* s)
388{
389 void_stack* ret_val;
390 void_stack* rev_ret = void_stack_new(1024);
391 const char* cur = s;
392 char* next = NULL;
393 char* copy;
394
395 if (rev_ret == NULL)
396 return NULL;
397 if (s == NULL)
398 return rev_ret;
399
400 while((next = strchr(cur, '/')) != NULL)
401 {
402 if ((next-cur) > 0)
403 {
404 copy = (char*)malloc((next-cur+1)*sizeof(char));
405 if(copy == NULL)
406 bailOut(2, "ERROR: Memory allocation problem.\n");
407
408 memcpy(copy, cur, next-cur);
409 copy[next-cur] = '\0';
410 void_stack_push(rev_ret, copy);
411 }
412 cur = next+1;
413 }
414 if(strlen(cur) > 0)
415 {
416 copy = strdup(cur);
417 void_stack_push(rev_ret, copy);
418 }
419
420 ret_val = void_stack_copy_reverse(rev_ret);
421 void_stack_destroy(rev_ret);
422
423 return ret_val;
424}
425
426/* Returns a quoted path from an nk_stack */
427char* stack2Path(void_stack* nk_stack)
428{
429 const REGF_NK_REC* cur;
430 uint32 buf_left = 127;
431 uint32 buf_len = buf_left+1;
432 uint32 name_len = 0;
433 uint32 grow_amt;
434 char* buf;
435 char* new_buf;
436 char* name;
437 void_stack_iterator* iter;
438
439 buf = (char*)malloc((buf_len)*sizeof(char));
440 if (buf == NULL)
441 return NULL;
442 buf[0] = '\0';
443
444 iter = void_stack_iterator_new(nk_stack);
445 if (iter == NULL)
446 {
447 free(buf);
448 return NULL;
449 }
450
451 /* skip root element */
452 cur = void_stack_iterator_next(iter);
453
454 while((cur = void_stack_iterator_next(iter)) != NULL)
455 {
456 buf[buf_len-buf_left-1] = '/';
457 buf_left -= 1;
458 name = quote_string(cur->keyname, key_special_chars);
459 name_len = strlen(name);
460 if(name_len+1 > buf_left)
461 {
462 grow_amt = (uint32)(buf_len/2);
463 buf_len += name_len+1+grow_amt-buf_left;
464 if((new_buf = realloc(buf, buf_len)) == NULL)
465 {
466 free(buf);
467 free(iter);
468 return NULL;
469 }
470 buf = new_buf;
471 buf_left = grow_amt + name_len + 1;
472 }
473 strncpy(buf+(buf_len-buf_left-1), name, name_len);
474 buf_left -= name_len;
475 buf[buf_len-buf_left-1] = '\0';
476 free(name);
477 }
478
479 return buf;
480}
481
482
483void printValue(REGF_VK_REC* vk, char* prefix)
484{
485 uint32 size;
486 uint8 tmp_buf[4];
487 char* quoted_value = NULL;
488 char* quoted_name = NULL;
489 char* conv_error = NULL;
490
491 /* Thanks Microsoft for making this process so straight-forward!!! */
492 size = (vk->data_size & ~VK_DATA_IN_OFFSET);
493 if(vk->data_size & VK_DATA_IN_OFFSET)
494 {
495 tmp_buf[0] = (uint8)((vk->data_off >> 3) & 0xFF);
496 tmp_buf[1] = (uint8)((vk->data_off >> 2) & 0xFF);
497 tmp_buf[2] = (uint8)((vk->data_off >> 1) & 0xFF);
498 tmp_buf[3] = (uint8)(vk->data_off & 0xFF);
499 if(size > 4)
500 size = 4;
501 quoted_value = data_to_ascii(tmp_buf, 4, vk->type, &conv_error);
502 }
503 else
504 {
505 /* XXX: This is a safety hack. No data fields have yet been found
506 * larger, but length limits are probably better got from fields
507 * in the registry itself, within reason.
508 */
509 if(size > 16384)
510 {
511 fprintf(stderr, "WARNING: key size %d larger than "
512 "16384, truncating...\n", size);
513 size = 16384;
514 }
515
516 quoted_value = data_to_ascii(vk->data, vk->data_size,
517 vk->type, &conv_error);
518 }
519
520 /* XXX: Sometimes value names can be NULL in registry. Need to
521 * figure out why and when, and generate the appropriate output
522 * for that condition.
523 */
524 quoted_name = quote_string(vk->valuename, common_special_chars);
525
526 if(quoted_value == NULL)
527 {
528 if(conv_error == NULL)
529 fprintf(stderr, "WARNING: Could not quote value for '%s/%s'. "
530 "Memory allocation failure likely.\n", prefix, quoted_name);
531 else
532 fprintf(stderr, "WARNING: Could not quote value for '%s/%s'. "
533 "Returned error: %s\n", prefix, quoted_name, conv_error);
534 }
535 /* XXX: should these always be printed? */
536 else if(conv_error != NULL && print_verbose)
537 fprintf(stderr, "VERBOSE: While quoting value for '%s/%s', "
538 "warning returned: %s\n", prefix, quoted_name, conv_error);
539
540 if(print_security)
541 printf("%s/%s,%s,%s,,,,,\n", prefix, quoted_name,
542 regfio_type_val2str(vk->type), quoted_value);
543 else
544 printf("%s/%s,%s,%s,\n", prefix, quoted_name,
545 regfio_type_val2str(vk->type), quoted_value);
546
547 if(quoted_value != NULL)
548 free(quoted_value);
549 if(quoted_name != NULL)
550 free(quoted_name);
551 if(conv_error != NULL)
552 free(conv_error);
553}
554
555
556void printValueList(REGF_NK_REC* nk, char* prefix)
557{
558 uint32 i;
559
560 for(i=0; i < nk->num_values; i++)
561 if(!type_filter_enabled || (nk->values[i].type == type_filter))
562 printValue(nk->values+i, prefix);
563}
564
565
566void printKey(REGF_NK_REC* k, char* full_path)
567{
568 static char empty_str[1] = "";
569 char* owner = NULL;
570 char* group = NULL;
571 char* sacl = NULL;
572 char* dacl = NULL;
573 char mtime[20];
574 time_t tmp_time[1];
575 struct tm* tmp_time_s = NULL;
576
577 *tmp_time = nt_time_to_unix(&k->mtime);
578 tmp_time_s = gmtime(tmp_time);
579 strftime(mtime, sizeof(mtime), "%Y-%m-%d %H:%M:%S", tmp_time_s);
580
581 if(print_security)
582 {
583 owner = regfio_get_owner(k->sec_desc->sec_desc);
584 group = regfio_get_group(k->sec_desc->sec_desc);
585 sacl = regfio_get_sacl(k->sec_desc->sec_desc);
586 dacl = regfio_get_dacl(k->sec_desc->sec_desc);
587 if(owner == NULL)
588 owner = empty_str;
589 if(group == NULL)
590 group = empty_str;
591 if(sacl == NULL)
592 sacl = empty_str;
593 if(dacl == NULL)
594 dacl = empty_str;
595
596 printf("%s,KEY,,%s,%s,%s,%s,%s\n", full_path, mtime,
597 owner, group, sacl, dacl);
598
599 if(owner != empty_str)
600 free(owner);
601 if(group != empty_str)
602 free(group);
603 if(sacl != empty_str)
604 free(sacl);
605 if(dacl != empty_str)
606 free(dacl);
607 }
608 else
609 printf("%s,KEY,,%s\n", full_path, mtime);
610}
611
612
613void printKeyTree(REGF_FILE* f, void_stack* nk_stack, const char* prefix)
614{
615 REGF_NK_REC* cur = NULL;
616 REGF_NK_REC* sub = NULL;
617 char* path = NULL;
618 char* val_path = NULL;
619 uint32 val_path_len = 0;
620 uint32 path_len = 0;
621 uint32 prefix_len = strlen(prefix);
622 int key_type = regfio_type_str2val("KEY");
623
624 if((cur = (REGF_NK_REC*)void_stack_cur(nk_stack)) != NULL)
625 {
626 cur->subkey_index = 0;
627 path = stack2Path(nk_stack);
628
629 if(print_verbose)
630 {
631 if(prefix[0] == '\0')
632 fprintf(stderr, "VERBOSE: Printing key tree under path: /\n");
633 else
634 fprintf(stderr, "VERBOSE: Printing key tree under path: %s\n",
635 prefix);
636 }
637
638 path_len = strlen(path);
639 val_path_len = prefix_len+path_len;
640 val_path = (char*)malloc(val_path_len+1+1);
641 if(val_path == NULL)
642 bailOut(2, "ERROR: Could not allocate val_path.\n");
643
644 strcpy(val_path, prefix);
645 strcpy(val_path+prefix_len, path);
646 if(val_path[0] == '\0')
647 {
648 val_path[0] = '/';
649 val_path[1] = '\0';
650 }
651 if(!type_filter_enabled || (key_type == type_filter))
652 printKey(cur, val_path);
653 if(!type_filter_enabled || (key_type != type_filter))
654 printValueList(cur, val_path);
655
656 while((cur = (REGF_NK_REC*)void_stack_cur(nk_stack)) != NULL)
657 {
658 if((sub = regfio_fetch_subkey(f, cur)) == NULL)
659 {
660 sub = void_stack_pop(nk_stack);
661 /* XXX: This is just a shallow free. Need to write deep free
662 * routines to replace the Samba code for this.
663 */
664 if(sub != NULL)
665 free(sub);
666 }
667 else
668 {
669 sub->subkey_index = 0;
670 void_stack_push(nk_stack, sub);
671 path = stack2Path(nk_stack);
672 if(path != NULL)
673 {
674 path_len = strlen(path);
675 if(val_path_len < prefix_len+path_len)
676 {
677 val_path_len = prefix_len+path_len;
678 val_path = (char*)realloc(val_path, val_path_len+1);
679 if(val_path == NULL)
680 bailOut(2, "ERROR: Could not reallocate val_path.\n");
681 }
682 strcpy(val_path, prefix);
683 strcpy(val_path+prefix_len, path);
684 if(!type_filter_enabled || (key_type == type_filter))
685 printKey(sub, val_path);
686 if(!type_filter_enabled || (key_type != type_filter))
687 printValueList(sub, val_path);
688 }
689 }
690 }
691 }
692 if(val_path != NULL)
693 free(val_path);
694 if(print_verbose)
695 fprintf(stderr, "VERBOSE: Finished printing key tree.\n");
696}
697
698
699/*
700 * Returns 0 if path was found.
701 * Returns 1 if path was not found.
702 * Returns less than 0 on other error.
703 */
704int retrievePath(REGF_FILE* f, void_stack* nk_stack,
705 void_stack* path_stack)
706{
707 REGF_NK_REC* sub = NULL;
708 REGF_NK_REC* cur = NULL;
709 void_stack* sub_nk_stack;
710 char* prefix;
711 char* cur_str = NULL;
712 char* path = NULL;
713 char* name;
714 uint16 path_depth;
715 uint32 i, prefix_len;
716 bool found_cur = true;
717 if(path_stack == NULL)
718 return -1;
719
720 path_depth = void_stack_size(path_stack);
721 if(path_depth < 1)
722 return -2;
723
724 if(void_stack_size(nk_stack) < 1)
725 return -3;
726 cur = (REGF_NK_REC*)void_stack_cur(nk_stack);
727
728 if(print_verbose)
729 fprintf(stderr, "VERBOSE: Beginning retrieval of specified path: %s\n",
730 path_filter);
731
732 while(void_stack_size(path_stack) > 1)
733 {
734 /* Search key records only */
735 cur_str = (char*)void_stack_pop(path_stack);
736
737 found_cur = false;
738 while(!found_cur &&
739 (sub = regfio_fetch_subkey(f, cur)) != NULL)
740 {
741 if(strcasecmp(sub->keyname, cur_str) == 0)
742 {
743 cur = sub;
744 void_stack_push(nk_stack, sub);
745 found_cur = true;
746 }
747 }
748 if(print_verbose && !found_cur)
749 fprintf(stderr, "VERBOSE: Could not find KEY '%s' in specified path.\n",
750 cur_str);
751
752 free(cur_str);
753 if(!found_cur)
754 return 1;
755 }
756
757 /* Last round, search value and key records */
758 cur_str = (char*)void_stack_pop(path_stack);
759
760 if(print_verbose)
761 fprintf(stderr, "VERBOSE: Searching values for last component"
762 " of specified path.\n");
763
764 for(i=0; (i < cur->num_values); i++)
765 {
766 /* XXX: Not sure when/why this can be NULL, but it's happened. */
767 if(sub->values[i].valuename != NULL
768 && strcasecmp(sub->values[i].valuename, cur_str) == 0)
769 {
770 path = stack2Path(nk_stack);
771
772 if(print_verbose)
773 fprintf(stderr, "VERBOSE: Found final path element as value.\n");
774
775 if(!type_filter_enabled || (sub->values[i].type == type_filter))
776 printValue(&sub->values[i], path);
777 if(path != NULL)
778 free(path);
779
780 return 0;
781 }
782 }
783
784 if(print_verbose)
785 fprintf(stderr, "VERBOSE: Searching keys for last component"
786 " of specified path.\n");
787
788 while((sub = regfio_fetch_subkey(f, cur)) != NULL)
789 {
790 if(strcasecmp(sub->keyname, cur_str) == 0)
791 {
792 sub_nk_stack = void_stack_new(1024);
793 void_stack_push(sub_nk_stack, sub);
794 prefix = stack2Path(nk_stack);
795 prefix_len = strlen(prefix);
796 prefix = realloc(prefix, prefix_len+strlen(sub->keyname)+2);
797 if(prefix == NULL)
798 return -1;
799 name = quote_string(sub->keyname, key_special_chars);
800 strcat(prefix, "/");
801 strcat(prefix, name);
802 free(name);
803
804 if(print_verbose)
805 fprintf(stderr, "VERBOSE: Found final path element as key.\n");
806
807 printKeyTree(f, sub_nk_stack, prefix);
808
809 return 0;
810 }
811 }
812
813 if(print_verbose)
814 fprintf(stderr, "VERBOSE: Could not find last element of path.\n");
815
816 return 1;
817}
818
819
820static void usage(void)
821{
822 fprintf(stderr, "Usage: reglookup [-v] [-s]"
823 " [-p <PATH_FILTER>] [-t <TYPE_FILTER>]"
824 " <REGISTRY_FILE>\n");
825 fprintf(stderr, "Version: 0.3.0\n");
826 fprintf(stderr, "Options:\n");
827 fprintf(stderr, "\t-v\t sets verbose mode.\n");
828 fprintf(stderr, "\t-h\t enables header row. (default)\n");
829 fprintf(stderr, "\t-H\t disables header row.\n");
830 fprintf(stderr, "\t-s\t enables security descriptor output.\n");
831 fprintf(stderr, "\t-S\t disables security descriptor output. (default)\n");
832 fprintf(stderr, "\t-p\t restrict output to elements below this path.\n");
833 fprintf(stderr, "\t-t\t restrict results to this specific data type.\n");
834 fprintf(stderr, "\n");
835}
836
837
838int main(int argc, char** argv)
839{
840 void_stack* nk_stack;
841 void_stack* path_stack;
842 REGF_FILE* f;
843 REGF_NK_REC* root;
844 int retr_path_ret;
845 uint32 argi, arge;
846
847 /* Process command line arguments */
848 if(argc < 2)
849 {
850 usage();
851 bailOut(1, "ERROR: Requires at least one argument.\n");
852 }
853
854 arge = argc-1;
855 for(argi = 1; argi < arge; argi++)
856 {
857 if (strcmp("-p", argv[argi]) == 0)
858 {
859 if(++argi >= arge)
860 {
861 usage();
862 bailOut(1, "ERROR: '-p' option requires parameter.\n");
863 }
864 if((path_filter = strdup(argv[argi])) == NULL)
865 bailOut(2, "ERROR: Memory allocation problem.\n");
866
867 path_filter_enabled = true;
868 }
869 else if (strcmp("-t", argv[argi]) == 0)
870 {
871 if(++argi >= arge)
872 {
873 usage();
874 bailOut(1, "ERROR: '-t' option requires parameter.\n");
875 }
876 if((type_filter = regfio_type_str2val(argv[argi])) < 0)
877 {
878 fprintf(stderr, "ERROR: Invalid type specified: %s.\n", argv[argi]);
879 bailOut(1, "");
880 }
881 type_filter_enabled = true;
882 }
883 else if (strcmp("-h", argv[argi]) == 0)
884 print_header = true;
885 else if (strcmp("-H", argv[argi]) == 0)
886 print_header = false;
887 else if (strcmp("-s", argv[argi]) == 0)
888 print_security = true;
889 else if (strcmp("-S", argv[argi]) == 0)
890 print_security = false;
891 else if (strcmp("-v", argv[argi]) == 0)
892 print_verbose = true;
893 else
894 {
895 usage();
896 fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
897 bailOut(1, "");
898 }
899 }
900 if((registry_file = strdup(argv[argi])) == NULL)
901 bailOut(2, "ERROR: Memory allocation problem.\n");
902
903 f = regfio_open(registry_file);
904 if(f == NULL)
905 {
906 fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
907 bailOut(3, "");
908 }
909
910 root = regfio_rootkey(f);
911 nk_stack = void_stack_new(1024);
912
913 if(void_stack_push(nk_stack, root))
914 {
915 if(print_header)
916 {
917 if(print_security)
918 printf("PATH,TYPE,VALUE,MTIME,OWNER,GROUP,SACL,DACL\n");
919 else
920 printf("PATH,TYPE,VALUE,MTIME\n");
921 }
922
923 path_stack = path2Stack(path_filter);
924 if(void_stack_size(path_stack) < 1)
925 printKeyTree(f, nk_stack, "");
926 else
927 {
928 retr_path_ret = retrievePath(f, nk_stack, path_stack);
929 if(retr_path_ret == 1)
930 fprintf(stderr, "WARNING: specified path not found.\n");
931 else if(retr_path_ret != 0)
932 bailOut(4, "ERROR:\n");
933 }
934 }
935 else
936 bailOut(2, "ERROR: Memory allocation problem.\n");
937
938 void_stack_destroy_deep(nk_stack);
939 regfio_close(f);
940
941 return 0;
942}
Note: See TracBrowser for help on using the repository browser.