source: trunk/src/reglookup.c @ 69

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

Improved interfaces to some low-layer value formatting functions.
Better error reporting.
Added more comments.

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