source: trunk/lib/regfi.c @ 168

Last change on this file since 168 was 168, checked in by tim, 14 years ago

merged remaining smb_deps items into regfi

began formatting API comments for use with doxygen

  • Property svn:keywords set to Id
File size: 89.3 KB
Line 
1/*
2 * Branched from Samba project Subversion repository, version #7470:
3 *   http://viewcvs.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c?rev=7470&view=auto
4 *
5 * Windows NT (and later) registry parsing library
6 *
7 * Copyright (C) 2005-2009 Timothy D. Morgan
8 * Copyright (C) 2005 Gerald (Jerry) Carter
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 3 of the License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * $Id: regfi.c 168 2010-03-03 00:08:42Z tim $
24 */
25
26/** @file */
27
28#include "regfi.h"
29
30
31/* Registry types mapping */
32const unsigned int regfi_num_reg_types = 12;
33static const char* regfi_type_names[] =
34  {"NONE", "SZ", "EXPAND_SZ", "BINARY", "DWORD", "DWORD_BE", "LINK",
35   "MULTI_SZ", "RSRC_LIST", "RSRC_DESC", "RSRC_REQ_LIST", "QWORD"};
36
37const char* regfi_encoding_names[] =
38  {"US-ASCII//TRANSLIT", "UTF-8//TRANSLIT", "UTF-16LE//TRANSLIT"};
39
40
41/******************************************************************************
42 ******************************************************************************/
43void regfi_add_message(REGFI_FILE* file, uint16_t msg_type, const char* fmt, ...)
44{
45  /* XXX: This function is not particularly efficient,
46   *      but then it is mostly used during errors.
47   */
48  uint32_t buf_size, buf_used;
49  char* new_msg;
50  va_list args;
51
52  if((file->msg_mask & msg_type) != 0)
53  {
54    if(file->last_message == NULL)
55      buf_used = 0;
56    else
57      buf_used = strlen(file->last_message);
58   
59    buf_size = buf_used+strlen(fmt)+160;
60    new_msg = realloc(file->last_message, buf_size);
61    if(new_msg == NULL)
62      /* XXX: should we report this? */
63      return;
64
65    switch (msg_type)
66    {
67    case REGFI_MSG_INFO:
68      strcpy(new_msg+buf_used, "INFO: ");
69      buf_used += 6;
70      break;
71    case REGFI_MSG_WARN:
72      strcpy(new_msg+buf_used, "WARN: ");
73      buf_used += 6;
74      break;
75    case REGFI_MSG_ERROR:
76      strcpy(new_msg+buf_used, "ERROR: ");
77      buf_used += 7;
78      break;
79    }
80
81    va_start(args, fmt);
82    vsnprintf(new_msg+buf_used, buf_size-buf_used, fmt, args);
83    va_end(args);
84    strncat(new_msg, "\n", buf_size-1);
85   
86    file->last_message = new_msg;
87  }
88}
89
90
91/******************************************************************************
92 ******************************************************************************/
93char* regfi_get_messages(REGFI_FILE* file)
94{
95  char* ret_val = file->last_message;
96  file->last_message = NULL;
97
98  return ret_val;
99}
100
101
102void regfi_set_message_mask(REGFI_FILE* file, uint16_t mask)
103{
104  file->msg_mask = mask;
105}
106
107
108/******************************************************************************
109 * Returns NULL for an invalid e
110 *****************************************************************************/
111static const char* regfi_encoding_int2str(REGFI_ENCODING e)
112{
113  if(e < REGFI_NUM_ENCODINGS)
114    return regfi_encoding_names[e];
115
116  return NULL;
117}
118
119
120/******************************************************************************
121 * Returns NULL for an invalid val
122 *****************************************************************************/
123const char* regfi_type_val2str(unsigned int val)
124{
125  if(val == REG_KEY)
126    return "KEY";
127 
128  if(val >= regfi_num_reg_types)
129    return NULL;
130 
131  return regfi_type_names[val];
132}
133
134
135/******************************************************************************
136 * Returns -1 on error
137 *****************************************************************************/
138int regfi_type_str2val(const char* str)
139{
140  int i;
141
142  if(strcmp("KEY", str) == 0)
143    return REG_KEY;
144
145  for(i=0; i < regfi_num_reg_types; i++)
146    if (strcmp(regfi_type_names[i], str) == 0) 
147      return i;
148
149  if(strcmp("DWORD_LE", str) == 0)
150    return REG_DWORD_LE;
151
152  return -1;
153}
154
155
156/* Security descriptor formatting functions  */
157
158const char* regfi_ace_type2str(uint8_t type)
159{
160  static const char* map[7] 
161    = {"ALLOW", "DENY", "AUDIT", "ALARM", 
162       "ALLOW CPD", "OBJ ALLOW", "OBJ DENY"};
163  if(type < 7)
164    return map[type];
165  else
166    /* XXX: would be nice to return the unknown integer value. 
167     *      However, as it is a const string, it can't be free()ed later on,
168     *      so that would need to change.
169     */
170    return "UNKNOWN";
171}
172
173
174/* XXX: need a better reference on the meaning of each flag. */
175/* For more info, see:
176 *   http://msdn2.microsoft.com/en-us/library/aa772242.aspx
177 */
178char* regfi_ace_flags2str(uint8_t flags)
179{
180  static const char* flag_map[32] = 
181    { "OI", /* Object Inherit */
182      "CI", /* Container Inherit */
183      "NP", /* Non-Propagate */
184      "IO", /* Inherit Only */
185      "IA", /* Inherited ACE */
186      NULL,
187      NULL,
188      NULL,
189    };
190
191  char* ret_val = malloc(35*sizeof(char));
192  char* fo = ret_val;
193  uint32_t i;
194  uint8_t f;
195
196  if(ret_val == NULL)
197    return NULL;
198
199  fo[0] = '\0';
200  if (!flags)
201    return ret_val;
202
203  for(i=0; i < 8; i++)
204  {
205    f = (1<<i);
206    if((flags & f) && (flag_map[i] != NULL))
207    {
208      strcpy(fo, flag_map[i]);
209      fo += strlen(flag_map[i]);
210      *(fo++) = ' ';
211      flags ^= f;
212    }
213  }
214 
215  /* Any remaining unknown flags are added at the end in hex. */
216  if(flags != 0)
217    sprintf(fo, "0x%.2X ", flags);
218
219  /* Chop off the last space if we've written anything to ret_val */
220  if(fo != ret_val)
221    fo[-1] = '\0';
222
223  return ret_val;
224}
225
226
227char* regfi_ace_perms2str(uint32_t perms)
228{
229  uint32_t i, p;
230  /* This is more than is needed by a fair margin. */
231  char* ret_val = malloc(350*sizeof(char));
232  char* r = ret_val;
233
234  /* Each represents one of 32 permissions bits.  NULL is for undefined/reserved bits.
235   * For more information, see:
236   *   http://msdn2.microsoft.com/en-gb/library/aa374892.aspx
237   *   http://msdn2.microsoft.com/en-gb/library/ms724878.aspx
238   */
239  static const char* perm_map[32] = 
240    {/* object-specific permissions (registry keys, in this case) */
241      "QRY_VAL",       /* KEY_QUERY_VALUE */
242      "SET_VAL",       /* KEY_SET_VALUE */
243      "CREATE_KEY",    /* KEY_CREATE_SUB_KEY */
244      "ENUM_KEYS",     /* KEY_ENUMERATE_SUB_KEYS */
245      "NOTIFY",        /* KEY_NOTIFY */
246      "CREATE_LNK",    /* KEY_CREATE_LINK - Reserved for system use. */
247      NULL,
248      NULL,
249      "WOW64_64",      /* KEY_WOW64_64KEY */
250      "WOW64_32",      /* KEY_WOW64_32KEY */
251      NULL,
252      NULL,
253      NULL,
254      NULL,
255      NULL,
256      NULL,
257      /* standard access rights */
258      "DELETE",        /* DELETE */
259      "R_CONT",        /* READ_CONTROL */
260      "W_DAC",         /* WRITE_DAC */
261      "W_OWNER",       /* WRITE_OWNER */
262      "SYNC",          /* SYNCHRONIZE - Shouldn't be set in registries */
263      NULL,
264      NULL,
265      NULL,
266      /* other generic */
267      "SYS_SEC",       /* ACCESS_SYSTEM_SECURITY */
268      "MAX_ALLWD",     /* MAXIMUM_ALLOWED */
269      NULL,
270      NULL,
271      "GEN_A",         /* GENERIC_ALL */
272      "GEN_X",         /* GENERIC_EXECUTE */
273      "GEN_W",         /* GENERIC_WRITE */
274      "GEN_R",         /* GENERIC_READ */
275    };
276
277
278  if(ret_val == NULL)
279    return NULL;
280
281  r[0] = '\0';
282  for(i=0; i < 32; i++)
283  {
284    p = (1<<i);
285    if((perms & p) && (perm_map[i] != NULL))
286    {
287      strcpy(r, perm_map[i]);
288      r += strlen(perm_map[i]);
289      *(r++) = ' ';
290      perms ^= p;
291    }
292  }
293 
294  /* Any remaining unknown permission bits are added at the end in hex. */
295  if(perms != 0)
296    sprintf(r, "0x%.8X ", perms);
297
298  /* Chop off the last space if we've written anything to ret_val */
299  if(r != ret_val)
300    r[-1] = '\0';
301
302  return ret_val;
303}
304
305
306char* regfi_sid2str(WINSEC_DOM_SID* sid)
307{
308  uint32_t i, size = WINSEC_MAX_SUBAUTHS*11 + 24;
309  uint32_t left = size;
310  uint8_t comps = sid->num_auths;
311  char* ret_val = malloc(size);
312 
313  if(ret_val == NULL)
314    return NULL;
315
316  if(comps > WINSEC_MAX_SUBAUTHS)
317    comps = WINSEC_MAX_SUBAUTHS;
318
319  left -= sprintf(ret_val, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
320
321  for (i = 0; i < comps; i++) 
322    left -= snprintf(ret_val+(size-left), left, "-%u", sid->sub_auths[i]);
323
324  return ret_val;
325}
326
327
328char* regfi_get_acl(WINSEC_ACL* acl)
329{
330  uint32_t i, extra, size = 0;
331  const char* type_str;
332  char* flags_str;
333  char* perms_str;
334  char* sid_str;
335  char* ace_delim = "";
336  char* ret_val = NULL;
337  char* tmp_val = NULL;
338  bool failed = false;
339  char field_delim = ':';
340
341  for (i = 0; i < acl->num_aces && !failed; i++)
342  {
343    sid_str = regfi_sid2str(acl->aces[i]->trustee);
344    type_str = regfi_ace_type2str(acl->aces[i]->type);
345    perms_str = regfi_ace_perms2str(acl->aces[i]->access_mask);
346    flags_str = regfi_ace_flags2str(acl->aces[i]->flags);
347   
348    if(flags_str != NULL && perms_str != NULL 
349       && type_str != NULL && sid_str != NULL)
350    {
351      /* XXX: this is slow */
352      extra = strlen(sid_str) + strlen(type_str) 
353        + strlen(perms_str) + strlen(flags_str) + 5;
354      tmp_val = realloc(ret_val, size+extra);
355
356      if(tmp_val == NULL)
357      {
358        free(ret_val);
359        ret_val = NULL;
360        failed = true;
361      }
362      else
363      {
364        ret_val = tmp_val;
365        size += sprintf(ret_val+size, "%s%s%c%s%c%s%c%s",
366                        ace_delim,sid_str,
367                        field_delim,type_str,
368                        field_delim,perms_str,
369                        field_delim,flags_str);
370        ace_delim = "|";
371      }
372    }
373    else
374      failed = true;
375
376    if(sid_str != NULL)
377      free(sid_str);
378    if(sid_str != NULL)
379      free(perms_str);
380    if(sid_str != NULL)
381      free(flags_str);
382  }
383
384  return ret_val;
385}
386
387
388char* regfi_get_sacl(WINSEC_DESC *sec_desc)
389{
390  if (sec_desc->sacl)
391    return regfi_get_acl(sec_desc->sacl);
392  else
393    return NULL;
394}
395
396
397char* regfi_get_dacl(WINSEC_DESC *sec_desc)
398{
399  if (sec_desc->dacl)
400    return regfi_get_acl(sec_desc->dacl);
401  else
402    return NULL;
403}
404
405
406char* regfi_get_owner(WINSEC_DESC *sec_desc)
407{
408  return regfi_sid2str(sec_desc->owner_sid);
409}
410
411
412char* regfi_get_group(WINSEC_DESC *sec_desc)
413{
414  return regfi_sid2str(sec_desc->grp_sid);
415}
416
417
418/*****************************************************************************
419 * This function is just like read(2), except that it continues to
420 * re-try reading from the file descriptor if EINTR or EAGAIN is received. 
421 * regfi_read will attempt to read length bytes from fd and write them to buf.
422 *
423 * On success, 0 is returned.  Upon failure, an errno code is returned.
424 *
425 * The number of bytes successfully read is returned through the length
426 * parameter by reference.  If both the return value and length parameter are
427 * returned as 0, then EOF was encountered immediately
428 *****************************************************************************/
429uint32_t regfi_read(int fd, uint8_t* buf, uint32_t* length)
430{
431  uint32_t rsize = 0;
432  uint32_t rret = 0;
433
434  do
435  {
436    rret = read(fd, buf + rsize, *length - rsize);
437    if(rret > 0)
438      rsize += rret;
439  }while(*length - rsize > 0 
440         && (rret > 0 || (rret == -1 && (errno == EAGAIN || errno == EINTR))));
441 
442  *length = rsize;
443  if (rret == -1 && errno != EINTR && errno != EAGAIN)
444    return errno;
445
446  return 0;
447}
448
449
450/*****************************************************************************
451 *
452 *****************************************************************************/
453bool regfi_parse_cell(int fd, uint32_t offset, uint8_t* hdr, uint32_t hdr_len,
454                      uint32_t* cell_length, bool* unalloc)
455{
456  uint32_t length;
457  int32_t raw_length;
458  uint8_t tmp[4];
459
460  if(lseek(fd, offset, SEEK_SET) == -1)
461    return false;
462
463  length = 4;
464  if((regfi_read(fd, tmp, &length) != 0) || length != 4)
465    return false;
466  raw_length = IVALS(tmp, 0);
467
468  if(raw_length < 0)
469  {
470    (*cell_length) = raw_length*(-1);
471    (*unalloc) = false;
472  }
473  else
474  {
475    (*cell_length) = raw_length;
476    (*unalloc) = true;
477  }
478
479  if(*cell_length - 4 < hdr_len)
480    return false;
481
482  if(hdr_len > 0)
483  {
484    length = hdr_len;
485    if((regfi_read(fd, hdr, &length) != 0) || length != hdr_len)
486      return false;
487  }
488
489  return true;
490}
491
492
493/******************************************************************************
494 * Given an offset and an hbin, is the offset within that hbin?
495 * The offset is a virtual file offset.
496 ******************************************************************************/
497static bool regfi_offset_in_hbin(const REGFI_HBIN* hbin, uint32_t voffset)
498{
499  if(!hbin)
500    return false;
501
502  if((voffset > hbin->first_hbin_off) 
503     && (voffset < (hbin->first_hbin_off + hbin->block_size)))
504    return true;
505               
506  return false;
507}
508
509
510
511/******************************************************************************
512 * Provide a physical offset and receive the correpsonding HBIN
513 * block for it.  NULL if one doesn't exist.
514 ******************************************************************************/
515const REGFI_HBIN* regfi_lookup_hbin(REGFI_FILE* file, uint32_t offset)
516{
517  return (const REGFI_HBIN*)range_list_find_data(file->hbins, offset);
518}
519
520
521/******************************************************************************
522 * Calculate the largest possible cell size given a physical offset.
523 * Largest size is based on the HBIN the offset is currently a member of.
524 * Returns negative values on error.
525 * (Since cells can only be ~2^31 in size, this works out.)
526 ******************************************************************************/
527int32_t regfi_calc_maxsize(REGFI_FILE* file, uint32_t offset)
528{
529  const REGFI_HBIN* hbin = regfi_lookup_hbin(file, offset);
530  if(hbin == NULL)
531    return -1;
532
533  return (hbin->block_size + hbin->file_off) - offset;
534}
535
536
537/******************************************************************************
538 ******************************************************************************/
539REGFI_SUBKEY_LIST* regfi_load_subkeylist(REGFI_FILE* file, uint32_t offset, 
540                                         uint32_t num_keys, uint32_t max_size, 
541                                         bool strict)
542{
543  REGFI_SUBKEY_LIST* ret_val;
544
545  ret_val = regfi_load_subkeylist_aux(file, offset, max_size, strict, 
546                                      REGFI_MAX_SUBKEY_DEPTH);
547  if(ret_val == NULL)
548  {
549    regfi_add_message(file, REGFI_MSG_WARN, "Failed to load subkey list at"
550                      " offset 0x%.8X.", offset);
551    return NULL;
552  }
553
554  if(num_keys != ret_val->num_keys)
555  {
556    /*  Not sure which should be authoritative, the number from the
557     *  NK record, or the number in the subkey list.  Just emit a warning for
558     *  now if they don't match.
559     */
560    regfi_add_message(file, REGFI_MSG_WARN, "Number of subkeys listed in parent"
561                      " (%d) did not match number found in subkey list/tree (%d)"
562                      " while parsing subkey list/tree at offset 0x%.8X.", 
563                      num_keys, ret_val->num_keys, offset);
564  }
565
566  return ret_val;
567}
568
569
570/******************************************************************************
571 ******************************************************************************/
572REGFI_SUBKEY_LIST* regfi_load_subkeylist_aux(REGFI_FILE* file, uint32_t offset, 
573                                             uint32_t max_size, bool strict,
574                                             uint8_t depth_left)
575{
576  REGFI_SUBKEY_LIST* ret_val;
577  REGFI_SUBKEY_LIST** sublists;
578  uint32_t i, num_sublists, off;
579  int32_t sublist_maxsize;
580
581  if(depth_left == 0)
582  {
583    regfi_add_message(file, REGFI_MSG_WARN, "Maximum depth reached"
584                      " while parsing subkey list/tree at offset 0x%.8X.", 
585                      offset);
586    return NULL;
587  }
588
589  ret_val = regfi_parse_subkeylist(file, offset, max_size, strict);
590  if(ret_val == NULL)
591    return NULL;
592
593  if(ret_val->recursive_type)
594  {
595    num_sublists = ret_val->num_children;
596    sublists = (REGFI_SUBKEY_LIST**)malloc(num_sublists
597                                           * sizeof(REGFI_SUBKEY_LIST*));
598    for(i=0; i < num_sublists; i++)
599    {
600      off = ret_val->elements[i].offset + REGFI_REGF_SIZE;
601
602      sublist_maxsize = regfi_calc_maxsize(file, off);
603      if(sublist_maxsize < 0)
604        sublists[i] = NULL;
605      else
606        sublists[i] = regfi_load_subkeylist_aux(file, off, sublist_maxsize, 
607                                                strict, depth_left-1);
608    }
609    talloc_free(ret_val);
610
611    return regfi_merge_subkeylists(num_sublists, sublists, strict);
612  }
613
614  return ret_val;
615}
616
617
618/******************************************************************************
619 ******************************************************************************/
620REGFI_SUBKEY_LIST* regfi_parse_subkeylist(REGFI_FILE* file, uint32_t offset, 
621                                          uint32_t max_size, bool strict)
622{
623  REGFI_SUBKEY_LIST* ret_val;
624  uint32_t i, cell_length, length, elem_size, read_len;
625  uint8_t* elements = NULL;
626  uint8_t buf[REGFI_SUBKEY_LIST_MIN_LEN];
627  bool unalloc;
628  bool recursive_type;
629
630  if(!regfi_parse_cell(file->fd, offset, buf, REGFI_SUBKEY_LIST_MIN_LEN, 
631                       &cell_length, &unalloc))
632  {
633    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while "
634                      "parsing subkey-list at offset 0x%.8X.", offset);
635    return NULL;
636  }
637
638  if(cell_length > max_size)
639  {
640    regfi_add_message(file, REGFI_MSG_WARN, "Cell size longer than max_size"
641                      " while parsing subkey-list at offset 0x%.8X.", offset);
642    if(strict)
643      return NULL;
644    cell_length = max_size & 0xFFFFFFF8;
645  }
646
647  recursive_type = false;
648  if(buf[0] == 'r' && buf[1] == 'i')
649  {
650    recursive_type = true;
651    elem_size = sizeof(uint32_t);
652  }
653  else if(buf[0] == 'l' && buf[1] == 'i')
654    elem_size = sizeof(uint32_t);
655  else if((buf[0] == 'l') && (buf[1] == 'f' || buf[1] == 'h'))
656    elem_size = sizeof(REGFI_SUBKEY_LIST_ELEM);
657  else
658  {
659    regfi_add_message(file, REGFI_MSG_ERROR, "Unknown magic number"
660                      " (0x%.2X, 0x%.2X) encountered while parsing"
661                      " subkey-list at offset 0x%.8X.", buf[0], buf[1], offset);
662    return NULL;
663  }
664
665  ret_val = talloc(NULL, REGFI_SUBKEY_LIST);
666  if(ret_val == NULL)
667    return NULL;
668
669  ret_val->offset = offset;
670  ret_val->cell_size = cell_length;
671  ret_val->magic[0] = buf[0];
672  ret_val->magic[1] = buf[1];
673  ret_val->recursive_type = recursive_type;
674  ret_val->num_children = SVAL(buf, 0x2);
675
676  if(!recursive_type)
677    ret_val->num_keys = ret_val->num_children;
678
679  length = elem_size*ret_val->num_children;
680  if(cell_length - REGFI_SUBKEY_LIST_MIN_LEN - sizeof(uint32_t) < length)
681  {
682    regfi_add_message(file, REGFI_MSG_WARN, "Number of elements too large for"
683                      " cell while parsing subkey-list at offset 0x%.8X.", 
684                      offset);
685    if(strict)
686      goto fail;
687    length = cell_length - REGFI_SUBKEY_LIST_MIN_LEN - sizeof(uint32_t);
688  }
689
690  ret_val->elements = talloc_array(ret_val, REGFI_SUBKEY_LIST_ELEM, 
691                                   ret_val->num_children);
692  if(ret_val->elements == NULL)
693    goto fail;
694
695  elements = (uint8_t*)malloc(length);
696  if(elements == NULL)
697    goto fail;
698
699  read_len = length;
700  if(regfi_read(file->fd, elements, &read_len) != 0 || read_len != length)
701    goto fail;
702
703  if(elem_size == sizeof(uint32_t))
704  {
705    for (i=0; i < ret_val->num_children; i++)
706    {
707      ret_val->elements[i].offset = IVAL(elements, i*elem_size);
708      ret_val->elements[i].hash = 0;
709    }
710  }
711  else
712  {
713    for (i=0; i < ret_val->num_children; i++)
714    {
715      ret_val->elements[i].offset = IVAL(elements, i*elem_size);
716      ret_val->elements[i].hash = IVAL(elements, i*elem_size+4);
717    }
718  }
719  free(elements);
720
721  return ret_val;
722
723 fail:
724  if(elements != NULL)
725    free(elements);
726  talloc_free(ret_val);
727  return NULL;
728}
729
730
731/*******************************************************************
732 *******************************************************************/
733REGFI_SUBKEY_LIST* regfi_merge_subkeylists(uint16_t num_lists, 
734                                           REGFI_SUBKEY_LIST** lists,
735                                           bool strict)
736{
737  uint32_t i,j,k;
738  REGFI_SUBKEY_LIST* ret_val;
739
740  if(lists == NULL)
741    return NULL;
742  ret_val = talloc(NULL, REGFI_SUBKEY_LIST);
743
744  if(ret_val == NULL)
745    return NULL;
746 
747  /* Obtain total number of elements */
748  ret_val->num_keys = 0;
749  for(i=0; i < num_lists; i++)
750  {
751    if(lists[i] != NULL)
752      ret_val->num_keys += lists[i]->num_children;
753  }
754  ret_val->num_children = ret_val->num_keys;
755
756  if(ret_val->num_keys > 0)
757  {
758    ret_val->elements = talloc_array(ret_val, REGFI_SUBKEY_LIST_ELEM,
759                                     ret_val->num_keys);
760    k=0;
761
762    if(ret_val->elements != NULL)
763    {
764      for(i=0; i < num_lists; i++)
765      {
766        if(lists[i] != NULL)
767        {
768          for(j=0; j < lists[i]->num_keys; j++)
769          {
770            ret_val->elements[k].hash = lists[i]->elements[j].hash;
771            ret_val->elements[k++].offset = lists[i]->elements[j].offset;
772          }
773        }
774      }
775    }
776  }
777 
778  for(i=0; i < num_lists; i++)
779    regfi_subkeylist_free(lists[i]);
780  free(lists);
781
782  return ret_val;
783}
784
785
786/******************************************************************************
787 *
788 ******************************************************************************/
789REGFI_SK_REC* regfi_parse_sk(REGFI_FILE* file, uint32_t offset, uint32_t max_size, 
790                             bool strict)
791{
792  REGFI_SK_REC* ret_val;
793  uint8_t* sec_desc_buf = NULL;
794  uint32_t cell_length, length;
795  uint8_t sk_header[REGFI_SK_MIN_LENGTH];
796  bool unalloc = false;
797
798  if(!regfi_parse_cell(file->fd, offset, sk_header, REGFI_SK_MIN_LENGTH,
799                       &cell_length, &unalloc))
800  {
801    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse SK record cell"
802                      " at offset 0x%.8X.", offset);
803    return NULL;
804  }
805   
806  if(sk_header[0] != 's' || sk_header[1] != 'k')
807  {
808    regfi_add_message(file, REGFI_MSG_WARN, "Magic number mismatch in parsing"
809                      " SK record at offset 0x%.8X.", offset);
810    return NULL;
811  }
812
813  ret_val = talloc(NULL, REGFI_SK_REC);
814  if(ret_val == NULL)
815    return NULL;
816
817  ret_val->offset = offset;
818  /* XXX: Is there a way to be more conservative (shorter) with
819   *      cell length when cell is unallocated?
820   */
821  ret_val->cell_size = cell_length;
822
823  if(ret_val->cell_size > max_size)
824    ret_val->cell_size = max_size & 0xFFFFFFF8;
825  if((ret_val->cell_size < REGFI_SK_MIN_LENGTH) 
826     || (strict && (ret_val->cell_size & 0x00000007) != 0))
827  {
828    regfi_add_message(file, REGFI_MSG_WARN, "Invalid cell size found while"
829                      " parsing SK record at offset 0x%.8X.", offset);
830    goto fail;
831  }
832
833  ret_val->magic[0] = sk_header[0];
834  ret_val->magic[1] = sk_header[1];
835
836  ret_val->unknown_tag = SVAL(sk_header, 0x2);
837  ret_val->prev_sk_off = IVAL(sk_header, 0x4);
838  ret_val->next_sk_off = IVAL(sk_header, 0x8);
839  ret_val->ref_count = IVAL(sk_header, 0xC);
840  ret_val->desc_size = IVAL(sk_header, 0x10);
841
842  if((ret_val->prev_sk_off & 0x00000007) != 0
843     || (ret_val->next_sk_off & 0x00000007) != 0)
844  {
845    regfi_add_message(file, REGFI_MSG_WARN, "SK record's next/previous offsets"
846                      " are not a multiple of 8 while parsing SK record at"
847                      " offset 0x%.8X.", offset);
848    goto fail;
849  }
850
851  if(ret_val->desc_size + REGFI_SK_MIN_LENGTH > ret_val->cell_size)
852  {
853    regfi_add_message(file, REGFI_MSG_WARN, "Security descriptor too large for"
854                      " cell while parsing SK record at offset 0x%.8X.", 
855                      offset);
856    goto fail;
857  }
858
859  sec_desc_buf = (uint8_t*)malloc(ret_val->desc_size);
860  if(sec_desc_buf == NULL)
861    goto fail;
862
863  length = ret_val->desc_size;
864  if(regfi_read(file->fd, sec_desc_buf, &length) != 0 
865     || length != ret_val->desc_size)
866  {
867    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read security"
868                      " descriptor while parsing SK record at offset 0x%.8X.",
869                      offset);
870    goto fail;
871  }
872
873  if(!(ret_val->sec_desc = winsec_parse_desc(ret_val, sec_desc_buf, 
874                                                   ret_val->desc_size)))
875  {
876    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to parse security"
877                      " descriptor while parsing SK record at offset 0x%.8X.",
878                      offset);
879    goto fail;
880  }
881
882  free(sec_desc_buf);
883  return ret_val;
884
885 fail:
886  if(sec_desc_buf != NULL)
887    free(sec_desc_buf);
888  talloc_free(ret_val);
889  return NULL;
890}
891
892
893REGFI_VALUE_LIST* regfi_parse_valuelist(REGFI_FILE* file, uint32_t offset, 
894                                        uint32_t num_values, bool strict)
895{
896  REGFI_VALUE_LIST* ret_val;
897  uint32_t i, cell_length, length, read_len;
898  bool unalloc;
899
900  if(!regfi_parse_cell(file->fd, offset, NULL, 0, &cell_length, &unalloc))
901  {
902    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read cell header"
903                      " while parsing value list at offset 0x%.8X.", offset);
904    return NULL;
905  }
906
907  if((cell_length & 0x00000007) != 0)
908  {
909    regfi_add_message(file, REGFI_MSG_WARN, "Cell length not a multiple of 8"
910                      " while parsing value list at offset 0x%.8X.", offset);
911    if(strict)
912      return NULL;
913    cell_length = cell_length & 0xFFFFFFF8;
914  }
915
916  if((num_values * sizeof(uint32_t)) > cell_length-sizeof(uint32_t))
917  {
918    regfi_add_message(file, REGFI_MSG_WARN, "Too many values found"
919                      " while parsing value list at offset 0x%.8X.", offset);
920    if(strict)
921      return NULL;
922    num_values = cell_length/sizeof(uint32_t) - sizeof(uint32_t);
923  }
924
925  read_len = num_values*sizeof(uint32_t);
926  ret_val = talloc(NULL, REGFI_VALUE_LIST);
927  if(ret_val == NULL)
928    return NULL;
929
930  ret_val->elements = (REGFI_VALUE_LIST_ELEM*)talloc_size(ret_val, read_len);
931  if(ret_val->elements == NULL)
932  {
933    talloc_free(ret_val);
934    return NULL;
935  }
936  ret_val->num_values = num_values;
937
938  length = read_len;
939  if((regfi_read(file->fd, (uint8_t*)ret_val->elements, &length) != 0) 
940     || length != read_len)
941  {
942    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read value pointers"
943                      " while parsing value list at offset 0x%.8X.", offset);
944    talloc_free(ret_val);
945    return NULL;
946  }
947 
948  for(i=0; i < num_values; i++)
949  {
950    /* Fix endianness */
951    ret_val->elements[i] = IVAL(&ret_val->elements[i], 0);
952
953    /* Validate the first num_values values to ensure they make sense */
954    if(strict)
955    {
956      /* XXX: Need to revisit this file length check when we start dealing
957       *      with partial files. */
958      if((ret_val->elements[i] + REGFI_REGF_SIZE > file->file_length)
959         || ((ret_val->elements[i] & 0x00000007) != 0))
960      {
961        regfi_add_message(file, REGFI_MSG_WARN, "Invalid value pointer"
962                          " (0x%.8X) found while parsing value list at offset"
963                          " 0x%.8X.", ret_val->elements[i], offset);
964        talloc_free(ret_val);
965        return NULL;
966      }
967    }
968  }
969
970  return ret_val;
971}
972
973
974
975/******************************************************************************
976 ******************************************************************************/
977REGFI_VK_REC* regfi_load_value(REGFI_FILE* file, uint32_t offset, 
978                               REGFI_ENCODING output_encoding, bool strict)
979{
980  REGFI_VK_REC* ret_val = NULL;
981  int32_t max_size, tmp_size;
982  REGFI_ENCODING from_encoding;
983
984  max_size = regfi_calc_maxsize(file, offset);
985  if(max_size < 0)
986    return NULL;
987 
988  ret_val = regfi_parse_vk(file, offset, max_size, strict);
989  if(ret_val == NULL)
990    return NULL;
991
992  /* XXX: Registry value names are supposedly limited to 16383 characters
993   *      according to:
994   *      http://msdn.microsoft.com/en-us/library/ms724872%28VS.85%29.aspx
995   *      Might want to emit a warning if this is exceeded. 
996   *      It is expected that "characters" could be variable width.
997   *      Also, it may be useful to use this information to limit false positives
998   *      when recovering deleted VK records.
999   */
1000
1001  from_encoding = (ret_val->flags & REGFI_VK_FLAG_ASCIINAME)
1002    ? REGFI_ENCODING_ASCII : REGFI_ENCODING_UTF16LE;
1003
1004  if(from_encoding == output_encoding)
1005  {
1006    ret_val->valuename_raw = talloc_realloc(ret_val, ret_val->valuename_raw,
1007                                            uint8_t, ret_val->name_length+1);
1008    ret_val->valuename_raw[ret_val->name_length] = '\0';
1009    ret_val->valuename = (char*)ret_val->valuename_raw;
1010  }
1011  else
1012  {
1013    ret_val->valuename = talloc_array(ret_val, char, ret_val->name_length+1);
1014    if(ret_val->valuename == NULL)
1015    {
1016      regfi_free_value(ret_val);
1017      return NULL;
1018    }
1019
1020    tmp_size = regfi_conv_charset(regfi_encoding_int2str(from_encoding),
1021                                  regfi_encoding_int2str(output_encoding),
1022                                  ret_val->valuename_raw, ret_val->valuename,
1023                                  ret_val->name_length, ret_val->name_length+1);
1024    if(tmp_size < 0)
1025    {
1026      regfi_add_message(file, REGFI_MSG_WARN, "Error occurred while converting"
1027                        " valuename to encoding %s.  Error message: %s",
1028                        regfi_encoding_int2str(output_encoding), 
1029                        strerror(-tmp_size));
1030      talloc_free(ret_val->valuename);
1031      ret_val->valuename = NULL;
1032    }
1033  }
1034
1035  return ret_val;
1036}
1037
1038
1039/******************************************************************************
1040 * If !strict, the list may contain NULLs, VK records may point to NULL.
1041 ******************************************************************************/
1042REGFI_VALUE_LIST* regfi_load_valuelist(REGFI_FILE* file, uint32_t offset, 
1043                                       uint32_t num_values, uint32_t max_size,
1044                                       bool strict)
1045{
1046  uint32_t usable_num_values;
1047
1048  if((num_values+1) * sizeof(uint32_t) > max_size)
1049  {
1050    regfi_add_message(file, REGFI_MSG_WARN, "Number of values indicated by"
1051                      " parent key (%d) would cause cell to straddle HBIN"
1052                      " boundary while loading value list at offset"
1053                      " 0x%.8X.", num_values, offset);
1054    if(strict)
1055      return NULL;
1056    usable_num_values = max_size/sizeof(uint32_t) - sizeof(uint32_t);
1057  }
1058  else
1059    usable_num_values = num_values;
1060
1061  return regfi_parse_valuelist(file, offset, usable_num_values, strict);
1062}
1063
1064
1065
1066/******************************************************************************
1067 *
1068 ******************************************************************************/
1069REGFI_NK_REC* regfi_load_key(REGFI_FILE* file, uint32_t offset, 
1070                             REGFI_ENCODING output_encoding, bool strict)
1071{
1072  REGFI_NK_REC* nk;
1073  uint32_t off;
1074  int32_t max_size, tmp_size;
1075  REGFI_ENCODING from_encoding;
1076
1077  max_size = regfi_calc_maxsize(file, offset);
1078  if (max_size < 0) 
1079    return NULL;
1080
1081  /* get the initial nk record */
1082  if((nk = regfi_parse_nk(file, offset, max_size, true)) == NULL)
1083  {
1084    regfi_add_message(file, REGFI_MSG_ERROR, "Could not load NK record at"
1085                      " offset 0x%.8X.", offset);
1086    return NULL;
1087  }
1088
1089  /* XXX: Registry key names are supposedly limited to 255 characters according to:
1090   *      http://msdn.microsoft.com/en-us/library/ms724872%28VS.85%29.aspx
1091   *      Might want to emit a warning if this is exceeded. 
1092   *      It is expected that "characters" could be variable width.
1093   *      Also, it may be useful to use this information to limit false positives
1094   *      when recovering deleted NK records.
1095   */
1096  from_encoding = (nk->flags & REGFI_NK_FLAG_ASCIINAME) 
1097    ? REGFI_ENCODING_ASCII : REGFI_ENCODING_UTF16LE;
1098
1099  if(from_encoding == output_encoding)
1100  {
1101    nk->keyname_raw = talloc_realloc(nk, nk->keyname_raw, uint8_t, nk->name_length+1);
1102    nk->keyname_raw[nk->name_length] = '\0';
1103    nk->keyname = (char*)nk->keyname_raw;
1104  }
1105  else
1106  {
1107    nk->keyname = talloc_array(nk, char, nk->name_length+1);
1108    if(nk->keyname == NULL)
1109    {
1110      regfi_free_key(nk);
1111      return NULL;
1112    }
1113
1114    tmp_size = regfi_conv_charset(regfi_encoding_int2str(from_encoding),
1115                                  regfi_encoding_int2str(output_encoding),
1116                                  nk->keyname_raw, nk->keyname,
1117                                  nk->name_length, nk->name_length+1);
1118    if(tmp_size < 0)
1119    {
1120      regfi_add_message(file, REGFI_MSG_WARN, "Error occurred while converting"
1121                        " keyname to encoding %s.  Error message: %s",
1122                        regfi_encoding_int2str(output_encoding), 
1123                        strerror(-tmp_size));
1124      talloc_free(nk->keyname);
1125      nk->keyname = NULL;
1126    }
1127  }
1128
1129
1130  /* get value list */
1131  if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE)) 
1132  {
1133    off = nk->values_off + REGFI_REGF_SIZE;
1134    max_size = regfi_calc_maxsize(file, off);
1135    if(max_size < 0)
1136    {
1137      if(strict)
1138      {
1139        regfi_free_key(nk);
1140        return NULL;
1141      }
1142      else
1143        nk->values = NULL;
1144
1145    }
1146    else
1147    {
1148      nk->values = regfi_load_valuelist(file, off, nk->num_values, 
1149                                        max_size, true);
1150      if(nk->values == NULL)
1151      {
1152        regfi_add_message(file, REGFI_MSG_WARN, "Could not load value list"
1153                          " for NK record at offset 0x%.8X.", offset);
1154        if(strict)
1155        {
1156          regfi_free_key(nk);
1157          return NULL;
1158        }
1159      }
1160      talloc_steal(nk, nk->values);
1161    }
1162  }
1163
1164  /* now get subkey list */
1165  if(nk->num_subkeys && (nk->subkeys_off != REGFI_OFFSET_NONE)) 
1166  {
1167    off = nk->subkeys_off + REGFI_REGF_SIZE;
1168    max_size = regfi_calc_maxsize(file, off);
1169    if(max_size < 0) 
1170    {
1171      if(strict)
1172      {
1173        regfi_free_key(nk);
1174        return NULL;
1175      }
1176      else
1177        nk->subkeys = NULL;
1178    }
1179    else
1180    {
1181      nk->subkeys = regfi_load_subkeylist(file, off, nk->num_subkeys,
1182                                          max_size, true);
1183
1184      if(nk->subkeys == NULL)
1185      {
1186        regfi_add_message(file, REGFI_MSG_WARN, "Could not load subkey list"
1187                          " while parsing NK record at offset 0x%.8X.", offset);
1188        nk->num_subkeys = 0;
1189      }
1190      talloc_steal(nk, nk->subkeys);
1191    }
1192  }
1193
1194  return nk;
1195}
1196
1197
1198/******************************************************************************
1199 ******************************************************************************/
1200const REGFI_SK_REC* regfi_load_sk(REGFI_FILE* file, uint32_t offset, bool strict)
1201{
1202  REGFI_SK_REC* ret_val = NULL;
1203  int32_t max_size;
1204  void* failure_ptr = NULL;
1205 
1206  /* First look if we have already parsed it */
1207  ret_val = (REGFI_SK_REC*)lru_cache_find(file->sk_cache, &offset, 4);
1208
1209  /* Bail out if we have previously cached a parse failure at this offset. */
1210  if(ret_val == (void*)REGFI_OFFSET_NONE)
1211    return NULL;
1212
1213  if(ret_val == NULL)
1214  {
1215    max_size = regfi_calc_maxsize(file, offset);
1216    if(max_size < 0)
1217      return NULL;
1218
1219    ret_val = regfi_parse_sk(file, offset, max_size, strict);
1220    if(ret_val == NULL)
1221    { /* Cache the parse failure and bail out. */
1222      failure_ptr = talloc(NULL, uint32_t);
1223      if(failure_ptr == NULL)
1224        return NULL;
1225      *(uint32_t*)failure_ptr = REGFI_OFFSET_NONE;
1226      lru_cache_update(file->sk_cache, &offset, 4, failure_ptr);
1227      return NULL;
1228    }
1229
1230    lru_cache_update(file->sk_cache, &offset, 4, ret_val);
1231  }
1232
1233  return ret_val;
1234}
1235
1236
1237
1238/******************************************************************************
1239 ******************************************************************************/
1240REGFI_NK_REC* regfi_find_root_nk(REGFI_FILE* file, const REGFI_HBIN* hbin, 
1241                                 REGFI_ENCODING output_encoding)
1242{
1243  REGFI_NK_REC* nk = NULL;
1244  uint32_t cell_length;
1245  uint32_t cur_offset = hbin->file_off+REGFI_HBIN_HEADER_SIZE;
1246  uint32_t hbin_end = hbin->file_off+hbin->block_size;
1247  bool unalloc;
1248
1249  while(cur_offset < hbin_end)
1250  {
1251    if(!regfi_parse_cell(file->fd, cur_offset, NULL, 0, &cell_length, &unalloc))
1252    {
1253      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell at offset"
1254                        " 0x%.8X while searching for root key.", cur_offset);
1255      return NULL;
1256    }
1257   
1258    if(!unalloc)
1259    {
1260      nk = regfi_load_key(file, cur_offset, output_encoding, true);
1261      if(nk != NULL)
1262      {
1263        if(nk->flags & REGFI_NK_FLAG_ROOT)
1264          return nk;
1265      }
1266    }
1267
1268    cur_offset += cell_length;
1269  }
1270
1271  return NULL;
1272}
1273
1274
1275/******************************************************************************
1276 ******************************************************************************/
1277REGFI_FILE* regfi_open(const char* filename)
1278{
1279  REGFI_FILE* ret_val;
1280  int fd;
1281
1282  /* open an existing file */
1283  if ((fd = open(filename, REGFI_OPEN_FLAGS)) == -1)
1284  {
1285    /* fprintf(stderr, "regfi_open: failure to open %s (%s)\n", filename, strerror(errno));*/
1286    return NULL;
1287  }
1288
1289  ret_val = regfi_alloc(fd);
1290
1291  if(ret_val == NULL)
1292    close(fd);
1293
1294  return ret_val;
1295}
1296
1297
1298/******************************************************************************
1299 ******************************************************************************/
1300REGFI_FILE* regfi_alloc(int fd)
1301{
1302  struct stat sbuf;
1303  REGFI_FILE* rb;
1304  REGFI_HBIN* hbin = NULL;
1305  uint32_t hbin_off, file_length, cache_secret;
1306  bool rla;
1307
1308  /* Determine file length.  Must be at least big enough
1309   * for the header and one hbin.
1310   */
1311  if (fstat(fd, &sbuf) == -1)
1312    return NULL;
1313  file_length = sbuf.st_size;
1314  if(file_length < REGFI_REGF_SIZE+REGFI_HBIN_ALLOC)
1315    return NULL;
1316
1317  /* Read file header */
1318  if ((rb = regfi_parse_regf(fd, true)) == NULL) 
1319  {
1320    /* fprintf(stderr, "regfi_alloc: Failed to read initial REGF block\n"); */
1321    return NULL;
1322  }
1323  rb->file_length = file_length; 
1324
1325  rb->hbins = range_list_new();
1326  if(rb->hbins == NULL)
1327  {
1328    /* fprintf(stderr, "regfi_alloc: Failed to create HBIN list.\n"); */
1329    talloc_free(rb);
1330    return NULL;
1331  }
1332  talloc_steal(rb, rb->hbins);
1333
1334  rla = true;
1335  hbin_off = REGFI_REGF_SIZE;
1336  hbin = regfi_parse_hbin(rb, hbin_off, true);
1337  while(hbin && rla)
1338  {
1339    rla = range_list_add(rb->hbins, hbin->file_off, hbin->block_size, hbin);
1340    if(rla)
1341      talloc_steal(rb->hbins, hbin);
1342    hbin_off = hbin->file_off + hbin->block_size;
1343    hbin = regfi_parse_hbin(rb, hbin_off, true);
1344  }
1345
1346  /* This secret isn't very secret, but we don't need a good one.  This
1347   * secret is just designed to prevent someone from trying to blow our
1348   * caching and make things slow.
1349   */
1350  cache_secret = 0x15DEAD05^time(NULL)^(getpid()<<16);
1351
1352  /* Cache an unlimited number of SK records.  Typically there are very few. */
1353  rb->sk_cache = lru_cache_create_ctx(rb, 0, cache_secret, true);
1354
1355  /* Default message mask */
1356  rb->msg_mask = REGFI_MSG_ERROR|REGFI_MSG_WARN;
1357
1358  /* success */
1359  return rb;
1360}
1361
1362
1363/******************************************************************************
1364 ******************************************************************************/
1365int regfi_close(REGFI_FILE* file)
1366{
1367  int fd;
1368
1369  /* nothing to do if there is no open file */
1370  if ((file == NULL) || (file->fd == -1))
1371    return 0;
1372
1373  fd = file->fd;
1374  file->fd = -1;
1375
1376  regfi_free(file);
1377
1378  return close(fd);
1379}
1380
1381
1382/******************************************************************************
1383 ******************************************************************************/
1384void regfi_free(REGFI_FILE *file)
1385{
1386  if(file->last_message != NULL)
1387    free(file->last_message);
1388
1389  talloc_free(file);
1390}
1391
1392
1393/******************************************************************************
1394 * First checks the offset given by the file header, then checks the
1395 * rest of the file if that fails.
1396 ******************************************************************************/
1397REGFI_NK_REC* regfi_rootkey(REGFI_FILE* file, REGFI_ENCODING output_encoding)
1398{
1399  REGFI_NK_REC* nk = NULL;
1400  REGFI_HBIN* hbin;
1401  uint32_t root_offset, i, num_hbins;
1402 
1403  if(!file)
1404    return NULL;
1405
1406  root_offset = file->root_cell+REGFI_REGF_SIZE;
1407  nk = regfi_load_key(file, root_offset, output_encoding, true);
1408  if(nk != NULL)
1409  {
1410    if(nk->flags & REGFI_NK_FLAG_ROOT)
1411      return nk;
1412  }
1413
1414  regfi_add_message(file, REGFI_MSG_WARN, "File header indicated root key at"
1415                    " location 0x%.8X, but no root key found."
1416                    " Searching rest of file...", root_offset);
1417 
1418  /* If the file header gives bad info, scan through the file one HBIN
1419   * block at a time looking for an NK record with a root key type.
1420   */
1421  num_hbins = range_list_size(file->hbins);
1422  for(i=0; i < num_hbins && nk == NULL; i++)
1423  {
1424    hbin = (REGFI_HBIN*)range_list_get(file->hbins, i)->data;
1425    nk = regfi_find_root_nk(file, hbin, output_encoding);
1426  }
1427
1428  return nk;
1429}
1430
1431
1432/******************************************************************************
1433 *****************************************************************************/
1434void regfi_free_key(REGFI_NK_REC* nk)
1435{
1436  regfi_subkeylist_free(nk->subkeys);
1437  talloc_free(nk);
1438}
1439
1440
1441/******************************************************************************
1442 *****************************************************************************/
1443void regfi_free_value(REGFI_VK_REC* vk)
1444{
1445  talloc_free(vk);
1446}
1447
1448
1449/******************************************************************************
1450 *****************************************************************************/
1451void regfi_subkeylist_free(REGFI_SUBKEY_LIST* list)
1452{
1453  if(list != NULL)
1454  {
1455    talloc_free(list);
1456  }
1457}
1458
1459
1460/******************************************************************************
1461 *****************************************************************************/
1462REGFI_ITERATOR* regfi_iterator_new(REGFI_FILE* file, 
1463                                   REGFI_ENCODING output_encoding)
1464{
1465  REGFI_NK_REC* root;
1466  REGFI_ITERATOR* ret_val;
1467
1468  if(output_encoding != REGFI_ENCODING_UTF8
1469     && output_encoding != REGFI_ENCODING_ASCII)
1470  { 
1471    regfi_add_message(file, REGFI_MSG_ERROR, "Invalid output_encoding supplied"
1472                      " in creation of regfi iterator.");
1473    return NULL;
1474  }
1475
1476  ret_val = talloc(NULL, REGFI_ITERATOR);
1477  if(ret_val == NULL)
1478    return NULL;
1479
1480  root = regfi_rootkey(file, output_encoding);
1481  if(root == NULL)
1482  {
1483    talloc_free(ret_val);
1484    return NULL;
1485  }
1486
1487  ret_val->key_positions = void_stack_new(REGFI_MAX_DEPTH);
1488  if(ret_val->key_positions == NULL)
1489  {
1490    talloc_free(ret_val);
1491    return NULL;
1492  }
1493  talloc_steal(ret_val, ret_val->key_positions);
1494
1495  ret_val->f = file;
1496  ret_val->cur_key = root;
1497  ret_val->cur_subkey = 0;
1498  ret_val->cur_value = 0;
1499  ret_val->string_encoding = output_encoding;
1500   
1501  return ret_val;
1502}
1503
1504
1505/******************************************************************************
1506 *****************************************************************************/
1507void regfi_iterator_free(REGFI_ITERATOR* i)
1508{
1509  talloc_free(i);
1510}
1511
1512
1513
1514/******************************************************************************
1515 *****************************************************************************/
1516/* XXX: some way of indicating reason for failure should be added. */
1517bool regfi_iterator_down(REGFI_ITERATOR* i)
1518{
1519  REGFI_NK_REC* subkey;
1520  REGFI_ITER_POSITION* pos;
1521
1522  pos = talloc(i->key_positions, REGFI_ITER_POSITION);
1523  if(pos == NULL)
1524    return false;
1525
1526  subkey = (REGFI_NK_REC*)regfi_iterator_cur_subkey(i);
1527  if(subkey == NULL)
1528  {
1529    talloc_free(pos);
1530    return false;
1531  }
1532
1533  pos->nk = i->cur_key;
1534  pos->cur_subkey = i->cur_subkey;
1535  if(!void_stack_push(i->key_positions, pos))
1536  {
1537    talloc_free(pos);
1538    regfi_free_key(subkey);
1539    return false;
1540  }
1541  talloc_steal(i, subkey);
1542
1543  i->cur_key = subkey;
1544  i->cur_subkey = 0;
1545  i->cur_value = 0;
1546
1547  return true;
1548}
1549
1550
1551/******************************************************************************
1552 *****************************************************************************/
1553bool regfi_iterator_up(REGFI_ITERATOR* i)
1554{
1555  REGFI_ITER_POSITION* pos;
1556
1557  pos = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions);
1558  if(pos == NULL)
1559    return false;
1560
1561  regfi_free_key(i->cur_key);
1562  i->cur_key = pos->nk;
1563  i->cur_subkey = pos->cur_subkey;
1564  i->cur_value = 0;
1565  talloc_free(pos);
1566
1567  return true;
1568}
1569
1570
1571/******************************************************************************
1572 *****************************************************************************/
1573bool regfi_iterator_to_root(REGFI_ITERATOR* i)
1574{
1575  while(regfi_iterator_up(i))
1576    continue;
1577
1578  return true;
1579}
1580
1581
1582/******************************************************************************
1583 *****************************************************************************/
1584bool regfi_iterator_find_subkey(REGFI_ITERATOR* i, const char* subkey_name)
1585{
1586  REGFI_NK_REC* subkey;
1587  bool found = false;
1588  uint32_t old_subkey = i->cur_subkey;
1589
1590  if(subkey_name == NULL)
1591    return false;
1592
1593  /* XXX: this alloc/free of each sub key might be a bit excessive */
1594  subkey = (REGFI_NK_REC*)regfi_iterator_first_subkey(i);
1595  while((subkey != NULL) && (found == false))
1596  {
1597    if(subkey->keyname != NULL 
1598       && strcasecmp(subkey->keyname, subkey_name) == 0)
1599      found = true;
1600    else
1601    {
1602      regfi_free_key(subkey);
1603      subkey = (REGFI_NK_REC*)regfi_iterator_next_subkey(i);
1604    }
1605  }
1606
1607  if(found == false)
1608  {
1609    i->cur_subkey = old_subkey;
1610    return false;
1611  }
1612
1613  regfi_free_key(subkey);
1614  return true;
1615}
1616
1617
1618/******************************************************************************
1619 *****************************************************************************/
1620bool regfi_iterator_walk_path(REGFI_ITERATOR* i, const char** path)
1621{
1622  uint32_t x;
1623  if(path == NULL)
1624    return false;
1625
1626  for(x=0; 
1627      ((path[x] != NULL) && regfi_iterator_find_subkey(i, path[x])
1628       && regfi_iterator_down(i));
1629      x++)
1630  { continue; }
1631
1632  if(path[x] == NULL)
1633    return true;
1634 
1635  /* XXX: is this the right number of times? */
1636  for(; x > 0; x--)
1637    regfi_iterator_up(i);
1638 
1639  return false;
1640}
1641
1642
1643/******************************************************************************
1644 *****************************************************************************/
1645const REGFI_NK_REC* regfi_iterator_cur_key(REGFI_ITERATOR* i)
1646{
1647  return i->cur_key;
1648}
1649
1650
1651/******************************************************************************
1652 *****************************************************************************/
1653const REGFI_SK_REC* regfi_iterator_cur_sk(REGFI_ITERATOR* i)
1654{
1655  if(i->cur_key == NULL || i->cur_key->sk_off == REGFI_OFFSET_NONE)
1656    return NULL;
1657
1658  return regfi_load_sk(i->f, i->cur_key->sk_off + REGFI_REGF_SIZE, true);
1659}
1660
1661
1662/******************************************************************************
1663 *****************************************************************************/
1664REGFI_NK_REC* regfi_iterator_first_subkey(REGFI_ITERATOR* i)
1665{
1666  i->cur_subkey = 0;
1667  return regfi_iterator_cur_subkey(i);
1668}
1669
1670
1671/******************************************************************************
1672 *****************************************************************************/
1673REGFI_NK_REC* regfi_iterator_cur_subkey(REGFI_ITERATOR* i)
1674{
1675  uint32_t nk_offset;
1676
1677  /* see if there is anything left to report */
1678  if (!(i->cur_key) || (i->cur_key->subkeys_off==REGFI_OFFSET_NONE)
1679      || (i->cur_subkey >= i->cur_key->num_subkeys))
1680    return NULL;
1681
1682  nk_offset = i->cur_key->subkeys->elements[i->cur_subkey].offset;
1683
1684  return regfi_load_key(i->f, nk_offset+REGFI_REGF_SIZE, i->string_encoding, 
1685                        true);
1686}
1687
1688
1689/******************************************************************************
1690 *****************************************************************************/
1691/* XXX: some way of indicating reason for failure should be added. */
1692REGFI_NK_REC* regfi_iterator_next_subkey(REGFI_ITERATOR* i)
1693{
1694  REGFI_NK_REC* subkey;
1695
1696  i->cur_subkey++;
1697  subkey = regfi_iterator_cur_subkey(i);
1698
1699  if(subkey == NULL)
1700    i->cur_subkey--;
1701
1702  return subkey;
1703}
1704
1705
1706/******************************************************************************
1707 *****************************************************************************/
1708bool regfi_iterator_find_value(REGFI_ITERATOR* i, const char* value_name)
1709{
1710  REGFI_VK_REC* cur;
1711  bool found = false;
1712  uint32_t old_value = i->cur_value;
1713
1714  /* XXX: cur->valuename can be NULL in the registry. 
1715   *      Should we allow for a way to search for that?
1716   */
1717  if(value_name == NULL)
1718    return false;
1719
1720  cur = regfi_iterator_first_value(i);
1721  while((cur != NULL) && (found == false))
1722  {
1723    if((cur->valuename != NULL)
1724       && (strcasecmp(cur->valuename, value_name) == 0))
1725      found = true;
1726    else
1727    {
1728      regfi_free_value(cur);
1729      cur = regfi_iterator_next_value(i);
1730    }
1731  }
1732 
1733  if(found == false)
1734  {
1735    i->cur_value = old_value;
1736    return false;
1737  }
1738
1739  regfi_free_value(cur);
1740  return true;
1741}
1742
1743
1744/******************************************************************************
1745 *****************************************************************************/
1746REGFI_VK_REC* regfi_iterator_first_value(REGFI_ITERATOR* i)
1747{
1748  i->cur_value = 0;
1749  return regfi_iterator_cur_value(i);
1750}
1751
1752
1753/******************************************************************************
1754 *****************************************************************************/
1755REGFI_VK_REC* regfi_iterator_cur_value(REGFI_ITERATOR* i)
1756{
1757  REGFI_VK_REC* ret_val = NULL;
1758  uint32_t voffset;
1759
1760  if(i->cur_key->values != NULL && i->cur_key->values->elements != NULL)
1761  {
1762    if(i->cur_value < i->cur_key->values->num_values)
1763    {
1764      voffset = i->cur_key->values->elements[i->cur_value];
1765      ret_val = regfi_load_value(i->f, voffset+REGFI_REGF_SIZE, 
1766                                 i->string_encoding, true);
1767    }
1768  }
1769
1770  return ret_val;
1771}
1772
1773
1774/******************************************************************************
1775 *****************************************************************************/
1776REGFI_VK_REC* regfi_iterator_next_value(REGFI_ITERATOR* i)
1777{
1778  REGFI_VK_REC* ret_val;
1779
1780  i->cur_value++;
1781  ret_val = regfi_iterator_cur_value(i);
1782  if(ret_val == NULL)
1783    i->cur_value--;
1784
1785  return ret_val;
1786}
1787
1788
1789/******************************************************************************
1790 *****************************************************************************/
1791REGFI_CLASSNAME* regfi_iterator_fetch_classname(REGFI_ITERATOR* i, 
1792                                                const REGFI_NK_REC* key)
1793{
1794  REGFI_CLASSNAME* ret_val;
1795  uint8_t* raw;
1796  char* interpreted;
1797  uint32_t offset;
1798  int32_t conv_size, max_size;
1799  uint16_t parse_length;
1800
1801  if(key->classname_off == REGFI_OFFSET_NONE || key->classname_length == 0)
1802    return NULL;
1803
1804  offset = key->classname_off + REGFI_REGF_SIZE;
1805  max_size = regfi_calc_maxsize(i->f, offset);
1806  if(max_size <= 0)
1807    return NULL;
1808
1809  parse_length = key->classname_length;
1810  raw = regfi_parse_classname(i->f, offset, &parse_length, max_size, true);
1811 
1812  if(raw == NULL)
1813  {
1814    regfi_add_message(i->f, REGFI_MSG_WARN, "Could not parse class"
1815                      " name at offset 0x%.8X for key record at offset 0x%.8X.",
1816                      offset, key->offset);
1817    return NULL;
1818  }
1819
1820  ret_val = talloc(NULL, REGFI_CLASSNAME);
1821  if(ret_val == NULL)
1822    return NULL;
1823
1824  ret_val->raw = raw;
1825  ret_val->size = parse_length;
1826  talloc_steal(ret_val, raw);
1827
1828  interpreted = talloc_array(NULL, char, parse_length);
1829
1830  conv_size = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE),
1831                                 regfi_encoding_int2str(i->string_encoding),
1832                                 raw, interpreted,
1833                                 parse_length, parse_length);
1834  if(conv_size < 0)
1835  {
1836    regfi_add_message(i->f, REGFI_MSG_WARN, "Error occurred while"
1837                      " converting classname to charset %s.  Error message: %s",
1838                      i->string_encoding, strerror(-conv_size));
1839    talloc_free(interpreted);
1840    ret_val->interpreted = NULL;
1841  }
1842  else
1843  {
1844    interpreted = talloc_realloc(NULL, interpreted, char, conv_size);
1845    ret_val->interpreted = interpreted;
1846    talloc_steal(ret_val, interpreted);
1847  }
1848
1849  return ret_val;
1850}
1851
1852
1853/******************************************************************************
1854 *****************************************************************************/
1855REGFI_DATA* regfi_iterator_fetch_data(REGFI_ITERATOR* i, 
1856                                      const REGFI_VK_REC* value)
1857{
1858  REGFI_DATA* ret_val = NULL;
1859  REGFI_BUFFER raw_data;
1860
1861  if(value->data_size != 0)
1862  {
1863    raw_data = regfi_load_data(i->f, value->data_off, value->data_size,
1864                              value->data_in_offset, true);
1865    if(raw_data.buf == NULL)
1866    {
1867      regfi_add_message(i->f, REGFI_MSG_WARN, "Could not parse data record"
1868                        " while parsing VK record at offset 0x%.8X.",
1869                        value->offset);
1870    }
1871    else
1872    {
1873      ret_val = regfi_buffer_to_data(raw_data);
1874
1875      if(ret_val == NULL)
1876      {
1877        regfi_add_message(i->f, REGFI_MSG_WARN, "Error occurred in converting"
1878                          " data buffer to data structure while interpreting "
1879                          "data for VK record at offset 0x%.8X.",
1880                          value->offset);
1881        talloc_free(raw_data.buf);
1882        return NULL;
1883      }
1884
1885      if(!regfi_interpret_data(i->f, i->string_encoding, value->type, ret_val))
1886      {
1887        regfi_add_message(i->f, REGFI_MSG_INFO, "Error occurred while"
1888                          " interpreting data for VK record at offset 0x%.8X.",
1889                          value->offset);
1890      }
1891    }
1892  }
1893 
1894  return ret_val;
1895}
1896
1897
1898/******************************************************************************
1899 *****************************************************************************/
1900void regfi_free_classname(REGFI_CLASSNAME* classname)
1901{
1902  talloc_free(classname);
1903}
1904
1905/******************************************************************************
1906 *****************************************************************************/
1907void regfi_free_data(REGFI_DATA* data)
1908{
1909  talloc_free(data);
1910}
1911
1912
1913/******************************************************************************
1914 *****************************************************************************/
1915REGFI_DATA* regfi_buffer_to_data(REGFI_BUFFER raw_data)
1916{
1917  REGFI_DATA* ret_val;
1918
1919  if(raw_data.buf == NULL)
1920    return NULL;
1921
1922  ret_val = talloc(NULL, REGFI_DATA);
1923  if(ret_val == NULL)
1924    return NULL;
1925 
1926  talloc_steal(ret_val, raw_data.buf);
1927  ret_val->raw = raw_data.buf;
1928  ret_val->size = raw_data.len;
1929  ret_val->interpreted_size = 0;
1930  ret_val->interpreted.qword = 0;
1931
1932  return ret_val;
1933}
1934
1935
1936/******************************************************************************
1937 *****************************************************************************/
1938bool regfi_interpret_data(REGFI_FILE* file, REGFI_ENCODING string_encoding,
1939                          uint32_t type, REGFI_DATA* data)
1940{
1941  uint8_t** tmp_array;
1942  uint8_t* tmp_str;
1943  int32_t tmp_size;
1944  uint32_t i, j, array_size;
1945
1946  if(data == NULL)
1947    return false;
1948
1949  switch (type)
1950  {
1951  case REG_SZ:
1952  case REG_EXPAND_SZ:
1953  /* REG_LINK is a symbolic link, stored as a unicode string. */
1954  case REG_LINK:
1955    tmp_str = talloc_array(NULL, uint8_t, data->size);
1956    if(tmp_str == NULL)
1957    {
1958      data->interpreted.string = NULL;
1959      data->interpreted_size = 0;
1960      return false;
1961    }
1962     
1963    tmp_size = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE),
1964                                  regfi_encoding_int2str(string_encoding),
1965                                  data->raw, (char*)tmp_str, 
1966                                  data->size, data->size);
1967    if(tmp_size < 0)
1968    {
1969      regfi_add_message(file, REGFI_MSG_INFO, "Error occurred while"
1970                        " converting data of type %d to %s.  Error message: %s",
1971                        type, string_encoding, strerror(-tmp_size));
1972      talloc_free(tmp_str);
1973      data->interpreted.string = NULL;
1974      data->interpreted_size = 0;
1975      return false;
1976    }
1977
1978    tmp_str = talloc_realloc(NULL, tmp_str, uint8_t, tmp_size);
1979    data->interpreted.string = tmp_str;
1980    data->interpreted_size = tmp_size;
1981    talloc_steal(data, tmp_str);
1982    break;
1983
1984  case REG_DWORD:
1985    if(data->size < 4)
1986    {
1987      data->interpreted.dword = 0;
1988      data->interpreted_size = 0;
1989      return false;
1990    }
1991    data->interpreted.dword = IVAL(data->raw, 0);
1992    data->interpreted_size = 4;
1993    break;
1994
1995  case REG_DWORD_BE:
1996    if(data->size < 4)
1997    {
1998      data->interpreted.dword_be = 0;
1999      data->interpreted_size = 0;
2000      return false;
2001    }
2002    data->interpreted.dword_be = RIVAL(data->raw, 0);
2003    data->interpreted_size = 4;
2004    break;
2005
2006  case REG_QWORD:
2007    if(data->size < 8)
2008    {
2009      data->interpreted.qword = 0;
2010      data->interpreted_size = 0;
2011      return false;
2012    }
2013    data->interpreted.qword = 
2014      (uint64_t)IVAL(data->raw, 0) + (((uint64_t)IVAL(data->raw, 4))<<32);
2015    data->interpreted_size = 8;
2016    break;
2017   
2018  case REG_MULTI_SZ:
2019    tmp_str = talloc_array(NULL, uint8_t, data->size);
2020    if(tmp_str == NULL)
2021    {
2022      data->interpreted.multiple_string = NULL;
2023      data->interpreted_size = 0;
2024      return false;
2025    }
2026
2027    /* Attempt to convert entire string from UTF-16LE to output encoding,
2028     * then parse and quote fields individually.
2029     */
2030    tmp_size = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE),
2031                                  regfi_encoding_int2str(string_encoding),
2032                                  data->raw, (char*)tmp_str,
2033                                  data->size, data->size);
2034    if(tmp_size < 0)
2035    {
2036      regfi_add_message(file, REGFI_MSG_INFO, "Error occurred while"
2037                        " converting data of type %d to %s.  Error message: %s",
2038                        type, string_encoding, strerror(-tmp_size));
2039      talloc_free(tmp_str);
2040      data->interpreted.multiple_string = NULL;
2041      data->interpreted_size = 0;
2042      return false;
2043    }
2044
2045    array_size = tmp_size+1;
2046    tmp_array = talloc_array(NULL, uint8_t*, array_size);
2047    if(tmp_array == NULL)
2048    {
2049      talloc_free(tmp_str);
2050      data->interpreted.string = NULL;
2051      data->interpreted_size = 0;
2052      return false;
2053    }
2054   
2055    tmp_array[0] = tmp_str;
2056    for(i=0,j=1; i < tmp_size && j < array_size-1; i++)
2057    {
2058      if(tmp_str[i] == '\0' && (i+1 < tmp_size))
2059        tmp_array[j++] = tmp_str+i+1;
2060    }
2061    tmp_array[j] = NULL;
2062    tmp_array = talloc_realloc(NULL, tmp_array, uint8_t*, j+1);
2063    data->interpreted.multiple_string = tmp_array;
2064    /* XXX: how meaningful is this?  should we store number of strings instead? */
2065    data->interpreted_size = tmp_size;
2066    talloc_steal(tmp_array, tmp_str);
2067    talloc_steal(data, tmp_array);
2068    break;
2069
2070  /* XXX: Dont know how to interpret these yet, just treat as binary */
2071  case REG_NONE:
2072    data->interpreted.none = data->raw;
2073    data->interpreted_size = data->size;
2074    break;
2075
2076  case REG_RESOURCE_LIST:
2077    data->interpreted.resource_list = data->raw;
2078    data->interpreted_size = data->size;
2079    break;
2080
2081  case REG_FULL_RESOURCE_DESCRIPTOR:
2082    data->interpreted.full_resource_descriptor = data->raw;
2083    data->interpreted_size = data->size;
2084    break;
2085
2086  case REG_RESOURCE_REQUIREMENTS_LIST:
2087    data->interpreted.resource_requirements_list = data->raw;
2088    data->interpreted_size = data->size;
2089    break;
2090
2091  case REG_BINARY:
2092    data->interpreted.binary = data->raw;
2093    data->interpreted_size = data->size;
2094    break;
2095
2096  default:
2097    data->interpreted.qword = 0;
2098    data->interpreted_size = 0;
2099    return false;
2100  }
2101
2102  data->type = type;
2103  return true;
2104}
2105
2106
2107/******************************************************************************
2108 * Convert from UTF-16LE to specified character set.
2109 * On error, returns a negative errno code.
2110 *****************************************************************************/
2111int32_t regfi_conv_charset(const char* input_charset, const char* output_charset,
2112                         uint8_t* input, char* output, 
2113                         uint32_t input_len, uint32_t output_max)
2114{
2115  iconv_t conv_desc;
2116  char* inbuf = (char*)input;
2117  char* outbuf = output;
2118  size_t in_len = (size_t)input_len;
2119  size_t out_len = (size_t)(output_max-1);
2120  int ret;
2121
2122  /* XXX: Consider creating a couple of conversion descriptors earlier,
2123   *      storing them on an iterator so they don't have to be recreated
2124   *      each time.
2125   */
2126
2127  /* Set up conversion descriptor. */
2128  conv_desc = iconv_open(output_charset, input_charset);
2129
2130  ret = iconv(conv_desc, &inbuf, &in_len, &outbuf, &out_len);
2131  if(ret == -1)
2132  {
2133    iconv_close(conv_desc);
2134    return -errno;
2135  }
2136  *outbuf = '\0';
2137
2138  iconv_close(conv_desc); 
2139  return output_max-out_len-1;
2140}
2141
2142
2143
2144/*******************************************************************
2145 * Computes the checksum of the registry file header.
2146 * buffer must be at least the size of a regf header (4096 bytes).
2147 *******************************************************************/
2148static uint32_t regfi_compute_header_checksum(uint8_t* buffer)
2149{
2150  uint32_t checksum, x;
2151  int i;
2152
2153  /* XOR of all bytes 0x0000 - 0x01FB */
2154
2155  checksum = x = 0;
2156 
2157  for ( i=0; i<0x01FB; i+=4 ) {
2158    x = IVAL(buffer, i );
2159    checksum ^= x;
2160  }
2161 
2162  return checksum;
2163}
2164
2165
2166/*******************************************************************
2167 * XXX: Add way to return more detailed error information.
2168 *******************************************************************/
2169REGFI_FILE* regfi_parse_regf(int fd, bool strict)
2170{
2171  uint8_t file_header[REGFI_REGF_SIZE];
2172  uint32_t length;
2173  REGFI_FILE* ret_val;
2174
2175  ret_val = talloc(NULL, REGFI_FILE);
2176  if(ret_val == NULL)
2177    return NULL;
2178
2179  ret_val->fd = fd;
2180  ret_val->sk_cache = NULL;
2181  ret_val->last_message = NULL;
2182  ret_val->hbins = NULL;
2183 
2184  length = REGFI_REGF_SIZE;
2185  if((regfi_read(fd, file_header, &length)) != 0 || length != REGFI_REGF_SIZE)
2186    goto fail;
2187 
2188  ret_val->checksum = IVAL(file_header, 0x1FC);
2189  ret_val->computed_checksum = regfi_compute_header_checksum(file_header);
2190  if (strict && (ret_val->checksum != ret_val->computed_checksum))
2191    goto fail;
2192
2193  memcpy(ret_val->magic, file_header, REGFI_REGF_MAGIC_SIZE);
2194  if(memcmp(ret_val->magic, "regf", REGFI_REGF_MAGIC_SIZE) != 0)
2195  {
2196    if(strict)
2197      goto fail;
2198    regfi_add_message(ret_val, REGFI_MSG_WARN, "Magic number mismatch "
2199                      "(%.2X %.2X %.2X %.2X) while parsing hive header",
2200                      ret_val->magic[0], ret_val->magic[1], 
2201                      ret_val->magic[2], ret_val->magic[3]);
2202  }
2203  ret_val->sequence1 = IVAL(file_header, 0x4);
2204  ret_val->sequence2 = IVAL(file_header, 0x8);
2205  ret_val->mtime.low = IVAL(file_header, 0xC);
2206  ret_val->mtime.high = IVAL(file_header, 0x10);
2207  ret_val->major_version = IVAL(file_header, 0x14);
2208  ret_val->minor_version = IVAL(file_header, 0x18);
2209  ret_val->type = IVAL(file_header, 0x1C);
2210  ret_val->format = IVAL(file_header, 0x20);
2211  ret_val->root_cell = IVAL(file_header, 0x24);
2212  ret_val->last_block = IVAL(file_header, 0x28);
2213
2214  ret_val->cluster = IVAL(file_header, 0x2C);
2215
2216  memcpy(ret_val->file_name, file_header+0x30,  REGFI_REGF_NAME_SIZE);
2217
2218  /* XXX: Should we add a warning if these uuid parsers fail?  Can they? */
2219  ret_val->rm_id = winsec_parse_uuid(ret_val, file_header+0x70, 16);
2220  ret_val->log_id = winsec_parse_uuid(ret_val, file_header+0x80, 16);
2221  ret_val->flags = IVAL(file_header, 0x90);
2222  ret_val->tm_id = winsec_parse_uuid(ret_val, file_header+0x94, 16);
2223  ret_val->guid_signature = IVAL(file_header, 0xa4);
2224
2225  memcpy(ret_val->reserved1, file_header+0xa8, REGFI_REGF_RESERVED1_SIZE);
2226  memcpy(ret_val->reserved2, file_header+0x200, REGFI_REGF_RESERVED2_SIZE);
2227
2228  ret_val->thaw_tm_id = winsec_parse_uuid(ret_val, file_header+0xFC8, 16);
2229  ret_val->thaw_rm_id = winsec_parse_uuid(ret_val, file_header+0xFD8, 16);
2230  ret_val->thaw_log_id = winsec_parse_uuid(ret_val, file_header+0xFE8, 16);
2231  ret_val->boot_type = IVAL(file_header, 0xFF8);
2232  ret_val->boot_recover = IVAL(file_header, 0xFFC);
2233
2234  return ret_val;
2235
2236 fail:
2237  talloc_free(ret_val);
2238  return NULL;
2239}
2240
2241
2242
2243/******************************************************************************
2244 * Given real file offset, read and parse the hbin at that location
2245 * along with it's associated cells.
2246 ******************************************************************************/
2247REGFI_HBIN* regfi_parse_hbin(REGFI_FILE* file, uint32_t offset, bool strict)
2248{
2249  REGFI_HBIN *hbin;
2250  uint8_t hbin_header[REGFI_HBIN_HEADER_SIZE];
2251  uint32_t length;
2252 
2253  if(offset >= file->file_length)
2254    return NULL;
2255
2256  if(lseek(file->fd, offset, SEEK_SET) == -1)
2257  {
2258    regfi_add_message(file, REGFI_MSG_ERROR, "Seek failed"
2259                      " while parsing hbin at offset 0x%.8X.", offset);
2260    return NULL;
2261  }
2262
2263  length = REGFI_HBIN_HEADER_SIZE;
2264  if((regfi_read(file->fd, hbin_header, &length) != 0) 
2265     || length != REGFI_HBIN_HEADER_SIZE)
2266    return NULL;
2267
2268  if(lseek(file->fd, offset, SEEK_SET) == -1)
2269  {
2270    regfi_add_message(file, REGFI_MSG_ERROR, "Seek failed"
2271                      " while parsing hbin at offset 0x%.8X.", offset);
2272    return NULL;
2273  }
2274
2275  hbin = talloc(NULL, REGFI_HBIN);
2276  if(hbin == NULL)
2277    return NULL;
2278  hbin->file_off = offset;
2279
2280  memcpy(hbin->magic, hbin_header, 4);
2281  if(strict && (memcmp(hbin->magic, "hbin", 4) != 0))
2282  {
2283    regfi_add_message(file, REGFI_MSG_INFO, "Magic number mismatch "
2284                      "(%.2X %.2X %.2X %.2X) while parsing hbin at offset"
2285                      " 0x%.8X.", hbin->magic[0], hbin->magic[1], 
2286                      hbin->magic[2], hbin->magic[3], offset);
2287    talloc_free(hbin);
2288    return NULL;
2289  }
2290
2291  hbin->first_hbin_off = IVAL(hbin_header, 0x4);
2292  hbin->block_size = IVAL(hbin_header, 0x8);
2293  /* this should be the same thing as hbin->block_size but just in case */
2294  hbin->next_block = IVAL(hbin_header, 0x1C);
2295
2296
2297  /* Ensure the block size is a multiple of 0x1000 and doesn't run off
2298   * the end of the file.
2299   */
2300  /* XXX: This may need to be relaxed for dealing with
2301   *      partial or corrupt files.
2302   */
2303  if((offset + hbin->block_size > file->file_length)
2304     || (hbin->block_size & 0xFFFFF000) != hbin->block_size)
2305  {
2306    regfi_add_message(file, REGFI_MSG_ERROR, "The hbin offset is not aligned"
2307                      " or runs off the end of the file"
2308                      " while parsing hbin at offset 0x%.8X.", offset);
2309    talloc_free(hbin);
2310    return NULL;
2311  }
2312
2313  return hbin;
2314}
2315
2316
2317/*******************************************************************
2318 *******************************************************************/
2319REGFI_NK_REC* regfi_parse_nk(REGFI_FILE* file, uint32_t offset, 
2320                             uint32_t max_size, bool strict)
2321{
2322  uint8_t nk_header[REGFI_NK_MIN_LENGTH];
2323  REGFI_NK_REC* ret_val;
2324  uint32_t length,cell_length;
2325  bool unalloc = false;
2326
2327  if(!regfi_parse_cell(file->fd, offset, nk_header, REGFI_NK_MIN_LENGTH,
2328                       &cell_length, &unalloc))
2329  {
2330    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell header"
2331                      " while parsing NK record at offset 0x%.8X.", offset);
2332    return NULL;
2333  }
2334
2335  /* A bit of validation before bothering to allocate memory */
2336  if((nk_header[0x0] != 'n') || (nk_header[0x1] != 'k'))
2337  {
2338    regfi_add_message(file, REGFI_MSG_WARN, "Magic number mismatch in parsing"
2339                      " NK record at offset 0x%.8X.", offset);
2340    return NULL;
2341  }
2342
2343  ret_val = talloc(NULL, REGFI_NK_REC);
2344  if(ret_val == NULL)
2345  {
2346    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to allocate memory while"
2347                      " parsing NK record at offset 0x%.8X.", offset);
2348    return NULL;
2349  }
2350
2351  ret_val->values = NULL;
2352  ret_val->subkeys = NULL;
2353  ret_val->offset = offset;
2354  ret_val->cell_size = cell_length;
2355
2356  if(ret_val->cell_size > max_size)
2357    ret_val->cell_size = max_size & 0xFFFFFFF8;
2358  if((ret_val->cell_size < REGFI_NK_MIN_LENGTH) 
2359     || (strict && (ret_val->cell_size & 0x00000007) != 0))
2360  {
2361    regfi_add_message(file, REGFI_MSG_WARN, "A length check failed while"
2362                      " parsing NK record at offset 0x%.8X.", offset);
2363    talloc_free(ret_val);
2364    return NULL;
2365  }
2366
2367  ret_val->magic[0] = nk_header[0x0];
2368  ret_val->magic[1] = nk_header[0x1];
2369  ret_val->flags = SVAL(nk_header, 0x2);
2370 
2371  if((ret_val->flags & ~REGFI_NK_KNOWN_FLAGS) != 0)
2372  {
2373    regfi_add_message(file, REGFI_MSG_WARN, "Unknown key flags (0x%.4X) while"
2374                      " parsing NK record at offset 0x%.8X.", 
2375                      (ret_val->flags & ~REGFI_NK_KNOWN_FLAGS), offset);
2376  }
2377
2378  ret_val->mtime.low = IVAL(nk_header, 0x4);
2379  ret_val->mtime.high = IVAL(nk_header, 0x8);
2380  /* If the key is unallocated and the MTIME is earlier than Jan 1, 1990
2381   * or later than Jan 1, 2290, we consider this a bad key.  This helps
2382   * weed out some false positives during deleted data recovery.
2383   */
2384  if(unalloc
2385     && ((ret_val->mtime.high < REGFI_MTIME_MIN_HIGH
2386          && ret_val->mtime.low < REGFI_MTIME_MIN_LOW)
2387         || (ret_val->mtime.high > REGFI_MTIME_MAX_HIGH
2388             && ret_val->mtime.low > REGFI_MTIME_MAX_LOW)))
2389    return NULL;
2390
2391  ret_val->unknown1 = IVAL(nk_header, 0xC);
2392  ret_val->parent_off = IVAL(nk_header, 0x10);
2393  ret_val->num_subkeys = IVAL(nk_header, 0x14);
2394  ret_val->unknown2 = IVAL(nk_header, 0x18);
2395  ret_val->subkeys_off = IVAL(nk_header, 0x1C);
2396  ret_val->unknown3 = IVAL(nk_header, 0x20);
2397  ret_val->num_values = IVAL(nk_header, 0x24);
2398  ret_val->values_off = IVAL(nk_header, 0x28);
2399  ret_val->sk_off = IVAL(nk_header, 0x2C);
2400  ret_val->classname_off = IVAL(nk_header, 0x30);
2401
2402  ret_val->max_bytes_subkeyname = IVAL(nk_header, 0x34);
2403  ret_val->max_bytes_subkeyclassname = IVAL(nk_header, 0x38);
2404  ret_val->max_bytes_valuename = IVAL(nk_header, 0x3C);
2405  ret_val->max_bytes_value = IVAL(nk_header, 0x40);
2406  ret_val->unk_index = IVAL(nk_header, 0x44);
2407
2408  ret_val->name_length = SVAL(nk_header, 0x48);
2409  ret_val->classname_length = SVAL(nk_header, 0x4A);
2410  ret_val->keyname = NULL;
2411
2412  if(ret_val->name_length + REGFI_NK_MIN_LENGTH > ret_val->cell_size)
2413  {
2414    if(strict)
2415    {
2416      regfi_add_message(file, REGFI_MSG_ERROR, "Contents too large for cell"
2417                        " while parsing NK record at offset 0x%.8X.", offset);
2418      talloc_free(ret_val);
2419      return NULL;
2420    }
2421    else
2422      ret_val->name_length = ret_val->cell_size - REGFI_NK_MIN_LENGTH;
2423  }
2424  else if (unalloc)
2425  { /* Truncate cell_size if it's much larger than the apparent total record length. */
2426    /* Round up to the next multiple of 8 */
2427    length = (ret_val->name_length + REGFI_NK_MIN_LENGTH) & 0xFFFFFFF8;
2428    if(length < ret_val->name_length + REGFI_NK_MIN_LENGTH)
2429      length+=8;
2430
2431    /* If cell_size is still greater, truncate. */
2432    if(length < ret_val->cell_size)
2433      ret_val->cell_size = length;
2434  }
2435
2436  ret_val->keyname_raw = talloc_array(ret_val, uint8_t, ret_val->name_length);
2437  if(ret_val->keyname_raw == NULL)
2438  {
2439    talloc_free(ret_val);
2440    return NULL;
2441  }
2442
2443  /* Don't need to seek, should be at the right offset */
2444  length = ret_val->name_length;
2445  if((regfi_read(file->fd, (uint8_t*)ret_val->keyname_raw, &length) != 0)
2446     || length != ret_val->name_length)
2447  {
2448    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read key name"
2449                      " while parsing NK record at offset 0x%.8X.", offset);
2450    talloc_free(ret_val);
2451    return NULL;
2452  }
2453
2454  return ret_val;
2455}
2456
2457
2458uint8_t* regfi_parse_classname(REGFI_FILE* file, uint32_t offset, 
2459                             uint16_t* name_length, uint32_t max_size, bool strict)
2460{
2461  uint8_t* ret_val = NULL;
2462  uint32_t length;
2463  uint32_t cell_length;
2464  bool unalloc = false;
2465
2466  if(*name_length > 0 && offset != REGFI_OFFSET_NONE
2467     && (offset & 0x00000007) == 0)
2468  {
2469    if(!regfi_parse_cell(file->fd, offset, NULL, 0, &cell_length, &unalloc))
2470    {
2471      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell header"
2472                        " while parsing class name at offset 0x%.8X.", offset);
2473        return NULL;
2474    }
2475
2476    if((cell_length & 0x0000007) != 0)
2477    {
2478      regfi_add_message(file, REGFI_MSG_ERROR, "Cell length not a multiple of 8"
2479                        " while parsing class name at offset 0x%.8X.", offset);
2480      return NULL;
2481    }
2482
2483    if(cell_length > max_size)
2484    {
2485      regfi_add_message(file, REGFI_MSG_WARN, "Cell stretches past hbin "
2486                        "boundary while parsing class name at offset 0x%.8X.",
2487                        offset);
2488      if(strict)
2489        return NULL;
2490      cell_length = max_size;
2491    }
2492
2493    if((cell_length - 4) < *name_length)
2494    {
2495      regfi_add_message(file, REGFI_MSG_WARN, "Class name is larger than"
2496                        " cell_length while parsing class name at offset"
2497                        " 0x%.8X.", offset);
2498      if(strict)
2499        return NULL;
2500      *name_length = cell_length - 4;
2501    }
2502   
2503    ret_val = talloc_array(NULL, uint8_t, *name_length);
2504    if(ret_val != NULL)
2505    {
2506      length = *name_length;
2507      if((regfi_read(file->fd, ret_val, &length) != 0)
2508         || length != *name_length)
2509      {
2510        regfi_add_message(file, REGFI_MSG_ERROR, "Could not read class name"
2511                          " while parsing class name at offset 0x%.8X.", offset);
2512        talloc_free(ret_val);
2513        return NULL;
2514      }
2515    }
2516  }
2517
2518  return ret_val;
2519}
2520
2521
2522/******************************************************************************
2523*******************************************************************************/
2524REGFI_VK_REC* regfi_parse_vk(REGFI_FILE* file, uint32_t offset, 
2525                             uint32_t max_size, bool strict)
2526{
2527  REGFI_VK_REC* ret_val;
2528  uint8_t vk_header[REGFI_VK_MIN_LENGTH];
2529  uint32_t raw_data_size, length, cell_length;
2530  bool unalloc = false;
2531
2532  if(!regfi_parse_cell(file->fd, offset, vk_header, REGFI_VK_MIN_LENGTH,
2533                       &cell_length, &unalloc))
2534  {
2535    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell header"
2536                      " while parsing VK record at offset 0x%.8X.", offset);
2537    return NULL;
2538  }
2539
2540  ret_val = talloc(NULL, REGFI_VK_REC);
2541  if(ret_val == NULL)
2542    return NULL;
2543
2544  ret_val->offset = offset;
2545  ret_val->cell_size = cell_length;
2546  ret_val->data = NULL;
2547  ret_val->valuename = NULL;
2548  ret_val->valuename_raw = NULL;
2549 
2550  if(ret_val->cell_size > max_size)
2551    ret_val->cell_size = max_size & 0xFFFFFFF8;
2552  if((ret_val->cell_size < REGFI_VK_MIN_LENGTH) 
2553     || (ret_val->cell_size & 0x00000007) != 0)
2554  {
2555    regfi_add_message(file, REGFI_MSG_WARN, "Invalid cell size encountered"
2556                      " while parsing VK record at offset 0x%.8X.", offset);
2557    talloc_free(ret_val);
2558    return NULL;
2559  }
2560
2561  ret_val->magic[0] = vk_header[0x0];
2562  ret_val->magic[1] = vk_header[0x1];
2563  if((ret_val->magic[0] != 'v') || (ret_val->magic[1] != 'k'))
2564  {
2565    /* XXX: This does not account for deleted keys under Win2K which
2566     *      often have this (and the name length) overwritten with
2567     *      0xFFFF.
2568     */
2569    regfi_add_message(file, REGFI_MSG_WARN, "Magic number mismatch"
2570                      " while parsing VK record at offset 0x%.8X.", offset);
2571    talloc_free(ret_val);
2572    return NULL;
2573  }
2574
2575  ret_val->name_length = SVAL(vk_header, 0x2);
2576  raw_data_size = IVAL(vk_header, 0x4);
2577  ret_val->data_size = raw_data_size & ~REGFI_VK_DATA_IN_OFFSET;
2578  /* The data is typically stored in the offset if the size <= 4,
2579   * in which case this flag is set.
2580   */
2581  ret_val->data_in_offset = (bool)(raw_data_size & REGFI_VK_DATA_IN_OFFSET);
2582  ret_val->data_off = IVAL(vk_header, 0x8);
2583  ret_val->type = IVAL(vk_header, 0xC);
2584  ret_val->flags = SVAL(vk_header, 0x10);
2585  ret_val->unknown1 = SVAL(vk_header, 0x12);
2586
2587  if(ret_val->name_length > 0)
2588  {
2589    if(ret_val->name_length + REGFI_VK_MIN_LENGTH + 4 > ret_val->cell_size)
2590    {
2591      regfi_add_message(file, REGFI_MSG_WARN, "Name too long for remaining cell"
2592                        " space while parsing VK record at offset 0x%.8X.",
2593                        offset);
2594      if(strict)
2595      {
2596        talloc_free(ret_val);
2597        return NULL;
2598      }
2599      else
2600        ret_val->name_length = ret_val->cell_size - REGFI_VK_MIN_LENGTH - 4;
2601    }
2602
2603    /* Round up to the next multiple of 8 */
2604    cell_length = (ret_val->name_length + REGFI_VK_MIN_LENGTH + 4) & 0xFFFFFFF8;
2605    if(cell_length < ret_val->name_length + REGFI_VK_MIN_LENGTH + 4)
2606      cell_length+=8;
2607
2608    ret_val->valuename_raw = talloc_array(ret_val, uint8_t, ret_val->name_length);
2609    if(ret_val->valuename_raw == NULL)
2610    {
2611      talloc_free(ret_val);
2612      return NULL;
2613    }
2614
2615    length = ret_val->name_length;
2616    if((regfi_read(file->fd, (uint8_t*)ret_val->valuename_raw, &length) != 0)
2617       || length != ret_val->name_length)
2618    {
2619      regfi_add_message(file, REGFI_MSG_ERROR, "Could not read value name"
2620                        " while parsing VK record at offset 0x%.8X.", offset);
2621      talloc_free(ret_val);
2622      return NULL;
2623    }
2624  }
2625  else
2626    cell_length = REGFI_VK_MIN_LENGTH + 4;
2627
2628  if(unalloc)
2629  {
2630    /* If cell_size is still greater, truncate. */
2631    if(cell_length < ret_val->cell_size)
2632      ret_val->cell_size = cell_length;
2633  }
2634
2635  return ret_val;
2636}
2637
2638
2639/******************************************************************************
2640 *
2641 ******************************************************************************/
2642REGFI_BUFFER regfi_load_data(REGFI_FILE* file, uint32_t voffset,
2643                             uint32_t length, bool data_in_offset,
2644                             bool strict)
2645{
2646  REGFI_BUFFER ret_val;
2647  uint32_t cell_length, offset;
2648  int32_t max_size;
2649  bool unalloc;
2650 
2651  /* Microsoft's documentation indicates that "available memory" is
2652   * the limit on value sizes for the more recent registry format version.
2653   * This is not only annoying, but it's probably also incorrect, since clearly
2654   * value data sizes are limited to 2^31 (high bit used as a flag) and even
2655   * with big data records, the apparent max size is:
2656   *   16344 * 2^16 = 1071104040 (~1GB).
2657   *
2658   * We choose to limit it to 1M which was the limit in older versions and
2659   * should rarely be exceeded unless the file is corrupt or malicious.
2660   * For more info, see:
2661   *   http://msdn.microsoft.com/en-us/library/ms724872%28VS.85%29.aspx
2662   */
2663  /* XXX: add way to skip this check at user discression. */
2664  if(length > REGFI_VK_MAX_DATA_LENGTH)
2665  {
2666    regfi_add_message(file, REGFI_MSG_WARN, "Value data size %d larger than "
2667                      "%d, truncating...", length, REGFI_VK_MAX_DATA_LENGTH);
2668    length = REGFI_VK_MAX_DATA_LENGTH;
2669  }
2670
2671  if(data_in_offset)
2672    return regfi_parse_little_data(file, voffset, length, strict);
2673  else
2674  {
2675    offset = voffset + REGFI_REGF_SIZE;
2676    max_size = regfi_calc_maxsize(file, offset);
2677    if(max_size < 0)
2678    {
2679      regfi_add_message(file, REGFI_MSG_WARN, "Could not find HBIN for data"
2680                        " at offset 0x%.8X.", offset);
2681      goto fail;
2682    }
2683   
2684    if(!regfi_parse_cell(file->fd, offset, NULL, 0,
2685                         &cell_length, &unalloc))
2686    {
2687      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
2688                        " parsing data record at offset 0x%.8X.", offset);
2689      goto fail;
2690    }
2691
2692    if((cell_length & 0x00000007) != 0)
2693    {
2694      regfi_add_message(file, REGFI_MSG_WARN, "Cell length not multiple of 8"
2695                        " while parsing data record at offset 0x%.8X.",
2696                        offset);
2697      goto fail;
2698    }
2699
2700    if(cell_length > max_size)
2701    {
2702      regfi_add_message(file, REGFI_MSG_WARN, "Cell extends past HBIN boundary"
2703                        " while parsing data record at offset 0x%.8X.",
2704                        offset);
2705      goto fail;
2706    }
2707
2708    if(cell_length - 4 < length)
2709    {
2710      /* XXX: All big data records thus far have been 16 bytes long. 
2711       *      Should we check for this precise size instead of just
2712       *      relying upon the above check?
2713       */
2714      if (file->major_version >= 1 && file->minor_version >= 5)
2715      {
2716        /* Attempt to parse a big data record */
2717        return regfi_load_big_data(file, offset, length, cell_length, 
2718                                   NULL, strict);
2719      }
2720      else
2721      {
2722        regfi_add_message(file, REGFI_MSG_WARN, "Data length (0x%.8X) larger than"
2723                          " remaining cell length (0x%.8X)"
2724                          " while parsing data record at offset 0x%.8X.", 
2725                          length, cell_length - 4, offset);
2726        if(strict)
2727          goto fail;
2728        else
2729          length = cell_length - 4;
2730      }
2731    }
2732
2733    ret_val = regfi_parse_data(file, offset, length, strict);
2734  }
2735
2736  return ret_val;
2737
2738 fail:
2739  ret_val.buf = NULL;
2740  ret_val.len = 0;
2741  return ret_val;
2742}
2743
2744
2745/******************************************************************************
2746 * Parses the common case data records stored in a single cell.
2747 ******************************************************************************/
2748REGFI_BUFFER regfi_parse_data(REGFI_FILE* file, uint32_t offset,
2749                              uint32_t length, bool strict)
2750{
2751  REGFI_BUFFER ret_val;
2752  uint32_t read_length;
2753
2754  ret_val.buf = NULL;
2755  ret_val.len = 0;
2756 
2757  if(lseek(file->fd, offset+4, SEEK_SET) == -1)
2758  {
2759    regfi_add_message(file, REGFI_MSG_WARN, "Could not seek while "
2760                      "reading data at offset 0x%.8X.", offset);
2761    return ret_val;
2762  }
2763
2764  if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL)
2765    return ret_val;
2766  ret_val.len = length;
2767 
2768  read_length = length;
2769  if((regfi_read(file->fd, ret_val.buf, &read_length) != 0)
2770     || read_length != length)
2771  {
2772    regfi_add_message(file, REGFI_MSG_ERROR, "Could not read data block while"
2773                      " parsing data record at offset 0x%.8X.", offset);
2774    talloc_free(ret_val.buf);
2775    ret_val.buf = NULL;
2776    ret_val.buf = 0;
2777  }
2778
2779  return ret_val;
2780}
2781
2782
2783
2784/******************************************************************************
2785 *
2786 ******************************************************************************/
2787REGFI_BUFFER regfi_parse_little_data(REGFI_FILE* file, uint32_t voffset,
2788                                     uint32_t length, bool strict)
2789{
2790  REGFI_BUFFER ret_val;
2791  uint8_t i;
2792
2793  ret_val.buf = NULL;
2794  ret_val.len = 0;
2795
2796  if(length > 4)
2797  {
2798    regfi_add_message(file, REGFI_MSG_ERROR, "Data in offset but length > 4"
2799                      " while parsing data record. (voffset=0x%.8X, length=%d)",
2800                      voffset, length);
2801    return ret_val;
2802  }
2803
2804  if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL)
2805    return ret_val;
2806  ret_val.len = length;
2807 
2808  for(i = 0; i < length; i++)
2809    ret_val.buf[i] = (uint8_t)((voffset >> i*8) & 0xFF);
2810
2811  return ret_val;
2812}
2813
2814/******************************************************************************
2815*******************************************************************************/
2816REGFI_BUFFER regfi_parse_big_data_header(REGFI_FILE* file, uint32_t offset, 
2817                                         uint32_t max_size, bool strict)
2818{
2819  REGFI_BUFFER ret_val;
2820  uint32_t cell_length;
2821  bool unalloc;
2822
2823  /* XXX: do something with unalloc? */
2824  ret_val.buf = (uint8_t*)talloc_array(NULL, uint8_t, REGFI_BIG_DATA_MIN_LENGTH);
2825  if(ret_val.buf == NULL)
2826    goto fail;
2827
2828  if(REGFI_BIG_DATA_MIN_LENGTH > max_size)
2829  {
2830    regfi_add_message(file, REGFI_MSG_WARN, "Big data header exceeded max_size "
2831                      "while parsing big data header at offset 0x%.8X.",offset);
2832    goto fail;
2833  }
2834
2835  if(!regfi_parse_cell(file->fd, offset, ret_val.buf, REGFI_BIG_DATA_MIN_LENGTH,
2836                       &cell_length, &unalloc))
2837  {
2838    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
2839                      " parsing big data header at offset 0x%.8X.", offset);
2840    goto fail;
2841  }
2842
2843  if((ret_val.buf[0] != 'd') || (ret_val.buf[1] != 'b'))
2844  {
2845    regfi_add_message(file, REGFI_MSG_WARN, "Unknown magic number"
2846                      " (0x%.2X, 0x%.2X) encountered while parsing"
2847                      " big data header at offset 0x%.8X.", 
2848                      ret_val.buf[0], ret_val.buf[1], offset);
2849    goto fail;
2850  }
2851
2852  ret_val.len = REGFI_BIG_DATA_MIN_LENGTH;
2853  return ret_val;
2854
2855 fail:
2856  if(ret_val.buf != NULL)
2857  {
2858    talloc_free(ret_val.buf);
2859    ret_val.buf = NULL;
2860  }
2861  ret_val.len = 0;
2862  return ret_val;
2863}
2864
2865
2866
2867/******************************************************************************
2868 *
2869 ******************************************************************************/
2870uint32_t* regfi_parse_big_data_indirect(REGFI_FILE* file, uint32_t offset,
2871                                      uint16_t num_chunks, bool strict)
2872{
2873  uint32_t* ret_val;
2874  uint32_t indirect_length;
2875  int32_t max_size;
2876  uint16_t i;
2877  bool unalloc;
2878
2879  /* XXX: do something with unalloc? */
2880
2881  max_size = regfi_calc_maxsize(file, offset);
2882  if((max_size < 0) || (num_chunks*sizeof(uint32_t) + 4 > max_size))
2883    return NULL;
2884
2885  ret_val = (uint32_t*)talloc_array(NULL, uint32_t, num_chunks);
2886  if(ret_val == NULL)
2887    goto fail;
2888
2889  if(!regfi_parse_cell(file->fd, offset, (uint8_t*)ret_val,
2890                       num_chunks*sizeof(uint32_t),
2891                       &indirect_length, &unalloc))
2892  {
2893    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
2894                      " parsing big data indirect record at offset 0x%.8X.", 
2895                      offset);
2896    goto fail;
2897  }
2898
2899  /* Convert pointers to proper endianess, verify they are aligned. */
2900  for(i=0; i<num_chunks; i++)
2901  {
2902    ret_val[i] = IVAL(ret_val, i*sizeof(uint32_t));
2903    if((ret_val[i] & 0x00000007) != 0)
2904      goto fail;
2905  }
2906 
2907  return ret_val;
2908
2909 fail:
2910  if(ret_val != NULL)
2911    talloc_free(ret_val);
2912  return NULL;
2913}
2914
2915
2916/******************************************************************************
2917 * Arguments:
2918 *  file       --
2919 *  offsets    -- list of virtual offsets.
2920 *  num_chunks --
2921 *  strict     --
2922 *
2923 * Returns:
2924 *  A range_list with physical offsets and complete lengths
2925 *  (including cell headers) of associated cells. 
2926 *  No data in range_list elements.
2927 ******************************************************************************/
2928range_list* regfi_parse_big_data_cells(REGFI_FILE* file, uint32_t* offsets,
2929                                       uint16_t num_chunks, bool strict)
2930{
2931  uint32_t cell_length, chunk_offset;
2932  range_list* ret_val;
2933  uint16_t i;
2934  bool unalloc;
2935 
2936  /* XXX: do something with unalloc? */
2937  ret_val = range_list_new();
2938  if(ret_val == NULL)
2939    goto fail;
2940 
2941  for(i=0; i<num_chunks; i++)
2942  {
2943    chunk_offset = offsets[i]+REGFI_REGF_SIZE;
2944    if(!regfi_parse_cell(file->fd, chunk_offset, NULL, 0,
2945                         &cell_length, &unalloc))
2946    {
2947      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
2948                        " parsing big data chunk at offset 0x%.8X.", 
2949                        chunk_offset);
2950      goto fail;
2951    }
2952
2953    if(!range_list_add(ret_val, chunk_offset, cell_length, NULL))
2954      goto fail;
2955  }
2956
2957  return ret_val;
2958
2959 fail:
2960  if(ret_val != NULL)
2961    range_list_free(ret_val);
2962  return NULL;
2963}
2964
2965
2966/******************************************************************************
2967*******************************************************************************/
2968REGFI_BUFFER regfi_load_big_data(REGFI_FILE* file, 
2969                                 uint32_t offset, uint32_t data_length, 
2970                                 uint32_t cell_length, range_list* used_ranges,
2971                                 bool strict)
2972{
2973  REGFI_BUFFER ret_val;
2974  uint16_t num_chunks, i;
2975  uint32_t read_length, data_left, tmp_len, indirect_offset;
2976  uint32_t* indirect_ptrs = NULL;
2977  REGFI_BUFFER bd_header;
2978  range_list* bd_cells = NULL;
2979  const range_list_element* cell_info;
2980
2981  ret_val.buf = NULL;
2982
2983  /* XXX: Add better error/warning messages */
2984
2985  bd_header = regfi_parse_big_data_header(file, offset, cell_length, strict);
2986  if(bd_header.buf == NULL)
2987    goto fail;
2988
2989  /* Keep track of used space for use by reglookup-recover */
2990  if(used_ranges != NULL)
2991    if(!range_list_add(used_ranges, offset, cell_length, NULL))
2992      goto fail;
2993
2994  num_chunks = SVAL(bd_header.buf, 0x2);
2995  indirect_offset = IVAL(bd_header.buf, 0x4) + REGFI_REGF_SIZE;
2996  talloc_free(bd_header.buf);
2997
2998  indirect_ptrs = regfi_parse_big_data_indirect(file, indirect_offset,
2999                                                num_chunks, strict);
3000  if(indirect_ptrs == NULL)
3001    goto fail;
3002
3003  if(used_ranges != NULL)
3004    if(!range_list_add(used_ranges, indirect_offset, num_chunks*4+4, NULL))
3005      goto fail;
3006 
3007  if((ret_val.buf = talloc_array(NULL, uint8_t, data_length)) == NULL)
3008    goto fail;
3009  data_left = data_length;
3010
3011  bd_cells = regfi_parse_big_data_cells(file, indirect_ptrs, num_chunks, strict);
3012  if(bd_cells == NULL)
3013    goto fail;
3014
3015  talloc_free(indirect_ptrs);
3016  indirect_ptrs = NULL;
3017 
3018  for(i=0; (i<num_chunks) && (data_left>0); i++)
3019  {
3020    cell_info = range_list_get(bd_cells, i);
3021    if(cell_info == NULL)
3022      goto fail;
3023
3024    /* XXX: This should be "cell_info->length-4" to account for the 4 byte cell
3025     *      length.  However, it has been observed that some (all?) chunks
3026     *      have an additional 4 bytes of 0 at the end of their cells that
3027     *      isn't part of the data, so we're trimming that off too.
3028     *      Perhaps it's just an 8 byte alignment requirement...
3029     */
3030    if(cell_info->length - 8 >= data_left)
3031    {
3032      if(i+1 != num_chunks)
3033      {
3034        regfi_add_message(file, REGFI_MSG_WARN, "Left over chunks detected "
3035                          "while constructing big data at offset 0x%.8X "
3036                          "(chunk offset 0x%.8X).", offset, cell_info->offset);
3037      }
3038      read_length = data_left;
3039    }
3040    else
3041      read_length = cell_info->length - 8;
3042
3043
3044    if(read_length > regfi_calc_maxsize(file, cell_info->offset))
3045    {
3046      regfi_add_message(file, REGFI_MSG_WARN, "A chunk exceeded the maxsize "
3047                        "while constructing big data at offset 0x%.8X "
3048                        "(chunk offset 0x%.8X).", offset, cell_info->offset);
3049      goto fail;
3050    }
3051
3052    if(lseek(file->fd, cell_info->offset+sizeof(uint32_t), SEEK_SET) == -1)
3053    {
3054      regfi_add_message(file, REGFI_MSG_WARN, "Could not seek to chunk while "
3055                        "constructing big data at offset 0x%.8X "
3056                        "(chunk offset 0x%.8X).", offset, cell_info->offset);
3057      goto fail;
3058    }
3059
3060    tmp_len = read_length;
3061    if(regfi_read(file->fd, ret_val.buf+(data_length-data_left), 
3062                  &read_length) != 0 || (read_length != tmp_len))
3063    {
3064      regfi_add_message(file, REGFI_MSG_WARN, "Could not read data chunk while"
3065                        " constructing big data at offset 0x%.8X"
3066                        " (chunk offset 0x%.8X).", offset, cell_info->offset);
3067      goto fail;
3068    }
3069
3070    if(used_ranges != NULL)
3071      if(!range_list_add(used_ranges, cell_info->offset,cell_info->length,NULL))
3072        goto fail;
3073
3074    data_left -= read_length;
3075  }
3076  range_list_free(bd_cells);
3077
3078  ret_val.len = data_length-data_left;
3079  return ret_val;
3080
3081 fail:
3082  if(ret_val.buf != NULL)
3083    talloc_free(ret_val.buf);
3084  if(indirect_ptrs != NULL)
3085    talloc_free(indirect_ptrs);
3086  if(bd_cells != NULL)
3087    range_list_free(bd_cells);
3088  ret_val.buf = NULL;
3089  ret_val.len = 0;
3090  return ret_val;
3091}
3092
3093
3094range_list* regfi_parse_unalloc_cells(REGFI_FILE* file)
3095{
3096  range_list* ret_val;
3097  REGFI_HBIN* hbin;
3098  const range_list_element* hbins_elem;
3099  uint32_t i, num_hbins, curr_off, cell_len;
3100  bool is_unalloc;
3101
3102  ret_val = range_list_new();
3103  if(ret_val == NULL)
3104    return NULL;
3105
3106  num_hbins = range_list_size(file->hbins);
3107  for(i=0; i<num_hbins; i++)
3108  {
3109    hbins_elem = range_list_get(file->hbins, i);
3110    if(hbins_elem == NULL)
3111      break;
3112    hbin = (REGFI_HBIN*)hbins_elem->data;
3113
3114    curr_off = REGFI_HBIN_HEADER_SIZE;
3115    while(curr_off < hbin->block_size)
3116    {
3117      if(!regfi_parse_cell(file->fd, hbin->file_off+curr_off, NULL, 0,
3118                           &cell_len, &is_unalloc))
3119        break;
3120     
3121      if((cell_len == 0) || ((cell_len & 0x00000007) != 0))
3122      {
3123        regfi_add_message(file, REGFI_MSG_ERROR, "Bad cell length encountered"
3124                          " while parsing unallocated cells at offset 0x%.8X.",
3125                          hbin->file_off+curr_off);
3126        break;
3127      }
3128
3129      /* for some reason the record_size of the last record in
3130         an hbin block can extend past the end of the block
3131         even though the record fits within the remaining
3132         space....aaarrrgggghhhhhh */ 
3133      if(curr_off + cell_len >= hbin->block_size)
3134        cell_len = hbin->block_size - curr_off;
3135     
3136      if(is_unalloc)
3137        range_list_add(ret_val, hbin->file_off+curr_off, 
3138                       cell_len, NULL);
3139     
3140      curr_off = curr_off+cell_len;
3141    }
3142  }
3143
3144  return ret_val;
3145}
3146
3147
3148/* From lib/time.c */
3149
3150/****************************************************************************
3151 Put a 8 byte filetime from a time_t
3152 This takes real GMT as input and converts to kludge-GMT
3153****************************************************************************/
3154void regfi_unix2nt_time(REGFI_NTTIME *nt, time_t t)
3155{
3156  double d;
3157 
3158  if (t==0) 
3159  {
3160    nt->low = 0;
3161    nt->high = 0;
3162    return;
3163  }
3164 
3165  if (t == TIME_T_MAX) 
3166  {
3167    nt->low = 0xffffffff;
3168    nt->high = 0x7fffffff;
3169    return;
3170  }             
3171 
3172  if (t == -1) 
3173  {
3174    nt->low = 0xffffffff;
3175    nt->high = 0xffffffff;
3176    return;
3177  }             
3178 
3179  /* this converts GMT to kludge-GMT */
3180  /* XXX: This was removed due to difficult dependency requirements. 
3181   *      So far, times appear to be correct without this adjustment, but
3182   *      that may be proven wrong with adequate testing.
3183   */
3184  /* t -= TimeDiff(t) - get_serverzone(); */
3185 
3186  d = (double)(t);
3187  d += TIME_FIXUP_CONSTANT;
3188  d *= 1.0e7;
3189 
3190  nt->high = (uint32_t)(d * (1.0/(4.0*(double)(1<<30))));
3191  nt->low  = (uint32_t)(d - ((double)nt->high)*4.0*(double)(1<<30));
3192}
3193
3194
3195/****************************************************************************
3196 Interpret an 8 byte "filetime" structure to a time_t
3197 It's originally in "100ns units since jan 1st 1601"
3198
3199 An 8 byte value of 0xffffffffffffffff will be returned as (time_t)0.
3200
3201 It appears to be kludge-GMT (at least for file listings). This means
3202 its the GMT you get by taking a localtime and adding the
3203 serverzone. This is NOT the same as GMT in some cases. This routine
3204 converts this to real GMT.
3205****************************************************************************/
3206time_t regfi_nt2unix_time(const REGFI_NTTIME* nt)
3207{
3208  double d;
3209  time_t ret;
3210  /* The next two lines are a fix needed for the
3211     broken SCO compiler. JRA. */
3212  time_t l_time_min = TIME_T_MIN;
3213  time_t l_time_max = TIME_T_MAX;
3214 
3215  if (nt->high == 0 || (nt->high == 0xffffffff && nt->low == 0xffffffff))
3216    return(0);
3217 
3218  d = ((double)nt->high)*4.0*(double)(1<<30);
3219  d += (nt->low&0xFFF00000);
3220  d *= 1.0e-7;
3221 
3222  /* now adjust by 369 years to make the secs since 1970 */
3223  d -= TIME_FIXUP_CONSTANT;
3224 
3225  if (d <= l_time_min)
3226    return (l_time_min);
3227 
3228  if (d >= l_time_max)
3229    return (l_time_max);
3230 
3231  ret = (time_t)(d+0.5);
3232 
3233  /* this takes us from kludge-GMT to real GMT */
3234  /* XXX: This was removed due to difficult dependency requirements. 
3235   *      So far, times appear to be correct without this adjustment, but
3236   *      that may be proven wrong with adequate testing.
3237   */
3238  /*
3239    ret -= get_serverzone();
3240    ret += LocTimeDiff(ret);
3241  */
3242
3243  return(ret);
3244}
3245
3246/* End of stuff from lib/time.c */
Note: See TracBrowser for help on using the repository browser.