source: trunk/lib/regfi.c @ 134

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

rewrote winsec library, stripping out Samba dependencies

eliminated remaining Samba prs functions

added support for 'li' subkey list records

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