source: releases/0.10.0/src/reglookup-recover.c @ 289

Last change on this file since 289 was 138, checked in by tim, 16 years ago

extended error message logging to allow for message type filtering

fine tuned message verbosity to more reasonable default levels for reglookup and reglookup-recover

updated related documentation

  • Property svn:keywords set to Id
File size: 23.0 KB
Line 
1/*
2 * This program attempts to recover deleted data structures in a registry hive.
3 *
4 * Copyright (C) 2008-2009 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 3 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-recover.c 138 2009-02-08 19:53:48Z tim $
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <sysexits.h>
25
26#include "../include/regfi.h"
27#include "../include/range_list.h"
28#include "../include/lru_cache.h"
29
30
31/* Globals, influenced by command line parameters */
32bool print_verbose = false;
33bool print_security = false;
34bool print_header = true;
35bool print_leftover = false;
36bool print_parsedraw = false;
37char* registry_file = NULL;
38
39#include "common.c"
40
41
42char* getQuotedData(int fd, uint32 offset, uint32 length)
43{
44  uint8* buf;
45  char* quoted_buf;
46  uint32 len;
47
48  if((lseek(fd, offset, SEEK_SET)) == -1)
49    return NULL;
50
51  buf = (uint8*)malloc(length);
52  if(buf == NULL)
53    return NULL;
54
55  len = length;
56  if((regfi_read(fd, buf, &length) != 0) || length != len)
57  {
58    free(buf);
59    return NULL;
60  }
61
62  quoted_buf = quote_buffer(buf, length, common_special_chars);
63  free(buf);
64
65  return quoted_buf;
66}
67
68
69void printKey(REGFI_FILE* f, REGFI_NK_REC* nk, const char* prefix)
70{
71  char mtime[20];
72  time_t tmp_time[1];
73  struct tm* tmp_time_s = NULL;
74  char* quoted_name = NULL;
75  char* quoted_raw = "";
76
77  *tmp_time = nt_time_to_unix(&nk->mtime);
78  tmp_time_s = gmtime(tmp_time);
79  strftime(mtime, sizeof(mtime), "%Y-%m-%d %H:%M:%S", tmp_time_s);
80
81  quoted_name = quote_string(nk->keyname, key_special_chars);
82  if (quoted_name == NULL)
83  {
84    quoted_name = malloc(1*sizeof(char));
85    if(quoted_name == NULL)
86      bailOut(EX_OSERR, "ERROR: Could not allocate sufficient memory.\n");
87    quoted_name[0] = '\0';
88
89    fprintf(stderr, "WARN: NULL key name in NK record at offset %.8X.\n",
90            nk->offset);
91  }
92
93  if(print_parsedraw)
94    quoted_raw = getQuotedData(f->fd, nk->offset, nk->cell_size);
95
96  printf("%.8X,%.8X,KEY,%s,%s,%s,%d,,,,,,,,%s\n", nk->offset, nk->cell_size,
97         prefix, quoted_name, mtime, nk->num_values, quoted_raw);
98 
99  if(print_parsedraw)
100    free(quoted_raw);
101  free(quoted_name);
102}
103
104
105void printValue(REGFI_FILE* f, const REGFI_VK_REC* vk, const char* prefix)
106{
107  char* quoted_value = NULL;
108  char* quoted_name = NULL;
109  char* quoted_raw = "";
110  char* conv_error = NULL;
111  const char* str_type = NULL;
112  uint32 size = vk->data_size;
113
114  /* Microsoft's documentation indicates that "available memory" is
115   * the limit on value sizes.  Annoying.  We limit it to 1M which
116   * should rarely be exceeded, unless the file is corrupt or
117   * malicious. For more info, see:
118   *   http://msdn2.microsoft.com/en-us/library/ms724872.aspx
119   */
120  /* XXX: Should probably do something different here for this tool.
121   *      Also, It would be really nice if this message somehow included the
122   *      name of the current value we're having trouble with, since
123   *      stderr/stdout don't always sync nicely.
124   */
125  if(size > REGFI_VK_MAX_DATA_LENGTH)
126  {
127    fprintf(stderr, "WARN: value data size %d larger than "
128            "%d, truncating...\n", size, REGFI_VK_MAX_DATA_LENGTH);
129    size = REGFI_VK_MAX_DATA_LENGTH;
130  }
131 
132  quoted_name = quote_string(vk->valuename, key_special_chars);
133  if (quoted_name == NULL)
134  { /* Value names are NULL when we're looking at the "(default)" value.
135     * Currently we just return a 0-length string to try an eliminate
136     * ambiguity with a literal "(default)" value.  The data type of a line
137     * in the output allows one to differentiate between the parent key and
138     * this value.
139     */
140    quoted_name = malloc(1*sizeof(char));
141    if(quoted_name == NULL)
142      bailOut(EX_OSERR, "ERROR: Could not allocate sufficient memory.\n");
143    quoted_name[0] = '\0';
144  }
145
146  quoted_value = data_to_ascii(vk->data, size, vk->type, &conv_error);
147  if(quoted_value == NULL)
148  {
149    quoted_value = malloc(1*sizeof(char));
150    if(quoted_value == NULL)
151      bailOut(EX_OSERR, "ERROR: Could not allocate sufficient memory.\n");
152    quoted_value[0] = '\0';
153
154    if(conv_error == NULL)
155      fprintf(stderr, "WARN: Could not quote value for '%s/%s'.  "
156              "Memory allocation failure likely.\n", prefix, quoted_name);
157    else if(print_verbose)
158      fprintf(stderr, "WARN: Could not quote value for '%s/%s'.  "
159              "Returned error: %s\n", prefix, quoted_name, conv_error);
160  }
161  /* XXX: should these always be printed? */
162  else if(conv_error != NULL && print_verbose)
163    fprintf(stderr, "INFO: While quoting value for '%s/%s', "
164            "warning returned: %s\n", prefix, quoted_name, conv_error);
165
166
167  if(print_parsedraw)
168    quoted_raw = getQuotedData(f->fd, vk->offset, vk->cell_size);
169
170  str_type = regfi_type_val2str(vk->type);
171  if(str_type == NULL)
172    printf("%.8X,%.8X,VALUE,%s,%s,,,0x%.8X,%s,%d,,,,,%s\n", 
173           vk->offset, vk->cell_size, prefix, quoted_name, 
174           vk->type, quoted_value, vk->data_size, quoted_raw);
175  else
176    printf("%.8X,%.8X,VALUE,%s,%s,,,%s,%s,%d,,,,,%s\n", 
177           vk->offset, vk->cell_size, prefix, quoted_name, 
178           str_type, quoted_value, vk->data_size, quoted_raw);
179
180  if(print_parsedraw)
181    free(quoted_raw);
182  if(quoted_value != NULL)
183    free(quoted_value);
184  if(quoted_name != NULL)
185    free(quoted_name);
186  if(conv_error != NULL)
187    free(conv_error);
188}
189
190
191void printSK(REGFI_FILE* f, REGFI_SK_REC* sk)
192{
193  char* quoted_raw = NULL;
194  char* empty_str = "";
195  char* owner = regfi_get_owner(sk->sec_desc);
196  char* group = regfi_get_group(sk->sec_desc);
197  char* sacl = regfi_get_sacl(sk->sec_desc);
198  char* dacl = regfi_get_dacl(sk->sec_desc);
199
200  if(print_parsedraw)
201    quoted_raw = getQuotedData(f->fd, sk->offset, sk->cell_size);
202
203  if(owner == NULL)
204    owner = empty_str;
205  if(group == NULL)
206    group = empty_str;
207  if(sacl == NULL)
208    sacl = empty_str;
209  if(dacl == NULL)
210    dacl = empty_str;
211
212  printf("%.8X,%.8X,SK,,,,,,,,%s,%s,%s,%s,%s\n", sk->offset, sk->cell_size,
213         owner, group, sacl, dacl, quoted_raw);
214 
215  if(owner != empty_str)
216    free(owner);
217  if(group != empty_str)
218    free(group);
219  if(sacl != empty_str)
220    free(sacl);
221  if(dacl != empty_str)
222    free(dacl);
223
224  if(print_parsedraw)
225    free(quoted_raw);
226}
227
228
229int printCell(REGFI_FILE* f, uint32 offset)
230{
231  char* quoted_buf;
232  uint32 cell_length;
233  bool unalloc;
234
235  if(!regfi_parse_cell(f->fd, offset, NULL, 0, &cell_length, &unalloc))
236    return 1;
237
238  quoted_buf = getQuotedData(f->fd, offset, cell_length);
239  if(quoted_buf == NULL)
240    return 2;
241
242  printf("%.8X,%.8X,RAW,,,,,,,,,,,,%s\n", offset, cell_length, quoted_buf);
243
244  free(quoted_buf);
245  return 0;
246}
247
248
249/* This function returns a properly quoted parent path or partial parent
250 * path for a given key.  Returns NULL on error, "" if no path was available.
251 * Paths returned must be free()d.
252 */
253/* XXX: This is not terribly efficient, as it may reparse many keys
254 *      repeatedly.  Should try to add caching.  Also, piecing the path
255 *      together is slow and redundant.
256 */
257char* getParentPath(REGFI_FILE* f, REGFI_NK_REC* nk)
258{
259  void_stack* path_stack = void_stack_new(REGFI_MAX_DEPTH);
260  REGFI_HBIN* hbin;
261  REGFI_NK_REC* cur_ancestor;
262  char* ret_val;
263  char* path_element;
264  char* tmp_str;
265  uint32 virt_offset, i, stack_size, ret_val_size, ret_val_left, element_size;
266  uint32 max_length;
267
268  /* The path_stack size limit should guarantee that we don't recurse forever. */
269  virt_offset = nk->parent_off;
270  while(virt_offset != REGFI_OFFSET_NONE)
271  { 
272    hbin = regfi_lookup_hbin(f, virt_offset);
273    if(hbin == NULL)
274      virt_offset = REGFI_OFFSET_NONE;
275    else
276    {
277      max_length = hbin->block_size + hbin->file_off
278        - (virt_offset+REGFI_REGF_SIZE);
279      cur_ancestor = regfi_parse_nk(f, virt_offset+REGFI_REGF_SIZE, 
280                                    max_length, true);
281      printMsgs(f);
282
283      if(cur_ancestor == NULL)
284        virt_offset = REGFI_OFFSET_NONE;
285      else
286      {
287        if((cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY1) 
288           || (cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY2))
289          virt_offset = REGFI_OFFSET_NONE;
290        else
291          virt_offset = cur_ancestor->parent_off;
292       
293        path_element = quote_string(cur_ancestor->keyname, key_special_chars);
294        if(path_element == NULL || !void_stack_push(path_stack, path_element))
295        {
296          free(cur_ancestor->keyname);
297          free(cur_ancestor);
298          void_stack_free_deep(path_stack);
299          return NULL;
300        }
301
302        regfi_key_free(cur_ancestor);
303      }
304    }
305  }
306 
307  stack_size = void_stack_size(path_stack);
308  ret_val_size = 16*stack_size;
309  if(ret_val_size == 0)
310    ret_val_size = 1;
311  ret_val_left = ret_val_size;
312  ret_val = malloc(ret_val_size);
313  if(ret_val == NULL)
314  {
315    void_stack_free_deep(path_stack);
316    return NULL;
317  }
318  ret_val[0] = '\0';
319
320  for(i=0; i<stack_size; i++)
321  {
322    path_element = void_stack_pop(path_stack);
323    element_size = strlen(path_element);
324    if(ret_val_left < element_size+2)
325    {
326      ret_val_size += element_size+16;
327      ret_val_left += element_size+16;
328      tmp_str = (char*)realloc(ret_val, ret_val_size);
329      if(tmp_str == NULL)
330      {
331        free(ret_val);
332        void_stack_free_deep(path_stack);
333        return NULL;
334      }
335      ret_val = tmp_str;
336    }
337
338    ret_val_left -= snprintf(ret_val+ret_val_size-ret_val_left,ret_val_left, "/%s", path_element);
339    free(path_element);
340  }
341  void_stack_free(path_stack);
342
343  return ret_val;
344}
345
346
347static void usage(void)
348{
349  fprintf(stderr, "Usage: reglookup-recover [options] <REGISTRY_FILE>\n");
350  fprintf(stderr, "Version: %s\n", REGLOOKUP_VERSION);
351  fprintf(stderr, "Options:\n");
352  fprintf(stderr, "\t-v\t sets verbose mode.\n");
353  fprintf(stderr, "\t-h\t enables header row. (default)\n");
354  fprintf(stderr, "\t-H\t disables header row.\n");
355  fprintf(stderr, "\t-l\t enables leftover(raw) cell output.\n");
356  fprintf(stderr, "\t-L\t disables leftover(raw) cell output. (default)\n");
357  fprintf(stderr, "\t-r\t enables raw cell output for parsed cells.\n");
358  fprintf(stderr, "\t-R\t disables raw cell output for parsed cells. (default)\n");
359  fprintf(stderr, "\n");
360}
361
362
363bool removeRange(range_list* rl, uint32 offset, uint32 length)
364{
365  int32 rm_idx;
366  const range_list_element* cur_elem;
367
368  rm_idx = range_list_find(rl, offset);
369  if(rm_idx < 0)
370  {
371    fprintf(stderr, "DEBUG: removeRange: rm_idx < 0; (%d)\n", rm_idx);
372    return false;
373  }
374
375  cur_elem = range_list_get(rl, rm_idx);
376  if(cur_elem == NULL)
377  {
378    fprintf(stderr, "DEBUG: removeRange: cur_elem == NULL.  rm_idx=%d\n", rm_idx);
379    return false;
380  }
381
382  if(offset > cur_elem->offset)
383  {
384    if(!range_list_split_element(rl, rm_idx, offset))
385    {
386      fprintf(stderr, "DEBUG: removeRange: first split failed\n");
387      return false;
388    }
389    rm_idx++;
390    cur_elem = range_list_get(rl, rm_idx);
391    if(cur_elem == NULL)
392    {
393      fprintf(stderr, 
394              "DEBUG: removeRange: cur_elem == NULL after first split.  rm_idx=%d\n",
395              rm_idx);
396      return false;
397    }
398  }
399 
400  if(offset+length < cur_elem->offset+cur_elem->length)
401  {
402    if(!range_list_split_element(rl, rm_idx, offset+length))
403    {
404      fprintf(stderr, "DEBUG: removeRange: second split failed\n");
405      return false;
406    }
407  }
408 
409  if(!range_list_remove(rl, rm_idx))
410  {
411    fprintf(stderr, "DEBUG: removeRange: remove failed\n");
412    return false;
413  }
414
415  return true;
416}
417
418
419/* NOTE: unalloc_keys should be an empty range_list. */
420int extractKeys(REGFI_FILE* f, 
421                range_list* unalloc_cells, 
422                range_list* unalloc_keys)
423{
424  const range_list_element* cur_elem;
425  REGFI_NK_REC* key;
426  uint32 i, j;
427
428  for(i=0; i < range_list_size(unalloc_cells); i++)
429  {
430    printMsgs(f);
431    cur_elem = range_list_get(unalloc_cells, i);
432    for(j=0; cur_elem->length > REGFI_NK_MIN_LENGTH
433          && j <= cur_elem->length-REGFI_NK_MIN_LENGTH; j+=8)
434    {
435      key = regfi_parse_nk(f, cur_elem->offset+j,
436                           cur_elem->length-j, false);
437      printMsgs(f);
438
439      if(key != NULL)
440      {
441        if(!range_list_add(unalloc_keys, key->offset, 
442                           key->cell_size, key))
443        {
444          fprintf(stderr, "ERROR: Couldn't add key to unalloc_keys.\n");
445          return 20;
446        }
447        j+=key->cell_size-8;
448      }
449    }
450  }
451
452  for(i=0; i<range_list_size(unalloc_keys); i++)
453  {
454    cur_elem = range_list_get(unalloc_keys, i);
455    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
456      return 30;
457  }
458
459  return 0;
460}
461
462
463int extractValueLists(REGFI_FILE* f,
464                      range_list* unalloc_cells,
465                      range_list* unalloc_keys)
466{
467  REGFI_NK_REC* nk;
468  REGFI_HBIN* hbin;
469  const range_list_element* cur_elem;
470  uint32 i, j, num_keys, off, values_length, max_length;
471
472  num_keys=range_list_size(unalloc_keys);
473  for(i=0; i<num_keys; i++)
474  {
475    cur_elem = range_list_get(unalloc_keys, i);
476    if(cur_elem == NULL)
477      return 10;
478    nk = cur_elem->data;
479
480    if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE))
481    {
482      hbin = regfi_lookup_hbin(f, nk->values_off);
483     
484      if(hbin != NULL)
485      {
486        off = nk->values_off + REGFI_REGF_SIZE;
487        max_length = hbin->block_size + hbin->file_off - off;
488        /* XXX: This is a hack.  We parse all value-lists, VK records,
489         *      and data records without regard for current allocation status. 
490         *      On the off chance that such a record correctly parsed but is
491         *      actually a reallocated structure used by something else, we
492         *      simply prune it after the fact.  Would be faster to check this
493         *      up front somehow.
494         */
495        nk->values = regfi_load_valuelist(f, off, nk->num_values, max_length,
496                                          false);
497        values_length = (nk->num_values+1)*sizeof(uint32);
498        if(values_length != (values_length & 0xFFFFFFF8))
499          values_length = (values_length & 0xFFFFFFF8) + 8;
500
501        if(nk->values != NULL)
502        {
503          if(!range_list_has_range(unalloc_cells, off, values_length))
504          { /* We've parsed a values-list which isn't in the unallocated list,
505             * so prune it.
506             */
507            for(j=0; j<nk->num_values; j++)
508            {
509              if(nk->values[j] != NULL)
510              {
511                if(nk->values[j]->data != NULL)
512                  free(nk->values[j]->data);
513                free(nk->values[j]);
514              }
515            }
516            free(nk->values);
517            nk->values = NULL;
518          }
519          else
520          { /* Values-list was recovered.  Remove from unalloc_cells and
521             * inspect values.
522             */
523            if(!removeRange(unalloc_cells, off, values_length))
524              return 20;
525
526            for(j=0; j < nk->num_values; j++)
527            {
528              if(nk->values[j] != NULL)
529              {
530                if(!range_list_has_range(unalloc_cells, nk->values[j]->offset, 
531                                         nk->values[j]->cell_size))
532                { /* We've parsed a value which isn't in the unallocated list,
533                   * so prune it.
534                   */
535                  if(nk->values[j]->data != NULL)
536                    free(nk->values[j]->data);
537                  free(nk->values[j]);
538                  nk->values[j] = NULL;
539                }
540                else
541                {
542                  /* A VK record was recovered.  Remove from unalloc_cells
543                   * and inspect data.
544                   */
545                  if(!removeRange(unalloc_cells, nk->values[j]->offset,
546                                  nk->values[j]->cell_size))
547                    return 21;
548
549                  /* Don't bother pruning or removing from unalloc_cells if
550                   * there is no data, or it is stored in the offset.
551                   */
552                  if(nk->values[j]->data != NULL && !nk->values[j]->data_in_offset)
553                  {
554                    off = nk->values[j]->data_off+REGFI_REGF_SIZE;
555                    if(!range_list_has_range(unalloc_cells, off, 
556                                             nk->values[j]->data_size))
557                    { /* We've parsed a data cell which isn't in the unallocated
558                       * list, so prune it.
559                       */
560                      free(nk->values[j]->data);
561                      nk->values[j]->data = NULL;
562                    }
563                    else
564                    { /*A data record was recovered. Remove from unalloc_cells.*/
565                      if(!removeRange(unalloc_cells, off, 
566                                      nk->values[j]->data_size))
567                        return 22;
568                    }
569                  }
570                }
571              }
572            }
573          }
574        }
575      }
576    }
577  }
578
579  return 0;
580}
581
582
583/* NOTE: unalloc_values should be an empty range_list. */
584int extractValues(REGFI_FILE* f,
585                  range_list* unalloc_cells,
586                  range_list* unalloc_values)
587{
588  const range_list_element* cur_elem;
589  REGFI_VK_REC* vk;
590  uint32 i, j, off;
591
592  for(i=0; i < range_list_size(unalloc_cells); i++)
593  {
594    printMsgs(f);
595    cur_elem = range_list_get(unalloc_cells, i);
596    for(j=0; j <= cur_elem->length; j+=8)
597    {
598      vk = regfi_parse_vk(f, cur_elem->offset+j, 
599                           cur_elem->length-j, false);
600      printMsgs(f);
601
602      if(vk != NULL)
603      {
604        if(!range_list_add(unalloc_values, vk->offset,
605                           vk->cell_size, vk))
606        {
607          fprintf(stderr, "ERROR: Couldn't add value to unalloc_values.\n");
608          return 20;
609        }
610        j+=vk->cell_size-8;
611      }
612    }
613  }
614 
615  /* Remove value ranges from the unalloc_cells before we continue. */
616  for(i=0; i<range_list_size(unalloc_values); i++)
617  {
618    cur_elem = range_list_get(unalloc_values, i);
619    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
620      return 30;
621  }
622
623  /* Now see if the data associated with each value is intact */
624  for(i=0; i<range_list_size(unalloc_values); i++)
625  {
626    cur_elem = range_list_get(unalloc_values, i);
627    vk = (REGFI_VK_REC*)cur_elem->data;
628    if(vk == NULL)
629      return 40;
630
631    if(vk->data != NULL && !vk->data_in_offset)
632    {
633      off = vk->data_off+REGFI_REGF_SIZE;
634      if(!range_list_has_range(unalloc_cells, off, vk->data_size))
635      { /* We've parsed a data cell which isn't in the unallocated
636         * list, so prune it.
637         */
638        free(vk->data);
639        vk->data = NULL;
640      }
641      else
642      { /*A data record was recovered. Remove from unalloc_cells.*/
643        if(!removeRange(unalloc_cells, off, vk->data_size))
644          return 50;
645      }
646    }
647  }
648
649  return 0;
650}
651
652
653/* NOTE: unalloc_sks should be an empty range_list. */
654int extractSKs(REGFI_FILE* f, 
655               range_list* unalloc_cells,
656               range_list* unalloc_sks)
657{
658  const range_list_element* cur_elem;
659  REGFI_SK_REC* sk;
660  uint32 i, j;
661
662  for(i=0; i < range_list_size(unalloc_cells); i++)
663  {
664    printMsgs(f);
665    cur_elem = range_list_get(unalloc_cells, i);
666    for(j=0; j <= cur_elem->length; j+=8)
667    {
668      sk = regfi_parse_sk(f, cur_elem->offset+j, 
669                          cur_elem->length-j, false);
670      printMsgs(f);
671
672      if(sk != NULL)
673      {
674        if(!range_list_add(unalloc_sks, sk->offset,
675                           sk->cell_size, sk))
676        {
677          fprintf(stderr, "ERROR: Couldn't add sk to unalloc_sks.\n");
678          return 20;
679        }
680        j+=sk->cell_size-8;
681      }
682    }
683  }
684
685  for(i=0; i<range_list_size(unalloc_sks); i++)
686  {
687    cur_elem = range_list_get(unalloc_sks, i);
688    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
689      return 30;
690  }
691
692  return 0;
693}
694
695
696int main(int argc, char** argv)
697{ 
698  REGFI_FILE* f;
699  const range_list_element* cur_elem;
700  range_list* unalloc_cells;
701  range_list* unalloc_keys;
702  range_list* unalloc_values;
703  range_list* unalloc_sks;
704  char** parent_paths;
705  char* tmp_name;
706  char* tmp_path;
707  REGFI_NK_REC* tmp_key;
708  REGFI_VK_REC* tmp_value;
709  uint32 argi, arge, i, j, ret, num_unalloc_keys;
710  /* uint32 test_offset;*/
711 
712  /* Process command line arguments */
713  if(argc < 2)
714  {
715    usage();
716    bailOut(EX_USAGE, "ERROR: Requires at least one argument.\n");
717  }
718 
719  arge = argc-1;
720  for(argi = 1; argi < arge; argi++)
721  {
722    if (strcmp("-v", argv[argi]) == 0)
723      print_verbose = true;
724    else if (strcmp("-h", argv[argi]) == 0)
725      print_header = true;
726    else if (strcmp("-H", argv[argi]) == 0)
727      print_header = false;
728    else if (strcmp("-l", argv[argi]) == 0)
729      print_leftover = true;
730    else if (strcmp("-L", argv[argi]) == 0)
731      print_leftover = false;
732    else if (strcmp("-r", argv[argi]) == 0)
733      print_parsedraw = true;
734    else if (strcmp("-R", argv[argi]) == 0)
735      print_parsedraw = false;
736    else
737    {
738      usage();
739      fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
740      bailOut(EX_USAGE, "");
741    }
742  }
743  /*test_offset = strtol(argv[argi++], NULL, 16);*/
744
745  if((registry_file = strdup(argv[argi])) == NULL)
746    bailOut(EX_OSERR, "ERROR: Memory allocation problem.\n");
747
748  f = regfi_open(registry_file);
749  if(f == NULL)
750  {
751    fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
752    bailOut(EX_NOINPUT, "");
753  }
754  if(print_verbose)
755    regfi_set_message_mask(f, REGFI_MSG_ERROR|REGFI_MSG_WARN|REGFI_MSG_INFO);
756  else
757    regfi_set_message_mask(f, REGFI_MSG_ERROR);
758
759  if(print_header)
760    printf("OFFSET,REC_LENGTH,REC_TYPE,PATH,NAME,"
761           "NK_MTIME,NK_NVAL,VK_TYPE,VK_VALUE,VK_DATA_LEN,"
762           "SK_OWNER,SK_GROUP,SK_SACL,SK_DACL,RAW_CELL\n");
763
764  unalloc_cells = regfi_parse_unalloc_cells(f);
765  if(unalloc_cells == NULL)
766  {
767    fprintf(stderr, "ERROR: Could not obtain list of unallocated cells.\n");
768    return 1;
769  }
770
771  unalloc_keys = range_list_new();
772  if(unalloc_keys == NULL)
773    return 10;
774
775  unalloc_values = range_list_new();
776  if(unalloc_values == NULL)
777    return 10;
778
779  unalloc_sks = range_list_new();
780  if(unalloc_sks == NULL)
781    return 10;
782
783  ret = extractKeys(f, unalloc_cells, unalloc_keys);
784  if(ret != 0)
785  {
786    fprintf(stderr, "ERROR: extractKeys() failed with %d.\n", ret);
787    return ret;
788  }
789
790  ret = extractValueLists(f, unalloc_cells, unalloc_keys);
791  if(ret != 0)
792  {
793    fprintf(stderr, "ERROR: extractValueLists() failed with %d.\n", ret);
794    return ret;
795  }
796
797  /* Carve any orphan values and associated data */
798  ret = extractValues(f, unalloc_cells, unalloc_values);
799  if(ret != 0)
800  {
801    fprintf(stderr, "ERROR: extractValues() failed with %d.\n", ret);
802    return ret;
803  }
804
805  /* Carve any SK records */
806  ret = extractSKs(f, unalloc_cells, unalloc_sks);
807  if(ret != 0)
808  {
809    fprintf(stderr, "ERROR: extractSKs() failed with %d.\n", ret);
810    return ret;
811  }
812
813  /* Now that we're done carving, associate recovered keys with parents,
814   * if at all possible.
815   */
816  num_unalloc_keys = range_list_size(unalloc_keys);
817  parent_paths = (char**)malloc(sizeof(char*)*num_unalloc_keys);
818  if(parent_paths == NULL)
819    return 10;
820
821  for(i=0; i < num_unalloc_keys; i++)
822  {
823    cur_elem = range_list_get(unalloc_keys, i);
824    tmp_key = (REGFI_NK_REC*)cur_elem->data;
825
826    if(tmp_key == NULL)
827      return 20;
828   
829    parent_paths[i] = getParentPath(f, tmp_key);
830    if(parent_paths[i] == NULL)
831      return 20;
832  }
833 
834  /* Now start the output */
835
836  for(i=0; i < num_unalloc_keys; i++)
837  {
838    cur_elem = range_list_get(unalloc_keys, i);
839    tmp_key = (REGFI_NK_REC*)cur_elem->data;
840
841    printKey(f, tmp_key, parent_paths[i]);
842    if(tmp_key->num_values > 0 && tmp_key->values != NULL)
843    {
844      tmp_name = quote_string(tmp_key->keyname, key_special_chars);
845      tmp_path = (char*)malloc(strlen(parent_paths[i])+strlen(tmp_name)+2);
846      if(tmp_path == NULL)
847      {
848        free(tmp_name);
849        return 10;
850      }
851
852      sprintf(tmp_path, "%s/%s", parent_paths[i], tmp_name);
853      for(j=0; j < tmp_key->num_values; j++)
854      {
855        tmp_value = tmp_key->values[j];
856        if(tmp_value != NULL)
857          printValue(f, tmp_value, tmp_path);
858      }
859      free(tmp_path);
860      free(tmp_name);
861      free(parent_paths[i]);
862    }
863  }
864  free(parent_paths);
865
866  /* Print out orphaned values */
867  for(i=0; i < range_list_size(unalloc_values); i++)
868  {
869    cur_elem = range_list_get(unalloc_values, i);
870    tmp_value = (REGFI_VK_REC*)cur_elem->data; 
871
872    printValue(f, tmp_value, "");
873  }
874 
875  if(print_leftover)
876  {
877    for(i=0; i < range_list_size(unalloc_cells); i++)
878    {
879      cur_elem = range_list_get(unalloc_cells, i);
880      printCell(f, cur_elem->offset);
881    }
882  }
883
884  return 0;
885}
Note: See TracBrowser for help on using the repository browser.