source: trunk/src/reglookup.c @ 66

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

fixed quoting bug in key names

fixed unicode decoding and string display bugs.

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