source: trunk/src/reglookup.c @ 80

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

Major API updates for regfi, and started porting reglookup to the API.

Code is non-functional, but should be soon.

  • Property svn:keywords set to Id
File size: 23.4 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 80 2007-01-17 01:46: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/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 */
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, uint32 len, uint32 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  uint32 i;
192  uint32 cur_str_len;
193  uint32 ascii_max, cur_str_max;
194  uint32 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 = regfi_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  default:
368    fprintf(stderr, "WARNING: Unrecognized registry data type (0x%.8X); quoting as binary.\n", type);
369   
370  case REG_NONE:
371  case REG_RESOURCE_LIST:
372  case REG_FULL_RESOURCE_DESCRIPTOR:
373  case REG_RESOURCE_REQUIREMENTS_LIST:
374
375  case REG_BINARY:
376    return quote_buffer(datap, len, common_special_chars);
377    break;
378  }
379
380  return NULL;
381}
382
383
384void_stack* path2Stack(const char* s)
385{
386  void_stack* ret_val;
387  void_stack* rev_ret = void_stack_new(REGF_MAX_DEPTH);
388  const char* cur = s;
389  char* next = NULL;
390  char* copy;
391
392  if (rev_ret == NULL)
393    return NULL;
394  if (s == NULL)
395    return rev_ret;
396 
397  while((next = strchr(cur, '/')) != NULL)
398  {
399    if ((next-cur) > 0)
400    {
401      copy = (char*)malloc((next-cur+1)*sizeof(char));
402      if(copy == NULL)
403        bailOut(2, "ERROR: Memory allocation problem.\n");
404         
405      memcpy(copy, cur, next-cur);
406      copy[next-cur] = '\0';
407      if(!void_stack_push(rev_ret, copy))
408        bailOut(2, "ERROR: Registry maximum depth exceeded.\n");
409    }
410    cur = next+1;
411  }
412  if(strlen(cur) > 0)
413  {
414    copy = strdup(cur);
415    if(!void_stack_push(rev_ret, copy))
416      bailOut(2, "ERROR: Registry maximum depth exceeded.\n");
417  }
418
419  ret_val = void_stack_copy_reverse(rev_ret);
420  void_stack_free(rev_ret);
421
422  return ret_val;
423}
424
425/* Returns a quoted path from an nk_stack */
426char* stack2Path(void_stack* nk_stack)
427{
428  const REGF_NK_REC* cur;
429  uint32 buf_left = 127;
430  uint32 buf_len = buf_left+1;
431  uint32 name_len = 0;
432  uint32 grow_amt;
433  char* buf; 
434  char* new_buf;
435  char* name;
436  void_stack_iterator* iter;
437 
438  buf = (char*)malloc((buf_len)*sizeof(char));
439  if (buf == NULL)
440    return NULL;
441  buf[0] = '\0';
442
443  iter = void_stack_iterator_new(nk_stack);
444  if (iter == NULL)
445  {
446    free(buf);
447    return NULL;
448  }
449
450  /* skip root element */
451  cur = void_stack_iterator_next(iter);
452
453  while((cur = void_stack_iterator_next(iter)) != NULL)
454  {
455    buf[buf_len-buf_left-1] = '/';
456    buf_left -= 1;
457    name = quote_string(cur->keyname, key_special_chars);
458    name_len = strlen(name);
459    if(name_len+1 > buf_left)
460    {
461      grow_amt = (uint32)(buf_len/2);
462      buf_len += name_len+1+grow_amt-buf_left;
463      if((new_buf = realloc(buf, buf_len)) == NULL)
464      {
465        free(buf);
466        free(iter);
467        return NULL;
468      }
469      buf = new_buf;
470      buf_left = grow_amt + name_len + 1;
471    }
472    strncpy(buf+(buf_len-buf_left-1), name, name_len);
473    buf_left -= name_len;
474    buf[buf_len-buf_left-1] = '\0';
475    free(name);
476  }
477
478  return buf;
479}
480
481
482void printValue(REGF_VK_REC* vk, char* prefix)
483{
484  char* quoted_value = NULL;
485  char* quoted_name = NULL;
486  char* conv_error = NULL;
487  const char* str_type = NULL;
488  uint32 size;
489  uint8 tmp_buf[4];
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      /* XXX: should we kick out a warning here?  If it is in the
501       *      offset and longer than four, file could be corrupt
502       *      or malicious... */
503      size = 4;
504    quoted_value = data_to_ascii(tmp_buf, 4, vk->type, &conv_error);
505  }
506  else
507  {
508    /* Microsoft's documentation indicates that "available memory" is
509     * the limit on value sizes.  Annoying.  We limit it to 1M which
510     * should rarely be exceeded, unless the file is corrupt or
511     * malicious. For more info, see:
512     *   http://msdn2.microsoft.com/en-us/library/ms724872.aspx
513     */
514    if(size > VK_MAX_DATA_LENGTH)
515    {
516      fprintf(stderr, "WARNING: value data size %d larger than "
517              "%d, truncating...\n", size, VK_MAX_DATA_LENGTH);
518      size = VK_MAX_DATA_LENGTH;
519    }
520
521    quoted_value = data_to_ascii(vk->data, vk->data_size, 
522                                 vk->type, &conv_error);
523  }
524 
525  /* XXX: Sometimes value names can be NULL in registry.  Need to
526   *      figure out why and when, and generate the appropriate output
527   *      for that condition.
528   */
529  quoted_name = quote_string(vk->valuename, common_special_chars);
530
531  if(quoted_value == NULL)
532  {
533    if(conv_error == NULL)
534      fprintf(stderr, "WARNING: Could not quote value for '%s/%s'.  "
535              "Memory allocation failure likely.\n", prefix, quoted_name);
536    else
537      fprintf(stderr, "WARNING: Could not quote value for '%s/%s'.  "
538              "Returned error: %s\n", prefix, quoted_name, conv_error);
539  }
540  /* XXX: should these always be printed? */
541  else if(conv_error != NULL && print_verbose)
542      fprintf(stderr, "VERBOSE: While quoting value for '%s/%s', "
543              "warning returned: %s\n", prefix, quoted_name, conv_error);
544
545  str_type = regfi_type_val2str(vk->type);
546  if(print_security)
547  {
548    if(str_type == NULL)
549      printf("%s/%s,0x%.8X,%s,,,,,\n", prefix, quoted_name,
550             vk->type, quoted_value);
551    else
552      printf("%s/%s,%s,%s,,,,,\n", prefix, quoted_name,
553             str_type, quoted_value);
554  }
555  else
556  {
557    if(str_type == NULL)
558      printf("%s/%s,0x%.8X,%s,\n", prefix, quoted_name,
559             vk->type, quoted_value);
560    else
561      printf("%s/%s,%s,%s,\n", prefix, quoted_name,
562             str_type, quoted_value);
563  }
564
565  if(quoted_value != NULL)
566    free(quoted_value);
567  if(quoted_name != NULL)
568    free(quoted_name);
569  if(conv_error != NULL)
570    free(conv_error);
571}
572
573
574void printValueList(REGFI_ITERATOR i, char* prefix)
575{
576  REGF_VK_REC* value;
577
578  value = regfi_iterator_first_value(i);
579  while(value != NULL)
580    if(!type_filter_enabled || (value.type == type_filter))
581      printValue(value, prefix);
582}
583
584
585void printKey(REGF_NK_REC* k, char* full_path)
586{
587  static char empty_str[1] = "";
588  char* owner = NULL;
589  char* group = NULL;
590  char* sacl = NULL;
591  char* dacl = NULL;
592  char mtime[20];
593  time_t tmp_time[1];
594  struct tm* tmp_time_s = NULL;
595
596  *tmp_time = nt_time_to_unix(&k->mtime);
597  tmp_time_s = gmtime(tmp_time);
598  strftime(mtime, sizeof(mtime), "%Y-%m-%d %H:%M:%S", tmp_time_s);
599
600  if(print_security)
601  {
602    owner = regfi_get_owner(k->sec_desc->sec_desc);
603    group = regfi_get_group(k->sec_desc->sec_desc);
604    sacl = regfi_get_sacl(k->sec_desc->sec_desc);
605    dacl = regfi_get_dacl(k->sec_desc->sec_desc);
606    if(owner == NULL)
607      owner = empty_str;
608    if(group == NULL)
609      group = empty_str;
610    if(sacl == NULL)
611      sacl = empty_str;
612    if(dacl == NULL)
613      dacl = empty_str;
614
615    printf("%s,KEY,,%s,%s,%s,%s,%s\n", full_path, mtime, 
616           owner, group, sacl, dacl);
617
618    if(owner != empty_str)
619      free(owner);
620    if(group != empty_str)
621      free(group);
622    if(sacl != empty_str)
623      free(sacl);
624    if(dacl != empty_str)
625      free(dacl);
626  }
627  else
628    printf("%s,KEY,,%s\n", full_path, mtime);
629}
630
631
632void printKeyTree(REGF_FILE* f, void_stack* nk_stack, const char* prefix)
633{
634  REGF_NK_REC* cur = NULL;
635  REGF_NK_REC* sub = NULL;
636  char* path = NULL;
637  char* val_path = NULL;
638  uint32 val_path_len = 0;
639  uint32 path_len = 0;
640  uint32 prefix_len = strlen(prefix);
641  int key_type = regfi_type_str2val("KEY");
642 
643  if((cur = (REGF_NK_REC*)void_stack_cur(nk_stack)) != NULL)
644  {
645    cur->subkey_index = 0;
646    path = stack2Path(nk_stack);
647
648    if(print_verbose)
649    {
650      if(prefix[0] == '\0')
651        fprintf(stderr, "VERBOSE: Printing key tree under path: /\n");
652      else
653        fprintf(stderr, "VERBOSE: Printing key tree under path: %s\n",
654                prefix);
655    }
656
657    path_len = strlen(path);
658    val_path_len = prefix_len+path_len;
659    val_path = (char*)malloc(val_path_len+1+1);
660    if(val_path == NULL)
661      bailOut(2, "ERROR: Could not allocate val_path.\n");
662
663    strcpy(val_path, prefix);
664    strcpy(val_path+prefix_len, path);
665    if(val_path[0] == '\0')
666    {
667      val_path[0] = '/';
668      val_path[1] = '\0';
669    }
670    if(!type_filter_enabled || (key_type == type_filter))
671      printKey(cur, val_path);
672    if(!type_filter_enabled || (key_type != type_filter))
673      printValueList(cur, val_path);
674   
675    while((cur = (REGF_NK_REC*)void_stack_cur(nk_stack)) != NULL)
676    {
677      if((sub = regfi_fetch_subkey(f, cur)) == NULL)
678      {
679        sub = void_stack_pop(nk_stack);
680        /* XXX: This is just a shallow free.  Need to write deep free
681         * routines to replace the Samba code for this.
682         */ 
683        if(sub != NULL)
684          free(sub);
685      }
686      else
687      {
688        sub->subkey_index = 0;
689        if(!void_stack_push(nk_stack, sub))
690          bailOut(2, "ERROR: Registry maximum depth exceeded.\n");
691        path = stack2Path(nk_stack);
692        if(path != NULL)
693        {
694          path_len = strlen(path);
695          if(val_path_len < prefix_len+path_len)
696          {
697            val_path_len = prefix_len+path_len;
698            val_path = (char*)realloc(val_path, val_path_len+1);
699            if(val_path == NULL)
700              bailOut(2, "ERROR: Could not reallocate val_path.\n");
701          }
702          strcpy(val_path, prefix);
703          strcpy(val_path+prefix_len, path);
704          if(!type_filter_enabled || (key_type == type_filter))
705            printKey(sub, val_path);
706          if(!type_filter_enabled || (key_type != type_filter))
707            printValueList(sub, val_path);
708        }
709      }
710    }
711  }
712  if(val_path != NULL)
713    free(val_path);
714  if(print_verbose)
715    fprintf(stderr, "VERBOSE: Finished printing key tree.\n");
716}
717
718/*
719 * Returns 0 if path was not found.
720 * Returns 1 if path was found as value.
721 * Returns 2 if path was found as key.
722 * Returns less than 0 on other error.
723 */
724int retrievePath(REGFI_ITERATOR* iter, char** path)
725{
726  REG_VK_REC* value;
727  uint32 i;
728  char* p;
729  char* tmp_path_joined;
730  char** tmp_path;
731 
732  if(path == NULL)
733    return -1;
734
735  /* One extra for any value at the end, and one more for NULL */
736  tmp_path = (char**)malloc(sizeof(char**)*(REGF_MAX_DEPTH+1+1));
737  if(tmp_path == NULL)
738    return -2;
739
740  /* Strip any potential value name at end of path */
741  for(i=0; 
742      (path[i] != NULL) && (path[i+1] != NULL) 
743        && (i < REGF_MAX_DEPTH+1+1);
744      i++)
745    tmp_path[i] = path[i];
746
747  tmp_path[i] = NULL;
748
749  if(print_verbose)
750    fprintf(stderr, "VERBOSE: Attempting to retrieve specified path: %s\n",
751            path_filter);
752
753  if(!regfi_iterator_walk_path(iter, tmp_path))
754  {
755    free(tmp_path);
756    return 0;
757  }
758
759  if(regfi_iterator_find_value(iter, path[i]))
760  {
761    if(print_verbose)
762      fprintf(stderr, "VERBOSE: Found final path element as value.\n");
763
764    value = regfi_iterator_cur_value(iter);
765    tmp_path_joined = joinPath(tmp_path);
766
767    if((value == NULL) || (tmp_path_joined == NULL))
768      bailOut(2, "ERROR: Unexpected error before printValue.\n");
769
770    printValue(value, tmp_path_joined);
771
772    free(tmp_path);
773    free(tmp_path_joined);
774    return 1;
775  }
776  else if(regfi_iterator_find_subkey(iter, path[i]))
777  {
778    if(print_verbose)
779      fprintf(stderr, "VERBOSE: Found final path element as key.\n");
780    return 2;
781  }
782
783  if(print_verbose)
784    fprintf(stderr, "VERBOSE: Could not find last element of path.\n");
785
786  return 0;
787}
788
789
790static void usage(void)
791{
792  fprintf(stderr, "Usage: reglookup [-v] [-s]"
793          " [-p <PATH_FILTER>] [-t <TYPE_FILTER>]"
794          " <REGISTRY_FILE>\n");
795  fprintf(stderr, "Version: 0.3.0\n");
796  fprintf(stderr, "Options:\n");
797  fprintf(stderr, "\t-v\t sets verbose mode.\n");
798  fprintf(stderr, "\t-h\t enables header row. (default)\n");
799  fprintf(stderr, "\t-H\t disables header row.\n");
800  fprintf(stderr, "\t-s\t enables security descriptor output.\n");
801  fprintf(stderr, "\t-S\t disables security descriptor output. (default)\n");
802  fprintf(stderr, "\t-p\t restrict output to elements below this path.\n");
803  fprintf(stderr, "\t-t\t restrict results to this specific data type.\n");
804  fprintf(stderr, "\n");
805}
806
807
808int main(int argc, char** argv)
809{
810  void_stack* path_stack;
811  char** path = NULL;
812  REGF_FILE* f;
813  REGF_NK_REC* root;
814  REGFI_ITERATOR* iter;
815  int retr_path_ret;
816  uint32 argi, arge;
817
818  /* Process command line arguments */
819  if(argc < 2)
820  {
821    usage();
822    bailOut(1, "ERROR: Requires at least one argument.\n");
823  }
824 
825  arge = argc-1;
826  for(argi = 1; argi < arge; argi++)
827  {
828    if (strcmp("-p", argv[argi]) == 0)
829    {
830      if(++argi >= arge)
831      {
832        usage();
833        bailOut(1, "ERROR: '-p' option requires parameter.\n");
834      }
835      if((path_filter = strdup(argv[argi])) == NULL)
836        bailOut(2, "ERROR: Memory allocation problem.\n");
837
838      path_filter_enabled = true;
839    }
840    else if (strcmp("-t", argv[argi]) == 0)
841    {
842      if(++argi >= arge)
843      {
844        usage();
845        bailOut(1, "ERROR: '-t' option requires parameter.\n");
846      }
847      if((type_filter = regfi_type_str2val(argv[argi])) < 0)
848      {
849        fprintf(stderr, "ERROR: Invalid type specified: %s.\n", argv[argi]);
850        bailOut(1, "");
851      }
852      type_filter_enabled = true;
853    }
854    else if (strcmp("-h", argv[argi]) == 0)
855      print_header = true;
856    else if (strcmp("-H", argv[argi]) == 0)
857      print_header = false;
858    else if (strcmp("-s", argv[argi]) == 0)
859      print_security = true;
860    else if (strcmp("-S", argv[argi]) == 0)
861      print_security = false;
862    else if (strcmp("-v", argv[argi]) == 0)
863      print_verbose = true;
864    else
865    {
866      usage();
867      fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
868      bailOut(1, "");
869    }
870  }
871  if((registry_file = strdup(argv[argi])) == NULL)
872    bailOut(2, "ERROR: Memory allocation problem.\n");
873
874  f = regfi_open(registry_file);
875  if(f == NULL)
876  {
877    fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
878    bailOut(3, "");
879  }
880
881  iter = regfi_iterator_new(f);
882  if(iter == NULL)
883    bailOut(3, "ERROR: Couldn't create registry iterator.\n");
884
885  if(path_filter_enabled && path_filter != NULL)
886    path = splitPath(path_filter);
887 
888  if(path != NULL)
889  {
890    retr_path_ret = retrievePath(iter, path);
891    if(retr_path_ret == 0)
892      fprintf(stderr, "WARNING: specified path not found.\n");
893    else if (retr_path_ret == 2)
894      printKeyTree(iter, path_filter);
895    else if(retr_path_ret != 0)
896      bailOut(4, "ERROR: Unknown error occurred in retrieving path.\n");
897  }
898  else
899    printKeyTree(iter, "");
900
901  regfi_iterator_free(iter);
902  regfi_close(f);
903
904  return 0;
905}
Note: See TracBrowser for help on using the repository browser.