source: trunk/lib/regfi.c @ 131

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

fixed an hbin length validation related to vk records
added hbin length validation for class names and data cells

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