source: trunk/src/reglookup.c @ 41

Last change on this file since 41 was 41, checked in by tim, 19 years ago

Added full printing of values, as with old code.

renamed type conversion functions to follow precedent.

  • Property svn:keywords set to Id
File size: 14.7 KB
Line 
1/*
2 * A utility to test functionality of Gerald Carter''s regfio interface.
3 *
4 * Copyright (C) 2005 Timothy D. Morgan
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
18 *
19 * $Id: reglookup.c 41 2005-08-01 01:13:15Z tim $
20 */
21
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <strings.h>
27#include "../include/regfio.h"
28#include "../include/void_stack.h"
29
30
31/* Globals, influenced by command line parameters */
32bool print_verbose = false;
33bool print_security = false;
34bool path_filter_enabled = false;
35bool type_filter_enabled = false;
36char* path_filter = NULL;
37int type_filter;
38char* registry_file = NULL;
39
40
41void bailOut(int code, char* message)
42{
43  fprintf(stderr, message);
44  exit(code);
45}
46
47
48/* Returns a newly malloc()ed string which contains original buffer,
49 * except for non-printable or special characters are quoted in hex
50 * with the syntax '\xQQ' where QQ is the hex ascii value of the quoted
51 * character.  A null terminator is added, as only ascii, not binary,
52 * is returned.
53 */
54static char* quote_buffer(const unsigned char* str, 
55                          unsigned int len, char* special)
56{
57  unsigned int i;
58  unsigned int num_written=0;
59  unsigned int out_len = sizeof(char)*len+1;
60  char* ret_val = malloc(out_len);
61
62  if(ret_val == NULL)
63    return NULL;
64
65  for(i=0; i<len; i++)
66  {
67    if(str[i] < 32 || str[i] > 126 || strchr(special, str[i]) != NULL)
68    {
69      out_len += 3;
70      /* XXX: may not be the most efficient way of getting enough memory. */
71      ret_val = realloc(ret_val, out_len);
72      if(ret_val == NULL)
73        break;
74      num_written += snprintf(ret_val+num_written, (out_len)-num_written,
75                              "\\x%.2X", str[i]);
76    }
77    else
78      ret_val[num_written++] = str[i];
79  }
80  ret_val[num_written] = '\0';
81
82  return ret_val;
83}
84
85
86/* Returns a newly malloc()ed string which contains original string,
87 * except for non-printable or special characters are quoted in hex
88 * with the syntax '\xQQ' where QQ is the hex ascii value of the quoted
89 * character.
90 */
91static char* quote_string(const char* str, char* special)
92{
93  unsigned int len = strlen(str);
94  char* ret_val = quote_buffer((const unsigned char*)str, len, special);
95
96  return ret_val;
97}
98
99
100/*
101 * Convert from UniCode to Ascii ... Does not take into account other lang
102 * Restrict by ascii_max if > 0
103 */
104static int uni_to_ascii(unsigned char *uni, unsigned char *ascii, 
105                        int ascii_max, int uni_max)
106{
107  int i = 0; 
108
109  while (i < ascii_max && (uni[i*2] || uni[i*2+1]))
110  {
111    if (uni_max > 0 && (i*2) >= uni_max) break;
112    ascii[i] = uni[i*2];
113    i++;
114  }
115  ascii[i] = '\0';
116
117  return i;
118}
119
120
121/*
122 * Convert a data value to a string for display
123 */
124static unsigned char* data_to_ascii(unsigned char *datap, int len, int type)
125{
126  unsigned char *asciip;
127  unsigned int i;
128  unsigned short num_nulls;
129  unsigned char* ascii;
130  unsigned char* cur_str;
131  unsigned char* cur_ascii;
132  char* cur_quoted;
133  unsigned int cur_str_len;
134  unsigned int ascii_max, cur_str_max;
135  unsigned int str_rem, cur_str_rem, alen;
136
137  switch (type) 
138  {
139  case REG_SZ:
140    if (print_verbose)
141      fprintf(stderr, "Len: %d\n", len);
142   
143    ascii_max = sizeof(char)*len;
144    ascii = malloc(ascii_max+4);
145    if(ascii == NULL)
146      return NULL;
147   
148    /* XXX: This has to be fixed. It has to be UNICODE */
149    uni_to_ascii(datap, ascii, len, ascii_max);
150    return ascii;
151    break;
152
153  case REG_EXPAND_SZ:
154    ascii_max = sizeof(char)*len;
155    ascii = malloc(ascii_max+2);
156    if(ascii == NULL)
157      return NULL;
158
159    uni_to_ascii(datap, ascii, len, ascii_max);
160    return ascii;
161    break;
162
163  case REG_BINARY:
164    ascii = (unsigned char*)quote_buffer(datap, len, "\\");
165    return ascii;
166    break;
167
168  case REG_DWORD:
169    ascii_max = sizeof(char)*10;
170    ascii = malloc(ascii_max+1);
171    if(ascii == NULL)
172      return NULL;
173
174    if (*(int *)datap == 0)
175      snprintf((char*)ascii, ascii_max, "0");
176    else
177      snprintf((char*)ascii, ascii_max, "0x%x", *(int *)datap);
178    return ascii;
179    break;
180
181  case REG_MULTI_SZ:
182    ascii_max = sizeof(char)*len*4;
183    cur_str_max = sizeof(char)*len+1;
184    cur_str = malloc(cur_str_max);
185    cur_ascii = malloc(cur_str_max);
186    ascii = malloc(ascii_max+4);
187    if(ascii == NULL)
188      return NULL;
189
190    /* Reads until it reaches 4 consecutive NULLs,
191     * which is two nulls in unicode, or until it reaches len, or until we
192     * run out of buffer.  The latter should never happen, but we shouldn't
193     * trust our file to have the right lengths/delimiters.
194     */
195    asciip = ascii;
196    num_nulls = 0;
197    str_rem = ascii_max;
198    cur_str_rem = cur_str_max;
199    cur_str_len = 0;
200
201    for(i=0; (i < len) && str_rem > 0; i++)
202    {
203      *(cur_str+cur_str_len) = *(datap+i);
204      if(*(cur_str+cur_str_len) == 0)
205        num_nulls++;
206      else
207        num_nulls = 0;
208      cur_str_len++;
209
210      if(num_nulls == 2)
211      {
212        uni_to_ascii(cur_str, cur_ascii, cur_str_max, 0);
213        /* XXX: Should backslashes be quoted as well? */
214        cur_quoted = quote_string((char*)cur_ascii, "|");
215        alen = snprintf((char*)asciip, str_rem, "%s", cur_quoted);
216        asciip += alen;
217        str_rem -= alen;
218        free(cur_quoted);
219
220        if(*(datap+i+1) == 0 && *(datap+i+2) == 0)
221          break;
222        else
223        {
224          alen = snprintf((char*)asciip, str_rem, "%c", '|');
225          asciip += alen;
226          str_rem -= alen;
227          memset(cur_str, 0, cur_str_max);
228          cur_str_len = 0;
229          num_nulls = 0;
230          /* To eliminate leading nulls in subsequent strings. */
231          i++;
232        }
233      }
234    }
235    *asciip = 0;
236    return ascii;
237    break;
238
239  default:
240    return NULL;
241    break;
242  } 
243
244  return NULL;
245}
246
247
248void_stack* path2Stack(const char* s)
249{
250  void_stack* ret_val;
251  void_stack* rev_ret = void_stack_new(1024);
252  const char* cur = s;
253  char* next = NULL;
254  char* copy;
255
256  if (rev_ret == NULL)
257    return NULL;
258  if (s == NULL)
259    return rev_ret;
260 
261  while((next = strchr(cur, '/')) != NULL)
262  {
263    if ((next-cur) > 0)
264    {
265      copy = (char*)malloc((next-cur+1)*sizeof(char));
266      if(copy == NULL)
267        bailOut(2, "ERROR: Memory allocation problem.\n");
268         
269      memcpy(copy, cur, next-cur);
270      copy[next-cur] = '\0';
271      void_stack_push(rev_ret, copy);
272    }
273    cur = next+1;
274  }
275  if(strlen(cur) > 0)
276  {
277    copy = strdup(cur);
278    void_stack_push(rev_ret, copy);
279  }
280
281  ret_val = void_stack_copy_reverse(rev_ret);
282  void_stack_destroy(rev_ret);
283
284  return ret_val;
285}
286
287
288char* stack2Path(void_stack* nk_stack)
289{
290  const REGF_NK_REC* cur;
291  uint32 buf_left = 127;
292  uint32 buf_len = buf_left+1;
293  uint32 name_len = 0;
294  uint32 grow_amt;
295  char* buf; 
296  char* new_buf;
297  void_stack_iterator* iter;
298 
299  buf = (char*)malloc((buf_len)*sizeof(char));
300  if (buf == NULL)
301    return NULL;
302  buf[0] = '\0';
303
304  iter = void_stack_iterator_new(nk_stack);
305  if (iter == NULL)
306  {
307    free(buf);
308    return NULL;
309  }
310
311  /* skip root element */
312  cur = void_stack_iterator_next(iter);
313
314  while((cur = void_stack_iterator_next(iter)) != NULL)
315  {
316    buf[buf_len-buf_left-1] = '/';
317    buf_left -= 1;
318    name_len = strlen(cur->keyname);
319    if(name_len+1 > buf_left)
320    {
321      grow_amt = (uint32)(buf_len/2);
322      buf_len += name_len+1+grow_amt-buf_left;
323      if((new_buf = realloc(buf, buf_len)) == NULL)
324      {
325        free(buf);
326        free(iter);
327        return NULL;
328      }
329      buf = new_buf;
330      buf_left = grow_amt + name_len + 1;
331    }
332    strncpy(buf+(buf_len-buf_left-1), cur->keyname, name_len);
333    buf_left -= name_len;
334    buf[buf_len-buf_left-1] = '\0';
335  }
336
337  return buf;
338}
339
340
341void printValue(REGF_VK_REC* vk, char* prefix)
342{
343  uint32 size;
344  uint8 tmp_buf[4];
345  char* quoted_value;
346
347  if(!type_filter_enabled || (vk->type == type_filter))
348  {
349    /* Thanks Microsoft for making this process so straight-forward!!! */
350    size = (vk->data_size & ~VK_DATA_IN_OFFSET);
351    if(vk->data_size & VK_DATA_IN_OFFSET)
352    {
353      tmp_buf[0] = (uint8)((vk->data_off >> 3) & 0xFF);
354      tmp_buf[1] = (uint8)((vk->data_off >> 2) & 0xFF);
355      tmp_buf[2] = (uint8)((vk->data_off >> 1) & 0xFF);
356      tmp_buf[3] = (uint8)(vk->data_off & 0xFF);
357      if(size > 4)
358        size = 4;
359      quoted_value = data_to_ascii(tmp_buf, 4, vk->type);
360    }
361    else
362    {
363      /* XXX: This is a safety hack.  No data fields have yet been found
364       * larger, but length limits are probably better got from fields
365       * in the registry itself, within reason.
366       */
367      if(size > 16384)
368      {
369        printf("WARNING: key size %d larger than 16384, truncating...\n", size);
370        size = 16384;
371      }
372      quoted_value = data_to_ascii(vk->data, vk->data_size, vk->type);
373    }
374
375    printf("%s/%s:%s=%s\n", prefix, vk->valuename,
376           regfio_type_val2str(vk->type), quoted_value);
377  }
378}
379
380
381void printValueList(REGF_NK_REC* nk, char* prefix)
382{
383  uint32 i;
384 
385  for(i=0; i < nk->num_values; i++)
386    printValue(&nk->values[i], prefix);
387}
388
389
390/* XXX: this function is god-awful.  Needs to be re-designed. */
391void printKeyTree(REGF_FILE* f, void_stack* nk_stack, char* prefix)
392{
393  REGF_NK_REC* cur;
394  REGF_NK_REC* sub;
395  char* path;
396  char* val_path;
397  int key_type = regfio_type_str2val("KEY");
398
399  if((cur = (REGF_NK_REC*)void_stack_cur(nk_stack)) != NULL)
400  {
401    cur->subkey_index = 0;
402    path = stack2Path(nk_stack);
403   
404    if(strlen(path) > 0)
405      if(!type_filter_enabled || (key_type == type_filter))
406        printf("%s%s:KEY\n", prefix, path);
407    if(!type_filter_enabled || (key_type != type_filter))
408      printValueList(cur, path);
409    while((cur = (REGF_NK_REC*)void_stack_cur(nk_stack)) != NULL)
410    {
411      if((sub = regfio_fetch_subkey(f, cur)) != NULL)
412      {
413        sub->subkey_index = 0;
414        void_stack_push(nk_stack, sub);
415        path = stack2Path(nk_stack);
416        if(path != NULL)
417        {
418          val_path = (char*)malloc(strlen(prefix)+strlen(path)+1);
419          sprintf(val_path, "%s%s", prefix, path);
420          if(!type_filter_enabled || (key_type == type_filter))
421            printf("%s:KEY\n", val_path);
422          if(!type_filter_enabled || (key_type != type_filter))
423            printValueList(sub, val_path);
424          free(val_path);
425          free(path);
426        }
427      }
428      else
429      {
430        cur = void_stack_pop(nk_stack);
431        /* XXX: This is just a shallow free.  Need to write deep free
432         * routines to replace the Samba code for this.
433         */ 
434        if(cur != NULL)
435          free(cur);
436      }
437    }
438  }
439}
440
441
442/*
443 * Returns 0 if path was found.
444 * Returns 1 if path was not found.
445 * Returns less than 0 on other error.
446 */
447int retrievePath(REGF_FILE* f, void_stack* nk_stack,
448                 void_stack* path_stack)
449{
450  REGF_NK_REC* sub; 
451  REGF_NK_REC* cur;
452  void_stack* sub_nk_stack;
453  char* prefix;
454  char* cur_str = NULL;
455  bool found_cur = true;
456  uint32 i;
457  uint16 path_depth;
458  if(path_stack == NULL)
459    return -1;
460
461  path_depth = void_stack_size(path_stack);
462  if(path_depth < 1)
463    return -2;
464
465  if(void_stack_size(nk_stack) < 1)
466    return -3;
467  cur = (REGF_NK_REC*)void_stack_cur(nk_stack);
468
469  while(void_stack_size(path_stack) > 1)
470  {
471    /* Search key records only */
472    cur_str = (char*)void_stack_pop(path_stack);
473
474    found_cur = false;
475    while(!found_cur &&
476          (sub = regfio_fetch_subkey(f, cur)) != NULL)
477    {
478      if(strcasecmp(sub->keyname, cur_str) == 0)
479      {
480        cur = sub;
481        void_stack_push(nk_stack, sub);
482        found_cur = true;
483      }
484    }
485    free(cur_str);
486
487    if(!found_cur)
488      return 1;
489  }
490
491  /* Last round, search value and key records */
492  cur_str = (char*)void_stack_pop(path_stack);
493
494  for(i=0; (i < cur->num_values); i++)
495  {
496    if(strcasecmp(sub->values[i].valuename, cur_str) == 0)
497    {
498      printValue(&sub->values[i], stack2Path(nk_stack));
499      return 0;
500    }
501  }
502
503  while((sub = regfio_fetch_subkey(f, cur)) != NULL)
504  {
505    if(strcasecmp(sub->keyname, cur_str) == 0)
506    {
507      sub_nk_stack = void_stack_new(1024);
508      void_stack_push(sub_nk_stack, sub);
509      void_stack_push(nk_stack, sub);
510      prefix = stack2Path(nk_stack);
511      printKeyTree(f, sub_nk_stack, prefix);
512      return 0;
513    }
514  }
515
516  return 1;
517}
518
519
520static void usage(void)
521{
522  fprintf(stderr, "Usage: readreg [-v] [-s]"
523          " [-p <PATH_FILTER>] [-t <TYPE_FILTER>]"
524          " <REGISTRY_FILE>\n");
525  /* XXX: replace version string with Subversion property? */
526  fprintf(stderr, "Version: 0.2\n");
527  fprintf(stderr, "Options:\n");
528  fprintf(stderr, "\t-v\t sets verbose mode.\n");
529  fprintf(stderr, "\t-s\t prints security descriptors.\n");
530  fprintf(stderr, "\t-p\t restrict output to elements below this path.\n");
531  fprintf(stderr, "\t-t\t restrict results to this specific data type.\n");
532  fprintf(stderr, "\n");
533}
534
535
536int main(int argc, char** argv)
537{
538  void_stack* nk_stack;
539  void_stack* path_stack;
540  REGF_FILE* f;
541  REGF_NK_REC* root;
542  int retr_path_ret;
543  uint32 argi;
544
545  /* Process command line arguments */
546  if(argc < 2)
547  {
548    usage();
549    bailOut(1, "ERROR: Requires 1 argument.\n");
550  }
551 
552  for(argi = 1; argi < argc; argi++)
553  {
554    if (strcmp("-p", argv[argi]) == 0)
555    {
556      if(++argi > argc)
557      {
558        usage();
559        bailOut(1, "ERROR: '-p' option requires parameter.\n");
560      }
561      if((path_filter = strdup(argv[argi])) == NULL)
562        bailOut(2, "ERROR: Memory allocation problem.\n");
563
564      path_filter_enabled = true;
565    }
566    else if (strcmp("-t", argv[argi]) == 0)
567    {
568      if(++argi > argc)
569      {
570        usage();
571        bailOut(1, "ERROR: '-t' option requires parameter.\n");
572      }
573      if((type_filter = regfio_type_str2val(argv[argi])) == 0)
574      {
575        fprintf(stderr, "ERROR: Invalid type specified: %s.\n", argv[argi]);
576        bailOut(1, "");
577      }
578
579      type_filter_enabled = true;
580    }
581    else if (strcmp("-s", argv[argi]) == 0)
582      print_security = true;
583    else if (strcmp("-v", argv[argi]) == 0)
584      print_verbose = true;
585    else if (argv[argi][0] == '-')
586    {
587      usage();
588      fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
589      bailOut(1, "");
590    }
591    else
592    {
593      if((registry_file = strdup(argv[argi])) == NULL)
594        bailOut(2, "ERROR: Memory allocation problem.\n");
595    }
596  }
597
598  f = regfio_open(registry_file);
599  if(f == NULL)
600  {
601    fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
602    bailOut(3, "");
603  }
604
605  root = regfio_rootkey(f);
606  nk_stack = void_stack_new(1024);
607
608  if(void_stack_push(nk_stack, root))
609  {
610    path_stack = path2Stack(path_filter);
611    if(void_stack_size(path_stack) < 1)
612      printKeyTree(f, nk_stack, "");
613    else
614    {
615      retr_path_ret = retrievePath(f, nk_stack, path_stack);
616      if(retr_path_ret == 1)
617        fprintf(stderr, "WARNING: specified path not found.\n");
618      else if(retr_path_ret != 0)
619        bailOut(4, "ERROR:\n");
620    }
621  }
622  else
623    bailOut(2, "ERROR: Memory allocation problem.\n");
624
625  void_stack_destroy_deep(nk_stack);
626  regfio_close(f);
627
628  return 0;
629}
Note: See TracBrowser for help on using the repository browser.