source: trunk/lib/regfi.c @ 135

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

cleaned up regfi API

started adding debugging infrastructure, but currently broken

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