source: trunk/src/reglookup.c @ 71

Last change on this file since 71 was 71, checked in by tim, 18 years ago

added additional warnings for broken registry entries.

  • Property svn:keywords set to Id
File size: 23.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-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 71 2006-07-30 19:32:43Z 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)*11;
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)*11;
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  /* XXX: this MULTI_SZ parser is pretty inefficient.  Should be
265   *      redone with fewer malloc calls and better string concatenation.
266   */
267  case REG_MULTI_SZ:
268    ascii_max = sizeof(char)*(len*4+1);
269    cur_str_max = sizeof(char)*(len+1);
270    cur_str = malloc(cur_str_max);
271    cur_ascii = malloc(cur_str_max);
272    ascii = malloc(ascii_max);
273    if(ascii == NULL || cur_str == NULL || cur_ascii == NULL)
274      return NULL;
275
276    /* Reads until it reaches 4 consecutive NULLs,
277     * which is two nulls in unicode, or until it reaches len, or until we
278     * run out of buffer.  The latter should never happen, but we shouldn't
279     * trust our file to have the right lengths/delimiters.
280     */
281    asciip = ascii;
282    num_nulls = 0;
283    str_rem = ascii_max;
284    cur_str_rem = cur_str_max;
285    cur_str_len = 0;
286
287    for(i=0; (i < len) && str_rem > 0; i++)
288    {
289      *(cur_str+cur_str_len) = *(datap+i);
290      if(*(cur_str+cur_str_len) == 0)
291        num_nulls++;
292      else
293        num_nulls = 0;
294      cur_str_len++;
295
296      if(num_nulls == 2)
297      {
298        ret_err = uni_to_ascii(cur_str, cur_ascii, cur_str_len-1, cur_str_max);
299        if(ret_err < 0)
300        {
301          /* XXX: should every sub-field error be enumerated? */
302          if(*error_msg == NULL)
303          {
304            tmp_err = strerror(-ret_err);
305            *error_msg = (char*)malloc(90+strlen(tmp_err)+1);
306            if(*error_msg == NULL)
307            {
308              free(cur_str);
309              free(cur_ascii);
310              free(ascii);
311              return NULL;
312            }
313            sprintf(*error_msg, "Unicode conversion failed on at least one "
314                    "MULTI_SZ sub-field; printing as binary.  Error: %s",
315                    tmp_err);
316          }
317          cur_quoted = quote_buffer(cur_str, cur_str_len-1, 
318                                    subfield_special_chars);
319        }
320        else
321          cur_quoted = quote_string(cur_ascii, subfield_special_chars);
322
323        alen = snprintf(asciip, str_rem, "%s", cur_quoted);
324        asciip += alen;
325        str_rem -= alen;
326        free(cur_quoted);
327
328        if(*(datap+i+1) == 0 && *(datap+i+2) == 0)
329          break;
330        else
331        {
332          if(str_rem > 0)
333          {
334            asciip[0] = '|';
335            asciip[1] = '\0';
336            asciip++;
337            str_rem--;
338          }
339          memset(cur_str, 0, cur_str_max);
340          cur_str_len = 0;
341          num_nulls = 0;
342          /* To eliminate leading nulls in subsequent strings. */
343          i++;
344        }
345      }
346    }
347    *asciip = 0;
348    free(cur_str);
349    free(cur_ascii);
350    return ascii;
351    break;
352
353  /* XXX: Dont know what to do with these yet, just print as binary... */
354  case REG_NONE:
355  case REG_RESOURCE_LIST:
356  case REG_FULL_RESOURCE_DESCRIPTOR:
357  case REG_RESOURCE_REQUIREMENTS_LIST:
358
359  case REG_BINARY:
360    return quote_buffer(datap, len, common_special_chars);
361    break;
362  }
363
364
365  /* Invalid type */
366  *error_msg = (char*)malloc(33+11+1);
367  if(*error_msg != NULL)
368    sprintf(*error_msg, "Unrecognized registry data type: %d", type);
369
370  return NULL;
371}
372
373
374void_stack* path2Stack(const char* s)
375{
376  void_stack* ret_val;
377  void_stack* rev_ret = void_stack_new(1024);
378  const char* cur = s;
379  char* next = NULL;
380  char* copy;
381
382  if (rev_ret == NULL)
383    return NULL;
384  if (s == NULL)
385    return rev_ret;
386 
387  while((next = strchr(cur, '/')) != NULL)
388  {
389    if ((next-cur) > 0)
390    {
391      copy = (char*)malloc((next-cur+1)*sizeof(char));
392      if(copy == NULL)
393        bailOut(2, "ERROR: Memory allocation problem.\n");
394         
395      memcpy(copy, cur, next-cur);
396      copy[next-cur] = '\0';
397      void_stack_push(rev_ret, copy);
398    }
399    cur = next+1;
400  }
401  if(strlen(cur) > 0)
402  {
403    copy = strdup(cur);
404    void_stack_push(rev_ret, copy);
405  }
406
407  ret_val = void_stack_copy_reverse(rev_ret);
408  void_stack_destroy(rev_ret);
409
410  return ret_val;
411}
412
413/* Returns a quoted path from an nk_stack */
414char* stack2Path(void_stack* nk_stack)
415{
416  const REGF_NK_REC* cur;
417  uint32 buf_left = 127;
418  uint32 buf_len = buf_left+1;
419  uint32 name_len = 0;
420  uint32 grow_amt;
421  char* buf; 
422  char* new_buf;
423  char* name;
424  void_stack_iterator* iter;
425 
426  buf = (char*)malloc((buf_len)*sizeof(char));
427  if (buf == NULL)
428    return NULL;
429  buf[0] = '\0';
430
431  iter = void_stack_iterator_new(nk_stack);
432  if (iter == NULL)
433  {
434    free(buf);
435    return NULL;
436  }
437
438  /* skip root element */
439  cur = void_stack_iterator_next(iter);
440
441  while((cur = void_stack_iterator_next(iter)) != NULL)
442  {
443    buf[buf_len-buf_left-1] = '/';
444    buf_left -= 1;
445    name = quote_string(cur->keyname, key_special_chars);
446    name_len = strlen(name);
447    if(name_len+1 > buf_left)
448    {
449      grow_amt = (uint32)(buf_len/2);
450      buf_len += name_len+1+grow_amt-buf_left;
451      if((new_buf = realloc(buf, buf_len)) == NULL)
452      {
453        free(buf);
454        free(iter);
455        return NULL;
456      }
457      buf = new_buf;
458      buf_left = grow_amt + name_len + 1;
459    }
460    strncpy(buf+(buf_len-buf_left-1), name, name_len);
461    buf_left -= name_len;
462    buf[buf_len-buf_left-1] = '\0';
463    free(name);
464  }
465
466  return buf;
467}
468
469
470void printValue(REGF_VK_REC* vk, char* prefix)
471{
472  uint32 size;
473  uint8 tmp_buf[4];
474  char* quoted_value = NULL;
475  char* quoted_name = NULL;
476  char* conv_error = NULL;
477
478  /* Thanks Microsoft for making this process so straight-forward!!! */
479  size = (vk->data_size & ~VK_DATA_IN_OFFSET);
480  if(vk->data_size & VK_DATA_IN_OFFSET)
481  {
482    tmp_buf[0] = (uint8)((vk->data_off >> 3) & 0xFF);
483    tmp_buf[1] = (uint8)((vk->data_off >> 2) & 0xFF);
484    tmp_buf[2] = (uint8)((vk->data_off >> 1) & 0xFF);
485    tmp_buf[3] = (uint8)(vk->data_off & 0xFF);
486    if(size > 4)
487      size = 4;
488    quoted_value = data_to_ascii(tmp_buf, 4, vk->type, &conv_error);
489  }
490  else
491  {
492    /* XXX: This is a safety hack.  No data fields have yet been found
493     * larger, but length limits are probably better got from fields
494     * in the registry itself, within reason.
495     */
496    if(size > 16384)
497    {
498      fprintf(stderr, "WARNING: key size %d larger than "
499              "16384, truncating...\n", size);
500      size = 16384;
501    }
502
503    quoted_value = data_to_ascii(vk->data, vk->data_size, 
504                                 vk->type, &conv_error);
505  }
506 
507  /* XXX: Sometimes value names can be NULL in registry.  Need to
508   *      figure out why and when, and generate the appropriate output
509   *      for that condition.
510   */
511  quoted_name = quote_string(vk->valuename, common_special_chars);
512
513  if(quoted_value == NULL)
514  {
515    if(conv_error == NULL)
516      fprintf(stderr, "WARNING: Could not quote value for '%s/%s'.  "
517              "Memory allocation failure likely.\n", prefix, quoted_name);
518    else
519      fprintf(stderr, "WARNING: Could not quote value for '%s/%s'.  "
520              "Returned error: %s\n", prefix, quoted_name, conv_error);
521  }
522  /* XXX: should these always be printed? */
523  else if(conv_error != NULL && print_verbose)
524      fprintf(stderr, "VERBOSE: While quoting value for '%s/%s', "
525              "warning returned: %s\n", prefix, quoted_name, conv_error);
526
527  if(print_security)
528    printf("%s/%s,%s,%s,,,,,\n", prefix, quoted_name,
529           regfio_type_val2str(vk->type), quoted_value);
530  else
531    printf("%s/%s,%s,%s,\n", prefix, quoted_name,
532           regfio_type_val2str(vk->type), quoted_value);
533 
534  if(quoted_value != NULL)
535    free(quoted_value);
536  if(quoted_name != NULL)
537    free(quoted_name);
538  if(conv_error != NULL)
539    free(conv_error);
540}
541
542
543void printValueList(REGF_NK_REC* nk, char* prefix)
544{
545  uint32 i;
546 
547  for(i=0; i < nk->num_values; i++)
548    if(!type_filter_enabled || (nk->values[i].type == type_filter))
549      printValue(nk->values+i, prefix);
550}
551
552
553void printKey(REGF_NK_REC* k, char* full_path)
554{
555  static char empty_str[1] = "";
556  char* owner = NULL;
557  char* group = NULL;
558  char* sacl = NULL;
559  char* dacl = NULL;
560  char mtime[20];
561  time_t tmp_time[1];
562  struct tm* tmp_time_s = NULL;
563
564  *tmp_time = nt_time_to_unix(&k->mtime);
565  tmp_time_s = gmtime(tmp_time);
566  strftime(mtime, sizeof(mtime), "%Y-%m-%d %H:%M:%S", tmp_time_s);
567
568  if(print_security)
569  {
570    owner = regfio_get_owner(k->sec_desc->sec_desc);
571    group = regfio_get_group(k->sec_desc->sec_desc);
572    sacl = regfio_get_sacl(k->sec_desc->sec_desc);
573    dacl = regfio_get_dacl(k->sec_desc->sec_desc);
574    if(owner == NULL)
575      owner = empty_str;
576    if(group == NULL)
577      group = empty_str;
578    if(sacl == NULL)
579      sacl = empty_str;
580    if(dacl == NULL)
581      dacl = empty_str;
582
583    printf("%s,KEY,,%s,%s,%s,%s,%s\n", full_path, mtime, 
584           owner, group, sacl, dacl);
585
586    if(owner != empty_str)
587      free(owner);
588    if(group != empty_str)
589      free(group);
590    if(sacl != empty_str)
591      free(sacl);
592    if(dacl != empty_str)
593      free(dacl);
594  }
595  else
596    printf("%s,KEY,,%s\n", full_path, mtime);
597}
598
599
600void printKeyTree(REGF_FILE* f, void_stack* nk_stack, const char* prefix)
601{
602  REGF_NK_REC* cur = NULL;
603  REGF_NK_REC* sub = NULL;
604  char* path = NULL;
605  char* val_path = NULL;
606  uint32 val_path_len = 0;
607  uint32 path_len = 0;
608  uint32 prefix_len = strlen(prefix);
609  int key_type = regfio_type_str2val("KEY");
610 
611  if((cur = (REGF_NK_REC*)void_stack_cur(nk_stack)) != NULL)
612  {
613    cur->subkey_index = 0;
614    path = stack2Path(nk_stack);
615
616    if(print_verbose)
617    {
618      if(prefix[0] == '\0')
619        fprintf(stderr, "VERBOSE: Printing key tree under path: /\n");
620      else
621        fprintf(stderr, "VERBOSE: Printing key tree under path: %s\n",
622                prefix);
623    }
624
625    path_len = strlen(path);
626    val_path_len = prefix_len+path_len;
627    val_path = (char*)malloc(val_path_len+1+1);
628    if(val_path == NULL)
629      bailOut(2, "ERROR: Could not allocate val_path.\n");
630
631    strcpy(val_path, prefix);
632    strcpy(val_path+prefix_len, path);
633    if(val_path[0] == '\0')
634    {
635      val_path[0] = '/';
636      val_path[1] = '\0';
637    }
638    if(!type_filter_enabled || (key_type == type_filter))
639      printKey(cur, val_path);
640    if(!type_filter_enabled || (key_type != type_filter))
641      printValueList(cur, val_path);
642   
643    while((cur = (REGF_NK_REC*)void_stack_cur(nk_stack)) != NULL)
644    {
645      if((sub = regfio_fetch_subkey(f, cur)) == NULL)
646      {
647        sub = void_stack_pop(nk_stack);
648        /* XXX: This is just a shallow free.  Need to write deep free
649         * routines to replace the Samba code for this.
650         */ 
651        if(sub != NULL)
652          free(sub);
653      }
654      else
655      {
656        sub->subkey_index = 0;
657        void_stack_push(nk_stack, sub);
658        path = stack2Path(nk_stack);
659        if(path != NULL)
660        {
661          path_len = strlen(path);
662          if(val_path_len < prefix_len+path_len)
663          {
664            val_path_len = prefix_len+path_len;
665            val_path = (char*)realloc(val_path, val_path_len+1);
666            if(val_path == NULL)
667              bailOut(2, "ERROR: Could not reallocate val_path.\n");
668          }
669          strcpy(val_path, prefix);
670          strcpy(val_path+prefix_len, path);
671          if(!type_filter_enabled || (key_type == type_filter))
672            printKey(sub, val_path);
673          if(!type_filter_enabled || (key_type != type_filter))
674            printValueList(sub, val_path);
675        }
676      }
677    }
678  }
679  if(val_path != NULL)
680    free(val_path);
681  if(print_verbose)
682    fprintf(stderr, "VERBOSE: Finished printing key tree.\n");
683}
684
685
686/*
687 * Returns 0 if path was found.
688 * Returns 1 if path was not found.
689 * Returns less than 0 on other error.
690 */
691int retrievePath(REGF_FILE* f, void_stack* nk_stack,
692                 void_stack* path_stack)
693{
694  REGF_NK_REC* sub = NULL; 
695  REGF_NK_REC* cur = NULL;
696  void_stack* sub_nk_stack;
697  char* prefix;
698  char* cur_str = NULL;
699  char* path = NULL;
700  char* name;
701  uint16 path_depth;
702  uint32 i, prefix_len;
703  bool found_cur = true;
704  if(path_stack == NULL)
705    return -1;
706
707  path_depth = void_stack_size(path_stack);
708  if(path_depth < 1)
709    return -2;
710
711  if(void_stack_size(nk_stack) < 1)
712    return -3;
713  cur = (REGF_NK_REC*)void_stack_cur(nk_stack);
714
715  if(print_verbose)
716    fprintf(stderr, "VERBOSE: Beginning retrieval of specified path: %s\n", 
717            path_filter);
718
719  while(void_stack_size(path_stack) > 1)
720  {
721    /* Search key records only */
722    cur_str = (char*)void_stack_pop(path_stack);
723
724    found_cur = false;
725    while(!found_cur &&
726          (sub = regfio_fetch_subkey(f, cur)) != NULL)
727    {
728      if(strcasecmp(sub->keyname, cur_str) == 0)
729      {
730        cur = sub;
731        void_stack_push(nk_stack, sub);
732        found_cur = true;
733      }
734    }
735    if(print_verbose && !found_cur)
736      fprintf(stderr, "VERBOSE: Could not find KEY '%s' in specified path.\n", 
737              cur_str);
738
739    free(cur_str);
740    if(!found_cur)
741      return 1;
742  }
743
744  /* Last round, search value and key records */
745  cur_str = (char*)void_stack_pop(path_stack);
746
747  if(print_verbose)
748    fprintf(stderr, "VERBOSE: Searching values for last component"
749                    " of specified path.\n");
750
751  for(i=0; (i < cur->num_values); i++)
752  {
753    /* XXX: Not sure when/why this can be NULL, but it's happened. */
754    if(sub->values[i].valuename != NULL 
755       && strcasecmp(sub->values[i].valuename, cur_str) == 0)
756    {
757      path = stack2Path(nk_stack);
758
759      if(print_verbose)
760        fprintf(stderr, "VERBOSE: Found final path element as value.\n");
761
762      if(!type_filter_enabled || (sub->values[i].type == type_filter))
763        printValue(&sub->values[i], path);
764      if(path != NULL)
765        free(path);
766
767      return 0;
768    }
769  }
770
771  if(print_verbose)
772    fprintf(stderr, "VERBOSE: Searching keys for last component"
773                    " of specified path.\n");
774
775  while((sub = regfio_fetch_subkey(f, cur)) != NULL)
776  {
777    if(strcasecmp(sub->keyname, cur_str) == 0)
778    {
779      sub_nk_stack = void_stack_new(1024);
780      void_stack_push(sub_nk_stack, sub);
781      prefix = stack2Path(nk_stack);
782      prefix_len = strlen(prefix);
783      prefix = realloc(prefix, prefix_len+strlen(sub->keyname)+2);
784      if(prefix == NULL)
785        return -1;
786      name = quote_string(sub->keyname, key_special_chars);
787      strcat(prefix, "/");
788      strcat(prefix, name);
789      free(name);
790
791      if(print_verbose)
792        fprintf(stderr, "VERBOSE: Found final path element as key.\n");
793
794      printKeyTree(f, sub_nk_stack, prefix);
795
796      return 0;
797    }
798  }
799
800  if(print_verbose)
801    fprintf(stderr, "VERBOSE: Could not find last element of path.\n");
802
803  return 1;
804}
805
806
807static void usage(void)
808{
809  fprintf(stderr, "Usage: reglookup [-v] [-s]"
810          " [-p <PATH_FILTER>] [-t <TYPE_FILTER>]"
811          " <REGISTRY_FILE>\n");
812  fprintf(stderr, "Version: 0.3.0\n");
813  fprintf(stderr, "Options:\n");
814  fprintf(stderr, "\t-v\t sets verbose mode.\n");
815  fprintf(stderr, "\t-h\t enables header row. (default)\n");
816  fprintf(stderr, "\t-H\t disables header row.\n");
817  fprintf(stderr, "\t-s\t enables security descriptor output.\n");
818  fprintf(stderr, "\t-S\t disables security descriptor output. (default)\n");
819  fprintf(stderr, "\t-p\t restrict output to elements below this path.\n");
820  fprintf(stderr, "\t-t\t restrict results to this specific data type.\n");
821  fprintf(stderr, "\n");
822}
823
824
825int main(int argc, char** argv)
826{
827  void_stack* nk_stack;
828  void_stack* path_stack;
829  REGF_FILE* f;
830  REGF_NK_REC* root;
831  int retr_path_ret;
832  uint32 argi, arge;
833
834  /* Process command line arguments */
835  if(argc < 2)
836  {
837    usage();
838    bailOut(1, "ERROR: Requires at least one argument.\n");
839  }
840 
841  arge = argc-1;
842  for(argi = 1; argi < arge; argi++)
843  {
844    if (strcmp("-p", argv[argi]) == 0)
845    {
846      if(++argi >= arge)
847      {
848        usage();
849        bailOut(1, "ERROR: '-p' option requires parameter.\n");
850      }
851      if((path_filter = strdup(argv[argi])) == NULL)
852        bailOut(2, "ERROR: Memory allocation problem.\n");
853
854      path_filter_enabled = true;
855    }
856    else if (strcmp("-t", argv[argi]) == 0)
857    {
858      if(++argi >= arge)
859      {
860        usage();
861        bailOut(1, "ERROR: '-t' option requires parameter.\n");
862      }
863      if((type_filter = regfio_type_str2val(argv[argi])) < 0)
864      {
865        fprintf(stderr, "ERROR: Invalid type specified: %s.\n", argv[argi]);
866        bailOut(1, "");
867      }
868      type_filter_enabled = true;
869    }
870    else if (strcmp("-h", argv[argi]) == 0)
871      print_header = true;
872    else if (strcmp("-H", argv[argi]) == 0)
873      print_header = false;
874    else if (strcmp("-s", argv[argi]) == 0)
875      print_security = true;
876    else if (strcmp("-S", argv[argi]) == 0)
877      print_security = false;
878    else if (strcmp("-v", argv[argi]) == 0)
879      print_verbose = true;
880    else
881    {
882      usage();
883      fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
884      bailOut(1, "");
885    }
886  }
887  if((registry_file = strdup(argv[argi])) == NULL)
888    bailOut(2, "ERROR: Memory allocation problem.\n");
889
890  f = regfio_open(registry_file);
891  if(f == NULL)
892  {
893    fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
894    bailOut(3, "");
895  }
896
897  root = regfio_rootkey(f);
898  nk_stack = void_stack_new(1024);
899
900  if(void_stack_push(nk_stack, root))
901  {
902    if(print_header)
903    {
904      if(print_security)
905        printf("PATH,TYPE,VALUE,MTIME,OWNER,GROUP,SACL,DACL\n");
906      else
907        printf("PATH,TYPE,VALUE,MTIME\n");
908    }
909
910    path_stack = path2Stack(path_filter);
911    if(void_stack_size(path_stack) < 1)
912      printKeyTree(f, nk_stack, "");
913    else
914    {
915      retr_path_ret = retrievePath(f, nk_stack, path_stack);
916      if(retr_path_ret == 1)
917        fprintf(stderr, "WARNING: specified path not found.\n");
918      else if(retr_path_ret != 0)
919        bailOut(4, "ERROR:\n");
920    }
921  }
922  else
923    bailOut(2, "ERROR: Memory allocation problem.\n");
924
925  void_stack_destroy_deep(nk_stack);
926  regfio_close(f);
927
928  return 0;
929}
Note: See TracBrowser for help on using the repository browser.