source: trunk/lib/regfi.c @ 136

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

fixed various integer issues and memory allocation issues

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

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