source: trunk/lib/regfi.c @ 138

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

extended error message logging to allow for message type filtering

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

updated related documentation

  • Property svn:keywords set to Id
File size: 59.2 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 138 2009-02-08 19:53:48Z tim $
24 */
25
26#include "../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  /* XXX: what was this old VI flag for??
204     XXX: Is this check right?  0xF == 1|2|4|8, which makes it redundant...
205  if (flags == 0xF) {
206    if (some) strcat(flg_output, " ");
207    some = 1;
208    strcat(flg_output, "VI");
209  }
210  */
211
212  return ret_val;
213}
214
215
216char* regfi_ace_perms2str(uint32 perms)
217{
218  uint32 i, p;
219  /* This is more than is needed by a fair margin. */
220  char* ret_val = malloc(350*sizeof(char));
221  char* r = ret_val;
222
223  /* Each represents one of 32 permissions bits.  NULL is for undefined/reserved bits.
224   * For more information, see:
225   *   http://msdn2.microsoft.com/en-gb/library/aa374892.aspx
226   *   http://msdn2.microsoft.com/en-gb/library/ms724878.aspx
227   */
228  static const char* perm_map[32] = 
229    {/* object-specific permissions (registry keys, in this case) */
230      "QRY_VAL",       /* KEY_QUERY_VALUE */
231      "SET_VAL",       /* KEY_SET_VALUE */
232      "CREATE_KEY",    /* KEY_CREATE_SUB_KEY */
233      "ENUM_KEYS",     /* KEY_ENUMERATE_SUB_KEYS */
234      "NOTIFY",        /* KEY_NOTIFY */
235      "CREATE_LNK",    /* KEY_CREATE_LINK - Reserved for system use. */
236      NULL,
237      NULL,
238      "WOW64_64",      /* KEY_WOW64_64KEY */
239      "WOW64_32",      /* KEY_WOW64_32KEY */
240      NULL,
241      NULL,
242      NULL,
243      NULL,
244      NULL,
245      NULL,
246      /* standard access rights */
247      "DELETE",        /* DELETE */
248      "R_CONT",        /* READ_CONTROL */
249      "W_DAC",         /* WRITE_DAC */
250      "W_OWNER",       /* WRITE_OWNER */
251      "SYNC",          /* SYNCHRONIZE - Shouldn't be set in registries */
252      NULL,
253      NULL,
254      NULL,
255      /* other generic */
256      "SYS_SEC",       /* ACCESS_SYSTEM_SECURITY */
257      "MAX_ALLWD",     /* MAXIMUM_ALLOWED */
258      NULL,
259      NULL,
260      "GEN_A",         /* GENERIC_ALL */
261      "GEN_X",         /* GENERIC_EXECUTE */
262      "GEN_W",         /* GENERIC_WRITE */
263      "GEN_R",         /* GENERIC_READ */
264    };
265
266
267  if(ret_val == NULL)
268    return NULL;
269
270  r[0] = '\0';
271  for(i=0; i < 32; i++)
272  {
273    p = (1<<i);
274    if((perms & p) && (perm_map[i] != NULL))
275    {
276      strcpy(r, perm_map[i]);
277      r += strlen(perm_map[i]);
278      *(r++) = ' ';
279      perms ^= p;
280    }
281  }
282 
283  /* Any remaining unknown permission bits are added at the end in hex. */
284  if(perms != 0)
285    sprintf(r, "0x%.8X ", perms);
286
287  /* Chop off the last space if we've written anything to ret_val */
288  if(r != ret_val)
289    r[-1] = '\0';
290
291  return ret_val;
292}
293
294
295char* regfi_sid2str(WINSEC_DOM_SID* sid)
296{
297  uint32 i, size = WINSEC_MAX_SUBAUTHS*11 + 24;
298  uint32 left = size;
299  uint8 comps = sid->num_auths;
300  char* ret_val = malloc(size);
301 
302  if(ret_val == NULL)
303    return NULL;
304
305  if(comps > WINSEC_MAX_SUBAUTHS)
306    comps = WINSEC_MAX_SUBAUTHS;
307
308  left -= sprintf(ret_val, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
309
310  for (i = 0; i < comps; i++) 
311    left -= snprintf(ret_val+(size-left), left, "-%u", sid->sub_auths[i]);
312
313  return ret_val;
314}
315
316
317char* regfi_get_acl(WINSEC_ACL* acl)
318{
319  uint32 i, extra, size = 0;
320  const char* type_str;
321  char* flags_str;
322  char* perms_str;
323  char* sid_str;
324  char* ace_delim = "";
325  char* ret_val = NULL;
326  char* tmp_val = NULL;
327  bool failed = false;
328  char field_delim = ':';
329
330  for (i = 0; i < acl->num_aces && !failed; i++)
331  {
332    sid_str = regfi_sid2str(acl->aces[i]->trustee);
333    type_str = regfi_ace_type2str(acl->aces[i]->type);
334    perms_str = regfi_ace_perms2str(acl->aces[i]->access_mask);
335    flags_str = regfi_ace_flags2str(acl->aces[i]->flags);
336   
337    if(flags_str != NULL && perms_str != NULL 
338       && type_str != NULL && sid_str != NULL)
339    {
340      /* XXX: this is slow */
341      extra = strlen(sid_str) + strlen(type_str) 
342        + strlen(perms_str) + strlen(flags_str) + 5;
343      tmp_val = realloc(ret_val, size+extra);
344
345      if(tmp_val == NULL)
346      {
347        free(ret_val);
348        ret_val = NULL;
349        failed = true;
350      }
351      else
352      {
353        ret_val = tmp_val;
354        size += snprintf(ret_val+size, extra, "%s%s%c%s%c%s%c%s",
355                         ace_delim,sid_str,
356                         field_delim,type_str,
357                         field_delim,perms_str,
358                         field_delim,flags_str);
359        ace_delim = "|";
360      }
361    }
362    else
363      failed = true;
364
365    if(sid_str != NULL)
366      free(sid_str);
367    if(sid_str != NULL)
368      free(perms_str);
369    if(sid_str != NULL)
370      free(flags_str);
371  }
372
373  return ret_val;
374}
375
376
377char* regfi_get_sacl(WINSEC_DESC *sec_desc)
378{
379  if (sec_desc->sacl)
380    return regfi_get_acl(sec_desc->sacl);
381  else
382    return NULL;
383}
384
385
386char* regfi_get_dacl(WINSEC_DESC *sec_desc)
387{
388  if (sec_desc->dacl)
389    return regfi_get_acl(sec_desc->dacl);
390  else
391    return NULL;
392}
393
394
395char* regfi_get_owner(WINSEC_DESC *sec_desc)
396{
397  return regfi_sid2str(sec_desc->owner_sid);
398}
399
400
401char* regfi_get_group(WINSEC_DESC *sec_desc)
402{
403  return regfi_sid2str(sec_desc->grp_sid);
404}
405
406
407/*****************************************************************************
408 * This function is just like read(2), except that it continues to
409 * re-try reading from the file descriptor if EINTR or EAGAIN is received. 
410 * regfi_read will attempt to read length bytes from fd and write them to buf.
411 *
412 * On success, 0 is returned.  Upon failure, an errno code is returned.
413 *
414 * The number of bytes successfully read is returned through the length
415 * parameter by reference.  If both the return value and length parameter are
416 * returned as 0, then EOF was encountered immediately
417 *****************************************************************************/
418uint32 regfi_read(int fd, uint8* buf, uint32* length)
419{
420  uint32 rsize = 0;
421  uint32 rret = 0;
422
423  do
424  {
425    rret = read(fd, buf + rsize, *length - rsize);
426    if(rret > 0)
427      rsize += rret;
428  }while(*length - rsize > 0 
429         && (rret > 0 || (rret == -1 && (errno == EAGAIN || errno == EINTR))));
430 
431  *length = rsize;
432  if (rret == -1 && errno != EINTR && errno != EAGAIN)
433    return errno;
434
435  return 0;
436}
437
438
439/*****************************************************************************
440 *
441 *****************************************************************************/
442bool regfi_parse_cell(int fd, uint32 offset, uint8* hdr, uint32 hdr_len,
443                      uint32* cell_length, bool* unalloc)
444{
445  uint32 length;
446  int32 raw_length;
447  uint8 tmp[4];
448
449  if(lseek(fd, offset, SEEK_SET) == -1)
450    return false;
451
452  length = 4;
453  if((regfi_read(fd, tmp, &length) != 0) || length != 4)
454    return false;
455  raw_length = IVALS(tmp, 0);
456
457  if(raw_length < 0)
458  {
459    (*cell_length) = raw_length*(-1);
460    (*unalloc) = false;
461  }
462  else
463  {
464    (*cell_length) = raw_length;
465    (*unalloc) = true;
466  }
467
468  if(*cell_length - 4 < hdr_len)
469    return false;
470
471  if(hdr_len > 0)
472  {
473    length = hdr_len;
474    if((regfi_read(fd, hdr, &length) != 0) || length != hdr_len)
475      return false;
476  }
477
478  return true;
479}
480
481
482/*******************************************************************
483 * Given an offset and an hbin, is the offset within that hbin?
484 * The offset is a virtual file offset.
485 *******************************************************************/
486static bool regfi_offset_in_hbin(REGFI_HBIN* hbin, uint32 offset)
487{
488  if(!hbin)
489    return false;
490
491  if((offset > hbin->first_hbin_off) 
492     && (offset < (hbin->first_hbin_off + hbin->block_size)))
493    return true;
494               
495  return false;
496}
497
498
499
500/*******************************************************************
501 * Provide a virtual offset and receive the correpsonding HBIN
502 * block for it.  NULL if one doesn't exist.
503 *******************************************************************/
504REGFI_HBIN* regfi_lookup_hbin(REGFI_FILE* file, uint32 offset)
505{
506  return (REGFI_HBIN*)range_list_find_data(file->hbins, offset+REGFI_REGF_SIZE);
507}
508
509
510/*******************************************************************
511 *******************************************************************/
512REGFI_SUBKEY_LIST* regfi_merge_subkeylists(uint16 num_lists, 
513                                          REGFI_SUBKEY_LIST** lists,
514                                          bool strict)
515{
516  uint32 i,j,k;
517  REGFI_SUBKEY_LIST* ret_val;
518
519  if(lists == NULL)
520    return NULL;
521  ret_val = (REGFI_SUBKEY_LIST*)zalloc(sizeof(REGFI_SUBKEY_LIST));
522
523  if(ret_val == NULL)
524    return NULL;
525 
526  /* Obtain total number of elements */
527  ret_val->num_keys = 0;
528  for(i=0; i < num_lists; i++)
529  {
530    if(lists[i] == NULL)
531    {
532      free(ret_val);
533      free(lists);
534      return NULL;
535    }
536    ret_val->num_keys += lists[i]->num_keys;
537  }
538 
539  if(ret_val->num_keys > 0)
540  {
541    ret_val->elements = 
542      (REGFI_SUBKEY_LIST_ELEM*)zalloc(sizeof(REGFI_SUBKEY_LIST_ELEM)
543                                     * ret_val->num_keys);
544    k=0;
545
546    if(ret_val->elements != NULL)
547    {
548      for(i=0; i<num_lists; i++)
549        for(j=0; j<lists[i]->num_keys; j++)
550        {
551          ret_val->elements[k].hash=lists[i]->elements[j].hash;
552          ret_val->elements[k++].nk_off=lists[i]->elements[j].nk_off;
553        }
554    }
555  }
556 
557  for(i=0; i < num_lists; i++)
558    regfi_subkeylist_free(lists[i]);
559  free(lists);
560
561  return ret_val;
562}
563
564
565
566/*******************************************************************
567 *******************************************************************/
568REGFI_SUBKEY_LIST* regfi_load_subkeylist(REGFI_FILE* file, uint32 offset, 
569                                        uint32 num_keys, uint32 max_size, 
570                                        bool strict)
571{
572  REGFI_SUBKEY_LIST* ret_val;
573  REGFI_SUBKEY_LIST** sublists;
574  REGFI_HBIN* sublist_hbin;
575  uint32 i, cell_length, length, num_sublists, off, max_length, elem_size;
576  uint8* hashes;
577  uint8 buf[REGFI_SUBKEY_LIST_MIN_LEN];
578  bool unalloc;
579
580  if(!regfi_parse_cell(file->fd, offset, buf, REGFI_SUBKEY_LIST_MIN_LEN, 
581                       &cell_length, &unalloc))
582    return NULL;
583
584  if(cell_length > max_size)
585  {
586    if(strict)
587      return NULL;
588    cell_length = max_size & 0xFFFFFFF8;
589  }
590
591  if(buf[0] == 'r' && buf[1] == 'i')
592  {
593    num_sublists = SVAL(buf, 0x2);
594
595    /* XXX: check cell_length vs num_sublists vs max_length */
596    length = num_sublists*sizeof(uint32);
597    hashes = (uint8*)zalloc(length);
598    if(hashes == NULL)
599      return NULL;
600
601    if(regfi_read(file->fd, hashes, &length) != 0
602       || length != num_sublists*sizeof(uint32))
603    { 
604      free(hashes);
605      return NULL; 
606    }
607
608    sublists = (REGFI_SUBKEY_LIST**)zalloc(num_sublists*sizeof(REGFI_SUBKEY_LIST*));   
609    for(i=0; i < num_sublists; i++)
610    {
611      off = IVAL(hashes, i*4)+REGFI_REGF_SIZE;
612      sublist_hbin = regfi_lookup_hbin(file, IVAL(hashes, i*4));
613      max_length = sublist_hbin->block_size + sublist_hbin->file_off - off;
614
615      /* XXX: Need to add a recursion depth limit of some kind. */
616      sublists[i] = regfi_load_subkeylist(file, off, 0, max_length, strict);
617    }
618    free(hashes);
619
620    return regfi_merge_subkeylists(num_sublists, sublists, strict);
621  }
622
623  if(buf[0] == 'l' && buf[1] == 'i')
624    elem_size = sizeof(uint32);
625  else if((buf[0] == 'l') && (buf[1] == 'f' || buf[1] == 'h'))
626    elem_size = sizeof(REGFI_SUBKEY_LIST_ELEM);
627  else
628  {
629    /* fprintf(stderr, "DEBUG: lf->header=%c%c\n", buf[0], buf[1]);*/
630    return NULL;
631  }
632
633  ret_val = (REGFI_SUBKEY_LIST*)zalloc(sizeof(REGFI_SUBKEY_LIST));
634  if(ret_val == NULL)
635    return NULL;
636
637  ret_val->offset = offset;
638  ret_val->cell_size = cell_length;
639  ret_val->magic[0] = buf[0];
640  ret_val->magic[1] = buf[1];
641
642  ret_val->num_keys = SVAL(buf, 0x2);
643  if(num_keys != ret_val->num_keys)
644  {
645    /*  Not sure which should be authoritative, the number from the
646     *  NK record, or the number in the subkey list.  Go with the larger
647     *  of the two to ensure all keys are found, since in 'ri' records,
648     *  there is no authoritative parent count for a leaf subkey list. 
649     *  Note the length checks on the cell later ensure that there won't
650     *  be any critical errors.
651     */
652    if(num_keys < ret_val->num_keys)
653      num_keys = ret_val->num_keys;
654    else
655      ret_val->num_keys = num_keys;
656  }
657
658  if(cell_length - REGFI_SUBKEY_LIST_MIN_LEN - sizeof(uint32) 
659     < ret_val->num_keys*elem_size)
660  {
661    free(ret_val);
662    return NULL;
663  }
664
665  length = elem_size*ret_val->num_keys;
666  ret_val->elements
667    = (REGFI_SUBKEY_LIST_ELEM*)zalloc(ret_val->num_keys
668                                     * sizeof(REGFI_SUBKEY_LIST_ELEM));
669  if(ret_val->elements == NULL)
670  {
671    free(ret_val);
672    return NULL;
673  }
674
675  hashes = (uint8*)zalloc(length);
676  if(hashes == NULL)
677  {
678    free(ret_val->elements);
679    free(ret_val);
680    return NULL;
681  }
682
683  if(regfi_read(file->fd, hashes, &length) != 0
684     || length != elem_size*ret_val->num_keys)
685  {
686    free(ret_val->elements);
687    free(ret_val);
688    return NULL;
689  }
690
691  if(buf[0] == 'l' && buf[1] == 'i')
692  {
693    for (i=0; i < ret_val->num_keys; i++)
694    {
695      ret_val->elements[i].nk_off = IVAL(hashes, i*elem_size);
696      ret_val->elements[i].hash = 0;
697    }
698  }
699  else
700  {
701    for (i=0; i < ret_val->num_keys; i++)
702    {
703      ret_val->elements[i].nk_off = IVAL(hashes, i*elem_size);
704      ret_val->elements[i].hash = IVAL(hashes, i*elem_size+4);
705    }
706  }
707  free(hashes);
708
709  return ret_val;
710}
711
712
713
714/*******************************************************************
715 *******************************************************************/
716REGFI_SK_REC* regfi_parse_sk(REGFI_FILE* file, uint32 offset, uint32 max_size, bool strict)
717{
718  REGFI_SK_REC* ret_val;
719  uint8* sec_desc_buf;
720  uint32 cell_length, length;
721  /*prs_struct ps;*/
722  uint8 sk_header[REGFI_SK_MIN_LENGTH];
723  bool unalloc = false;
724
725  if(!regfi_parse_cell(file->fd, offset, sk_header, REGFI_SK_MIN_LENGTH,
726                       &cell_length, &unalloc))
727  {
728    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse SK record cell"
729                      " at offset 0x%.8X.", offset);
730    return NULL;
731  }
732   
733  if(sk_header[0] != 's' || sk_header[1] != 'k')
734  {
735    regfi_add_message(file, REGFI_MSG_WARN, "Magic number mismatch in parsing"
736                      " SK record at offset 0x%.8X.", offset);
737    return NULL;
738  }
739
740  ret_val = (REGFI_SK_REC*)zalloc(sizeof(REGFI_SK_REC));
741  if(ret_val == NULL)
742    return NULL;
743
744  ret_val->offset = offset;
745  /* XXX: Is there a way to be more conservative (shorter) with
746   *      cell length when cell is unallocated?
747   */
748  ret_val->cell_size = cell_length;
749
750  if(ret_val->cell_size > max_size)
751    ret_val->cell_size = max_size & 0xFFFFFFF8;
752  if((ret_val->cell_size < REGFI_SK_MIN_LENGTH) 
753     || (strict && ret_val->cell_size != (ret_val->cell_size & 0xFFFFFFF8)))
754  {
755    regfi_add_message(file, REGFI_MSG_WARN, "Invalid cell size found while"
756                      " parsing SK record at offset 0x%.8X.", offset);
757    free(ret_val);
758    return NULL;
759  }
760
761  ret_val->magic[0] = sk_header[0];
762  ret_val->magic[1] = sk_header[1];
763
764  /* XXX: Can additional validation be added here? */
765  ret_val->unknown_tag = SVAL(sk_header, 0x2);
766  ret_val->prev_sk_off = IVAL(sk_header, 0x4);
767  ret_val->next_sk_off = IVAL(sk_header, 0x8);
768  ret_val->ref_count = IVAL(sk_header, 0xC);
769  ret_val->desc_size = IVAL(sk_header, 0x10);
770
771  if(ret_val->desc_size + REGFI_SK_MIN_LENGTH > ret_val->cell_size)
772  {
773    regfi_add_message(file, REGFI_MSG_ERROR, "Security descriptor too large for"
774                      " cell while parsing SK record at offset 0x%.8X.", 
775                      offset);
776    free(ret_val);
777    return NULL;
778  }
779
780  sec_desc_buf = (uint8*)zalloc(ret_val->desc_size);
781  if(ret_val == NULL)
782  {
783    free(ret_val);
784    return NULL;
785  }
786
787  length = ret_val->desc_size;
788  if(regfi_read(file->fd, sec_desc_buf, &length) != 0 
789     || length != ret_val->desc_size)
790  {
791    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read security"
792                      " descriptor while parsing SK record at offset 0x%.8X.",
793                      offset);
794    free(ret_val);
795    return NULL;
796  }
797
798  if(!(ret_val->sec_desc = winsec_parse_desc(sec_desc_buf, ret_val->desc_size)))
799  {
800    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to parse security"
801                      " descriptor while parsing SK record at offset 0x%.8X.",
802                      offset);
803    free(sec_desc_buf);
804    free(ret_val);
805    return NULL;
806  }
807  free(sec_desc_buf);
808
809
810  return ret_val;
811}
812
813
814uint32* regfi_parse_valuelist(REGFI_FILE* file, uint32 offset, 
815                              uint32 num_values, bool strict)
816{
817  uint32* ret_val;
818  uint32 i, cell_length, length, read_len;
819  bool unalloc;
820
821  if(!regfi_parse_cell(file->fd, offset, NULL, 0, &cell_length, &unalloc))
822  {
823    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read cell header"
824                      " while parsing value list at offset 0x%.8X.", offset);
825    return NULL;
826  }
827
828  if(cell_length != (cell_length & 0xFFFFFFF8))
829  {
830    if(strict)
831      return NULL;
832    cell_length = cell_length & 0xFFFFFFF8;
833  }
834  if((num_values * sizeof(uint32)) > cell_length-sizeof(uint32))
835  {
836    regfi_add_message(file, REGFI_MSG_ERROR, "Too many values found"
837                      " while parsing value list at offset 0x%.8X.", offset);
838    return NULL;
839  }
840
841  read_len = num_values*sizeof(uint32);
842  ret_val = (uint32*)malloc(read_len);
843  if(ret_val == NULL)
844    return NULL;
845
846  length = read_len;
847  if((regfi_read(file->fd, (uint8*)ret_val, &length) != 0) || length != read_len)
848  {
849    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read value pointers"
850                      " while parsing value list at offset 0x%.8X.", offset);
851    free(ret_val);
852    return NULL;
853  }
854 
855  for(i=0; i < num_values; i++)
856  {
857    /* Fix endianness */
858    ret_val[i] = IVAL(&ret_val[i], 0);
859
860    /* Validate the first num_values values to ensure they make sense */
861    if(strict)
862    {
863      if((ret_val[i] + REGFI_REGF_SIZE > file->file_length)
864         || ((ret_val[i] & 0xFFFFFFF8) != ret_val[i]))
865      {
866        regfi_add_message(file, REGFI_MSG_ERROR, "Invalid value pointer"
867                          " (0x%.8X) found while parsing value list at offset"
868                          " 0x%.8X.", ret_val[i], offset);
869        free(ret_val);
870        return NULL;
871      }
872    }
873  }
874
875  return ret_val;
876}
877
878
879
880/******************************************************************************
881 * If !strict, the list may contain NULLs, VK records may point to NULL.
882 ******************************************************************************/
883REGFI_VK_REC** regfi_load_valuelist(REGFI_FILE* file, uint32 offset, 
884                                   uint32 num_values, uint32 max_size, 
885                                   bool strict)
886{
887  REGFI_VK_REC** ret_val;
888  REGFI_HBIN* hbin;
889  uint32 i, vk_offset, vk_max_length, usable_num_values;
890  uint32* voffsets;
891
892  if((num_values+1) * sizeof(uint32) > max_size)
893  {
894    if(strict)
895      return NULL;
896    usable_num_values = max_size/sizeof(uint32) - sizeof(uint32);
897  }
898  else
899    usable_num_values = num_values;
900
901  voffsets = regfi_parse_valuelist(file, offset, usable_num_values, strict);
902  if(voffsets == NULL)
903    return NULL;
904
905  ret_val = (REGFI_VK_REC**)zalloc(sizeof(REGFI_VK_REC*) * usable_num_values);
906  if(ret_val == NULL)
907  {
908    free(voffsets);
909    return NULL;
910  }
911 
912  for(i=0; i < usable_num_values; i++)
913  {
914    hbin = regfi_lookup_hbin(file, voffsets[i]);
915    if(!hbin)
916    {
917      free(voffsets);
918      free(ret_val);
919      return NULL;
920    }
921
922    vk_offset =  voffsets[i] + REGFI_REGF_SIZE;
923    vk_max_length = hbin->block_size + hbin->file_off - vk_offset;
924    ret_val[i] = regfi_parse_vk(file, vk_offset, vk_max_length, strict);
925    if(ret_val[i] == NULL)
926    { /* If we're being strict, throw out the whole list.
927       * Otherwise, let it be NULL.
928       */
929      if(strict)
930      {
931        free(voffsets);
932        free(ret_val);
933        return NULL;
934      }
935    }
936  }
937
938  free(voffsets);
939  return ret_val;
940}
941
942
943
944/*******************************************************************
945 * XXX: Need to add full key caching using a
946 *      custom cache structure.
947 *******************************************************************/
948REGFI_NK_REC* regfi_load_key(REGFI_FILE* file, uint32 offset, bool strict)
949{
950  REGFI_HBIN* hbin;
951  REGFI_HBIN* sub_hbin;
952  REGFI_NK_REC* nk;
953  uint32 max_length, off;
954
955  hbin = regfi_lookup_hbin(file, offset-REGFI_REGF_SIZE);
956  if (hbin == NULL) 
957    return NULL;
958
959  /* get the initial nk record */
960  max_length = hbin->block_size + hbin->file_off - offset;
961  if ((nk = regfi_parse_nk(file, offset, max_length, true)) == NULL)
962  {
963    regfi_add_message(file, REGFI_MSG_ERROR, "Could not load NK record at"
964                      " offset 0x%.8X.", offset);
965    return NULL;
966  }
967
968  /* fill in values */
969  if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE)) 
970  {
971    sub_hbin = hbin;
972    if(!regfi_offset_in_hbin(hbin, nk->values_off)) 
973      sub_hbin = regfi_lookup_hbin(file, nk->values_off);
974   
975    if(sub_hbin == NULL)
976    {
977      if(strict)
978      {
979        free(nk);
980        return NULL;
981      }
982      else
983        nk->values = NULL;
984
985    }
986    else
987    {
988      off = nk->values_off + REGFI_REGF_SIZE;
989      max_length = sub_hbin->block_size + sub_hbin->file_off - off;
990      nk->values = regfi_load_valuelist(file, off, nk->num_values, max_length, 
991                                        true);
992      if(strict && nk->values == NULL)
993      {
994        regfi_add_message(file, REGFI_MSG_ERROR, "Could not load value list"
995                          " for NK record at offset 0x%.8X.",
996                          offset);
997        free(nk);
998        return NULL;
999      }
1000
1001    }
1002  }
1003
1004  /* now get subkeys */
1005  if(nk->num_subkeys && (nk->subkeys_off != REGFI_OFFSET_NONE)) 
1006  {
1007    sub_hbin = hbin;
1008    if(!regfi_offset_in_hbin(hbin, nk->subkeys_off))
1009      sub_hbin = regfi_lookup_hbin(file, nk->subkeys_off);
1010
1011    if (sub_hbin == NULL) 
1012    {
1013      if(strict)
1014      {
1015        regfi_key_free(nk);
1016        return NULL;
1017      }
1018      else
1019        nk->subkeys = NULL;
1020    }
1021    else
1022    {
1023      off = nk->subkeys_off + REGFI_REGF_SIZE;
1024      max_length = sub_hbin->block_size + sub_hbin->file_off - off;
1025      nk->subkeys = regfi_load_subkeylist(file, off, nk->num_subkeys,
1026                                          max_length, true);
1027
1028      if(nk->subkeys == NULL)
1029      {
1030        /* XXX: Should we free the key and bail out here instead? 
1031         *      During nonstrict?
1032         */
1033        nk->num_subkeys = 0;
1034      }
1035    }
1036  }
1037
1038  return nk;
1039}
1040
1041
1042/******************************************************************************
1043 ******************************************************************************/
1044static bool regfi_find_root_nk(REGFI_FILE* file, uint32 offset, uint32 hbin_size,
1045                               uint32* root_offset)
1046{
1047  uint8 tmp[4];
1048  int32 record_size;
1049  uint32 length, hbin_offset = 0;
1050  REGFI_NK_REC* nk = NULL;
1051  bool found = false;
1052
1053  for(record_size=0; !found && (hbin_offset < hbin_size); )
1054  {
1055    if(lseek(file->fd, offset+hbin_offset, SEEK_SET) == -1)
1056      return false;
1057   
1058    length = 4;
1059    if((regfi_read(file->fd, tmp, &length) != 0) || length != 4)
1060      return false;
1061    record_size = IVALS(tmp, 0);
1062
1063    if(record_size < 0)
1064    {
1065      record_size = record_size*(-1);
1066      nk = regfi_parse_nk(file, offset+hbin_offset, hbin_size-hbin_offset, true);
1067      if(nk != NULL)
1068      {
1069        if((nk->key_type == REGFI_NK_TYPE_ROOTKEY1)
1070           || (nk->key_type == REGFI_NK_TYPE_ROOTKEY2))
1071        {
1072          found = true;
1073          *root_offset = nk->offset;
1074        }
1075        free(nk);
1076      }
1077    }
1078
1079    hbin_offset += record_size;
1080  }
1081
1082  return found;
1083}
1084
1085
1086/*******************************************************************
1087 * Open the registry file and then read in the REGF block to get the
1088 * first hbin offset.
1089 *******************************************************************/
1090REGFI_FILE* regfi_open(const char* filename)
1091{
1092  struct stat sbuf;
1093  REGFI_FILE* rb;
1094  REGFI_HBIN* hbin = NULL;
1095  uint32 hbin_off, file_length;
1096  int fd;
1097  bool rla;
1098
1099  /* open an existing file */
1100  if ((fd = open(filename, O_RDONLY)) == -1) 
1101  {
1102    /* DEBUG(0,("regfi_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
1103    return NULL;
1104  }
1105 
1106  /* Determine file length.  Must be at least big enough
1107   * for the header and one hbin.
1108   */
1109  if (fstat(fd, &sbuf) == -1)
1110    return NULL;
1111  file_length = sbuf.st_size;
1112  if(file_length < REGFI_REGF_SIZE+REGFI_HBIN_ALLOC)
1113    return NULL;
1114
1115  /* read in an existing file */
1116  if ((rb = regfi_parse_regf(fd, true)) == NULL) 
1117  {
1118    /* DEBUG(0,("regfi_open: Failed to read initial REGF block\n"));*/
1119    close(fd);
1120    return NULL;
1121  }
1122  rb->file_length = file_length; 
1123
1124  rb->hbins = range_list_new();
1125  if(rb->hbins == NULL)
1126  {
1127    range_list_free(rb->hbins);
1128    close(fd);
1129    free(rb);
1130    return NULL;
1131  }
1132 
1133  rla = true;
1134  hbin_off = REGFI_REGF_SIZE;
1135  hbin = regfi_parse_hbin(rb, hbin_off, true);
1136  while(hbin && rla)
1137  {
1138    rla = range_list_add(rb->hbins, hbin->file_off, hbin->block_size, hbin);
1139    hbin_off = hbin->file_off + hbin->block_size;
1140    hbin = regfi_parse_hbin(rb, hbin_off, true);
1141  }
1142
1143  /* Default message mask */
1144  rb->msg_mask = REGFI_MSG_ERROR|REGFI_MSG_WARN;
1145
1146  /* success */
1147  return rb;
1148}
1149
1150
1151/*******************************************************************
1152 *******************************************************************/
1153int regfi_close( REGFI_FILE *file )
1154{
1155  int fd;
1156  uint32 i;
1157
1158  /* nothing to do if there is no open file */
1159  if ((file == NULL) || (file->fd == -1))
1160    return 0;
1161
1162  fd = file->fd;
1163  file->fd = -1;
1164  for(i=0; i < range_list_size(file->hbins); i++)
1165    free(range_list_get(file->hbins, i)->data);
1166  range_list_free(file->hbins);
1167
1168  free(file);
1169
1170  return close(fd);
1171}
1172
1173
1174/******************************************************************************
1175 * There should be only *one* root key in the registry file based
1176 * on my experience.  --jerry
1177 *****************************************************************************/
1178REGFI_NK_REC* regfi_rootkey(REGFI_FILE *file)
1179{
1180  REGFI_NK_REC* nk = NULL;
1181  REGFI_HBIN*   hbin;
1182  uint32       root_offset, i, num_hbins;
1183 
1184  if(!file)
1185    return NULL;
1186
1187  /* Scan through the file one HBIN block at a time looking
1188     for an NK record with a type == 0x002c.
1189     Normally this is the first nk record in the first hbin
1190     block (but I'm not assuming that for now) */
1191
1192  num_hbins = range_list_size(file->hbins);
1193  for(i=0; i < num_hbins; i++)
1194  {
1195    hbin = (REGFI_HBIN*)range_list_get(file->hbins, i)->data;
1196    if(regfi_find_root_nk(file, hbin->file_off+REGFI_HBIN_HEADER_SIZE, 
1197                          hbin->block_size-REGFI_HBIN_HEADER_SIZE, &root_offset))
1198    {
1199      nk = regfi_load_key(file, root_offset, true);
1200      break;
1201    }
1202  }
1203
1204  return nk;
1205}
1206
1207
1208/******************************************************************************
1209 *****************************************************************************/
1210void regfi_key_free(REGFI_NK_REC* nk)
1211{
1212  uint32 i;
1213 
1214  if((nk->values != NULL) && (nk->values_off!=REGFI_OFFSET_NONE))
1215  {
1216    for(i=0; i < nk->num_values; i++)
1217    {
1218      if(nk->values[i]->valuename != NULL)
1219        free(nk->values[i]->valuename);
1220      if(nk->values[i]->data != NULL)
1221        free(nk->values[i]->data);
1222      free(nk->values[i]);
1223    }
1224    free(nk->values);
1225  }
1226
1227  regfi_subkeylist_free(nk->subkeys);
1228
1229  if(nk->keyname != NULL)
1230    free(nk->keyname);
1231  if(nk->classname != NULL)
1232    free(nk->classname);
1233
1234  /* XXX: not freeing sec_desc because these are cached.  This needs to be reviewed. */
1235  free(nk);
1236}
1237
1238
1239/******************************************************************************
1240 *****************************************************************************/
1241void regfi_subkeylist_free(REGFI_SUBKEY_LIST* list)
1242{
1243  if(list != NULL)
1244  {
1245    free(list->elements);
1246    free(list);
1247  }
1248}
1249
1250
1251/******************************************************************************
1252 *****************************************************************************/
1253REGFI_ITERATOR* regfi_iterator_new(REGFI_FILE* fh)
1254{
1255  REGFI_NK_REC* root;
1256  REGFI_ITERATOR* ret_val = (REGFI_ITERATOR*)malloc(sizeof(REGFI_ITERATOR));
1257  if(ret_val == NULL)
1258    return NULL;
1259
1260  root = regfi_rootkey(fh);
1261  if(root == NULL)
1262  {
1263    free(ret_val);
1264    return NULL;
1265  }
1266
1267  ret_val->key_positions = void_stack_new(REGFI_MAX_DEPTH);
1268  if(ret_val->key_positions == NULL)
1269  {
1270    free(ret_val);
1271    free(root);
1272    return NULL;
1273  }
1274
1275  /* This secret isn't very secret, but we don't need a good one.  This
1276   * secret is just designed to prevent someone from trying to blow our
1277   * caching and make things slow.
1278   */
1279  ret_val->sk_recs = lru_cache_create(127, 0x15DEAD05^time(NULL)
1280                                           ^(getpid()<<16)^(getppid()<<8),
1281                                      true);
1282
1283  ret_val->f = fh;
1284  ret_val->cur_key = root;
1285  ret_val->cur_subkey = 0;
1286  ret_val->cur_value = 0;
1287
1288  return ret_val;
1289}
1290
1291
1292/******************************************************************************
1293 *****************************************************************************/
1294void regfi_iterator_free(REGFI_ITERATOR* i)
1295{
1296  REGFI_ITER_POSITION* cur;
1297
1298  if(i->cur_key != NULL)
1299    regfi_key_free(i->cur_key);
1300
1301  while((cur = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions)) != NULL)
1302  {
1303    regfi_key_free(cur->nk);
1304    free(cur);
1305  }
1306 
1307  lru_cache_destroy(i->sk_recs);
1308
1309  free(i);
1310}
1311
1312
1313
1314/******************************************************************************
1315 *****************************************************************************/
1316/* XXX: some way of indicating reason for failure should be added. */
1317bool regfi_iterator_down(REGFI_ITERATOR* i)
1318{
1319  REGFI_NK_REC* subkey;
1320  REGFI_ITER_POSITION* pos;
1321
1322  pos = (REGFI_ITER_POSITION*)malloc(sizeof(REGFI_ITER_POSITION));
1323  if(pos == NULL)
1324    return false;
1325
1326  subkey = (REGFI_NK_REC*)regfi_iterator_cur_subkey(i);
1327  if(subkey == NULL)
1328  {
1329    free(pos);
1330    return false;
1331  }
1332
1333  pos->nk = i->cur_key;
1334  pos->cur_subkey = i->cur_subkey;
1335  if(!void_stack_push(i->key_positions, pos))
1336  {
1337    free(pos);
1338    regfi_key_free(subkey);
1339    return false;
1340  }
1341
1342  i->cur_key = subkey;
1343  i->cur_subkey = 0;
1344  i->cur_value = 0;
1345
1346  return true;
1347}
1348
1349
1350/******************************************************************************
1351 *****************************************************************************/
1352bool regfi_iterator_up(REGFI_ITERATOR* i)
1353{
1354  REGFI_ITER_POSITION* pos;
1355
1356  pos = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions);
1357  if(pos == NULL)
1358    return false;
1359
1360  regfi_key_free(i->cur_key);
1361  i->cur_key = pos->nk;
1362  i->cur_subkey = pos->cur_subkey;
1363  i->cur_value = 0;
1364  free(pos);
1365
1366  return true;
1367}
1368
1369
1370/******************************************************************************
1371 *****************************************************************************/
1372bool regfi_iterator_to_root(REGFI_ITERATOR* i)
1373{
1374  while(regfi_iterator_up(i))
1375    continue;
1376
1377  return true;
1378}
1379
1380
1381/******************************************************************************
1382 *****************************************************************************/
1383bool regfi_iterator_find_subkey(REGFI_ITERATOR* i, const char* subkey_name)
1384{
1385  REGFI_NK_REC* subkey;
1386  bool found = false;
1387  uint32 old_subkey = i->cur_subkey;
1388
1389  if(subkey_name == NULL)
1390    return false;
1391
1392  /* XXX: this alloc/free of each sub key might be a bit excessive */
1393  subkey = (REGFI_NK_REC*)regfi_iterator_first_subkey(i);
1394  while((subkey != NULL) && (found == false))
1395  {
1396    if(subkey->keyname != NULL 
1397       && strcasecmp(subkey->keyname, subkey_name) == 0)
1398      found = true;
1399    else
1400    {
1401      regfi_key_free(subkey);
1402      subkey = (REGFI_NK_REC*)regfi_iterator_next_subkey(i);
1403    }
1404  }
1405
1406  if(found == false)
1407  {
1408    i->cur_subkey = old_subkey;
1409    return false;
1410  }
1411
1412  regfi_key_free(subkey);
1413  return true;
1414}
1415
1416
1417/******************************************************************************
1418 *****************************************************************************/
1419bool regfi_iterator_walk_path(REGFI_ITERATOR* i, const char** path)
1420{
1421  uint32 x;
1422  if(path == NULL)
1423    return false;
1424
1425  for(x=0; 
1426      ((path[x] != NULL) && regfi_iterator_find_subkey(i, path[x])
1427       && regfi_iterator_down(i));
1428      x++)
1429  { continue; }
1430
1431  if(path[x] == NULL)
1432    return true;
1433 
1434  /* XXX: is this the right number of times? */
1435  for(; x > 0; x--)
1436    regfi_iterator_up(i);
1437 
1438  return false;
1439}
1440
1441
1442/******************************************************************************
1443 *****************************************************************************/
1444const REGFI_NK_REC* regfi_iterator_cur_key(REGFI_ITERATOR* i)
1445{
1446  return i->cur_key;
1447}
1448
1449
1450/******************************************************************************
1451 *****************************************************************************/
1452const REGFI_SK_REC* regfi_iterator_cur_sk(REGFI_ITERATOR* i)
1453{
1454  REGFI_SK_REC* ret_val = NULL;
1455  REGFI_HBIN* hbin;
1456  uint32 max_length, off;
1457
1458  if(i->cur_key == NULL)
1459    return NULL;
1460 
1461  /* First look if we have already parsed it */
1462  if((i->cur_key->sk_off!=REGFI_OFFSET_NONE)
1463     && !(ret_val =(REGFI_SK_REC*)lru_cache_find(i->sk_recs, 
1464                                                &i->cur_key->sk_off, 4)))
1465  {
1466    hbin = regfi_lookup_hbin(i->f, i->cur_key->sk_off);
1467
1468    if(hbin == NULL)
1469      return NULL;
1470
1471    off = i->cur_key->sk_off + REGFI_REGF_SIZE;
1472    max_length = hbin->block_size + hbin->file_off - off;
1473    ret_val = regfi_parse_sk(i->f, off, max_length, true);
1474    if(ret_val == NULL)
1475      return NULL;
1476
1477    ret_val->sk_off = i->cur_key->sk_off;
1478    lru_cache_update(i->sk_recs, &i->cur_key->sk_off, 4, ret_val);
1479  }
1480
1481  return ret_val;
1482}
1483
1484
1485
1486/******************************************************************************
1487 *****************************************************************************/
1488const REGFI_NK_REC* regfi_iterator_first_subkey(REGFI_ITERATOR* i)
1489{
1490  i->cur_subkey = 0;
1491  return regfi_iterator_cur_subkey(i);
1492}
1493
1494
1495/******************************************************************************
1496 *****************************************************************************/
1497const REGFI_NK_REC* regfi_iterator_cur_subkey(REGFI_ITERATOR* i)
1498{
1499  uint32 nk_offset;
1500
1501  /* see if there is anything left to report */
1502  if (!(i->cur_key) || (i->cur_key->subkeys_off==REGFI_OFFSET_NONE)
1503      || (i->cur_subkey >= i->cur_key->num_subkeys))
1504    return NULL;
1505
1506  nk_offset = i->cur_key->subkeys->elements[i->cur_subkey].nk_off;
1507
1508  return regfi_load_key(i->f, nk_offset+REGFI_REGF_SIZE, true);
1509}
1510
1511
1512/******************************************************************************
1513 *****************************************************************************/
1514/* XXX: some way of indicating reason for failure should be added. */
1515const REGFI_NK_REC* regfi_iterator_next_subkey(REGFI_ITERATOR* i)
1516{
1517  const REGFI_NK_REC* subkey;
1518
1519  i->cur_subkey++;
1520  subkey = regfi_iterator_cur_subkey(i);
1521
1522  if(subkey == NULL)
1523    i->cur_subkey--;
1524
1525  return subkey;
1526}
1527
1528
1529/******************************************************************************
1530 *****************************************************************************/
1531bool regfi_iterator_find_value(REGFI_ITERATOR* i, const char* value_name)
1532{
1533  const REGFI_VK_REC* cur;
1534  bool found = false;
1535
1536  /* XXX: cur->valuename can be NULL in the registry. 
1537   *      Should we allow for a way to search for that?
1538   */
1539  if(value_name == NULL)
1540    return false;
1541
1542  cur = regfi_iterator_first_value(i);
1543  while((cur != NULL) && (found == false))
1544  {
1545    if((cur->valuename != NULL)
1546       && (strcasecmp(cur->valuename, value_name) == 0))
1547      found = true;
1548    else
1549      cur = regfi_iterator_next_value(i);
1550  }
1551
1552  return found;
1553}
1554
1555
1556/******************************************************************************
1557 *****************************************************************************/
1558const REGFI_VK_REC* regfi_iterator_first_value(REGFI_ITERATOR* i)
1559{
1560  i->cur_value = 0;
1561  return regfi_iterator_cur_value(i);
1562}
1563
1564
1565/******************************************************************************
1566 *****************************************************************************/
1567const REGFI_VK_REC* regfi_iterator_cur_value(REGFI_ITERATOR* i)
1568{
1569  REGFI_VK_REC* ret_val = NULL;
1570  if(i->cur_value < i->cur_key->num_values)
1571    ret_val = i->cur_key->values[i->cur_value];
1572
1573  return ret_val;
1574}
1575
1576
1577/******************************************************************************
1578 *****************************************************************************/
1579const REGFI_VK_REC* regfi_iterator_next_value(REGFI_ITERATOR* i)
1580{
1581  const REGFI_VK_REC* ret_val;
1582
1583  i->cur_value++;
1584  ret_val = regfi_iterator_cur_value(i);
1585  if(ret_val == NULL)
1586    i->cur_value--;
1587
1588  return ret_val;
1589}
1590
1591
1592
1593/*******************************************************************
1594 * Computes the checksum of the registry file header.
1595 * buffer must be at least the size of an regf header (4096 bytes).
1596 *******************************************************************/
1597static uint32 regfi_compute_header_checksum(uint8* buffer)
1598{
1599  uint32 checksum, x;
1600  int i;
1601
1602  /* XOR of all bytes 0x0000 - 0x01FB */
1603
1604  checksum = x = 0;
1605 
1606  for ( i=0; i<0x01FB; i+=4 ) {
1607    x = IVAL(buffer, i );
1608    checksum ^= x;
1609  }
1610 
1611  return checksum;
1612}
1613
1614
1615/*******************************************************************
1616 * XXX: Add way to return more detailed error information.
1617 *******************************************************************/
1618REGFI_FILE* regfi_parse_regf(int fd, bool strict)
1619{
1620  uint8 file_header[REGFI_REGF_SIZE];
1621  uint32 length;
1622  REGFI_FILE* ret_val;
1623
1624  ret_val = (REGFI_FILE*)zalloc(sizeof(REGFI_FILE));
1625  if(ret_val == NULL)
1626    return NULL;
1627
1628  ret_val->fd = fd;
1629
1630  length = REGFI_REGF_SIZE;
1631  if((regfi_read(fd, file_header, &length)) != 0 
1632     || length != REGFI_REGF_SIZE)
1633  {
1634    free(ret_val);
1635    return NULL;
1636  }
1637
1638  ret_val->checksum = IVAL(file_header, 0x1FC);
1639  ret_val->computed_checksum = regfi_compute_header_checksum(file_header);
1640  if (strict && (ret_val->checksum != ret_val->computed_checksum))
1641  {
1642    free(ret_val);
1643    return NULL;
1644  }
1645
1646  memcpy(ret_val->magic, file_header, REGFI_REGF_MAGIC_SIZE);
1647  if(strict && (memcmp(ret_val->magic, "regf", REGFI_REGF_MAGIC_SIZE) != 0))
1648  {
1649    free(ret_val);
1650    return NULL;
1651  }
1652 
1653  ret_val->unknown1 = IVAL(file_header, 0x4);
1654  ret_val->unknown2 = IVAL(file_header, 0x8);
1655
1656  ret_val->mtime.low = IVAL(file_header, 0xC);
1657  ret_val->mtime.high = IVAL(file_header, 0x10);
1658
1659  ret_val->unknown3 = IVAL(file_header, 0x14);
1660  ret_val->unknown4 = IVAL(file_header, 0x18);
1661  ret_val->unknown5 = IVAL(file_header, 0x1C);
1662  ret_val->unknown6 = IVAL(file_header, 0x20);
1663 
1664  ret_val->data_offset = IVAL(file_header, 0x24);
1665  ret_val->last_block = IVAL(file_header, 0x28);
1666
1667  ret_val->unknown7 = IVAL(file_header, 0x2C);
1668
1669  return ret_val;
1670}
1671
1672
1673
1674/*******************************************************************
1675 * Given real file offset, read and parse the hbin at that location
1676 * along with it's associated cells.
1677 *******************************************************************/
1678/* XXX: Need a way to return types of errors.
1679 */
1680REGFI_HBIN* regfi_parse_hbin(REGFI_FILE* file, uint32 offset, bool strict)
1681{
1682  REGFI_HBIN *hbin;
1683  uint8 hbin_header[REGFI_HBIN_HEADER_SIZE];
1684  uint32 length;
1685 
1686  if(offset >= file->file_length)
1687    return NULL;
1688
1689  if(lseek(file->fd, offset, SEEK_SET) == -1)
1690  {
1691    regfi_add_message(file, REGFI_MSG_ERROR, "Seek failed"
1692                      " while parsing hbin at offset 0x%.8X.", offset);
1693    return NULL;
1694  }
1695
1696  length = REGFI_HBIN_HEADER_SIZE;
1697  if((regfi_read(file->fd, hbin_header, &length) != 0) 
1698     || length != REGFI_HBIN_HEADER_SIZE)
1699    return NULL;
1700
1701  if(lseek(file->fd, offset, SEEK_SET) == -1)
1702  {
1703    regfi_add_message(file, REGFI_MSG_ERROR, "Seek failed"
1704                      " while parsing hbin at offset 0x%.8X.", offset);
1705    return NULL;
1706  }
1707
1708  if(!(hbin = (REGFI_HBIN*)zalloc(sizeof(REGFI_HBIN)))) 
1709    return NULL;
1710  hbin->file_off = offset;
1711
1712  memcpy(hbin->magic, hbin_header, 4);
1713  if(strict && (memcmp(hbin->magic, "hbin", 4) != 0))
1714  {
1715    regfi_add_message(file, REGFI_MSG_INFO, "Magic number mismatch "
1716                      "(%.2X %.2X %.2X %.2X) while parsing hbin at offset"
1717                      " 0x%.8X.", hbin->magic[0], hbin->magic[1], 
1718                      hbin->magic[2], hbin->magic[3], offset);
1719    free(hbin);
1720    return NULL;
1721  }
1722
1723  hbin->first_hbin_off = IVAL(hbin_header, 0x4);
1724  hbin->block_size = IVAL(hbin_header, 0x8);
1725  /* this should be the same thing as hbin->block_size but just in case */
1726  hbin->next_block = IVAL(hbin_header, 0x1C);
1727
1728
1729  /* Ensure the block size is a multiple of 0x1000 and doesn't run off
1730   * the end of the file.
1731   */
1732  /* XXX: This may need to be relaxed for dealing with
1733   *      partial or corrupt files.
1734   */
1735  if((offset + hbin->block_size > file->file_length)
1736     || (hbin->block_size & 0xFFFFF000) != hbin->block_size)
1737  {
1738    regfi_add_message(file, REGFI_MSG_ERROR, "The hbin offset is not aligned"
1739                      " or runs off the end of the file"
1740                      " while parsing hbin at offset 0x%.8X.", offset);
1741    free(hbin);
1742    return NULL;
1743  }
1744
1745  return hbin;
1746}
1747
1748
1749/*******************************************************************
1750 *******************************************************************/
1751REGFI_NK_REC* regfi_parse_nk(REGFI_FILE* file, uint32 offset, 
1752                            uint32 max_size, bool strict)
1753{
1754  uint8 nk_header[REGFI_NK_MIN_LENGTH];
1755  REGFI_HBIN *hbin;
1756  REGFI_NK_REC* ret_val;
1757  uint32 length,cell_length;
1758  uint32 class_offset, class_maxsize;
1759  bool unalloc = false;
1760
1761  if(!regfi_parse_cell(file->fd, offset, nk_header, REGFI_NK_MIN_LENGTH,
1762                       &cell_length, &unalloc))
1763  {
1764    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell header"
1765                      " while parsing NK record at offset 0x%.8X.", offset);
1766    return NULL;
1767  }
1768
1769  /* A bit of validation before bothering to allocate memory */
1770  if((nk_header[0x0] != 'n') || (nk_header[0x1] != 'k'))
1771  {
1772    regfi_add_message(file, REGFI_MSG_WARN, "Magic number mismatch in parsing"
1773                      " NK record at offset 0x%.8X.", offset);
1774    return NULL;
1775  }
1776
1777  ret_val = (REGFI_NK_REC*)zalloc(sizeof(REGFI_NK_REC));
1778  if(ret_val == NULL)
1779  {
1780    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to allocate memory while"
1781                      " parsing NK record at offset 0x%.8X.", offset);
1782    return NULL;
1783  }
1784
1785  ret_val->offset = offset;
1786  ret_val->cell_size = cell_length;
1787
1788  if(ret_val->cell_size > max_size)
1789    ret_val->cell_size = max_size & 0xFFFFFFF8;
1790  if((ret_val->cell_size < REGFI_NK_MIN_LENGTH) 
1791     || (strict && ret_val->cell_size != (ret_val->cell_size & 0xFFFFFFF8)))
1792  {
1793    regfi_add_message(file, REGFI_MSG_ERROR, "A length check failed while"
1794                      " parsing NK record at offset 0x%.8X.", offset);
1795    free(ret_val);
1796    return NULL;
1797  }
1798
1799  ret_val->magic[0] = nk_header[0x0];
1800  ret_val->magic[1] = nk_header[0x1];
1801  ret_val->key_type = SVAL(nk_header, 0x2);
1802  if((ret_val->key_type != REGFI_NK_TYPE_NORMALKEY)
1803     && (ret_val->key_type != REGFI_NK_TYPE_ROOTKEY1) 
1804     && (ret_val->key_type != REGFI_NK_TYPE_ROOTKEY2)
1805     && (ret_val->key_type != REGFI_NK_TYPE_LINKKEY)
1806     && (ret_val->key_type != REGFI_NK_TYPE_UNKNOWN1)
1807     && (ret_val->key_type != REGFI_NK_TYPE_UNKNOWN2)
1808     && (ret_val->key_type != REGFI_NK_TYPE_UNKNOWN3))
1809  {
1810    regfi_add_message(file, REGFI_MSG_WARN, "Unknown key type (0x%.4X) while"
1811                      " parsing NK record at offset 0x%.8X.", 
1812                      ret_val->key_type, offset);
1813  }
1814
1815  ret_val->mtime.low = IVAL(nk_header, 0x4);
1816  ret_val->mtime.high = IVAL(nk_header, 0x8);
1817  /* If the key is unallocated and the MTIME is earlier than Jan 1, 1990
1818   * or later than Jan 1, 2290, we consider this a bad key.  This helps
1819   * weed out some false positives during deleted data recovery.
1820   */
1821  if(unalloc
1822     && ((ret_val->mtime.high < REGFI_MTIME_MIN_HIGH
1823          && ret_val->mtime.low < REGFI_MTIME_MIN_LOW)
1824         || (ret_val->mtime.high > REGFI_MTIME_MAX_HIGH
1825             && ret_val->mtime.low > REGFI_MTIME_MAX_LOW)))
1826    return NULL;
1827
1828  ret_val->unknown1 = IVAL(nk_header, 0xC);
1829  ret_val->parent_off = IVAL(nk_header, 0x10);
1830  ret_val->num_subkeys = IVAL(nk_header, 0x14);
1831  ret_val->unknown2 = IVAL(nk_header, 0x18);
1832  ret_val->subkeys_off = IVAL(nk_header, 0x1C);
1833  ret_val->unknown3 = IVAL(nk_header, 0x20);
1834  ret_val->num_values = IVAL(nk_header, 0x24);
1835  ret_val->values_off = IVAL(nk_header, 0x28);
1836  ret_val->sk_off = IVAL(nk_header, 0x2C);
1837  ret_val->classname_off = IVAL(nk_header, 0x30);
1838
1839  ret_val->max_bytes_subkeyname = IVAL(nk_header, 0x34);
1840  ret_val->max_bytes_subkeyclassname = IVAL(nk_header, 0x38);
1841  ret_val->max_bytes_valuename = IVAL(nk_header, 0x3C);
1842  ret_val->max_bytes_value = IVAL(nk_header, 0x40);
1843  ret_val->unk_index = IVAL(nk_header, 0x44);
1844
1845  ret_val->name_length = SVAL(nk_header, 0x48);
1846  ret_val->classname_length = SVAL(nk_header, 0x4A);
1847
1848
1849  if(ret_val->name_length + REGFI_NK_MIN_LENGTH > ret_val->cell_size)
1850  {
1851    if(strict)
1852    {
1853      regfi_add_message(file, REGFI_MSG_ERROR, "Contents too large for cell"
1854                        " while parsing NK record at offset 0x%.8X.", offset);
1855      free(ret_val);
1856      return NULL;
1857    }
1858    else
1859      ret_val->name_length = ret_val->cell_size - REGFI_NK_MIN_LENGTH;
1860  }
1861  else if (unalloc)
1862  { /* Truncate cell_size if it's much larger than the apparent total record length. */
1863    /* Round up to the next multiple of 8 */
1864    length = (ret_val->name_length + REGFI_NK_MIN_LENGTH) & 0xFFFFFFF8;
1865    if(length < ret_val->name_length + REGFI_NK_MIN_LENGTH)
1866      length+=8;
1867
1868    /* If cell_size is still greater, truncate. */
1869    if(length < ret_val->cell_size)
1870      ret_val->cell_size = length;
1871  }
1872
1873  ret_val->keyname = (char*)zalloc(sizeof(char)*(ret_val->name_length+1));
1874  if(ret_val->keyname == NULL)
1875  {
1876    free(ret_val);
1877    return NULL;
1878  }
1879
1880  /* Don't need to seek, should be at the right offset */
1881  length = ret_val->name_length;
1882  if((regfi_read(file->fd, (uint8*)ret_val->keyname, &length) != 0)
1883     || length != ret_val->name_length)
1884  {
1885    regfi_add_message(file, REGFI_MSG_ERROR, "Failed to read key name"
1886                      " while parsing NK record at offset 0x%.8X.", offset);
1887    free(ret_val->keyname);
1888    free(ret_val);
1889    return NULL;
1890  }
1891  ret_val->keyname[ret_val->name_length] = '\0';
1892
1893  if(ret_val->classname_off != REGFI_OFFSET_NONE)
1894  {
1895    hbin = regfi_lookup_hbin(file, ret_val->classname_off);
1896    if(hbin)
1897    {
1898      class_offset = ret_val->classname_off+REGFI_REGF_SIZE;
1899      class_maxsize = hbin->block_size + hbin->file_off - class_offset;
1900      ret_val->classname
1901        = regfi_parse_classname(file, class_offset, &ret_val->classname_length, 
1902                                class_maxsize, strict);
1903    }
1904    else
1905    {
1906      ret_val->classname = NULL;
1907      regfi_add_message(file, REGFI_MSG_WARN, "Could not find hbin for class"
1908                        " name while parsing NK record at offset 0x%.8X.", 
1909                        offset);
1910    }
1911    /* XXX: Should add this back and make it more strict?
1912    if(strict && ret_val->classname == NULL)
1913        return NULL;
1914    */
1915  }
1916
1917  return ret_val;
1918}
1919
1920
1921char* regfi_parse_classname(REGFI_FILE* file, uint32 offset, 
1922                            uint16* name_length, uint32 max_size, bool strict)
1923{
1924  char* ret_val = NULL;
1925  uint32 length;
1926  uint32 cell_length;
1927  bool unalloc = false;
1928
1929  if(*name_length > 0 && offset != REGFI_OFFSET_NONE
1930     && offset == (offset & 0xFFFFFFF8))
1931  {
1932    if(!regfi_parse_cell(file->fd, offset, NULL, 0, &cell_length, &unalloc))
1933    {
1934      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell header"
1935                        " while parsing class name at offset 0x%.8X.", offset);
1936        return NULL;
1937    }
1938
1939    if((cell_length & 0xFFFFFFF8) != cell_length)
1940    {
1941      regfi_add_message(file, REGFI_MSG_ERROR, "Cell length not a multiple of 8"
1942                        " while parsing class name at offset 0x%.8X.", offset);
1943      return NULL;
1944    }
1945
1946    if(cell_length > max_size)
1947    {
1948      regfi_add_message(file, REGFI_MSG_WARN, "Cell stretches past hbin "
1949                        "boundary while parsing class name at offset 0x%.8X.",
1950                        offset);
1951      if(strict)
1952        return NULL;
1953      cell_length = max_size;
1954    }
1955
1956    if((cell_length - 4) < *name_length)
1957    {
1958      regfi_add_message(file, REGFI_MSG_WARN, "Class name is larger than"
1959                        " cell_length while parsing class name at offset"
1960                        " 0x%.8X.", offset);
1961      if(strict)
1962        return NULL;
1963      *name_length = cell_length - 4;
1964    }
1965   
1966    ret_val = (char*)zalloc(*name_length);
1967    if(ret_val != NULL)
1968    {
1969      length = *name_length;
1970      if((regfi_read(file->fd, (uint8*)ret_val, &length) != 0)
1971         || length != *name_length)
1972      {
1973        regfi_add_message(file, REGFI_MSG_ERROR, "Could not read class name"
1974                          " while parsing class name at offset 0x%.8X.", offset);
1975        free(ret_val);
1976        return NULL;
1977      }
1978    }
1979  }
1980
1981  return ret_val;
1982}
1983
1984
1985/*******************************************************************
1986 *******************************************************************/
1987REGFI_VK_REC* regfi_parse_vk(REGFI_FILE* file, uint32 offset, 
1988                            uint32 max_size, bool strict)
1989{
1990  REGFI_VK_REC* ret_val;
1991  REGFI_HBIN *hbin;
1992  uint8 vk_header[REGFI_VK_MIN_LENGTH];
1993  uint32 raw_data_size, length, cell_length;
1994  uint32 data_offset, data_maxsize;
1995  bool unalloc = false;
1996
1997  if(!regfi_parse_cell(file->fd, offset, vk_header, REGFI_VK_MIN_LENGTH,
1998                       &cell_length, &unalloc))
1999  {
2000    regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell header"
2001                      " while parsing VK record at offset 0x%.8X.", offset);
2002    return NULL;
2003  }
2004
2005  ret_val = (REGFI_VK_REC*)zalloc(sizeof(REGFI_VK_REC));
2006  if(ret_val == NULL)
2007    return NULL;
2008
2009  ret_val->offset = offset;
2010  ret_val->cell_size = cell_length;
2011
2012  if(ret_val->cell_size > max_size)
2013    ret_val->cell_size = max_size & 0xFFFFFFF8;
2014  if((ret_val->cell_size < REGFI_VK_MIN_LENGTH) 
2015     || ret_val->cell_size != (ret_val->cell_size & 0xFFFFFFF8))
2016  {
2017    regfi_add_message(file, REGFI_MSG_WARN, "Invalid cell size encountered"
2018                      " while parsing VK record at offset 0x%.8X.", offset);
2019    free(ret_val);
2020    return NULL;
2021  }
2022
2023  ret_val->magic[0] = vk_header[0x0];
2024  ret_val->magic[1] = vk_header[0x1];
2025  if((ret_val->magic[0] != 'v') || (ret_val->magic[1] != 'k'))
2026  {
2027    /* XXX: This does not account for deleted keys under Win2K which
2028     *      often have this (and the name length) overwritten with
2029     *      0xFFFF.
2030     */
2031    regfi_add_message(file, REGFI_MSG_WARN, "Magic number mismatch"
2032                      " while parsing VK record at offset 0x%.8X.", offset);
2033    free(ret_val);
2034    return NULL;
2035  }
2036
2037  ret_val->name_length = SVAL(vk_header, 0x2);
2038  raw_data_size = IVAL(vk_header, 0x4);
2039  ret_val->data_size = raw_data_size & ~REGFI_VK_DATA_IN_OFFSET;
2040  ret_val->data_in_offset = (bool)(raw_data_size & REGFI_VK_DATA_IN_OFFSET);
2041  ret_val->data_off = IVAL(vk_header, 0x8);
2042  ret_val->type = IVAL(vk_header, 0xC);
2043  ret_val->flag = SVAL(vk_header, 0x10);
2044  ret_val->unknown1 = SVAL(vk_header, 0x12);
2045
2046  if(ret_val->flag & REGFI_VK_FLAG_NAME_PRESENT)
2047  {
2048    if(ret_val->name_length + REGFI_VK_MIN_LENGTH + 4 > ret_val->cell_size)
2049    {
2050      regfi_add_message(file, REGFI_MSG_WARN, "Name too long for remaining cell"
2051                        " space while parsing VK record at offset 0x%.8X.",
2052                        offset);
2053      if(strict)
2054      {
2055        free(ret_val);
2056        return NULL;
2057      }
2058      else
2059        ret_val->name_length = ret_val->cell_size - REGFI_VK_MIN_LENGTH - 4;
2060    }
2061
2062    /* Round up to the next multiple of 8 */
2063    cell_length = (ret_val->name_length + REGFI_VK_MIN_LENGTH + 4) & 0xFFFFFFF8;
2064    if(cell_length < ret_val->name_length + REGFI_VK_MIN_LENGTH + 4)
2065      cell_length+=8;
2066
2067    ret_val->valuename = (char*)zalloc(sizeof(char)*(ret_val->name_length+1));
2068    if(ret_val->valuename == NULL)
2069    {
2070      free(ret_val);
2071      return NULL;
2072    }
2073
2074    length = ret_val->name_length;
2075    if((regfi_read(file->fd, (uint8*)ret_val->valuename, &length) != 0)
2076       || length != ret_val->name_length)
2077    {
2078      regfi_add_message(file, REGFI_MSG_ERROR, "Could not read value name"
2079                        " while parsing VK record at offset 0x%.8X.", offset);
2080      free(ret_val->valuename);
2081      free(ret_val);
2082      return NULL;
2083    }
2084    ret_val->valuename[ret_val->name_length] = '\0';
2085
2086  }
2087  else
2088    cell_length = REGFI_VK_MIN_LENGTH + 4;
2089
2090  if(unalloc)
2091  {
2092    /* If cell_size is still greater, truncate. */
2093    if(cell_length < ret_val->cell_size)
2094      ret_val->cell_size = cell_length;
2095  }
2096
2097  if(ret_val->data_size == 0)
2098    ret_val->data = NULL;
2099  else
2100  {
2101    if(ret_val->data_in_offset)
2102    {
2103      ret_val->data = regfi_parse_data(file, ret_val->data_off, 
2104                                       raw_data_size, 4, strict);
2105    }
2106    else
2107    {
2108      hbin = regfi_lookup_hbin(file, ret_val->data_off);
2109      if(hbin)
2110      {
2111        data_offset = ret_val->data_off+REGFI_REGF_SIZE;
2112        data_maxsize = hbin->block_size + hbin->file_off - data_offset;
2113        ret_val->data = regfi_parse_data(file, data_offset, raw_data_size,
2114                                         data_maxsize, strict);
2115       
2116      }
2117      else
2118      {
2119        regfi_add_message(file, REGFI_MSG_WARN, "Could not find hbin for data"
2120                          " while parsing VK record at offset 0x%.8X.", offset);
2121        ret_val->data = NULL;
2122      }
2123    }
2124
2125    if(ret_val->data == NULL)
2126    {
2127      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse data record"
2128                        " while parsing VK record at offset 0x%.8X.", offset);
2129    }
2130  }
2131
2132  return ret_val;
2133}
2134
2135
2136uint8* regfi_parse_data(REGFI_FILE* file, uint32 offset, uint32 length,
2137                        uint32 max_size, bool strict)
2138{
2139  uint8* ret_val;
2140  uint32 read_length, cell_length;
2141  uint8 i;
2142  bool unalloc;
2143
2144  /* The data is typically stored in the offset if the size <= 4 */
2145  if (length & REGFI_VK_DATA_IN_OFFSET)
2146  {
2147    length = length & ~REGFI_VK_DATA_IN_OFFSET;
2148    if(length > 4)
2149    {
2150      regfi_add_message(file, REGFI_MSG_ERROR, "Data in offset but length > 4"
2151                        " while parsing data record at offset 0x%.8X.", 
2152                        offset);
2153      return NULL;
2154    }
2155
2156    if((ret_val = (uint8*)zalloc(sizeof(uint8)*length)) == NULL)
2157      return NULL;
2158
2159    for(i = 0; i < length; i++)
2160      ret_val[i] = (uint8)((offset >> i*8) & 0xFF);
2161  }
2162  else
2163  {
2164    if(!regfi_parse_cell(file->fd, offset, NULL, 0,
2165                         &cell_length, &unalloc))
2166    {
2167      regfi_add_message(file, REGFI_MSG_WARN, "Could not parse cell while"
2168                        " parsing data record at offset 0x%.8X.", offset);
2169      return NULL;
2170    }
2171
2172    if((cell_length & 0xFFFFFFF8) != cell_length)
2173    {
2174      regfi_add_message(file, REGFI_MSG_WARN, "Cell length not multiple of 8"
2175                        " while parsing data record at offset 0x%.8X.",
2176                        offset);
2177      return NULL;
2178    }
2179
2180    if(cell_length > max_size)
2181    {
2182      regfi_add_message(file, REGFI_MSG_WARN, "Cell extends past hbin boundary"
2183                        " while parsing data record at offset 0x%.8X.", 
2184                        offset);
2185      if(strict)
2186        return NULL;
2187      else
2188        cell_length = max_size;
2189    }
2190
2191    if(cell_length - 4 < length)
2192    {
2193      /* XXX: This strict condition has been triggered in multiple registries.
2194       *      Not sure the cause, but the data length values are very large,
2195       *      such as 53392.
2196       */
2197      regfi_add_message(file, REGFI_MSG_WARN, "Data length (0x%.8X) larger than"
2198                        " remaining cell length (0x%.8X)"
2199                        " while parsing data record at offset 0x%.8X.", 
2200                        length, cell_length - 4, offset);
2201      if(strict)
2202        return NULL;
2203      else
2204        length = cell_length - 4;
2205    }
2206
2207    if((ret_val = (uint8*)zalloc(sizeof(uint8)*length)) == NULL)
2208      return NULL;
2209
2210    read_length = length;
2211    if((regfi_read(file->fd, ret_val, &read_length) != 0) 
2212       || read_length != length)
2213    {
2214      regfi_add_message(file, REGFI_MSG_ERROR, "Could not read data block while"
2215                        " parsing data record at offset 0x%.8X.", offset);
2216      free(ret_val);
2217      return NULL;
2218    }
2219  }
2220
2221  return ret_val;
2222}
2223
2224
2225range_list* regfi_parse_unalloc_cells(REGFI_FILE* file)
2226{
2227  range_list* ret_val;
2228  REGFI_HBIN* hbin;
2229  const range_list_element* hbins_elem;
2230  uint32 i, num_hbins, curr_off, cell_len;
2231  bool is_unalloc;
2232
2233  ret_val = range_list_new();
2234  if(ret_val == NULL)
2235    return NULL;
2236
2237  num_hbins = range_list_size(file->hbins);
2238  for(i=0; i<num_hbins; i++)
2239  {
2240    hbins_elem = range_list_get(file->hbins, i);
2241    if(hbins_elem == NULL)
2242      break;
2243    hbin = (REGFI_HBIN*)hbins_elem->data;
2244
2245    curr_off = REGFI_HBIN_HEADER_SIZE;
2246    while(curr_off < hbin->block_size)
2247    {
2248      if(!regfi_parse_cell(file->fd, hbin->file_off+curr_off, NULL, 0,
2249                           &cell_len, &is_unalloc))
2250        break;
2251     
2252      if((cell_len == 0) || ((cell_len & 0xFFFFFFF8) != cell_len))
2253        /* XXX: should report an error here. */
2254        break;
2255     
2256      /* for some reason the record_size of the last record in
2257         an hbin block can extend past the end of the block
2258         even though the record fits within the remaining
2259         space....aaarrrgggghhhhhh */ 
2260      if(curr_off + cell_len >= hbin->block_size)
2261        cell_len = hbin->block_size - curr_off;
2262     
2263      if(is_unalloc)
2264        range_list_add(ret_val, hbin->file_off+curr_off, 
2265                       cell_len, NULL);
2266     
2267      curr_off = curr_off+cell_len;
2268    }
2269  }
2270
2271  return ret_val;
2272}
Note: See TracBrowser for help on using the repository browser.