source: trunk/src/reglookup-recover.c @ 136

Last change on this file since 136 was 136, checked in by tim, 15 years ago

fixed various integer issues and memory allocation issues

polished error message functions and added initial messages in a few places

  • Property svn:keywords set to Id
File size: 22.8 KB
Line 
1/*
2 * This program attempts to recover deleted data structures in a registry hive.
3 *
4 * Copyright (C) 2008 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 136 2009-01-23 17:29:51Z 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, "WARNING: 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, "WARNING: 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, "WARNING: Could not quote value for '%s/%s'.  "
156              "Memory allocation failure likely.\n", prefix, quoted_name);
157    else if(print_verbose)
158      fprintf(stderr, "WARNING: 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, "VERBOSE: 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      if(cur_ancestor == NULL)
282        virt_offset = REGFI_OFFSET_NONE;
283      else
284      {
285        if((cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY1) 
286           || (cur_ancestor->key_type == REGFI_NK_TYPE_ROOTKEY2))
287          virt_offset = REGFI_OFFSET_NONE;
288        else
289          virt_offset = cur_ancestor->parent_off;
290       
291        path_element = quote_string(cur_ancestor->keyname, key_special_chars);
292        if(path_element == NULL || !void_stack_push(path_stack, path_element))
293        {
294          free(cur_ancestor->keyname);
295          free(cur_ancestor);
296          void_stack_free_deep(path_stack);
297          return NULL;
298        }
299
300        regfi_key_free(cur_ancestor);
301      }
302    }
303  }
304 
305  stack_size = void_stack_size(path_stack);
306  ret_val_size = 16*stack_size;
307  if(ret_val_size == 0)
308    ret_val_size = 1;
309  ret_val_left = ret_val_size;
310  ret_val = malloc(ret_val_size);
311  if(ret_val == NULL)
312  {
313    void_stack_free_deep(path_stack);
314    return NULL;
315  }
316  ret_val[0] = '\0';
317
318  for(i=0; i<stack_size; i++)
319  {
320    path_element = void_stack_pop(path_stack);
321    element_size = strlen(path_element);
322    if(ret_val_left < element_size+2)
323    {
324      ret_val_size += element_size+16;
325      ret_val_left += element_size+16;
326      tmp_str = (char*)realloc(ret_val, ret_val_size);
327      if(tmp_str == NULL)
328      {
329        free(ret_val);
330        void_stack_free_deep(path_stack);
331        return NULL;
332      }
333      ret_val = tmp_str;
334    }
335
336    ret_val_left -= snprintf(ret_val+ret_val_size-ret_val_left,ret_val_left, "/%s", path_element);
337    free(path_element);
338  }
339  void_stack_free(path_stack);
340
341  return ret_val;
342}
343
344
345static void usage(void)
346{
347  fprintf(stderr, "Usage: reglookup-recover [options] <REGISTRY_FILE>\n");
348  fprintf(stderr, "Version: %s\n", REGLOOKUP_VERSION);
349  fprintf(stderr, "Options:\n");
350  fprintf(stderr, "\t-v\t sets verbose mode.\n");
351  fprintf(stderr, "\t-h\t enables header row. (default)\n");
352  fprintf(stderr, "\t-H\t disables header row.\n");
353  fprintf(stderr, "\t-l\t enables leftover(raw) cell output.\n");
354  fprintf(stderr, "\t-L\t disables leftover(raw) cell output. (default)\n");
355  fprintf(stderr, "\t-r\t enables raw cell output for parsed cells.\n");
356  fprintf(stderr, "\t-R\t disables raw cell output for parsed cells. (default)\n");
357  fprintf(stderr, "\n");
358}
359
360
361bool removeRange(range_list* rl, uint32 offset, uint32 length)
362{
363  int32 rm_idx;
364  const range_list_element* cur_elem;
365
366  rm_idx = range_list_find(rl, offset);
367  if(rm_idx < 0)
368  {
369    fprintf(stderr, "DEBUG: removeRange: rm_idx < 0; (%d)\n", rm_idx);
370    return false;
371  }
372
373  cur_elem = range_list_get(rl, rm_idx);
374  if(cur_elem == NULL)
375  {
376    fprintf(stderr, "DEBUG: removeRange: cur_elem == NULL.  rm_idx=%d\n", rm_idx);
377    return false;
378  }
379
380  if(offset > cur_elem->offset)
381  {
382    if(!range_list_split_element(rl, rm_idx, offset))
383    {
384      fprintf(stderr, "DEBUG: removeRange: first split failed\n");
385      return false;
386    }
387    rm_idx++;
388    cur_elem = range_list_get(rl, rm_idx);
389    if(cur_elem == NULL)
390    {
391      fprintf(stderr, 
392              "DEBUG: removeRange: cur_elem == NULL after first split.  rm_idx=%d\n",
393              rm_idx);
394      return false;
395    }
396  }
397 
398  if(offset+length < cur_elem->offset+cur_elem->length)
399  {
400    if(!range_list_split_element(rl, rm_idx, offset+length))
401    {
402      fprintf(stderr, "DEBUG: removeRange: second split failed\n");
403      return false;
404    }
405  }
406 
407  if(!range_list_remove(rl, rm_idx))
408  {
409    fprintf(stderr, "DEBUG: removeRange: remove failed\n");
410    return false;
411  }
412
413  return true;
414}
415
416
417/* NOTE: unalloc_keys should be an empty range_list. */
418int extractKeys(REGFI_FILE* f, 
419                range_list* unalloc_cells, 
420                range_list* unalloc_keys)
421{
422  const range_list_element* cur_elem;
423  REGFI_NK_REC* key;
424  uint32 i, j;
425
426  for(i=0; i < range_list_size(unalloc_cells); i++)
427  {
428    cur_elem = range_list_get(unalloc_cells, i);
429    for(j=0; cur_elem->length > REGFI_NK_MIN_LENGTH
430          && j <= cur_elem->length-REGFI_NK_MIN_LENGTH; j+=8)
431    {
432      key = regfi_parse_nk(f, cur_elem->offset+j,
433                           cur_elem->length-j, false);
434      if(key != NULL)
435      {
436        if(!range_list_add(unalloc_keys, key->offset, 
437                           key->cell_size, key))
438        {
439          fprintf(stderr, "ERROR: Couldn't add key to unalloc_keys.\n");
440          return 20;
441        }
442        j+=key->cell_size-8;
443      }
444    }
445  }
446
447  for(i=0; i<range_list_size(unalloc_keys); i++)
448  {
449    cur_elem = range_list_get(unalloc_keys, i);
450    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
451      return 30;
452  }
453
454  return 0;
455}
456
457
458int extractValueLists(REGFI_FILE* f,
459                      range_list* unalloc_cells,
460                      range_list* unalloc_keys)
461{
462  REGFI_NK_REC* nk;
463  REGFI_HBIN* hbin;
464  const range_list_element* cur_elem;
465  uint32 i, j, num_keys, off, values_length, max_length;
466
467  num_keys=range_list_size(unalloc_keys);
468  for(i=0; i<num_keys; i++)
469  {
470    cur_elem = range_list_get(unalloc_keys, i);
471    if(cur_elem == NULL)
472      return 10;
473    nk = cur_elem->data;
474
475    if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE))
476    {
477      hbin = regfi_lookup_hbin(f, nk->values_off);
478     
479      if(hbin != NULL)
480      {
481        off = nk->values_off + REGFI_REGF_SIZE;
482        max_length = hbin->block_size + hbin->file_off - off;
483        /* XXX: This is a hack.  We parse all value-lists, VK records,
484         *      and data records without regard for current allocation status. 
485         *      On the off chance that such a record correctly parsed but is
486         *      actually a reallocated structure used by something else, we
487         *      simply prune it after the fact.  Would be faster to check this
488         *      up front somehow.
489         */
490        nk->values = regfi_load_valuelist(f, off, nk->num_values, max_length,
491                                          false);
492        values_length = (nk->num_values+1)*sizeof(uint32);
493        if(values_length != (values_length & 0xFFFFFFF8))
494          values_length = (values_length & 0xFFFFFFF8) + 8;
495
496        if(nk->values != NULL)
497        {
498          if(!range_list_has_range(unalloc_cells, off, values_length))
499          { /* We've parsed a values-list which isn't in the unallocated list,
500             * so prune it.
501             */
502            for(j=0; j<nk->num_values; j++)
503            {
504              if(nk->values[j] != NULL)
505              {
506                if(nk->values[j]->data != NULL)
507                  free(nk->values[j]->data);
508                free(nk->values[j]);
509              }
510            }
511            free(nk->values);
512            nk->values = NULL;
513          }
514          else
515          { /* Values-list was recovered.  Remove from unalloc_cells and
516             * inspect values.
517             */
518            if(!removeRange(unalloc_cells, off, values_length))
519              return 20;
520
521            for(j=0; j < nk->num_values; j++)
522            {
523              if(nk->values[j] != NULL)
524              {
525                if(!range_list_has_range(unalloc_cells, nk->values[j]->offset, 
526                                         nk->values[j]->cell_size))
527                { /* We've parsed a value which isn't in the unallocated list,
528                   * so prune it.
529                   */
530                  if(nk->values[j]->data != NULL)
531                    free(nk->values[j]->data);
532                  free(nk->values[j]);
533                  nk->values[j] = NULL;
534                }
535                else
536                {
537                  /* A VK record was recovered.  Remove from unalloc_cells
538                   * and inspect data.
539                   */
540                  if(!removeRange(unalloc_cells, nk->values[j]->offset,
541                                  nk->values[j]->cell_size))
542                    return 21;
543
544                  /* Don't bother pruning or removing from unalloc_cells if
545                   * there is no data, or it is stored in the offset.
546                   */
547                  if(nk->values[j]->data != NULL && !nk->values[j]->data_in_offset)
548                  {
549                    off = nk->values[j]->data_off+REGFI_REGF_SIZE;
550                    if(!range_list_has_range(unalloc_cells, off, 
551                                             nk->values[j]->data_size))
552                    { /* We've parsed a data cell which isn't in the unallocated
553                       * list, so prune it.
554                       */
555                      free(nk->values[j]->data);
556                      nk->values[j]->data = NULL;
557                    }
558                    else
559                    { /*A data record was recovered. Remove from unalloc_cells.*/
560                      if(!removeRange(unalloc_cells, off, 
561                                      nk->values[j]->data_size))
562                        return 22;
563                    }
564                  }
565                }
566              }
567            }
568          }
569        }
570      }
571    }
572  }
573
574  return 0;
575}
576
577
578/* NOTE: unalloc_values should be an empty range_list. */
579int extractValues(REGFI_FILE* f,
580                  range_list* unalloc_cells,
581                  range_list* unalloc_values)
582{
583  const range_list_element* cur_elem;
584  REGFI_VK_REC* vk;
585  uint32 i, j, off;
586
587  for(i=0; i < range_list_size(unalloc_cells); i++)
588  {
589    cur_elem = range_list_get(unalloc_cells, i);
590    for(j=0; j <= cur_elem->length; j+=8)
591    {
592      vk = regfi_parse_vk(f, cur_elem->offset+j, 
593                           cur_elem->length-j, false);
594      if(vk != NULL)
595      {
596        if(!range_list_add(unalloc_values, vk->offset,
597                           vk->cell_size, vk))
598        {
599          fprintf(stderr, "ERROR: Couldn't add value to unalloc_values.\n");
600          return 20;
601        }
602        j+=vk->cell_size-8;
603      }
604    }
605  }
606 
607  /* Remove value ranges from the unalloc_cells before we continue. */
608  for(i=0; i<range_list_size(unalloc_values); i++)
609  {
610    cur_elem = range_list_get(unalloc_values, i);
611    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
612      return 30;
613  }
614
615  /* Now see if the data associated with each value is intact */
616  for(i=0; i<range_list_size(unalloc_values); i++)
617  {
618    cur_elem = range_list_get(unalloc_values, i);
619    vk = (REGFI_VK_REC*)cur_elem->data;
620    if(vk == NULL)
621      return 40;
622
623    if(vk->data != NULL && !vk->data_in_offset)
624    {
625      off = vk->data_off+REGFI_REGF_SIZE;
626      if(!range_list_has_range(unalloc_cells, off, vk->data_size))
627      { /* We've parsed a data cell which isn't in the unallocated
628         * list, so prune it.
629         */
630        free(vk->data);
631        vk->data = NULL;
632      }
633      else
634      { /*A data record was recovered. Remove from unalloc_cells.*/
635        if(!removeRange(unalloc_cells, off, vk->data_size))
636          return 50;
637      }
638    }
639  }
640
641  return 0;
642}
643
644
645/* NOTE: unalloc_sks should be an empty range_list. */
646int extractSKs(REGFI_FILE* f, 
647               range_list* unalloc_cells,
648               range_list* unalloc_sks)
649{
650  const range_list_element* cur_elem;
651  REGFI_SK_REC* sk;
652  uint32 i, j;
653
654  for(i=0; i < range_list_size(unalloc_cells); i++)
655  {
656    cur_elem = range_list_get(unalloc_cells, i);
657    for(j=0; j <= cur_elem->length; j+=8)
658    {
659      sk = regfi_parse_sk(f, cur_elem->offset+j, 
660                          cur_elem->length-j, false);
661      if(sk != NULL)
662      {
663        if(!range_list_add(unalloc_sks, sk->offset,
664                           sk->cell_size, sk))
665        {
666          fprintf(stderr, "ERROR: Couldn't add sk to unalloc_sks.\n");
667          return 20;
668        }
669        j+=sk->cell_size-8;
670      }
671    }
672  }
673
674  for(i=0; i<range_list_size(unalloc_sks); i++)
675  {
676    cur_elem = range_list_get(unalloc_sks, i);
677    if(!removeRange(unalloc_cells, cur_elem->offset, cur_elem->length))
678      return 30;
679  }
680
681  return 0;
682}
683
684
685int main(int argc, char** argv)
686{ 
687  REGFI_FILE* f;
688  const range_list_element* cur_elem;
689  range_list* unalloc_cells;
690  range_list* unalloc_keys;
691  range_list* unalloc_values;
692  range_list* unalloc_sks;
693  char** parent_paths;
694  char* tmp_name;
695  char* tmp_path;
696  REGFI_NK_REC* tmp_key;
697  REGFI_VK_REC* tmp_value;
698  uint32 argi, arge, i, j, ret, num_unalloc_keys;
699  /* uint32 test_offset;*/
700 
701  /* Process command line arguments */
702  if(argc < 2)
703  {
704    usage();
705    bailOut(EX_USAGE, "ERROR: Requires at least one argument.\n");
706  }
707 
708  arge = argc-1;
709  for(argi = 1; argi < arge; argi++)
710  {
711    if (strcmp("-v", argv[argi]) == 0)
712      print_verbose = true;
713    else if (strcmp("-h", argv[argi]) == 0)
714      print_header = true;
715    else if (strcmp("-H", argv[argi]) == 0)
716      print_header = false;
717    else if (strcmp("-l", argv[argi]) == 0)
718      print_leftover = true;
719    else if (strcmp("-L", argv[argi]) == 0)
720      print_leftover = false;
721    else if (strcmp("-r", argv[argi]) == 0)
722      print_parsedraw = true;
723    else if (strcmp("-R", argv[argi]) == 0)
724      print_parsedraw = false;
725    else
726    {
727      usage();
728      fprintf(stderr, "ERROR: Unrecognized option: %s\n", argv[argi]);
729      bailOut(EX_USAGE, "");
730    }
731  }
732  /*test_offset = strtol(argv[argi++], NULL, 16);*/
733
734  if((registry_file = strdup(argv[argi])) == NULL)
735    bailOut(EX_OSERR, "ERROR: Memory allocation problem.\n");
736
737  f = regfi_open(registry_file);
738  if(f == NULL)
739  {
740    fprintf(stderr, "ERROR: Couldn't open registry file: %s\n", registry_file);
741    bailOut(EX_NOINPUT, "");
742  }
743
744  if(print_header)
745    printf("OFFSET,REC_LENGTH,REC_TYPE,PATH,NAME,"
746           "NK_MTIME,NK_NVAL,VK_TYPE,VK_VALUE,VK_DATA_LEN,"
747           "SK_OWNER,SK_GROUP,SK_SACL,SK_DACL,RAW_CELL\n");
748
749  unalloc_cells = regfi_parse_unalloc_cells(f);
750  if(unalloc_cells == NULL)
751  {
752    fprintf(stderr, "ERROR: Could not obtain list of unallocated cells.\n");
753    return 1;
754  }
755
756  unalloc_keys = range_list_new();
757  if(unalloc_keys == NULL)
758    return 10;
759
760  unalloc_values = range_list_new();
761  if(unalloc_values == NULL)
762    return 10;
763
764  unalloc_sks = range_list_new();
765  if(unalloc_sks == NULL)
766    return 10;
767
768  ret = extractKeys(f, unalloc_cells, unalloc_keys);
769  if(ret != 0)
770  {
771    fprintf(stderr, "ERROR: extractKeys() failed with %d.\n", ret);
772    return ret;
773  }
774
775  ret = extractValueLists(f, unalloc_cells, unalloc_keys);
776  if(ret != 0)
777  {
778    fprintf(stderr, "ERROR: extractValueLists() failed with %d.\n", ret);
779    return ret;
780  }
781
782  /* Carve any orphan values and associated data */
783  ret = extractValues(f, unalloc_cells, unalloc_values);
784  if(ret != 0)
785  {
786    fprintf(stderr, "ERROR: extractValues() failed with %d.\n", ret);
787    return ret;
788  }
789
790  /* Carve any SK records */
791  ret = extractSKs(f, unalloc_cells, unalloc_sks);
792  if(ret != 0)
793  {
794    fprintf(stderr, "ERROR: extractSKs() failed with %d.\n", ret);
795    return ret;
796  }
797
798  /* Now that we're done carving, associate recovered keys with parents,
799   * if at all possible.
800   */
801  num_unalloc_keys = range_list_size(unalloc_keys);
802  parent_paths = (char**)malloc(sizeof(char*)*num_unalloc_keys);
803  if(parent_paths == NULL)
804    return 10;
805
806  for(i=0; i < num_unalloc_keys; i++)
807  {
808    cur_elem = range_list_get(unalloc_keys, i);
809    tmp_key = (REGFI_NK_REC*)cur_elem->data;
810
811    if(tmp_key == NULL)
812      return 20;
813   
814    parent_paths[i] = getParentPath(f, tmp_key);
815    if(parent_paths[i] == NULL)
816      return 20;
817  }
818 
819  /* Now start the output */
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    printKey(f, tmp_key, parent_paths[i]);
827    if(tmp_key->num_values > 0 && tmp_key->values != NULL)
828    {
829      tmp_name = quote_string(tmp_key->keyname, key_special_chars);
830      tmp_path = (char*)malloc(strlen(parent_paths[i])+strlen(tmp_name)+2);
831      if(tmp_path == NULL)
832      {
833        free(tmp_name);
834        return 10;
835      }
836
837      sprintf(tmp_path, "%s/%s", parent_paths[i], tmp_name);
838      for(j=0; j < tmp_key->num_values; j++)
839      {
840        tmp_value = tmp_key->values[j];
841        if(tmp_value != NULL)
842          printValue(f, tmp_value, tmp_path);
843      }
844      free(tmp_path);
845      free(tmp_name);
846      free(parent_paths[i]);
847    }
848  }
849  free(parent_paths);
850
851  /* Print out orphaned values */
852  for(i=0; i < range_list_size(unalloc_values); i++)
853  {
854    cur_elem = range_list_get(unalloc_values, i);
855    tmp_value = (REGFI_VK_REC*)cur_elem->data; 
856
857    printValue(f, tmp_value, "");
858  }
859 
860  if(print_leftover)
861  {
862    for(i=0; i < range_list_size(unalloc_cells); i++)
863    {
864      cur_elem = range_list_get(unalloc_cells, i);
865      printCell(f, cur_elem->offset);
866    }
867  }
868
869  return 0;
870}
Note: See TracBrowser for help on using the repository browser.