source: trunk/lib/regfi.c @ 159

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

began rearranging data parsing. Moved charater set conversion and basic parsing logic into regfi

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