source: trunk/src/reglookup.c @ 65

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

various minor speedups and memory leak fixes. Added support for NONE and LINK types.

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