source: trunk/src/reglookup.c @ 70

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

made iconv parameter types more correct.

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