source: trunk/lib/regfi.c @ 135

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

cleaned up regfi API

started adding debugging infrastructure, but currently broken

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