source: trunk/lib/regfi.c @ 228

Last change on this file since 228 was 228, checked in by tim, 13 years ago

added a test case for pyregfi multithreaded use
updated the regfi multithreaded test case
fixed several ctypes interface problems in pyregfi
added locking to pyregfi iterators for thread safety
fixed regfi talloc race conditions with an additional lock

  • Property svn:keywords set to Id
File size: 102.0 KB
Line 
1/*
2 * Copyright (C) 2005-2010 Timothy D. Morgan
3 * Copyright (C) 2005 Gerald (Jerry) Carter
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 3 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 * $Id: regfi.c 228 2011-04-18 20:25:46Z tim $
19 */
20
21/**
22 * @file
23 *
24 * Windows NT (and later) read-only registry library
25 *
26 * See @ref regfi.h for more information.
27 *
28 * Branched from Samba project Subversion repository, version #7470:
29 *   http://viewcvs.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c?rev=7470&view=auto
30 *
31 * Since then, it has been heavily rewritten, simplified, and improved.
32 */
33
34#include "regfi.h"
35
36
37/* Registry types mapping */
38const unsigned int regfi_num_reg_types = 12;
39static const char* regfi_type_names[] =
40  {"NONE", "SZ", "EXPAND_SZ", "BINARY", "DWORD", "DWORD_BE", "LINK",
41   "MULTI_SZ", "RSRC_LIST", "RSRC_DESC", "RSRC_REQ_LIST", "QWORD"};
42
43const char* regfi_encoding_names[] =
44  {"US-ASCII//TRANSLIT", "UTF-8//TRANSLIT", "UTF-16LE//TRANSLIT"};
45
46
47/* Ensures regfi_init runs only once */
48static pthread_once_t regfi_init_once = PTHREAD_ONCE_INIT;
49
50
51
52/******************************************************************************
53 ******************************************************************************/
54void regfi_log_free(void* ptr)
55{
56  REGFI_LOG* log_info = (REGFI_LOG*)ptr;
57 
58  if(log_info->messages != NULL)
59    free(log_info->messages);
60
61  talloc_free(log_info);
62}
63
64
65/******************************************************************************
66 ******************************************************************************/
67void regfi_init()
68{
69  int err;
70  if((err = pthread_key_create(&regfi_log_key, regfi_log_free)) != 0)
71    fprintf(stderr, "ERROR: key_create: %s\n", strerror(err));
72  errno = err;
73}
74
75
76/******************************************************************************
77 ******************************************************************************/
78REGFI_LOG* regfi_log_new()
79{
80  int err;
81  REGFI_LOG* log_info = talloc(NULL, REGFI_LOG);
82  if(log_info == NULL)
83    return NULL;
84
85  log_info->msg_mask = REGFI_DEFAULT_LOG_MASK;
86  log_info->messages = NULL;
87
88  pthread_once(&regfi_init_once, regfi_init);
89
90  if((err = pthread_setspecific(regfi_log_key, log_info)) != 0)
91  {
92    fprintf(stderr, "ERROR: setspecific: %s\n", strerror(err));
93    goto fail;
94  }
95
96  return log_info;
97
98 fail:
99  talloc_free(log_info);
100  errno = err;
101  return NULL;
102}
103
104
105/******************************************************************************
106 ******************************************************************************/
107void regfi_log_add(uint16_t msg_type, const char* fmt, ...)
108{
109  /* XXX: Switch internal storage over to a linked list or stack.
110   *      Then add a regfi_log_get function that returns the list in some
111   *      convenient, user-friendly data structure.  regfi_log_get_str should
112   *      stick around and will simply smush the list into a big string when
113   *      it's called, rather than having messages smushed when they're first
114   *      written to the log.
115   */
116  uint32_t buf_size, buf_used;
117  char* new_msg;
118  REGFI_LOG* log_info;
119  va_list args;
120
121  log_info = (REGFI_LOG*)pthread_getspecific(regfi_log_key);
122  if(log_info == NULL && (log_info = regfi_log_new()) == NULL)
123    return;
124
125  if((log_info->msg_mask & msg_type) == 0)
126    return;
127
128  if(log_info->messages == NULL)
129    buf_used = 0;
130  else
131    buf_used = strlen(log_info->messages);
132 
133  buf_size = buf_used+strlen(fmt)+160;
134  new_msg = realloc(log_info->messages, buf_size);
135  if(new_msg == NULL)
136    /* XXX: should we report this? */
137    return;
138 
139  switch (msg_type)
140  {
141  case REGFI_LOG_INFO:
142    strcpy(new_msg+buf_used, "INFO: ");
143    buf_used += 6;
144    break;
145  case REGFI_LOG_WARN:
146    strcpy(new_msg+buf_used, "WARN: ");
147    buf_used += 6;
148    break;
149  case REGFI_LOG_ERROR:
150    strcpy(new_msg+buf_used, "ERROR: ");
151    buf_used += 7;
152    break;
153  }
154 
155  va_start(args, fmt);
156  vsnprintf(new_msg+buf_used, buf_size-buf_used, fmt, args);
157  va_end(args);
158  strncat(new_msg, "\n", buf_size-1);
159 
160  log_info->messages = new_msg;
161}
162
163
164/******************************************************************************
165 ******************************************************************************/
166char* regfi_log_get_str()
167{
168  char* ret_val;
169  REGFI_LOG* log_info = (REGFI_LOG*)pthread_getspecific(regfi_log_key);
170  if(log_info == NULL && (log_info = regfi_log_new()) == NULL)
171    return NULL;
172 
173  ret_val = log_info->messages;
174  log_info->messages = NULL;
175
176  return ret_val;
177}
178
179
180/******************************************************************************
181 ******************************************************************************/
182bool regfi_log_set_mask(uint16_t msg_mask)
183{
184  REGFI_LOG* log_info = (REGFI_LOG*)pthread_getspecific(regfi_log_key);
185  if(log_info == NULL && (log_info = regfi_log_new()) == NULL)
186  {
187      return false;
188  }
189
190  log_info->msg_mask = msg_mask;
191  return true;
192}
193
194
195/******************************************************************************
196 * Returns NULL for an invalid e
197 *****************************************************************************/
198static const char* regfi_encoding_int2str(REGFI_ENCODING e)
199{
200  if(e < REGFI_NUM_ENCODINGS)
201    return regfi_encoding_names[e];
202
203  return NULL;
204}
205
206
207/******************************************************************************
208 * Returns NULL for an invalid val
209 *****************************************************************************/
210const char* regfi_type_val2str(unsigned int val)
211{
212  if(val == REG_KEY)
213    return "KEY";
214 
215  if(val >= regfi_num_reg_types)
216    return NULL;
217 
218  return regfi_type_names[val];
219}
220
221
222/******************************************************************************
223 * Returns -1 on error
224 *****************************************************************************/
225int regfi_type_str2val(const char* str)
226{
227  int i;
228
229  if(strcmp("KEY", str) == 0)
230    return REG_KEY;
231
232  for(i=0; i < regfi_num_reg_types; i++)
233    if (strcmp(regfi_type_names[i], str) == 0) 
234      return i;
235
236  if(strcmp("DWORD_LE", str) == 0)
237    return REG_DWORD_LE;
238
239  return -1;
240}
241
242
243/* Security descriptor formatting functions  */
244
245const char* regfi_ace_type2str(uint8_t type)
246{
247  static const char* map[7] 
248    = {"ALLOW", "DENY", "AUDIT", "ALARM", 
249       "ALLOW CPD", "OBJ ALLOW", "OBJ DENY"};
250  if(type < 7)
251    return map[type];
252  else
253    /* XXX: would be nice to return the unknown integer value. 
254     *      However, as it is a const string, it can't be free()ed later on,
255     *      so that would need to change.
256     */
257    return "UNKNOWN";
258}
259
260
261/* XXX: need a better reference on the meaning of each flag. */
262/* For more info, see:
263 *   http://msdn2.microsoft.com/en-us/library/aa772242.aspx
264 */
265char* regfi_ace_flags2str(uint8_t flags)
266{
267  static const char* flag_map[32] = 
268    { "OI", /* Object Inherit */
269      "CI", /* Container Inherit */
270      "NP", /* Non-Propagate */
271      "IO", /* Inherit Only */
272      "IA", /* Inherited ACE */
273      NULL,
274      NULL,
275      NULL,
276    };
277
278  char* ret_val = malloc(35*sizeof(char));
279  char* fo = ret_val;
280  uint32_t i;
281  uint8_t f;
282
283  if(ret_val == NULL)
284    return NULL;
285
286  fo[0] = '\0';
287  if (!flags)
288    return ret_val;
289
290  for(i=0; i < 8; i++)
291  {
292    f = (1<<i);
293    if((flags & f) && (flag_map[i] != NULL))
294    {
295      strcpy(fo, flag_map[i]);
296      fo += strlen(flag_map[i]);
297      *(fo++) = ' ';
298      flags ^= f;
299    }
300  }
301 
302  /* Any remaining unknown flags are added at the end in hex. */
303  if(flags != 0)
304    sprintf(fo, "0x%.2X ", flags);
305
306  /* Chop off the last space if we've written anything to ret_val */
307  if(fo != ret_val)
308    fo[-1] = '\0';
309
310  return ret_val;
311}
312
313
314char* regfi_ace_perms2str(uint32_t perms)
315{
316  uint32_t i, p;
317  /* This is more than is needed by a fair margin. */
318  char* ret_val = malloc(350*sizeof(char));
319  char* r = ret_val;
320
321  /* Each represents one of 32 permissions bits.  NULL is for undefined/reserved bits.
322   * For more information, see:
323   *   http://msdn2.microsoft.com/en-gb/library/aa374892.aspx
324   *   http://msdn2.microsoft.com/en-gb/library/ms724878.aspx
325   */
326  static const char* perm_map[32] = 
327    {/* object-specific permissions (registry keys, in this case) */
328      "QRY_VAL",       /* KEY_QUERY_VALUE */
329      "SET_VAL",       /* KEY_SET_VALUE */
330      "CREATE_KEY",    /* KEY_CREATE_SUB_KEY */
331      "ENUM_KEYS",     /* KEY_ENUMERATE_SUB_KEYS */
332      "NOTIFY",        /* KEY_NOTIFY */
333      "CREATE_LNK",    /* KEY_CREATE_LINK - Reserved for system use. */
334      NULL,
335      NULL,
336      "WOW64_64",      /* KEY_WOW64_64KEY */
337      "WOW64_32",      /* KEY_WOW64_32KEY */
338      NULL,
339      NULL,
340      NULL,
341      NULL,
342      NULL,
343      NULL,
344      /* standard access rights */
345      "DELETE",        /* DELETE */
346      "R_CONT",        /* READ_CONTROL */
347      "W_DAC",         /* WRITE_DAC */
348      "W_OWNER",       /* WRITE_OWNER */
349      "SYNC",          /* SYNCHRONIZE - Shouldn't be set in registries */
350      NULL,
351      NULL,
352      NULL,
353      /* other generic */
354      "SYS_SEC",       /* ACCESS_SYSTEM_SECURITY */
355      "MAX_ALLWD",     /* MAXIMUM_ALLOWED */
356      NULL,
357      NULL,
358      "GEN_A",         /* GENERIC_ALL */
359      "GEN_X",         /* GENERIC_EXECUTE */
360      "GEN_W",         /* GENERIC_WRITE */
361      "GEN_R",         /* GENERIC_READ */
362    };
363
364
365  if(ret_val == NULL)
366    return NULL;
367
368  r[0] = '\0';
369  for(i=0; i < 32; i++)
370  {
371    p = (1<<i);
372    if((perms & p) && (perm_map[i] != NULL))
373    {
374      strcpy(r, perm_map[i]);
375      r += strlen(perm_map[i]);
376      *(r++) = ' ';
377      perms ^= p;
378    }
379  }
380 
381  /* Any remaining unknown permission bits are added at the end in hex. */
382  if(perms != 0)
383    sprintf(r, "0x%.8X ", perms);
384
385  /* Chop off the last space if we've written anything to ret_val */
386  if(r != ret_val)
387    r[-1] = '\0';
388
389  return ret_val;
390}
391
392
393char* regfi_sid2str(WINSEC_DOM_SID* sid)
394{
395  uint32_t i, size = WINSEC_MAX_SUBAUTHS*11 + 24;
396  uint32_t left = size;
397  uint8_t comps = sid->num_auths;
398  char* ret_val = malloc(size);
399 
400  if(ret_val == NULL)
401    return NULL;
402
403  if(comps > WINSEC_MAX_SUBAUTHS)
404    comps = WINSEC_MAX_SUBAUTHS;
405
406  left -= sprintf(ret_val, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
407
408  for (i = 0; i < comps; i++) 
409    left -= snprintf(ret_val+(size-left), left, "-%u", sid->sub_auths[i]);
410
411  return ret_val;
412}
413
414
415char* regfi_get_acl(WINSEC_ACL* acl)
416{
417  uint32_t i, extra, size = 0;
418  const char* type_str;
419  char* flags_str;
420  char* perms_str;
421  char* sid_str;
422  char* ace_delim = "";
423  char* ret_val = NULL;
424  char* tmp_val = NULL;
425  bool failed = false;
426  char field_delim = ':';
427
428  for (i = 0; i < acl->num_aces && !failed; i++)
429  {
430    sid_str = regfi_sid2str(acl->aces[i]->trustee);
431    type_str = regfi_ace_type2str(acl->aces[i]->type);
432    perms_str = regfi_ace_perms2str(acl->aces[i]->access_mask);
433    flags_str = regfi_ace_flags2str(acl->aces[i]->flags);
434   
435    if(flags_str != NULL && perms_str != NULL 
436       && type_str != NULL && sid_str != NULL)
437    {
438      /* XXX: this is slow */
439      extra = strlen(sid_str) + strlen(type_str) 
440        + strlen(perms_str) + strlen(flags_str) + 5;
441      tmp_val = realloc(ret_val, size+extra);
442
443      if(tmp_val == NULL)
444      {
445        free(ret_val);
446        ret_val = NULL;
447        failed = true;
448      }
449      else
450      {
451        ret_val = tmp_val;
452        size += sprintf(ret_val+size, "%s%s%c%s%c%s%c%s",
453                        ace_delim,sid_str,
454                        field_delim,type_str,
455                        field_delim,perms_str,
456                        field_delim,flags_str);
457        ace_delim = "|";
458      }
459    }
460    else
461      failed = true;
462
463    if(sid_str != NULL)
464      free(sid_str);
465    if(sid_str != NULL)
466      free(perms_str);
467    if(sid_str != NULL)
468      free(flags_str);
469  }
470
471  return ret_val;
472}
473
474
475char* regfi_get_sacl(WINSEC_DESC *sec_desc)
476{
477  if (sec_desc->sacl)
478    return regfi_get_acl(sec_desc->sacl);
479  else
480    return NULL;
481}
482
483
484char* regfi_get_dacl(WINSEC_DESC *sec_desc)
485{
486  if (sec_desc->dacl)
487    return regfi_get_acl(sec_desc->dacl);
488  else
489    return NULL;
490}
491
492
493char* regfi_get_owner(WINSEC_DESC *sec_desc)
494{
495  return regfi_sid2str(sec_desc->owner_sid);
496}
497
498
499char* regfi_get_group(WINSEC_DESC *sec_desc)
500{
501  return regfi_sid2str(sec_desc->grp_sid);
502}
503
504
505bool regfi_read_lock(REGFI_FILE* file, pthread_rwlock_t* lock, const char* context)
506{
507  int lock_ret = pthread_rwlock_rdlock(lock);
508  if(lock_ret != 0)
509  {
510    regfi_log_add(REGFI_LOG_ERROR, "Error obtaining read lock in"
511                      "%s due to: %s\n", context, strerror(lock_ret));
512    return false;
513  }
514
515  return true;
516}
517
518
519bool regfi_write_lock(REGFI_FILE* file, pthread_rwlock_t* lock, const char* context)
520{
521  int lock_ret = pthread_rwlock_wrlock(lock);
522  if(lock_ret != 0)
523  {
524    regfi_log_add(REGFI_LOG_ERROR, "Error obtaining write lock in"
525                      "%s due to: %s\n", context, strerror(lock_ret));
526    return false;
527  }
528
529  return true;
530}
531
532
533bool regfi_rw_unlock(REGFI_FILE* file, pthread_rwlock_t* lock, const char* context)
534{
535  int lock_ret = pthread_rwlock_unlock(lock);
536  if(lock_ret != 0)
537  {
538    regfi_log_add(REGFI_LOG_ERROR, "Error releasing lock in"
539                      "%s due to: %s\n", context, strerror(lock_ret));
540    return false;
541  }
542
543  return true;
544}
545
546
547bool regfi_lock(REGFI_FILE* file, pthread_mutex_t* lock, const char* context)
548{
549  int lock_ret = pthread_mutex_lock(lock);
550  if(lock_ret != 0)
551  {
552    regfi_log_add(REGFI_LOG_ERROR, "Error obtaining mutex lock in"
553                      "%s due to: %s\n", context, strerror(lock_ret));
554    return false;
555  }
556
557  return true;
558}
559
560
561bool regfi_unlock(REGFI_FILE* file, pthread_mutex_t* lock, const char* context)
562{
563  int lock_ret = pthread_mutex_unlock(lock);
564  if(lock_ret != 0)
565  {
566    regfi_log_add(REGFI_LOG_ERROR, "Error releasing mutex lock in"
567                      "%s due to: %s\n", context, strerror(lock_ret));
568    return false;
569  }
570
571  return true;
572}
573
574
575int64_t regfi_raw_seek(REGFI_RAW_FILE* self, uint64_t offset, int whence)
576{
577  if(sizeof(off_t) == 4 && offset > 2147483647)
578  {
579    errno = EOVERFLOW;
580    return -1;
581  }
582  return lseek(*(int*)self->state, offset, whence);
583}
584
585ssize_t regfi_raw_read(REGFI_RAW_FILE* self, void* buf, size_t count)
586{
587  return read(*(int*)self->state, buf, count);
588}
589
590
591/*****************************************************************************
592 * Convenience function to wrap up the ugly callback stuff
593 *****************************************************************************/
594uint64_t regfi_seek(REGFI_RAW_FILE* file_cb, uint64_t offset, int whence)
595{
596  return file_cb->seek(file_cb, offset, whence);
597}
598
599
600/*****************************************************************************
601 * This function is just like read(2), except that it continues to
602 * re-try reading from the file descriptor if EINTR or EAGAIN is received. 
603 * regfi_read will attempt to read length bytes from the file and write them to
604 * buf.
605 *
606 * On success, 0 is returned.  Upon failure, an errno code is returned.
607 *
608 * The number of bytes successfully read is returned through the length
609 * parameter by reference.  If both the return value and length parameter are
610 * returned as 0, then EOF was encountered immediately
611 *****************************************************************************/
612uint32_t regfi_read(REGFI_RAW_FILE* file_cb, uint8_t* buf, uint32_t* length)
613{
614  uint32_t rsize = 0;
615  uint32_t rret = 0;
616
617  do
618  {
619    rret = file_cb->read(file_cb, 
620                         buf + rsize, 
621                         *length - rsize);
622    if(rret > 0)
623      rsize += rret;
624  }while(*length - rsize > 0 
625         && (rret > 0 || (rret == -1 && (errno == EAGAIN || errno == EINTR))));
626 
627  *length = rsize;
628  if (rret == -1 && errno != EINTR && errno != EAGAIN)
629    return errno;
630
631  return 0;
632}
633
634
635/*****************************************************************************
636 *
637 *****************************************************************************/
638bool regfi_parse_cell(REGFI_RAW_FILE* file_cb, uint32_t offset, uint8_t* hdr, 
639                      uint32_t hdr_len, uint32_t* cell_length, bool* unalloc)
640{
641  uint32_t length;
642  int32_t raw_length;
643  uint8_t tmp[4];
644
645  if(regfi_seek(file_cb, offset, SEEK_SET) == -1)
646    return false;
647
648  length = 4;
649  if((regfi_read(file_cb, tmp, &length) != 0) || length != 4)
650    return false;
651  raw_length = IVALS(tmp, 0);
652
653  if(raw_length < 0)
654  {
655    (*cell_length) = raw_length*(-1);
656    (*unalloc) = false;
657  }
658  else
659  {
660    (*cell_length) = raw_length;
661    (*unalloc) = true;
662  }
663
664  if(*cell_length - 4 < hdr_len)
665    return false;
666
667  if(hdr_len > 0)
668  {
669    length = hdr_len;
670    if((regfi_read(file_cb, hdr, &length) != 0) || length != hdr_len)
671      return false;
672  }
673
674  return true;
675}
676
677
678/******************************************************************************
679 * Given an offset and an hbin, is the offset within that hbin?
680 * The offset is a virtual file offset.
681 ******************************************************************************/
682static bool regfi_offset_in_hbin(const REGFI_HBIN* hbin, uint32_t voffset)
683{
684  if(!hbin)
685    return false;
686
687  if((voffset > hbin->first_hbin_off) 
688     && (voffset < (hbin->first_hbin_off + hbin->block_size)))
689    return true;
690               
691  return false;
692}
693
694
695
696/******************************************************************************
697 * Provide a physical offset and receive the correpsonding HBIN
698 * block for it.  NULL if one doesn't exist.
699 ******************************************************************************/
700const REGFI_HBIN* regfi_lookup_hbin(REGFI_FILE* file, uint32_t offset)
701{
702  return (const REGFI_HBIN*)range_list_find_data(file->hbins, offset);
703}
704
705
706/******************************************************************************
707 * Calculate the largest possible cell size given a physical offset.
708 * Largest size is based on the HBIN the offset is currently a member of.
709 * Returns negative values on error.
710 * (Since cells can only be ~2^31 in size, this works out.)
711 ******************************************************************************/
712int32_t regfi_calc_maxsize(REGFI_FILE* file, uint32_t offset)
713{
714  const REGFI_HBIN* hbin = regfi_lookup_hbin(file, offset);
715  if(hbin == NULL)
716    return -1;
717
718  return (hbin->block_size + hbin->file_off) - offset;
719}
720
721
722/******************************************************************************
723 ******************************************************************************/
724REGFI_SUBKEY_LIST* regfi_load_subkeylist(REGFI_FILE* file, uint32_t offset, 
725                                         uint32_t num_keys, uint32_t max_size, 
726                                         bool strict)
727{
728  REGFI_SUBKEY_LIST* ret_val;
729
730  ret_val = regfi_load_subkeylist_aux(file, offset, max_size, strict, 
731                                      REGFI_MAX_SUBKEY_DEPTH);
732  if(ret_val == NULL)
733  {
734    regfi_log_add(REGFI_LOG_WARN, "Failed to load subkey list at"
735                      " offset 0x%.8X.", offset);
736    return NULL;
737  }
738
739  if(num_keys != ret_val->num_keys)
740  {
741    /*  Not sure which should be authoritative, the number from the
742     *  NK record, or the number in the subkey list.  Just emit a warning for
743     *  now if they don't match.
744     */
745    regfi_log_add(REGFI_LOG_WARN, "Number of subkeys listed in parent"
746                      " (%d) did not match number found in subkey list/tree (%d)"
747                      " while parsing subkey list/tree at offset 0x%.8X.", 
748                      num_keys, ret_val->num_keys, offset);
749  }
750
751  return ret_val;
752}
753
754
755/******************************************************************************
756 ******************************************************************************/
757REGFI_SUBKEY_LIST* regfi_load_subkeylist_aux(REGFI_FILE* file, uint32_t offset, 
758                                             uint32_t max_size, bool strict,
759                                             uint8_t depth_left)
760{
761  REGFI_SUBKEY_LIST* ret_val;
762  REGFI_SUBKEY_LIST** sublists;
763  uint32_t i, num_sublists, off;
764  int32_t sublist_maxsize;
765
766  if(depth_left == 0)
767  {
768    regfi_log_add(REGFI_LOG_WARN, "Maximum depth reached"
769                      " while parsing subkey list/tree at offset 0x%.8X.", 
770                      offset);
771    return NULL;
772  }
773
774  ret_val = regfi_parse_subkeylist(file, offset, max_size, strict);
775  if(ret_val == NULL)
776    return NULL;
777
778  if(ret_val->recursive_type)
779  {
780    num_sublists = ret_val->num_children;
781    sublists = (REGFI_SUBKEY_LIST**)malloc(num_sublists
782                                           * sizeof(REGFI_SUBKEY_LIST*));
783    for(i=0; i < num_sublists; i++)
784    {
785      off = ret_val->elements[i].offset + REGFI_REGF_SIZE;
786
787      sublist_maxsize = regfi_calc_maxsize(file, off);
788      if(sublist_maxsize < 0)
789        sublists[i] = NULL;
790      else
791        sublists[i] = regfi_load_subkeylist_aux(file, off, sublist_maxsize, 
792                                                strict, depth_left-1);
793    }
794    talloc_free(ret_val);
795
796    return regfi_merge_subkeylists(num_sublists, sublists, strict);
797  }
798
799  return ret_val;
800}
801
802
803/******************************************************************************
804 ******************************************************************************/
805REGFI_SUBKEY_LIST* regfi_parse_subkeylist(REGFI_FILE* file, uint32_t offset, 
806                                          uint32_t max_size, bool strict)
807{
808  REGFI_SUBKEY_LIST* ret_val;
809  uint32_t i, cell_length, length, elem_size, read_len;
810  uint8_t* elements = NULL;
811  uint8_t buf[REGFI_SUBKEY_LIST_MIN_LEN];
812  bool unalloc;
813  bool recursive_type;
814
815  if(!regfi_lock(file, &file->cb_lock, "regfi_parse_subkeylist"))
816     goto fail;
817
818  if(!regfi_parse_cell(file->cb, offset, buf, REGFI_SUBKEY_LIST_MIN_LEN,
819                       &cell_length, &unalloc))
820  {
821    regfi_log_add(REGFI_LOG_WARN, "Could not parse cell while "
822                      "parsing subkey-list at offset 0x%.8X.", offset);
823    goto fail_locked;
824  }
825
826  if(cell_length > max_size)
827  {
828    regfi_log_add(REGFI_LOG_WARN, "Cell size longer than max_size"
829                      " while parsing subkey-list at offset 0x%.8X.", offset);
830    if(strict)
831      goto fail_locked;
832    cell_length = max_size & 0xFFFFFFF8;
833  }
834
835  recursive_type = false;
836  if(buf[0] == 'r' && buf[1] == 'i')
837  {
838    recursive_type = true;
839    elem_size = sizeof(uint32_t);
840  }
841  else if(buf[0] == 'l' && buf[1] == 'i')
842  {
843    elem_size = sizeof(uint32_t);
844  }
845  else if((buf[0] == 'l') && (buf[1] == 'f' || buf[1] == 'h'))
846    elem_size = sizeof(REGFI_SUBKEY_LIST_ELEM);
847  else
848  {
849    regfi_log_add(REGFI_LOG_ERROR, "Unknown magic number"
850                      " (0x%.2X, 0x%.2X) encountered while parsing"
851                      " subkey-list at offset 0x%.8X.", buf[0], buf[1], offset);
852    goto fail_locked;
853  }
854
855  ret_val = talloc(NULL, REGFI_SUBKEY_LIST);
856  if(ret_val == NULL)
857    goto fail_locked;
858
859  ret_val->offset = offset;
860  ret_val->cell_size = cell_length;
861  ret_val->magic[0] = buf[0];
862  ret_val->magic[1] = buf[1];
863  ret_val->recursive_type = recursive_type;
864  ret_val->num_children = SVAL(buf, 0x2);
865
866  if(!recursive_type)
867    ret_val->num_keys = ret_val->num_children;
868
869  length = elem_size*ret_val->num_children;
870  if(cell_length - REGFI_SUBKEY_LIST_MIN_LEN - sizeof(uint32_t) < length)
871  {
872    regfi_log_add(REGFI_LOG_WARN, "Number of elements too large for"
873                      " cell while parsing subkey-list at offset 0x%.8X.", 
874                      offset);
875    if(strict)
876      goto fail_locked;
877    length = cell_length - REGFI_SUBKEY_LIST_MIN_LEN - sizeof(uint32_t);
878  }
879
880  ret_val->elements = talloc_array(ret_val, REGFI_SUBKEY_LIST_ELEM, 
881                                   ret_val->num_children);
882  if(ret_val->elements == NULL)
883    goto fail_locked;
884
885  elements = (uint8_t*)malloc(length);
886  if(elements == NULL)
887    goto fail_locked;
888
889  read_len = length;
890  if(regfi_read(file->cb, elements, &read_len) != 0 || read_len!=length)
891    goto fail_locked;
892
893  if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_subkeylist"))
894     goto fail;
895
896  if(elem_size == sizeof(uint32_t))
897  {
898    for (i=0; i < ret_val->num_children; i++)
899    {
900      ret_val->elements[i].offset = IVAL(elements, i*elem_size);
901      ret_val->elements[i].hash = 0;
902    }
903  }
904  else
905  {
906    for (i=0; i < ret_val->num_children; i++)
907    {
908      ret_val->elements[i].offset = IVAL(elements, i*elem_size);
909      ret_val->elements[i].hash = IVAL(elements, i*elem_size+4);
910    }
911  }
912  free(elements);
913
914  return ret_val;
915
916 fail_locked:
917  regfi_unlock(file, &file->cb_lock, "regfi_parse_subkeylist");
918 fail:
919  if(elements != NULL)
920    free(elements);
921  talloc_free(ret_val);
922  return NULL;
923}
924
925
926/*******************************************************************
927 *******************************************************************/
928REGFI_SUBKEY_LIST* regfi_merge_subkeylists(uint16_t num_lists, 
929                                           REGFI_SUBKEY_LIST** lists,
930                                           bool strict)
931{
932  uint32_t i,j,k;
933  REGFI_SUBKEY_LIST* ret_val;
934
935  if(lists == NULL)
936    return NULL;
937  ret_val = talloc(NULL, REGFI_SUBKEY_LIST);
938
939  if(ret_val == NULL)
940    return NULL;
941 
942  /* Obtain total number of elements */
943  ret_val->num_keys = 0;
944  for(i=0; i < num_lists; i++)
945  {
946    if(lists[i] != NULL)
947      ret_val->num_keys += lists[i]->num_children;
948  }
949  ret_val->num_children = ret_val->num_keys;
950
951  if(ret_val->num_keys > 0)
952  {
953    ret_val->elements = talloc_array(ret_val, REGFI_SUBKEY_LIST_ELEM,
954                                     ret_val->num_keys);
955    k=0;
956
957    if(ret_val->elements != NULL)
958    {
959      for(i=0; i < num_lists; i++)
960      {
961        if(lists[i] != NULL)
962        {
963          for(j=0; j < lists[i]->num_keys; j++)
964          {
965            ret_val->elements[k].hash = lists[i]->elements[j].hash;
966            ret_val->elements[k++].offset = lists[i]->elements[j].offset;
967          }
968        }
969      }
970    }
971  }
972 
973  for(i=0; i < num_lists; i++)
974    talloc_free(lists[i]);
975  free(lists);
976
977  return ret_val;
978}
979
980
981/******************************************************************************
982 *
983 ******************************************************************************/
984REGFI_SK* regfi_parse_sk(REGFI_FILE* file, uint32_t offset, uint32_t max_size, 
985                             bool strict)
986{
987  REGFI_SK* ret_val = NULL;
988  uint8_t* sec_desc_buf = NULL;
989  uint32_t cell_length, length;
990  uint8_t sk_header[REGFI_SK_MIN_LENGTH];
991  bool unalloc = false;
992
993  if(!regfi_lock(file, &file->cb_lock, "regfi_parse_sk"))
994     goto fail;
995
996  if(!regfi_parse_cell(file->cb, offset, sk_header, REGFI_SK_MIN_LENGTH,
997                       &cell_length, &unalloc))
998  {
999    regfi_log_add(REGFI_LOG_WARN, "Could not parse SK record cell"
1000                      " at offset 0x%.8X.", offset);
1001    goto fail_locked;
1002  }
1003   
1004  if(sk_header[0] != 's' || sk_header[1] != 'k')
1005  {
1006    regfi_log_add(REGFI_LOG_WARN, "Magic number mismatch in parsing"
1007                      " SK record at offset 0x%.8X.", offset);
1008    goto fail_locked;
1009  }
1010
1011  ret_val = talloc(NULL, REGFI_SK);
1012  if(ret_val == NULL)
1013    goto fail_locked;
1014
1015  ret_val->offset = offset;
1016  /* XXX: Is there a way to be more conservative (shorter) with
1017   *      cell length when cell is unallocated?
1018   */
1019  ret_val->cell_size = cell_length;
1020
1021  if(ret_val->cell_size > max_size)
1022    ret_val->cell_size = max_size & 0xFFFFFFF8;
1023  if((ret_val->cell_size < REGFI_SK_MIN_LENGTH) 
1024     || (strict && (ret_val->cell_size & 0x00000007) != 0))
1025  {
1026    regfi_log_add(REGFI_LOG_WARN, "Invalid cell size found while"
1027                      " parsing SK record at offset 0x%.8X.", offset);
1028    goto fail_locked;
1029  }
1030
1031  ret_val->magic[0] = sk_header[0];
1032  ret_val->magic[1] = sk_header[1];
1033
1034  ret_val->unknown_tag = SVAL(sk_header, 0x2);
1035  ret_val->prev_sk_off = IVAL(sk_header, 0x4);
1036  ret_val->next_sk_off = IVAL(sk_header, 0x8);
1037  ret_val->ref_count = IVAL(sk_header, 0xC);
1038  ret_val->desc_size = IVAL(sk_header, 0x10);
1039
1040  if((ret_val->prev_sk_off & 0x00000007) != 0
1041     || (ret_val->next_sk_off & 0x00000007) != 0)
1042  {
1043    regfi_log_add(REGFI_LOG_WARN, "SK record's next/previous offsets"
1044                      " are not a multiple of 8 while parsing SK record at"
1045                      " offset 0x%.8X.", offset);
1046    goto fail_locked;
1047  }
1048
1049  if(ret_val->desc_size + REGFI_SK_MIN_LENGTH > ret_val->cell_size)
1050  {
1051    regfi_log_add(REGFI_LOG_WARN, "Security descriptor too large for"
1052                      " cell while parsing SK record at offset 0x%.8X.", 
1053                      offset);
1054    goto fail_locked;
1055  }
1056
1057  sec_desc_buf = (uint8_t*)malloc(ret_val->desc_size);
1058  if(sec_desc_buf == NULL)
1059    goto fail_locked;
1060
1061  length = ret_val->desc_size;
1062  if(regfi_read(file->cb, sec_desc_buf, &length) != 0 
1063     || length != ret_val->desc_size)
1064  {
1065    regfi_log_add(REGFI_LOG_ERROR, "Failed to read security"
1066                      " descriptor while parsing SK record at offset 0x%.8X.",
1067                      offset);
1068    goto fail_locked;
1069  }
1070
1071  if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_sk"))
1072     goto fail;
1073
1074  if(!(ret_val->sec_desc = winsec_parse_desc(ret_val, sec_desc_buf, 
1075                                                   ret_val->desc_size)))
1076  {
1077    regfi_log_add(REGFI_LOG_ERROR, "Failed to parse security"
1078                      " descriptor while parsing SK record at offset 0x%.8X.",
1079                      offset);
1080    goto fail;
1081  }
1082
1083  free(sec_desc_buf);
1084  return ret_val;
1085
1086 fail_locked:
1087  regfi_unlock(file, &file->cb_lock, "regfi_parse_sk");
1088 fail:
1089  if(sec_desc_buf != NULL)
1090    free(sec_desc_buf);
1091  talloc_free(ret_val);
1092  return NULL;
1093}
1094
1095
1096REGFI_VALUE_LIST* regfi_parse_valuelist(REGFI_FILE* file, uint32_t offset, 
1097                                        uint32_t num_values, bool strict)
1098{
1099  REGFI_VALUE_LIST* ret_val;
1100  uint32_t i, cell_length, length, read_len;
1101  bool unalloc;
1102
1103  if(!regfi_lock(file, &file->cb_lock, "regfi_parse_valuelist"))
1104     goto fail;
1105
1106  if(!regfi_parse_cell(file->cb, offset, NULL, 0, &cell_length, &unalloc))
1107  {
1108    regfi_log_add(REGFI_LOG_ERROR, "Failed to read cell header"
1109                      " while parsing value list at offset 0x%.8X.", offset);
1110    goto fail_locked;
1111  }
1112
1113  if((cell_length & 0x00000007) != 0)
1114  {
1115    regfi_log_add(REGFI_LOG_WARN, "Cell length not a multiple of 8"
1116                      " while parsing value list at offset 0x%.8X.", offset);
1117    if(strict)
1118      goto fail_locked;
1119    cell_length = cell_length & 0xFFFFFFF8;
1120  }
1121
1122  if((num_values * sizeof(uint32_t)) > cell_length-sizeof(uint32_t))
1123  {
1124    regfi_log_add(REGFI_LOG_WARN, "Too many values found"
1125                      " while parsing value list at offset 0x%.8X.", offset);
1126    if(strict)
1127      goto fail_locked;
1128    num_values = cell_length/sizeof(uint32_t) - sizeof(uint32_t);
1129  }
1130
1131  read_len = num_values*sizeof(uint32_t);
1132  ret_val = talloc(NULL, REGFI_VALUE_LIST);
1133  if(ret_val == NULL)
1134    goto fail_locked;
1135
1136  ret_val->elements = (REGFI_VALUE_LIST_ELEM*)talloc_size(ret_val, read_len);
1137  if(ret_val->elements == NULL)
1138    goto fail_locked;
1139
1140  ret_val->offset = offset;
1141  ret_val->cell_size = cell_length;
1142  ret_val->num_values = num_values;
1143
1144  length = read_len;
1145  if((regfi_read(file->cb, (uint8_t*)ret_val->elements, &length) != 0) 
1146     || length != read_len)
1147  {
1148    regfi_log_add(REGFI_LOG_ERROR, "Failed to read value pointers"
1149                      " while parsing value list at offset 0x%.8X.", offset);
1150    goto fail_locked;
1151  }
1152 
1153  if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_valuelist"))
1154     goto fail;
1155
1156  for(i=0; i < num_values; i++)
1157  {
1158    /* Fix endianness */
1159    ret_val->elements[i] = IVAL(&ret_val->elements[i], 0);
1160
1161    /* Validate the first num_values values to ensure they make sense */
1162    if(strict)
1163    {
1164      /* XXX: Need to revisit this file length check when we start dealing
1165       *      with partial files. */
1166      if((ret_val->elements[i] + REGFI_REGF_SIZE > file->file_length)
1167         || ((ret_val->elements[i] & 0x00000007) != 0))
1168      {
1169        regfi_log_add(REGFI_LOG_WARN, "Invalid value pointer"
1170                          " (0x%.8X) found while parsing value list at offset"
1171                          " 0x%.8X.", ret_val->elements[i], offset);
1172        goto fail;
1173      }
1174    }
1175  }
1176
1177  return ret_val;
1178
1179 fail_locked:
1180  regfi_unlock(file, &file->cb_lock, "regfi_parse_valuelist");
1181 fail:
1182  talloc_free(ret_val);
1183  return NULL;
1184}
1185
1186/* XXX: should give this boolean return type to indicate errors */
1187void regfi_interpret_valuename(REGFI_FILE* file, REGFI_VK* vk, 
1188                               REGFI_ENCODING output_encoding, bool strict)
1189{
1190  /* XXX: Registry value names are supposedly limited to 16383 characters
1191   *      according to:
1192   *      http://msdn.microsoft.com/en-us/library/ms724872%28VS.85%29.aspx
1193   *      Might want to emit a warning if this is exceeded. 
1194   *      It is expected that "characters" could be variable width.
1195   *      Also, it may be useful to use this information to limit false positives
1196   *      when recovering deleted VK records.
1197   */
1198  int32_t tmp_size;
1199  REGFI_ENCODING from_encoding = (vk->flags & REGFI_VK_FLAG_ASCIINAME)
1200    ? REGFI_ENCODING_ASCII : REGFI_ENCODING_UTF16LE;
1201
1202  if(from_encoding == output_encoding)
1203  {
1204    vk->name_raw[vk->name_length] = '\0';
1205    vk->name = (char*)vk->name_raw;
1206  }
1207  else
1208  {
1209    vk->name = talloc_array(vk, char, vk->name_length+1);
1210    if(vk->name == NULL)
1211      return;
1212
1213    tmp_size = regfi_conv_charset(regfi_encoding_int2str(from_encoding),
1214                                  regfi_encoding_int2str(output_encoding),
1215                                  vk->name_raw, vk->name,
1216                                  vk->name_length, vk->name_length+1);
1217    if(tmp_size < 0)
1218    {
1219      regfi_log_add(REGFI_LOG_WARN, "Error occurred while converting"
1220                        " value name to encoding %s.  Error message: %s",
1221                        regfi_encoding_int2str(output_encoding), 
1222                        strerror(-tmp_size));
1223      talloc_free(vk->name);
1224      vk->name = NULL;
1225    }
1226  }
1227}
1228
1229
1230/******************************************************************************
1231 ******************************************************************************/
1232REGFI_VK* regfi_load_value(REGFI_FILE* file, uint32_t offset, 
1233                           REGFI_ENCODING output_encoding, bool strict)
1234{
1235  REGFI_VK* ret_val = NULL;
1236  int32_t max_size;
1237
1238  max_size = regfi_calc_maxsize(file, offset);
1239  if(max_size < 0)
1240    return NULL;
1241 
1242  ret_val = regfi_parse_vk(file, offset, max_size, strict);
1243  if(ret_val == NULL)
1244    return NULL;
1245
1246  regfi_interpret_valuename(file, ret_val, output_encoding, strict);
1247
1248  return ret_val;
1249}
1250
1251
1252/******************************************************************************
1253 * If !strict, the list may contain NULLs, VK records may point to NULL.
1254 ******************************************************************************/
1255REGFI_VALUE_LIST* regfi_load_valuelist(REGFI_FILE* file, uint32_t offset, 
1256                                       uint32_t num_values, uint32_t max_size,
1257                                       bool strict)
1258{
1259  uint32_t usable_num_values;
1260
1261  if((num_values+1) * sizeof(uint32_t) > max_size)
1262  {
1263    regfi_log_add(REGFI_LOG_WARN, "Number of values indicated by"
1264                      " parent key (%d) would cause cell to straddle HBIN"
1265                      " boundary while loading value list at offset"
1266                      " 0x%.8X.", num_values, offset);
1267    if(strict)
1268      return NULL;
1269    usable_num_values = max_size/sizeof(uint32_t) - sizeof(uint32_t);
1270  }
1271  else
1272    usable_num_values = num_values;
1273
1274  return regfi_parse_valuelist(file, offset, usable_num_values, strict);
1275}
1276
1277
1278/* XXX: should give this boolean return type to indicate errors */
1279void regfi_interpret_keyname(REGFI_FILE* file, REGFI_NK* nk, 
1280                             REGFI_ENCODING output_encoding, bool strict)
1281{
1282  /* XXX: Registry key names are supposedly limited to 255 characters according to:
1283   *      http://msdn.microsoft.com/en-us/library/ms724872%28VS.85%29.aspx
1284   *      Might want to emit a warning if this is exceeded. 
1285   *      It is expected that "characters" could be variable width.
1286   *      Also, it may be useful to use this information to limit false positives
1287   *      when recovering deleted NK records.
1288   */
1289  int32_t tmp_size;
1290  REGFI_ENCODING from_encoding = (nk->flags & REGFI_NK_FLAG_ASCIINAME) 
1291    ? REGFI_ENCODING_ASCII : REGFI_ENCODING_UTF16LE;
1292 
1293  if(from_encoding == output_encoding)
1294  {
1295    nk->name_raw[nk->name_length] = '\0';
1296    nk->name = (char*)nk->name_raw;
1297  }
1298  else
1299  {
1300    nk->name = talloc_array(nk, char, nk->name_length+1);
1301    if(nk->name == NULL)
1302      return;
1303
1304    memset(nk->name,0,nk->name_length+1);
1305
1306    tmp_size = regfi_conv_charset(regfi_encoding_int2str(from_encoding),
1307                                  regfi_encoding_int2str(output_encoding),
1308                                  nk->name_raw, nk->name,
1309                                  nk->name_length, nk->name_length+1);
1310    if(tmp_size < 0)
1311    {
1312      regfi_log_add(REGFI_LOG_WARN, "Error occurred while converting"
1313                        " key name to encoding %s.  Error message: %s",
1314                        regfi_encoding_int2str(output_encoding), 
1315                        strerror(-tmp_size));
1316      talloc_free(nk->name);
1317      nk->name = NULL;
1318    }
1319  }
1320}
1321
1322
1323/******************************************************************************
1324 *
1325 ******************************************************************************/
1326REGFI_NK* regfi_load_key(REGFI_FILE* file, uint32_t offset,
1327                         REGFI_ENCODING output_encoding, bool strict)
1328{
1329  REGFI_NK* nk;
1330  uint32_t off;
1331  int32_t max_size;
1332
1333  max_size = regfi_calc_maxsize(file, offset);
1334  if (max_size < 0) 
1335    return NULL;
1336
1337  /* get the initial nk record */
1338  if((nk = regfi_parse_nk(file, offset, max_size, true)) == NULL)
1339  {
1340    regfi_log_add(REGFI_LOG_ERROR, "Could not load NK record at"
1341                  " offset 0x%.8X.", offset);
1342    return NULL;
1343  }
1344
1345  regfi_interpret_keyname(file, nk, output_encoding, strict);
1346
1347  /* get value list */
1348  if(nk->num_values && (nk->values_off!=REGFI_OFFSET_NONE)) 
1349  {
1350    off = nk->values_off + REGFI_REGF_SIZE;
1351    max_size = regfi_calc_maxsize(file, off);
1352    if(max_size < 0)
1353    {
1354      if(strict)
1355      {
1356        talloc_free(nk);
1357        return NULL;
1358      }
1359      else
1360        nk->values = NULL;
1361
1362    }
1363    else
1364    {
1365      nk->values = regfi_load_valuelist(file, off, nk->num_values, 
1366                                        max_size, true);
1367      if(nk->values == NULL)
1368      {
1369        regfi_log_add(REGFI_LOG_WARN, "Could not load value list"
1370                      " for NK record at offset 0x%.8X.", offset);
1371        if(strict)
1372        {
1373          talloc_free(nk);
1374          return NULL;
1375        }
1376      }
1377      talloc_reparent(NULL, nk, nk->values);
1378    }
1379  }
1380
1381  /* now get subkey list */
1382  if(nk->num_subkeys && (nk->subkeys_off != REGFI_OFFSET_NONE)) 
1383  {
1384    off = nk->subkeys_off + REGFI_REGF_SIZE;
1385    max_size = regfi_calc_maxsize(file, off);
1386    if(max_size < 0) 
1387    {
1388      if(strict)
1389      {
1390        talloc_free(nk);
1391        return NULL;
1392      }
1393      else
1394        nk->subkeys = NULL;
1395    }
1396    else
1397    {
1398      nk->subkeys = regfi_load_subkeylist(file, off, nk->num_subkeys,
1399                                          max_size, true);
1400
1401      if(nk->subkeys == NULL)
1402      {
1403        regfi_log_add(REGFI_LOG_WARN, "Could not load subkey list"
1404                      " while parsing NK record at offset 0x%.8X.", offset);
1405        nk->num_subkeys = 0;
1406      }
1407      talloc_reparent(NULL, nk, nk->subkeys);
1408    }
1409  }
1410
1411  return nk;
1412}
1413
1414
1415/******************************************************************************
1416 ******************************************************************************/
1417const REGFI_SK* regfi_load_sk(REGFI_FILE* file, uint32_t offset, bool strict)
1418{
1419  REGFI_SK* ret_val = NULL;
1420  int32_t max_size;
1421  void* failure_ptr = NULL;
1422 
1423  max_size = regfi_calc_maxsize(file, offset);
1424  if(max_size < 0)
1425    return NULL;
1426
1427  if(file->sk_cache == NULL)
1428    return regfi_parse_sk(file, offset, max_size, strict);
1429
1430  if(!regfi_lock(file, &file->sk_lock, "regfi_load_sk"))
1431    return NULL;
1432
1433  /* First look if we have already parsed it */
1434  ret_val = (REGFI_SK*)lru_cache_find(file->sk_cache, &offset, 4);
1435
1436  /* Bail out if we have previously cached a parse failure at this offset. */
1437  if(ret_val == (void*)REGFI_OFFSET_NONE)
1438    return NULL;
1439
1440  if(ret_val == NULL)
1441  {
1442    ret_val = regfi_parse_sk(file, offset, max_size, strict);
1443    if(ret_val == NULL)
1444    { /* Cache the parse failure and bail out. */
1445      failure_ptr = talloc(NULL, uint32_t);
1446      if(failure_ptr == NULL)
1447        return NULL;
1448      *(uint32_t*)failure_ptr = REGFI_OFFSET_NONE;
1449      lru_cache_update(file->sk_cache, &offset, 4, failure_ptr);
1450
1451      /* Let the cache be the only owner of this */
1452      talloc_unlink(NULL, failure_ptr);
1453      return NULL;
1454    }
1455  }
1456
1457  if(!regfi_unlock(file, &file->sk_lock, "regfi_load_sk"))
1458  {
1459    talloc_unlink(NULL, ret_val);
1460    return NULL;
1461  }
1462
1463  return ret_val;
1464}
1465
1466
1467
1468/******************************************************************************
1469 ******************************************************************************/
1470REGFI_NK* regfi_find_root_nk(REGFI_FILE* file, const REGFI_HBIN* hbin, 
1471                             REGFI_ENCODING output_encoding)
1472{
1473  REGFI_NK* nk = NULL;
1474  uint32_t cell_length;
1475  uint32_t cur_offset = hbin->file_off+REGFI_HBIN_HEADER_SIZE;
1476  uint32_t hbin_end = hbin->file_off+hbin->block_size;
1477  bool unalloc;
1478
1479  while(cur_offset < hbin_end)
1480  {
1481
1482    if(!regfi_lock(file, &file->cb_lock, "regfi_find_root_nk"))
1483      return NULL;
1484
1485    if(!regfi_parse_cell(file->cb, cur_offset, NULL, 0, &cell_length, &unalloc))
1486    {
1487      regfi_log_add(REGFI_LOG_WARN, "Could not parse cell at offset"
1488                    " 0x%.8X while searching for root key.", cur_offset);
1489      return NULL;
1490    }
1491
1492    if(!regfi_unlock(file, &file->cb_lock, "regfi_find_root_nk"))
1493      return NULL;
1494
1495    if(!unalloc)
1496    {
1497      nk = regfi_load_key(file, cur_offset, output_encoding, true);
1498      if(nk != NULL)
1499      {
1500        if(nk->flags & REGFI_NK_FLAG_ROOT)
1501          return nk;
1502      }
1503    }
1504
1505    cur_offset += cell_length;
1506  }
1507
1508  return NULL;
1509}
1510
1511
1512
1513/******************************************************************************
1514 ******************************************************************************/
1515REGFI_FILE* regfi_alloc(int fd, REGFI_ENCODING output_encoding)
1516{
1517  REGFI_FILE* ret_val;
1518  REGFI_RAW_FILE* file_cb = talloc(NULL, REGFI_RAW_FILE);
1519  if(file_cb == NULL) 
1520    return NULL;
1521
1522  file_cb->state = (void*)talloc(file_cb, int);
1523  if(file_cb->state == NULL)
1524    goto fail;
1525  *(int*)file_cb->state = fd;
1526 
1527  file_cb->cur_off = 0;
1528  file_cb->size = 0;
1529  file_cb->read = &regfi_raw_read;
1530  file_cb->seek = &regfi_raw_seek;
1531 
1532  ret_val = regfi_alloc_cb(file_cb, output_encoding);
1533  if(ret_val == NULL)
1534    goto fail;
1535
1536  /* In this case, we want file_cb to be freed when ret_val is */
1537  talloc_reparent(NULL, ret_val, file_cb);
1538  return ret_val;
1539
1540 fail:
1541    talloc_free(file_cb);
1542    return NULL;
1543}
1544
1545
1546/******************************************************************************
1547 ******************************************************************************/
1548static int regfi_free_cb(void* f)
1549{
1550  REGFI_FILE* file = (REGFI_FILE*)f;
1551
1552  pthread_mutex_destroy(&file->cb_lock);
1553  pthread_rwlock_destroy(&file->hbins_lock);
1554  pthread_mutex_destroy(&file->sk_lock);
1555
1556  return 0;
1557}
1558
1559
1560/******************************************************************************
1561 ******************************************************************************/
1562REGFI_FILE* regfi_alloc_cb(REGFI_RAW_FILE* file_cb, 
1563                           REGFI_ENCODING output_encoding)
1564{
1565  REGFI_FILE* rb;
1566  REGFI_HBIN* hbin = NULL;
1567  uint32_t hbin_off, cache_secret;
1568  int64_t file_length;
1569  bool rla;
1570
1571  /* Determine file length.  Must be at least big enough for the header
1572   * and one hbin.
1573   */
1574  file_length = regfi_seek(file_cb, 0, SEEK_END);
1575  if(file_length < REGFI_REGF_SIZE+REGFI_HBIN_ALLOC)
1576  {
1577    regfi_log_add(REGFI_LOG_ERROR, "File length (%d) too short to contain a"
1578                  " header and at least one HBIN.", file_length);
1579    return NULL;
1580  }
1581  regfi_seek(file_cb, 0, SEEK_SET);
1582
1583  if(output_encoding != REGFI_ENCODING_UTF8
1584     && output_encoding != REGFI_ENCODING_ASCII)
1585  { 
1586    regfi_log_add(REGFI_LOG_ERROR, "Invalid output_encoding supplied"
1587                  " in creation of regfi iterator.");
1588    return NULL;
1589  }
1590
1591  /* Read file header */
1592  if ((rb = regfi_parse_regf(file_cb, false)) == NULL)
1593  {
1594    regfi_log_add(REGFI_LOG_ERROR, "Failed to read REGF block.");
1595    return NULL;
1596  }
1597  rb->file_length = file_length;
1598  rb->cb = file_cb;
1599  rb->string_encoding = output_encoding;
1600
1601  if(pthread_mutex_init(&rb->cb_lock, NULL) != 0)
1602  {
1603    regfi_log_add(REGFI_LOG_ERROR, "Failed to create cb_lock mutex.");
1604    goto fail;
1605  }
1606
1607  if(pthread_rwlock_init(&rb->hbins_lock, NULL) != 0)
1608  {
1609    regfi_log_add(REGFI_LOG_ERROR, "Failed to create hbins_lock rwlock.");
1610    goto fail;
1611  }
1612
1613  if(pthread_mutex_init(&rb->sk_lock, NULL) != 0)
1614  {
1615    regfi_log_add(REGFI_LOG_ERROR, "Failed to create sk_lock mutex.");
1616    goto fail;
1617  }
1618
1619  if(pthread_mutex_init(&rb->mem_lock, NULL) != 0)
1620  {
1621    regfi_log_add(REGFI_LOG_ERROR, "Failed to create mem_lock mutex.");
1622    goto fail;
1623  }
1624
1625  rb->hbins = range_list_new();
1626  if(rb->hbins == NULL)
1627  {
1628    regfi_log_add(REGFI_LOG_ERROR, "Failed to create HBIN range_list.");
1629    goto fail;
1630  }
1631  talloc_reparent(NULL, rb, rb->hbins);
1632
1633  rla = true;
1634  hbin_off = REGFI_REGF_SIZE;
1635  hbin = regfi_parse_hbin(rb, hbin_off, true);
1636  while(hbin && rla)
1637  {
1638    rla = range_list_add(rb->hbins, hbin->file_off, hbin->block_size, hbin);
1639    if(rla)
1640      talloc_reparent(NULL, rb->hbins, hbin);
1641
1642    hbin_off = hbin->file_off + hbin->block_size;
1643    hbin = regfi_parse_hbin(rb, hbin_off, true);
1644  }
1645
1646  /* This secret isn't very secret, but we don't need a good one.  This
1647   * secret is just designed to prevent someone from trying to blow our
1648   * caching and make things slow.
1649   */
1650  cache_secret = 0x15DEAD05^time(NULL)^(getpid()<<16);
1651
1652  if(REGFI_CACHE_SK)
1653    rb->sk_cache = lru_cache_create_ctx(rb, 64, cache_secret, true);
1654  else
1655    rb->sk_cache = NULL;
1656
1657  /* success */
1658  talloc_set_destructor(rb, regfi_free_cb);
1659  return rb;
1660
1661 fail:
1662  pthread_mutex_destroy(&rb->cb_lock);
1663  pthread_rwlock_destroy(&rb->hbins_lock);
1664  pthread_mutex_destroy(&rb->sk_lock);
1665  pthread_mutex_destroy(&rb->mem_lock);
1666
1667  range_list_free(rb->hbins);
1668  talloc_free(rb);
1669  return NULL;
1670}
1671
1672
1673/******************************************************************************
1674 ******************************************************************************/
1675void regfi_free(REGFI_FILE* file)
1676{
1677  /* Callback handles cleanup side effects */
1678  talloc_free(file);
1679}
1680
1681
1682/******************************************************************************
1683 * First checks the offset given by the file header, then checks the
1684 * rest of the file if that fails.
1685 ******************************************************************************/
1686const REGFI_NK* regfi_get_rootkey(REGFI_FILE* file)
1687{
1688  REGFI_NK* nk = NULL;
1689  REGFI_HBIN* hbin;
1690  uint32_t root_offset, i, num_hbins;
1691 
1692  if(!file)
1693    return NULL;
1694
1695  root_offset = file->root_cell+REGFI_REGF_SIZE;
1696  nk = regfi_load_key(file, root_offset, file->string_encoding, true);
1697  if(nk != NULL)
1698  {
1699    if(nk->flags & REGFI_NK_FLAG_ROOT)
1700      return nk;
1701  }
1702
1703  regfi_log_add(REGFI_LOG_WARN, "File header indicated root key at"
1704                " location 0x%.8X, but no root key found."
1705                " Searching rest of file...", root_offset);
1706 
1707  /* If the file header gives bad info, scan through the file one HBIN
1708   * block at a time looking for an NK record with a root key type.
1709   */
1710 
1711  if(!regfi_read_lock(file, &file->hbins_lock, "regfi_get_rootkey"))
1712    return NULL;
1713
1714  num_hbins = range_list_size(file->hbins);
1715  for(i=0; i < num_hbins && nk == NULL; i++)
1716  {
1717    hbin = (REGFI_HBIN*)range_list_get(file->hbins, i)->data;
1718    nk = regfi_find_root_nk(file, hbin, file->string_encoding);
1719  }
1720
1721  if(!regfi_rw_unlock(file, &file->hbins_lock, "regfi_get_rootkey"))
1722    return NULL;
1723
1724  return nk;
1725}
1726
1727
1728/******************************************************************************
1729 *****************************************************************************/
1730void regfi_free_record(REGFI_FILE* file, const void* record)
1731{
1732  if(!regfi_lock(file, &file->mem_lock, "regfi_free_record"))
1733    return;
1734
1735  talloc_unlink(NULL, (void*)record);
1736
1737  regfi_unlock(file, &file->mem_lock, "regfi_free_record");
1738}
1739
1740
1741/******************************************************************************
1742 *****************************************************************************/
1743bool regfi_reference_record(REGFI_FILE* file, const void* record)
1744{
1745  bool ret_val = false;
1746  if(!regfi_lock(file, &file->mem_lock, "regfi_reference_record"))
1747    return ret_val;
1748 
1749  if(talloc_reference(NULL, record) != NULL)
1750    ret_val = true;
1751
1752  regfi_unlock(file, &file->mem_lock, "regfi_reference_record");
1753  return ret_val;
1754}
1755
1756
1757/******************************************************************************
1758 *****************************************************************************/
1759uint32_t regfi_fetch_num_subkeys(const REGFI_NK* key)
1760{
1761  uint32_t num_in_list = 0;
1762  if(key == NULL)
1763    return 0;
1764
1765  if(key->subkeys != NULL)
1766    num_in_list = key->subkeys->num_keys;
1767
1768  if(num_in_list != key->num_subkeys)
1769  {
1770    regfi_log_add(REGFI_LOG_INFO, "Key at offset 0x%.8X contains %d keys in its"
1771                  " subkey list but reports %d should be available.", 
1772                  key->offset, num_in_list, key->num_subkeys);
1773    return (num_in_list < key->num_subkeys)?num_in_list:key->num_subkeys;
1774  }
1775 
1776  return num_in_list;
1777}
1778
1779
1780/******************************************************************************
1781 *****************************************************************************/
1782uint32_t regfi_fetch_num_values(const REGFI_NK* key)
1783{
1784  uint32_t num_in_list = 0;
1785  if(key == NULL)
1786    return 0;
1787
1788  if(key->values != NULL)
1789    num_in_list = key->values->num_values;
1790
1791  if(num_in_list != key->num_values)
1792  {
1793    regfi_log_add(REGFI_LOG_INFO, "Key at offset 0x%.8X contains %d values in"
1794                  " its value list but reports %d should be available.",
1795                  key->offset, num_in_list, key->num_values);
1796    return (num_in_list < key->num_values)?num_in_list:key->num_values;
1797  }
1798 
1799  return num_in_list;
1800}
1801
1802
1803/******************************************************************************
1804 *****************************************************************************/
1805REGFI_ITERATOR* regfi_iterator_new(REGFI_FILE* file)
1806{
1807  REGFI_NK* root;
1808  REGFI_ITERATOR* ret_val;
1809
1810  ret_val = talloc(NULL, REGFI_ITERATOR);
1811  if(ret_val == NULL)
1812    return NULL;
1813
1814  root = (REGFI_NK*)regfi_get_rootkey(file);
1815  if(root == NULL)
1816  {
1817    talloc_free(ret_val);
1818    return NULL;
1819  }
1820  ret_val->cur_key = root;
1821  talloc_reparent(NULL, ret_val, root);
1822
1823  ret_val->key_positions = void_stack_new(REGFI_MAX_DEPTH);
1824  if(ret_val->key_positions == NULL)
1825  {
1826    talloc_free(ret_val);
1827    return NULL;
1828  }
1829  talloc_reparent(NULL, ret_val, ret_val->key_positions);
1830
1831  ret_val->f = file;
1832  ret_val->cur_subkey = 0;
1833  ret_val->cur_value = 0;
1834   
1835  return ret_val;
1836}
1837
1838
1839/******************************************************************************
1840 *****************************************************************************/
1841void regfi_iterator_free(REGFI_ITERATOR* i)
1842{
1843  talloc_unlink(NULL, i);
1844}
1845
1846
1847
1848/******************************************************************************
1849 *****************************************************************************/
1850/* XXX: some way of indicating reason for failure should be added. */
1851bool regfi_iterator_down(REGFI_ITERATOR* i)
1852{
1853  REGFI_NK* subkey;
1854  REGFI_ITER_POSITION* pos;
1855
1856  pos = talloc(i->key_positions, REGFI_ITER_POSITION);
1857  if(pos == NULL)
1858    return false;
1859
1860  subkey = (REGFI_NK*)regfi_iterator_cur_subkey(i);
1861  if(subkey == NULL)
1862  {
1863    talloc_free(pos);
1864    return false;
1865  }
1866
1867  pos->nk = i->cur_key;
1868  pos->cur_subkey = i->cur_subkey;
1869  if(!void_stack_push(i->key_positions, pos))
1870  {
1871    talloc_free(pos);
1872    talloc_unlink(NULL, subkey);
1873    return false;
1874  } 
1875  talloc_reparent(NULL, i, subkey);
1876
1877  i->cur_key = subkey;
1878  i->cur_subkey = 0;
1879  i->cur_value = 0;
1880
1881  return true;
1882}
1883
1884
1885/******************************************************************************
1886 *****************************************************************************/
1887bool regfi_iterator_up(REGFI_ITERATOR* i)
1888{
1889  REGFI_ITER_POSITION* pos;
1890
1891  pos = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions);
1892  if(pos == NULL)
1893    return false;
1894
1895  if(!regfi_lock(i->f, &i->f->mem_lock, "regfi_iterator_up"))
1896    return false;
1897 
1898  talloc_unlink(i, i->cur_key);
1899  regfi_unlock(i->f, &i->f->mem_lock, "regfi_iterator_up");
1900
1901  i->cur_key = pos->nk;
1902  i->cur_subkey = pos->cur_subkey;
1903  i->cur_value = 0;
1904  talloc_free(pos);
1905
1906  return true;
1907}
1908
1909
1910/******************************************************************************
1911 *****************************************************************************/
1912bool regfi_iterator_to_root(REGFI_ITERATOR* i)
1913{
1914  while(regfi_iterator_up(i))
1915    continue;
1916
1917  return true;
1918}
1919
1920
1921/******************************************************************************
1922 *****************************************************************************/
1923bool regfi_iterator_find_subkey(REGFI_ITERATOR* i, const char* name)
1924{
1925  uint32_t new_index;
1926
1927  if(regfi_find_subkey(i->f, i->cur_key, name, &new_index))
1928  {
1929    i->cur_subkey = new_index;
1930    return true;
1931  }
1932
1933  return false;
1934}
1935
1936
1937/******************************************************************************
1938 *****************************************************************************/
1939bool regfi_iterator_walk_path(REGFI_ITERATOR* i, const char** path)
1940{
1941  uint32_t x;
1942  if(path == NULL)
1943    return false;
1944
1945  for(x=0; 
1946      ((path[x] != NULL) && regfi_iterator_find_subkey(i, path[x])
1947       && regfi_iterator_down(i));
1948      x++)
1949  { continue; }
1950
1951  if(path[x] == NULL)
1952  {
1953    return true;
1954  }
1955
1956  /* XXX: is this the right number of times? */
1957  for(; x > 0; x--)
1958    regfi_iterator_up(i);
1959 
1960  return false;
1961}
1962
1963
1964/******************************************************************************
1965 *****************************************************************************/
1966const REGFI_NK* regfi_iterator_cur_key(REGFI_ITERATOR* i)
1967{
1968  const REGFI_NK* ret_val = NULL;
1969  if(!regfi_lock(i->f, &i->f->mem_lock, "regfi_iterator_cur_key"))
1970    return ret_val;
1971
1972  ret_val = talloc_reference(NULL, i->cur_key);
1973
1974  regfi_unlock(i->f, &i->f->mem_lock, "regfi_iterator_cur_key"); 
1975  return ret_val;
1976}
1977
1978
1979/******************************************************************************
1980 *****************************************************************************/
1981const REGFI_SK* regfi_fetch_sk(REGFI_FILE* file, const REGFI_NK* key)
1982{
1983  if(key == NULL || key->sk_off == REGFI_OFFSET_NONE)
1984    return NULL;
1985
1986  return regfi_load_sk(file, key->sk_off + REGFI_REGF_SIZE, true);
1987}
1988
1989
1990/******************************************************************************
1991 *****************************************************************************/
1992bool regfi_iterator_first_subkey(REGFI_ITERATOR* i)
1993{
1994  i->cur_subkey = 0;
1995 
1996  return ((i->cur_key != NULL) && (i->cur_key->subkeys_off!=REGFI_OFFSET_NONE) 
1997          && (i->cur_subkey < regfi_fetch_num_subkeys(i->cur_key)));
1998}
1999
2000
2001/******************************************************************************
2002 *****************************************************************************/
2003const REGFI_NK* regfi_iterator_cur_subkey(REGFI_ITERATOR* i)
2004{
2005  return regfi_get_subkey(i->f, i->cur_key, i->cur_subkey);
2006}
2007
2008
2009/******************************************************************************
2010 *****************************************************************************/
2011bool regfi_iterator_next_subkey(REGFI_ITERATOR* i)
2012{
2013  i->cur_subkey++;
2014
2015  return ((i->cur_key != NULL) && (i->cur_key->subkeys_off!=REGFI_OFFSET_NONE) 
2016          && (i->cur_subkey < regfi_fetch_num_subkeys(i->cur_key))); 
2017}
2018
2019
2020/******************************************************************************
2021 *****************************************************************************/
2022bool regfi_iterator_find_value(REGFI_ITERATOR* i, const char* name)
2023{
2024  uint32_t new_index;
2025
2026  if(regfi_find_value(i->f, i->cur_key, name, &new_index))
2027  {
2028    i->cur_value = new_index;
2029    return true;
2030  }
2031
2032  return false;
2033}
2034
2035
2036/******************************************************************************
2037 *****************************************************************************/
2038bool regfi_iterator_first_value(REGFI_ITERATOR* i)
2039{
2040  i->cur_value = 0;
2041  return (i->cur_key->values != NULL && i->cur_key->values->elements != NULL 
2042          && (i->cur_value < regfi_fetch_num_values(i->cur_key)));
2043}
2044
2045
2046/******************************************************************************
2047 *****************************************************************************/
2048const REGFI_VK* regfi_iterator_cur_value(REGFI_ITERATOR* i)
2049{
2050  return regfi_get_value(i->f, i->cur_key, i->cur_value);
2051}
2052
2053
2054/******************************************************************************
2055 *****************************************************************************/
2056bool regfi_iterator_next_value(REGFI_ITERATOR* i)
2057{
2058  i->cur_value++;
2059  return (i->cur_key->values != NULL && i->cur_key->values->elements != NULL 
2060          && (i->cur_value < regfi_fetch_num_values(i->cur_key)));
2061}
2062
2063
2064/******************************************************************************
2065 *****************************************************************************/
2066const REGFI_CLASSNAME* regfi_fetch_classname(REGFI_FILE* file,
2067                                             const REGFI_NK* key)
2068{
2069  REGFI_CLASSNAME* ret_val;
2070  uint8_t* raw;
2071  char* interpreted;
2072  uint32_t offset;
2073  int32_t conv_size, max_size;
2074  uint16_t parse_length;
2075
2076  if(key->classname_off == REGFI_OFFSET_NONE || key->classname_length == 0)
2077    return NULL;
2078
2079  offset = key->classname_off + REGFI_REGF_SIZE;
2080  max_size = regfi_calc_maxsize(file, offset);
2081  if(max_size <= 0)
2082    return NULL;
2083
2084  parse_length = key->classname_length;
2085  raw = regfi_parse_classname(file, offset, &parse_length, max_size, true);
2086 
2087  if(raw == NULL)
2088  {
2089    regfi_log_add(REGFI_LOG_WARN, "Could not parse class"
2090                  " name at offset 0x%.8X for key record at offset 0x%.8X.",
2091                  offset, key->offset);
2092    return NULL;
2093  }
2094
2095  ret_val = talloc(NULL, REGFI_CLASSNAME);
2096  if(ret_val == NULL)
2097    return NULL;
2098
2099  ret_val->offset = offset;
2100  ret_val->raw = raw;
2101  ret_val->size = parse_length;
2102  talloc_reparent(NULL, ret_val, raw);
2103
2104  interpreted = talloc_array(NULL, char, parse_length);
2105
2106  conv_size = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE),
2107                                 regfi_encoding_int2str(file->string_encoding),
2108                                 raw, interpreted,
2109                                 parse_length, parse_length);
2110  if(conv_size < 0)
2111  {
2112    regfi_log_add(REGFI_LOG_WARN, "Error occurred while"
2113                  " converting classname to charset %s.  Error message: %s",
2114                  file->string_encoding, strerror(-conv_size));
2115    talloc_free(interpreted);
2116    ret_val->interpreted = NULL;
2117  }
2118  else
2119  {
2120    /* XXX: check for NULL return here? */
2121    interpreted = talloc_realloc(NULL, interpreted, char, conv_size);
2122    ret_val->interpreted = interpreted;
2123    talloc_reparent(NULL, ret_val, interpreted);
2124  }
2125
2126  return ret_val;
2127}
2128
2129
2130/******************************************************************************
2131 *****************************************************************************/
2132const REGFI_DATA* regfi_fetch_data(REGFI_FILE* file, 
2133                                   const REGFI_VK* value)
2134{
2135  REGFI_DATA* ret_val = NULL;
2136  REGFI_BUFFER raw_data;
2137
2138  if(value->data_size != 0)
2139  {
2140    raw_data = regfi_load_data(file, value->data_off, value->data_size,
2141                               value->data_in_offset, true);
2142    if(raw_data.buf == NULL)
2143    {
2144      regfi_log_add(REGFI_LOG_WARN, "Could not parse data record"
2145                    " while parsing VK record at offset 0x%.8X.",
2146                    value->offset);
2147    }
2148    else
2149    {
2150      ret_val = regfi_buffer_to_data(raw_data);
2151
2152      if(ret_val == NULL)
2153      {
2154        regfi_log_add(REGFI_LOG_WARN, "Error occurred in converting"
2155                      " data buffer to data structure while interpreting "
2156                      "data for VK record at offset 0x%.8X.",
2157                      value->offset);
2158        talloc_free(raw_data.buf);
2159        return NULL;
2160      }
2161
2162      if(!regfi_interpret_data(file, file->string_encoding, 
2163                               value->type, ret_val))
2164      {
2165        regfi_log_add(REGFI_LOG_INFO, "Error occurred while"
2166                      " interpreting data for VK record at offset 0x%.8X.",
2167                      value->offset);
2168      }
2169    }
2170  }
2171 
2172  return ret_val;
2173}
2174
2175
2176
2177/******************************************************************************
2178 *****************************************************************************/
2179bool regfi_find_subkey(REGFI_FILE* file, const REGFI_NK* key, 
2180                       const char* name, uint32_t* index)
2181{
2182  const REGFI_NK* cur;
2183  uint32_t i;
2184  uint32_t num_subkeys = regfi_fetch_num_subkeys(key);
2185  bool found = false;
2186
2187  /* XXX: cur->name can be NULL in the registry. 
2188   *      Should we allow for a way to search for that?
2189   */
2190  if(name == NULL)
2191    return false;
2192
2193  for(i=0; (i < num_subkeys) && (found == false); i++)
2194  {
2195    cur = regfi_get_subkey(file, key, i);
2196    if(cur == NULL)
2197      return false;
2198
2199    if((cur->name != NULL)
2200       && (strcasecmp(cur->name, name) == 0))
2201    {
2202      found = true;
2203      *index = i;
2204    }
2205
2206    regfi_free_record(file, cur);
2207  }
2208
2209  return found;
2210}
2211
2212
2213
2214/******************************************************************************
2215 *****************************************************************************/
2216bool regfi_find_value(REGFI_FILE* file, const REGFI_NK* key, 
2217                      const char* name, uint32_t* index)
2218{
2219  const REGFI_VK* cur;
2220  uint32_t i;
2221  uint32_t num_values = regfi_fetch_num_values(key);
2222  bool found = false;
2223
2224  /* XXX: cur->name can be NULL in the registry. 
2225   *      Should we allow for a way to search for that?
2226   */
2227  if(name == NULL)
2228    return false;
2229
2230  for(i=0; (i < num_values) && (found == false); i++)
2231  {
2232    cur = regfi_get_value(file, key, i);
2233    if(cur == NULL)
2234      return false;
2235
2236    if((cur->name != NULL)
2237       && (strcasecmp(cur->name, name) == 0))
2238    {
2239      found = true;
2240      *index = i;
2241    }
2242
2243    regfi_free_record(file, cur);
2244  }
2245
2246  return found;
2247}
2248
2249
2250
2251/******************************************************************************
2252 *****************************************************************************/
2253const REGFI_NK* regfi_get_subkey(REGFI_FILE* file, const REGFI_NK* key, 
2254                                 uint32_t index)
2255{
2256  if(index < regfi_fetch_num_subkeys(key))
2257  {
2258    return regfi_load_key(file, 
2259                          key->subkeys->elements[index].offset+REGFI_REGF_SIZE,
2260                          file->string_encoding, true);
2261  }
2262
2263  return NULL;
2264}
2265
2266
2267/******************************************************************************
2268 *****************************************************************************/
2269const REGFI_VK* regfi_get_value(REGFI_FILE* file, const REGFI_NK* key, 
2270                                uint32_t index)
2271{
2272  if(index < regfi_fetch_num_values(key))
2273  {
2274    return regfi_load_value(file, 
2275                            key->values->elements[index]+REGFI_REGF_SIZE,
2276                            file->string_encoding, true);
2277  }
2278
2279  return NULL; 
2280}
2281
2282
2283
2284/******************************************************************************
2285 *****************************************************************************/
2286const REGFI_NK* regfi_get_parentkey(REGFI_FILE* file, const REGFI_NK* key)
2287{
2288  if(key != NULL && key->parent_off != REGFI_OFFSET_NONE)
2289    return regfi_load_key(file, 
2290                          key->parent_off+REGFI_REGF_SIZE,
2291                          file->string_encoding, true);
2292
2293  return NULL;
2294}
2295
2296
2297
2298/******************************************************************************
2299 *****************************************************************************/
2300REGFI_DATA* regfi_buffer_to_data(REGFI_BUFFER raw_data)
2301{
2302  REGFI_DATA* ret_val;
2303
2304  if(raw_data.buf == NULL)
2305    return NULL;
2306
2307  ret_val = talloc(NULL, REGFI_DATA);
2308  if(ret_val == NULL)
2309    return NULL;
2310 
2311  talloc_reparent(NULL, ret_val, raw_data.buf);
2312  ret_val->raw = raw_data.buf;
2313  ret_val->size = raw_data.len;
2314  ret_val->interpreted_size = 0;
2315  ret_val->interpreted.qword = 0;
2316
2317  return ret_val;
2318}
2319
2320
2321/******************************************************************************
2322 *****************************************************************************/
2323bool regfi_interpret_data(REGFI_FILE* file, REGFI_ENCODING string_encoding,
2324                          uint32_t type, REGFI_DATA* data)
2325{
2326  uint8_t** tmp_array;
2327  uint8_t* tmp_str;
2328  int32_t tmp_size;
2329  uint32_t i, j, array_size;
2330
2331  if(data == NULL)
2332    return false;
2333
2334  switch (type)
2335  {
2336  case REG_SZ:
2337  case REG_EXPAND_SZ:
2338  /* REG_LINK is a symbolic link, stored as a unicode string. */
2339  case REG_LINK:
2340    tmp_str = talloc_array(NULL, uint8_t, data->size);
2341    if(tmp_str == NULL)
2342    {
2343      data->interpreted.string = NULL;
2344      data->interpreted_size = 0;
2345      return false;
2346    }
2347     
2348    tmp_size = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE),
2349                                  regfi_encoding_int2str(string_encoding),
2350                                  data->raw, (char*)tmp_str, 
2351                                  data->size, data->size);
2352    if(tmp_size < 0)
2353    {
2354      regfi_log_add(REGFI_LOG_INFO, "Error occurred while"
2355                    " converting data of type %d to %d.  Error message: %s",
2356                    type, string_encoding, strerror(-tmp_size));
2357      talloc_free(tmp_str);
2358      data->interpreted.string = NULL;
2359      data->interpreted_size = 0;
2360      return false;
2361    }
2362
2363    /* XXX: check for NULL */
2364    tmp_str = talloc_realloc(NULL, tmp_str, uint8_t, tmp_size);
2365    data->interpreted.string = tmp_str;
2366    data->interpreted_size = tmp_size;
2367    talloc_reparent(NULL, data, tmp_str);
2368    break;
2369
2370  case REG_DWORD:
2371    if(data->size < 4)
2372    {
2373      data->interpreted.dword = 0;
2374      data->interpreted_size = 0;
2375      return false;
2376    }
2377    data->interpreted.dword = IVAL(data->raw, 0);
2378    data->interpreted_size = 4;
2379    break;
2380
2381  case REG_DWORD_BE:
2382    if(data->size < 4)
2383    {
2384      data->interpreted.dword_be = 0;
2385      data->interpreted_size = 0;
2386      return false;
2387    }
2388    data->interpreted.dword_be = RIVAL(data->raw, 0);
2389    data->interpreted_size = 4;
2390    break;
2391
2392  case REG_QWORD:
2393    if(data->size < 8)
2394    {
2395      data->interpreted.qword = 0;
2396      data->interpreted_size = 0;
2397      return false;
2398    }
2399    data->interpreted.qword = 
2400      (uint64_t)IVAL(data->raw, 0) + (((uint64_t)IVAL(data->raw, 4))<<32);
2401    data->interpreted_size = 8;
2402    break;
2403   
2404  case REG_MULTI_SZ:
2405    tmp_str = talloc_array(NULL, uint8_t, data->size);
2406    if(tmp_str == NULL)
2407    {
2408      data->interpreted.multiple_string = NULL;
2409      data->interpreted_size = 0;
2410      return false;
2411    }
2412
2413    /* Attempt to convert entire string from UTF-16LE to output encoding,
2414     * then parse and quote fields individually.
2415     */
2416    tmp_size = regfi_conv_charset(regfi_encoding_int2str(REGFI_ENCODING_UTF16LE),
2417                                  regfi_encoding_int2str(string_encoding),
2418                                  data->raw, (char*)tmp_str,
2419                                  data->size, data->size);
2420    if(tmp_size < 0)
2421    {
2422      regfi_log_add(REGFI_LOG_INFO, "Error occurred while"
2423                    " converting data of type %d to %s.  Error message: %s",
2424                    type, string_encoding, strerror(-tmp_size));
2425      talloc_free(tmp_str);
2426      data->interpreted.multiple_string = NULL;
2427      data->interpreted_size = 0;
2428      return false;
2429    }
2430
2431    array_size = tmp_size+1;
2432    tmp_array = talloc_array(NULL, uint8_t*, array_size);
2433    if(tmp_array == NULL)
2434    {
2435      talloc_free(tmp_str);
2436      data->interpreted.string = NULL;
2437      data->interpreted_size = 0;
2438      return false;
2439    }
2440   
2441    tmp_array[0] = tmp_str;
2442    for(i=0,j=1; i < tmp_size && j < array_size-1; i++)
2443    {
2444      if(tmp_str[i] == '\0' && (i+1 < tmp_size) && tmp_str[i+1] != '\0')
2445        tmp_array[j++] = tmp_str+i+1;
2446    }
2447    tmp_array[j] = NULL;
2448    tmp_array = talloc_realloc(NULL, tmp_array, uint8_t*, j+1);
2449    data->interpreted.multiple_string = tmp_array;
2450    /* XXX: how meaningful is this?  should we store number of strings instead? */
2451    data->interpreted_size = tmp_size;
2452    talloc_reparent(NULL, tmp_array, tmp_str);
2453    talloc_reparent(NULL, data, tmp_array);
2454    break;
2455
2456  /* XXX: Dont know how to interpret these yet, just treat as binary */
2457  case REG_NONE:
2458    data->interpreted.none = data->raw;
2459    data->interpreted_size = data->size;
2460    break;
2461
2462  case REG_RESOURCE_LIST:
2463    data->interpreted.resource_list = data->raw;
2464    data->interpreted_size = data->size;
2465    break;
2466
2467  case REG_FULL_RESOURCE_DESCRIPTOR:
2468    data->interpreted.full_resource_descriptor = data->raw;
2469    data->interpreted_size = data->size;
2470    break;
2471
2472  case REG_RESOURCE_REQUIREMENTS_LIST:
2473    data->interpreted.resource_requirements_list = data->raw;
2474    data->interpreted_size = data->size;
2475    break;
2476
2477  case REG_BINARY:
2478    data->interpreted.binary = data->raw;
2479    data->interpreted_size = data->size;
2480    break;
2481
2482  default:
2483    data->interpreted.qword = 0;
2484    data->interpreted_size = 0;
2485    return false;
2486  }
2487
2488  data->type = type;
2489  return true;
2490}
2491
2492
2493/******************************************************************************
2494 * Convert from UTF-16LE to specified character set.
2495 * On error, returns a negative errno code.
2496 *****************************************************************************/
2497int32_t regfi_conv_charset(const char* input_charset, const char* output_charset,
2498                           uint8_t* input, char* output, 
2499                           uint32_t input_len, uint32_t output_max)
2500{
2501  iconv_t conv_desc;
2502  char* inbuf = (char*)input;
2503  char* outbuf = output;
2504  size_t in_len = (size_t)input_len;
2505  size_t out_len = (size_t)(output_max-1);
2506  int ret;
2507
2508  /* XXX: Consider creating a couple of conversion descriptors earlier,
2509   *      storing them on an iterator so they don't have to be recreated
2510   *      each time.
2511   */
2512
2513  /* Set up conversion descriptor. */
2514  conv_desc = iconv_open(output_charset, input_charset);
2515
2516  ret = iconv(conv_desc, &inbuf, &in_len, &outbuf, &out_len);
2517  if(ret == -1)
2518  {
2519    iconv_close(conv_desc);
2520    return -errno;
2521  }
2522  *outbuf = '\0';
2523
2524  iconv_close(conv_desc); 
2525  return output_max-out_len-1;
2526}
2527
2528
2529
2530/*******************************************************************
2531 * Computes the checksum of the registry file header.
2532 * buffer must be at least the size of a regf header (4096 bytes).
2533 *******************************************************************/
2534static uint32_t regfi_compute_header_checksum(uint8_t* buffer)
2535{
2536  uint32_t checksum, x;
2537  int i;
2538
2539  /* XOR of all bytes 0x0000 - 0x01FB */
2540
2541  checksum = x = 0;
2542 
2543  for ( i=0; i<0x01FB; i+=4 ) {
2544    x = IVAL(buffer, i );
2545    checksum ^= x;
2546  }
2547 
2548  return checksum;
2549}
2550
2551
2552/*******************************************************************
2553 *******************************************************************/
2554REGFI_FILE* regfi_parse_regf(REGFI_RAW_FILE* file_cb, bool strict)
2555{
2556  uint8_t file_header[REGFI_REGF_SIZE];
2557  uint32_t length;
2558  REGFI_FILE* ret_val;
2559
2560  ret_val = talloc(NULL, REGFI_FILE);
2561  if(ret_val == NULL)
2562    return NULL;
2563
2564  ret_val->sk_cache = NULL;
2565  ret_val->hbins = NULL;
2566
2567  length = REGFI_REGF_SIZE;
2568  if((regfi_read(file_cb, file_header, &length)) != 0 
2569     || length != REGFI_REGF_SIZE)
2570  {
2571    regfi_log_add(REGFI_LOG_WARN, "Read failed while parsing REGF structure.");
2572    goto fail;
2573  }
2574
2575  ret_val->checksum = IVAL(file_header, 0x1FC);
2576  ret_val->computed_checksum = regfi_compute_header_checksum(file_header);
2577  if (strict && (ret_val->checksum != ret_val->computed_checksum))
2578  {
2579    regfi_log_add(REGFI_LOG_WARN, "Stored header checksum (%.8X) did not equal"
2580                  " computed checksum (%.8X).",
2581                  ret_val->checksum, ret_val->computed_checksum);
2582    if(strict)
2583      goto fail;
2584  }
2585
2586  memcpy(ret_val->magic, file_header, REGFI_REGF_MAGIC_SIZE);
2587  if(memcmp(ret_val->magic, "regf", REGFI_REGF_MAGIC_SIZE) != 0)
2588  {
2589    regfi_log_add(REGFI_LOG_ERROR, "Magic number mismatch "
2590                  "(%.2X %.2X %.2X %.2X) while parsing hive header",
2591                  ret_val->magic[0], ret_val->magic[1], 
2592                  ret_val->magic[2], ret_val->magic[3]);
2593    goto fail;
2594  }
2595
2596  ret_val->sequence1 = IVAL(file_header, 0x4);
2597  ret_val->sequence2 = IVAL(file_header, 0x8);
2598  ret_val->mtime.low = IVAL(file_header, 0xC);
2599  ret_val->mtime.high = IVAL(file_header, 0x10);
2600  ret_val->major_version = IVAL(file_header, 0x14);
2601  ret_val->minor_version = IVAL(file_header, 0x18);
2602  ret_val->type = IVAL(file_header, 0x1C);
2603  ret_val->format = IVAL(file_header, 0x20);
2604  ret_val->root_cell = IVAL(file_header, 0x24);
2605  ret_val->last_block = IVAL(file_header, 0x28);
2606  ret_val->cluster = IVAL(file_header, 0x2C);
2607
2608  memcpy(ret_val->file_name, file_header+0x30,  REGFI_REGF_NAME_SIZE);
2609
2610  /* XXX: Should we add a warning if these uuid parsers fail?  Can they? */
2611  ret_val->rm_id = winsec_parse_uuid(ret_val, file_header+0x70, 16);
2612  ret_val->log_id = winsec_parse_uuid(ret_val, file_header+0x80, 16);
2613  ret_val->flags = IVAL(file_header, 0x90);
2614  ret_val->tm_id = winsec_parse_uuid(ret_val, file_header+0x94, 16);
2615  ret_val->guid_signature = IVAL(file_header, 0xa4);
2616
2617  memcpy(ret_val->reserved1, file_header+0xa8, REGFI_REGF_RESERVED1_SIZE);
2618  memcpy(ret_val->reserved2, file_header+0x200, REGFI_REGF_RESERVED2_SIZE);
2619
2620  ret_val->thaw_tm_id = winsec_parse_uuid(ret_val, file_header+0xFC8, 16);
2621  ret_val->thaw_rm_id = winsec_parse_uuid(ret_val, file_header+0xFD8, 16);
2622  ret_val->thaw_log_id = winsec_parse_uuid(ret_val, file_header+0xFE8, 16);
2623  ret_val->boot_type = IVAL(file_header, 0xFF8);
2624  ret_val->boot_recover = IVAL(file_header, 0xFFC);
2625
2626  return ret_val;
2627
2628 fail:
2629  talloc_free(ret_val);
2630  return NULL;
2631}
2632
2633
2634
2635/******************************************************************************
2636 * Given real file offset, read and parse the hbin at that location
2637 * along with it's associated cells.
2638 ******************************************************************************/
2639REGFI_HBIN* regfi_parse_hbin(REGFI_FILE* file, uint32_t offset, bool strict)
2640{
2641  REGFI_HBIN* hbin = NULL;
2642  uint8_t hbin_header[REGFI_HBIN_HEADER_SIZE];
2643  uint32_t length;
2644 
2645  if(offset >= file->file_length)
2646    goto fail;
2647 
2648  if(!regfi_lock(file, &file->cb_lock, "regfi_parse_hbin"))
2649    goto fail;
2650
2651  if(regfi_seek(file->cb, offset, SEEK_SET) == -1)
2652  {
2653    regfi_log_add(REGFI_LOG_ERROR, "Seek failed"
2654                  " while parsing hbin at offset 0x%.8X.", offset);
2655    goto fail_locked;
2656  }
2657
2658  length = REGFI_HBIN_HEADER_SIZE;
2659  if((regfi_read(file->cb, hbin_header, &length) != 0) 
2660     || length != REGFI_HBIN_HEADER_SIZE)
2661  {
2662    regfi_log_add(REGFI_LOG_ERROR, "Read failed"
2663                  " while parsing hbin at offset 0x%.8X.", offset);
2664    goto fail_locked;
2665  }
2666
2667  if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_hbin"))
2668    goto fail;
2669
2670  hbin = talloc(NULL, REGFI_HBIN);
2671  if(hbin == NULL)
2672    goto fail;
2673  hbin->file_off = offset;
2674
2675  memcpy(hbin->magic, hbin_header, 4);
2676  if(strict && (memcmp(hbin->magic, "hbin", 4) != 0))
2677  {
2678    /* This always seems to happen at the end of a file, so we make it an INFO
2679     * message, rather than something more serious.
2680     */
2681    regfi_log_add(REGFI_LOG_INFO, "Magic number mismatch "
2682                  "(%.2X %.2X %.2X %.2X) while parsing hbin at offset"
2683                  " 0x%.8X.", hbin->magic[0], hbin->magic[1], 
2684                  hbin->magic[2], hbin->magic[3], offset);
2685    goto fail;
2686  }
2687
2688  hbin->first_hbin_off = IVAL(hbin_header, 0x4);
2689  hbin->block_size = IVAL(hbin_header, 0x8);
2690  /* this should be the same thing as hbin->block_size, but just in case */
2691  hbin->next_block = IVAL(hbin_header, 0x1C);
2692
2693
2694  /* Ensure the block size is a multiple of 0x1000 and doesn't run off
2695   * the end of the file.
2696   */
2697  /* XXX: This may need to be relaxed for dealing with
2698   *      partial or corrupt files.
2699   */
2700  if((offset + hbin->block_size > file->file_length)
2701     || (hbin->block_size & 0xFFFFF000) != hbin->block_size)
2702  {
2703    regfi_log_add(REGFI_LOG_ERROR, "The hbin offset is not aligned"
2704                  " or runs off the end of the file"
2705                  " while parsing hbin at offset 0x%.8X.", offset);
2706    goto fail;
2707  }
2708
2709  return hbin;
2710
2711 fail_locked:
2712  regfi_unlock(file, &file->cb_lock, "regfi_parse_hbin");
2713 fail:
2714  talloc_free(hbin);
2715  return NULL;
2716}
2717
2718
2719/*******************************************************************
2720 *******************************************************************/
2721REGFI_NK* regfi_parse_nk(REGFI_FILE* file, uint32_t offset, 
2722                         uint32_t max_size, bool strict)
2723{
2724  uint8_t nk_header[REGFI_NK_MIN_LENGTH];
2725  REGFI_NK* ret_val;
2726  uint32_t length,cell_length;
2727  bool unalloc = false;
2728
2729  ret_val = talloc(NULL, REGFI_NK);
2730  if(ret_val == NULL)
2731  {
2732    regfi_log_add(REGFI_LOG_ERROR, "Failed to allocate memory while"
2733                  " parsing NK record at offset 0x%.8X.", offset);
2734    goto fail;
2735  }
2736
2737  if(!regfi_lock(file, &file->cb_lock, "regfi_parse_nk"))
2738    goto fail;
2739
2740  if(!regfi_parse_cell(file->cb, offset, nk_header, REGFI_NK_MIN_LENGTH,
2741                       &cell_length, &unalloc))
2742  {
2743    regfi_log_add(REGFI_LOG_WARN, "Could not parse cell header"
2744                  " while parsing NK record at offset 0x%.8X.", offset);
2745    goto fail_locked;
2746  }
2747
2748  if((nk_header[0x0] != 'n') || (nk_header[0x1] != 'k'))
2749  {
2750    regfi_log_add(REGFI_LOG_WARN, "Magic number mismatch in parsing"
2751                  " NK record at offset 0x%.8X.", offset);
2752    goto fail_locked;
2753  }
2754
2755  ret_val->values = NULL;
2756  ret_val->subkeys = NULL;
2757  ret_val->offset = offset;
2758  ret_val->cell_size = cell_length;
2759
2760  if(ret_val->cell_size > max_size)
2761    ret_val->cell_size = max_size & 0xFFFFFFF8;
2762  if((ret_val->cell_size < REGFI_NK_MIN_LENGTH) 
2763     || (strict && (ret_val->cell_size & 0x00000007) != 0))
2764  {
2765    regfi_log_add(REGFI_LOG_WARN, "A length check failed while"
2766                  " parsing NK record at offset 0x%.8X.", offset);
2767    goto fail_locked;
2768  }
2769
2770  ret_val->magic[0] = nk_header[0x0];
2771  ret_val->magic[1] = nk_header[0x1];
2772  ret_val->flags = SVAL(nk_header, 0x2);
2773 
2774  if((ret_val->flags & ~REGFI_NK_KNOWN_FLAGS) != 0)
2775  {
2776    regfi_log_add(REGFI_LOG_WARN, "Unknown key flags (0x%.4X) while"
2777                  " parsing NK record at offset 0x%.8X.", 
2778                  (ret_val->flags & ~REGFI_NK_KNOWN_FLAGS), offset);
2779  }
2780
2781  ret_val->mtime.low = IVAL(nk_header, 0x4);
2782  ret_val->mtime.high = IVAL(nk_header, 0x8);
2783  /* If the key is unallocated and the MTIME is earlier than Jan 1, 1990
2784   * or later than Jan 1, 2290, we consider this a bad key.  This helps
2785   * weed out some false positives during deleted data recovery.
2786   */
2787  if(unalloc
2788     && (ret_val->mtime.high < REGFI_MTIME_MIN_HIGH
2789         || ret_val->mtime.high > REGFI_MTIME_MAX_HIGH))
2790  { goto fail_locked; }
2791
2792  ret_val->unknown1 = IVAL(nk_header, 0xC);
2793  ret_val->parent_off = IVAL(nk_header, 0x10);
2794  ret_val->num_subkeys = IVAL(nk_header, 0x14);
2795  ret_val->unknown2 = IVAL(nk_header, 0x18);
2796  ret_val->subkeys_off = IVAL(nk_header, 0x1C);
2797  ret_val->unknown3 = IVAL(nk_header, 0x20);
2798  ret_val->num_values = IVAL(nk_header, 0x24);
2799  ret_val->values_off = IVAL(nk_header, 0x28);
2800  ret_val->sk_off = IVAL(nk_header, 0x2C);
2801  ret_val->classname_off = IVAL(nk_header, 0x30);
2802
2803  ret_val->max_bytes_subkeyname = IVAL(nk_header, 0x34);
2804  ret_val->max_bytes_subkeyclassname = IVAL(nk_header, 0x38);
2805  ret_val->max_bytes_valuename = IVAL(nk_header, 0x3C);
2806  ret_val->max_bytes_value = IVAL(nk_header, 0x40);
2807  ret_val->unk_index = IVAL(nk_header, 0x44);
2808
2809  ret_val->name_length = SVAL(nk_header, 0x48);
2810  ret_val->classname_length = SVAL(nk_header, 0x4A);
2811  ret_val->name = NULL;
2812
2813  if(ret_val->name_length + REGFI_NK_MIN_LENGTH > ret_val->cell_size)
2814  {
2815    if(strict)
2816    {
2817      regfi_log_add(REGFI_LOG_ERROR, "Contents too large for cell"
2818                    " while parsing NK record at offset 0x%.8X.", offset);
2819      goto fail_locked;
2820    }
2821    else
2822      ret_val->name_length = ret_val->cell_size - REGFI_NK_MIN_LENGTH;
2823  }
2824  else if (unalloc)
2825  { /* Truncate cell_size if it's much larger than the apparent total record length. */
2826    /* Round up to the next multiple of 8 */
2827    length = (ret_val->name_length + REGFI_NK_MIN_LENGTH) & 0xFFFFFFF8;
2828    if(length < ret_val->name_length + REGFI_NK_MIN_LENGTH)
2829      length+=8;
2830
2831    /* If cell_size is still greater, truncate. */
2832    if(length < ret_val->cell_size)
2833      ret_val->cell_size = length;
2834  }
2835
2836  /* +1 to length in case we decided to use this directly as a string later */
2837  ret_val->name_raw = talloc_array(ret_val, uint8_t, ret_val->name_length+1);
2838  if(ret_val->name_raw == NULL)
2839    goto fail_locked;
2840
2841  /* Don't need to seek, should be at the right offset */
2842  length = ret_val->name_length;
2843  if((regfi_read(file->cb, (uint8_t*)ret_val->name_raw, &length) != 0)
2844     || length != ret_val->name_length)
2845  {
2846    regfi_log_add(REGFI_LOG_ERROR, "Failed to read key name"
2847                  " while parsing NK record at offset 0x%.8X.", offset);
2848    goto fail_locked;
2849  }
2850
2851  if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_nk"))
2852    goto fail;
2853
2854  return ret_val;
2855
2856 fail_locked:
2857  regfi_unlock(file, &file->cb_lock, "regfi_parse_nk");
2858 fail:
2859  talloc_free(ret_val);
2860  return NULL;
2861}
2862
2863
2864uint8_t* regfi_parse_classname(REGFI_FILE* file, uint32_t offset, 
2865                               uint16_t* name_length, uint32_t max_size, bool strict)
2866{
2867  uint8_t* ret_val = NULL;
2868  uint32_t length;
2869  uint32_t cell_length;
2870  bool unalloc = false;
2871
2872  if(*name_length <= 0 || offset == REGFI_OFFSET_NONE 
2873     || (offset & 0x00000007) != 0)
2874  { goto fail; }
2875
2876  if(!regfi_lock(file, &file->cb_lock, "regfi_parse_classname"))
2877    goto fail;
2878
2879  if(!regfi_parse_cell(file->cb, offset, NULL, 0, &cell_length, &unalloc))
2880  {
2881    regfi_log_add(REGFI_LOG_WARN, "Could not parse cell header"
2882                  " while parsing class name at offset 0x%.8X.", offset);
2883    goto fail_locked;
2884  }
2885 
2886  if((cell_length & 0x0000007) != 0)
2887  {
2888    regfi_log_add(REGFI_LOG_ERROR, "Cell length not a multiple of 8"
2889                  " while parsing class name at offset 0x%.8X.", offset);
2890    goto fail_locked;
2891  }
2892 
2893  if(cell_length > max_size)
2894  {
2895    regfi_log_add(REGFI_LOG_WARN, "Cell stretches past hbin "
2896                  "boundary while parsing class name at offset 0x%.8X.",
2897                  offset);
2898    if(strict)
2899      goto fail_locked;
2900    cell_length = max_size;
2901  }
2902 
2903  if((cell_length - 4) < *name_length)
2904  {
2905    regfi_log_add(REGFI_LOG_WARN, "Class name is larger than"
2906                  " cell_length while parsing class name at offset"
2907                  " 0x%.8X.", offset);
2908    if(strict)
2909      goto fail_locked;
2910    *name_length = cell_length - 4;
2911  }
2912 
2913  ret_val = talloc_array(NULL, uint8_t, *name_length);
2914  if(ret_val != NULL)
2915  {
2916    length = *name_length;
2917    if((regfi_read(file->cb, ret_val, &length) != 0)
2918       || length != *name_length)
2919    {
2920      regfi_log_add(REGFI_LOG_ERROR, "Could not read class name"
2921                    " while parsing class name at offset 0x%.8X.", offset);
2922      goto fail_locked;
2923    }
2924  }
2925
2926  if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_classname"))
2927    goto fail;
2928
2929  return ret_val;
2930
2931 fail_locked:
2932  regfi_unlock(file, &file->cb_lock, "regfi_parse_classname");
2933 fail:
2934  talloc_free(ret_val);
2935  return NULL;
2936}
2937
2938
2939/******************************************************************************
2940*******************************************************************************/
2941REGFI_VK* regfi_parse_vk(REGFI_FILE* file, uint32_t offset, 
2942                             uint32_t max_size, bool strict)
2943{
2944  REGFI_VK* ret_val;
2945  uint8_t vk_header[REGFI_VK_MIN_LENGTH];
2946  uint32_t raw_data_size, length, cell_length;
2947  bool unalloc = false;
2948
2949  ret_val = talloc(NULL, REGFI_VK);
2950  if(ret_val == NULL)
2951    goto fail;
2952
2953  if(!regfi_lock(file, &file->cb_lock, "regfi_parse_nk"))
2954    goto fail;
2955
2956  if(!regfi_parse_cell(file->cb, offset, vk_header, REGFI_VK_MIN_LENGTH,
2957                       &cell_length, &unalloc))
2958  {
2959    regfi_log_add(REGFI_LOG_WARN, "Could not parse cell header"
2960                  " while parsing VK record at offset 0x%.8X.", offset);
2961    goto fail_locked;
2962  }
2963
2964  ret_val->offset = offset;
2965  ret_val->cell_size = cell_length;
2966  ret_val->name = NULL;
2967  ret_val->name_raw = NULL;
2968 
2969  if(ret_val->cell_size > max_size)
2970    ret_val->cell_size = max_size & 0xFFFFFFF8;
2971  if((ret_val->cell_size < REGFI_VK_MIN_LENGTH) 
2972     || (ret_val->cell_size & 0x00000007) != 0)
2973  {
2974    regfi_log_add(REGFI_LOG_WARN, "Invalid cell size encountered"
2975                  " while parsing VK record at offset 0x%.8X.", offset);
2976    goto fail_locked;
2977  }
2978
2979  ret_val->magic[0] = vk_header[0x0];
2980  ret_val->magic[1] = vk_header[0x1];
2981  if((ret_val->magic[0] != 'v') || (ret_val->magic[1] != 'k'))
2982  {
2983    /* XXX: This does not account for deleted keys under Win2K which
2984     *      often have this (and the name length) overwritten with
2985     *      0xFFFF.
2986     */
2987    regfi_log_add(REGFI_LOG_WARN, "Magic number mismatch"
2988                  " while parsing VK record at offset 0x%.8X.", offset);
2989    goto fail_locked;
2990  }
2991
2992  ret_val->name_length = SVAL(vk_header, 0x2);
2993  raw_data_size = IVAL(vk_header, 0x4);
2994  ret_val->data_size = raw_data_size & ~REGFI_VK_DATA_IN_OFFSET;
2995  /* The data is typically stored in the offset if the size <= 4,
2996   * in which case this flag is set.
2997   */
2998  ret_val->data_in_offset = (bool)(raw_data_size & REGFI_VK_DATA_IN_OFFSET);
2999  ret_val->data_off = IVAL(vk_header, 0x8);
3000  ret_val->type = IVAL(vk_header, 0xC);
3001  ret_val->flags = SVAL(vk_header, 0x10);
3002  ret_val->unknown1 = SVAL(vk_header, 0x12);
3003
3004  if(ret_val->name_length > 0)
3005  {
3006    if(ret_val->name_length + REGFI_VK_MIN_LENGTH + 4 > ret_val->cell_size)
3007    {
3008      regfi_log_add(REGFI_LOG_WARN, "Name too long for remaining cell"
3009                    " space while parsing VK record at offset 0x%.8X.",
3010                    offset);
3011      if(strict)
3012        goto fail_locked;
3013      else
3014        ret_val->name_length = ret_val->cell_size - REGFI_VK_MIN_LENGTH - 4;
3015    }
3016
3017    /* Round up to the next multiple of 8 */
3018    cell_length = (ret_val->name_length + REGFI_VK_MIN_LENGTH + 4) & 0xFFFFFFF8;
3019    if(cell_length < ret_val->name_length + REGFI_VK_MIN_LENGTH + 4)
3020      cell_length+=8;
3021
3022    /* +1 to length in case we decided to use this directly as a string later */
3023    ret_val->name_raw = talloc_array(ret_val, uint8_t, ret_val->name_length+1);
3024    if(ret_val->name_raw == NULL)
3025      goto fail_locked;
3026
3027    length = ret_val->name_length;
3028    if((regfi_read(file->cb, (uint8_t*)ret_val->name_raw, &length) != 0)
3029       || length != ret_val->name_length)
3030    {
3031      regfi_log_add(REGFI_LOG_ERROR, "Could not read value name"
3032                    " while parsing VK record at offset 0x%.8X.", offset);
3033      goto fail_locked;
3034    }
3035  }
3036  else
3037    cell_length = REGFI_VK_MIN_LENGTH + 4;
3038
3039  if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_nk"))
3040    goto fail;
3041
3042  if(unalloc)
3043  {
3044    /* If cell_size is still greater, truncate. */
3045    if(cell_length < ret_val->cell_size)
3046      ret_val->cell_size = cell_length;
3047  }
3048
3049  return ret_val;
3050 
3051 fail_locked:
3052  regfi_unlock(file, &file->cb_lock, "regfi_parse_vk");
3053 fail:
3054  talloc_free(ret_val);
3055  return NULL;
3056}
3057
3058
3059/******************************************************************************
3060 *
3061 ******************************************************************************/
3062REGFI_BUFFER regfi_load_data(REGFI_FILE* file, uint32_t voffset,
3063                             uint32_t length, bool data_in_offset,
3064                             bool strict)
3065{
3066  REGFI_BUFFER ret_val;
3067  uint32_t cell_length, offset;
3068  int32_t max_size;
3069  bool unalloc;
3070 
3071  /* Microsoft's documentation indicates that "available memory" is
3072   * the limit on value sizes for the more recent registry format version.
3073   * This is not only annoying, but it's probably also incorrect, since clearly
3074   * value data sizes are limited to 2^31 (high bit used as a flag) and even
3075   * with big data records, the apparent max size is:
3076   *   16344 * 2^16 = 1071104040 (~1GB).
3077   *
3078   * We choose to limit it to 1M which was the limit in older versions and
3079   * should rarely be exceeded unless the file is corrupt or malicious.
3080   * For more info, see:
3081   *   http://msdn.microsoft.com/en-us/library/ms724872%28VS.85%29.aspx
3082   */
3083  /* XXX: add way to skip this check at user discression. */
3084  if(length > REGFI_VK_MAX_DATA_LENGTH)
3085  {
3086    regfi_log_add(REGFI_LOG_WARN, "Value data size %d larger than "
3087                  "%d, truncating...", length, REGFI_VK_MAX_DATA_LENGTH);
3088    length = REGFI_VK_MAX_DATA_LENGTH;
3089  }
3090
3091  if(data_in_offset)
3092    return regfi_parse_little_data(file, voffset, length, strict);
3093  else
3094  {
3095    offset = voffset + REGFI_REGF_SIZE;
3096    max_size = regfi_calc_maxsize(file, offset);
3097    if(max_size < 0)
3098    {
3099      regfi_log_add(REGFI_LOG_WARN, "Could not find HBIN for data"
3100                    " at offset 0x%.8X.", offset);
3101      goto fail;
3102    }
3103   
3104    if(!regfi_lock(file, &file->cb_lock, "regfi_load_data"))
3105      goto fail;
3106
3107    if(!regfi_parse_cell(file->cb, offset, NULL, 0,
3108                         &cell_length, &unalloc))
3109    {
3110      regfi_log_add(REGFI_LOG_WARN, "Could not parse cell while"
3111                    " parsing data record at offset 0x%.8X.", offset);
3112      goto fail_locked;
3113    }
3114
3115    if(!regfi_unlock(file, &file->cb_lock, "regfi_load_data"))
3116      goto fail;
3117
3118    if((cell_length & 0x00000007) != 0)
3119    {
3120      regfi_log_add(REGFI_LOG_WARN, "Cell length not multiple of 8"
3121                    " while parsing data record at offset 0x%.8X.",
3122                    offset);
3123      goto fail;
3124    }
3125
3126    if(cell_length > max_size)
3127    {
3128      regfi_log_add(REGFI_LOG_WARN, "Cell extends past HBIN boundary"
3129                    " while parsing data record at offset 0x%.8X.",
3130                    offset);
3131      goto fail;
3132    }
3133
3134    if(cell_length - 4 < length)
3135    {
3136      /* XXX: All big data records thus far have been 16 bytes long. 
3137       *      Should we check for this precise size instead of just
3138       *      relying upon the above check?
3139       */
3140      if (file->major_version >= 1 && file->minor_version >= 5)
3141      {
3142        /* Attempt to parse a big data record */
3143        return regfi_load_big_data(file, offset, length, cell_length, 
3144                                   NULL, strict);
3145      }
3146      else
3147      {
3148        regfi_log_add(REGFI_LOG_WARN, "Data length (0x%.8X) larger than"
3149                      " remaining cell length (0x%.8X)"
3150                      " while parsing data record at offset 0x%.8X.", 
3151                      length, cell_length - 4, offset);
3152        if(strict)
3153          goto fail;
3154        else
3155          length = cell_length - 4;
3156      }
3157    }
3158
3159    ret_val = regfi_parse_data(file, offset, length, strict);
3160  }
3161
3162  return ret_val;
3163
3164 fail_locked:
3165  regfi_unlock(file, &file->cb_lock, "regfi_load_data");
3166 fail:
3167  ret_val.buf = NULL;
3168  ret_val.len = 0;
3169  return ret_val;
3170}
3171
3172
3173/******************************************************************************
3174 * Parses the common case data records stored in a single cell.
3175 ******************************************************************************/
3176REGFI_BUFFER regfi_parse_data(REGFI_FILE* file, uint32_t offset,
3177                              uint32_t length, bool strict)
3178{
3179  REGFI_BUFFER ret_val;
3180  uint32_t read_length;
3181
3182  ret_val.buf = NULL;
3183  ret_val.len = 0;
3184 
3185  if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL)
3186    goto fail;
3187  ret_val.len = length;
3188
3189  if(!regfi_lock(file, &file->cb_lock, "regfi_parse_data"))
3190    goto fail;
3191
3192  if(regfi_seek(file->cb, offset+4, SEEK_SET) == -1)
3193  {
3194    regfi_log_add(REGFI_LOG_WARN, "Could not seek while "
3195                  "reading data at offset 0x%.8X.", offset);
3196    goto fail_locked;
3197  }
3198 
3199  read_length = length;
3200  if((regfi_read(file->cb, ret_val.buf, &read_length) != 0)
3201     || read_length != length)
3202  {
3203    regfi_log_add(REGFI_LOG_ERROR, "Could not read data block while"
3204                  " parsing data record at offset 0x%.8X.", offset);
3205    goto fail_locked;
3206  }
3207
3208  if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_data"))
3209    goto fail;
3210
3211  return ret_val;
3212
3213 fail_locked:
3214  regfi_unlock(file, &file->cb_lock, "regfi_parse_data");
3215 fail:
3216  talloc_free(ret_val.buf);
3217  ret_val.buf = NULL;
3218  ret_val.buf = 0;
3219  return ret_val;
3220}
3221
3222
3223
3224/******************************************************************************
3225 *
3226 ******************************************************************************/
3227REGFI_BUFFER regfi_parse_little_data(REGFI_FILE* file, uint32_t voffset,
3228                                     uint32_t length, bool strict)
3229{
3230  uint8_t i;
3231  REGFI_BUFFER ret_val;
3232
3233  ret_val.buf = NULL;
3234  ret_val.len = 0;
3235
3236  if(length > 4)
3237  {
3238    regfi_log_add(REGFI_LOG_ERROR, "Data in offset but length > 4"
3239                  " while parsing data record. (voffset=0x%.8X, length=%d)",
3240                  voffset, length);
3241    return ret_val;
3242  }
3243
3244  if((ret_val.buf = talloc_array(NULL, uint8_t, length)) == NULL)
3245    return ret_val;
3246  ret_val.len = length;
3247 
3248  for(i = 0; i < length; i++)
3249    ret_val.buf[i] = (uint8_t)((voffset >> i*8) & 0xFF);
3250
3251  return ret_val;
3252}
3253
3254/******************************************************************************
3255*******************************************************************************/
3256REGFI_BUFFER regfi_parse_big_data_header(REGFI_FILE* file, uint32_t offset, 
3257                                         uint32_t max_size, bool strict)
3258{
3259  REGFI_BUFFER ret_val;
3260  uint32_t cell_length;
3261  bool unalloc;
3262
3263  /* XXX: do something with unalloc? */
3264  ret_val.buf = (uint8_t*)talloc_array(NULL, uint8_t, REGFI_BIG_DATA_MIN_LENGTH);
3265  if(ret_val.buf == NULL)
3266    goto fail;
3267
3268  if(REGFI_BIG_DATA_MIN_LENGTH > max_size)
3269  {
3270    regfi_log_add(REGFI_LOG_WARN, "Big data header exceeded max_size "
3271                  "while parsing big data header at offset 0x%.8X.",offset);
3272    goto fail;
3273  }
3274
3275  if(!regfi_lock(file, &file->cb_lock, "regfi_parse_big_data_header"))
3276    goto fail;
3277
3278
3279  if(!regfi_parse_cell(file->cb, offset, ret_val.buf, REGFI_BIG_DATA_MIN_LENGTH,
3280                       &cell_length, &unalloc))
3281  {
3282    regfi_log_add(REGFI_LOG_WARN, "Could not parse cell while"
3283                  " parsing big data header at offset 0x%.8X.", offset);
3284    goto fail_locked;
3285  }
3286
3287  if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_big_data_header"))
3288    goto fail;
3289
3290  if((ret_val.buf[0] != 'd') || (ret_val.buf[1] != 'b'))
3291  {
3292    regfi_log_add(REGFI_LOG_WARN, "Unknown magic number"
3293                  " (0x%.2X, 0x%.2X) encountered while parsing"
3294                  " big data header at offset 0x%.8X.", 
3295                  ret_val.buf[0], ret_val.buf[1], offset);
3296    goto fail;
3297  }
3298
3299  ret_val.len = REGFI_BIG_DATA_MIN_LENGTH;
3300  return ret_val;
3301
3302 fail_locked:
3303  regfi_unlock(file, &file->cb_lock, "regfi_parse_big_data_header");
3304 fail:
3305  talloc_free(ret_val.buf);
3306  ret_val.buf = NULL;
3307  ret_val.len = 0;
3308  return ret_val;
3309}
3310
3311
3312
3313/******************************************************************************
3314 *
3315 ******************************************************************************/
3316uint32_t* regfi_parse_big_data_indirect(REGFI_FILE* file, uint32_t offset,
3317                                      uint16_t num_chunks, bool strict)
3318{
3319  uint32_t* ret_val;
3320  uint32_t indirect_length;
3321  int32_t max_size;
3322  uint16_t i;
3323  bool unalloc;
3324
3325  /* XXX: do something with unalloc? */
3326
3327  max_size = regfi_calc_maxsize(file, offset);
3328  if((max_size < 0) || (num_chunks*sizeof(uint32_t) + 4 > max_size))
3329    return NULL;
3330
3331  ret_val = (uint32_t*)talloc_array(NULL, uint32_t, num_chunks);
3332  if(ret_val == NULL)
3333    goto fail;
3334
3335  if(!regfi_lock(file, &file->cb_lock, "regfi_parse_big_data_indirect"))
3336    goto fail;
3337
3338  if(!regfi_parse_cell(file->cb, offset, (uint8_t*)ret_val,
3339                       num_chunks*sizeof(uint32_t),
3340                       &indirect_length, &unalloc))
3341  {
3342    regfi_log_add(REGFI_LOG_WARN, "Could not parse cell while"
3343                  " parsing big data indirect record at offset 0x%.8X.", 
3344                  offset);
3345    goto fail_locked;
3346  }
3347
3348  if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_big_data_indirect"))
3349    goto fail;
3350
3351  /* Convert pointers to proper endianess, verify they are aligned. */
3352  for(i=0; i<num_chunks; i++)
3353  {
3354    ret_val[i] = IVAL(ret_val, i*sizeof(uint32_t));
3355    if((ret_val[i] & 0x00000007) != 0)
3356      goto fail;
3357  }
3358 
3359  return ret_val;
3360
3361 fail_locked:
3362  regfi_unlock(file, &file->cb_lock, "regfi_parse_big_data_indirect");
3363 fail:
3364  talloc_free(ret_val);
3365  return NULL;
3366}
3367
3368
3369/******************************************************************************
3370 * Arguments:
3371 *  file       --
3372 *  offsets    -- list of virtual offsets.
3373 *  num_chunks --
3374 *  strict     --
3375 *
3376 * Returns:
3377 *  A range_list with physical offsets and complete lengths
3378 *  (including cell headers) of associated cells. 
3379 *  No data in range_list elements.
3380 ******************************************************************************/
3381range_list* regfi_parse_big_data_cells(REGFI_FILE* file, uint32_t* offsets,
3382                                       uint16_t num_chunks, bool strict)
3383{
3384  uint32_t cell_length, chunk_offset;
3385  range_list* ret_val;
3386  uint16_t i;
3387  bool unalloc;
3388 
3389  /* XXX: do something with unalloc? */
3390  ret_val = range_list_new();
3391  if(ret_val == NULL)
3392    goto fail;
3393 
3394  for(i=0; i<num_chunks; i++)
3395  {
3396    if(!regfi_lock(file, &file->cb_lock, "regfi_parse_big_data_cells"))
3397      goto fail;
3398
3399    chunk_offset = offsets[i]+REGFI_REGF_SIZE;
3400    if(!regfi_parse_cell(file->cb, chunk_offset, NULL, 0,
3401                         &cell_length, &unalloc))
3402    {
3403      regfi_log_add(REGFI_LOG_WARN, "Could not parse cell while"
3404                    " parsing big data chunk at offset 0x%.8X.", 
3405                    chunk_offset);
3406      goto fail_locked;
3407    }
3408
3409    if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_big_data_cells"))
3410      goto fail;
3411
3412    if(!range_list_add(ret_val, chunk_offset, cell_length, NULL))
3413      goto fail;
3414  }
3415
3416  return ret_val;
3417
3418 fail_locked:
3419  regfi_unlock(file, &file->cb_lock, "regfi_parse_big_data_cells");
3420 fail:
3421  if(ret_val != NULL)
3422    range_list_free(ret_val);
3423  return NULL;
3424}
3425
3426
3427/******************************************************************************
3428*******************************************************************************/
3429REGFI_BUFFER regfi_load_big_data(REGFI_FILE* file, 
3430                                 uint32_t offset, uint32_t data_length, 
3431                                 uint32_t cell_length, range_list* used_ranges,
3432                                 bool strict)
3433{
3434  REGFI_BUFFER ret_val;
3435  uint16_t num_chunks, i;
3436  uint32_t read_length, data_left, tmp_len, indirect_offset;
3437  uint32_t* indirect_ptrs = NULL;
3438  REGFI_BUFFER bd_header;
3439  range_list* bd_cells = NULL;
3440  const range_list_element* cell_info;
3441
3442  ret_val.buf = NULL;
3443
3444  /* XXX: Add better error/warning messages */
3445
3446  bd_header = regfi_parse_big_data_header(file, offset, cell_length, strict);
3447  if(bd_header.buf == NULL)
3448    goto fail;
3449
3450  /* Keep track of used space for use by reglookup-recover */
3451  if(used_ranges != NULL)
3452    if(!range_list_add(used_ranges, offset, cell_length, NULL))
3453      goto fail;
3454
3455  num_chunks = SVAL(bd_header.buf, 0x2);
3456  indirect_offset = IVAL(bd_header.buf, 0x4) + REGFI_REGF_SIZE;
3457  talloc_free(bd_header.buf);
3458
3459  indirect_ptrs = regfi_parse_big_data_indirect(file, indirect_offset,
3460                                                num_chunks, strict);
3461  if(indirect_ptrs == NULL)
3462    goto fail;
3463
3464  if(used_ranges != NULL)
3465    if(!range_list_add(used_ranges, indirect_offset, num_chunks*4+4, NULL))
3466      goto fail;
3467 
3468  if((ret_val.buf = talloc_array(NULL, uint8_t, data_length)) == NULL)
3469    goto fail;
3470  data_left = data_length;
3471
3472  bd_cells = regfi_parse_big_data_cells(file, indirect_ptrs, num_chunks, strict);
3473  if(bd_cells == NULL)
3474    goto fail;
3475
3476  talloc_free(indirect_ptrs);
3477  indirect_ptrs = NULL;
3478 
3479  for(i=0; (i<num_chunks) && (data_left>0); i++)
3480  {
3481    cell_info = range_list_get(bd_cells, i);
3482    if(cell_info == NULL)
3483      goto fail;
3484
3485    /* XXX: This should be "cell_info->length-4" to account for the 4 byte cell
3486     *      length.  However, it has been observed that some (all?) chunks
3487     *      have an additional 4 bytes of 0 at the end of their cells that
3488     *      isn't part of the data, so we're trimming that off too.
3489     *      Perhaps it's just an 8 byte alignment requirement...
3490     */
3491    if(cell_info->length - 8 >= data_left)
3492    {
3493      if(i+1 != num_chunks)
3494      {
3495        regfi_log_add(REGFI_LOG_WARN, "Left over chunks detected "
3496                      "while constructing big data at offset 0x%.8X "
3497                      "(chunk offset 0x%.8X).", offset, cell_info->offset);
3498      }
3499      read_length = data_left;
3500    }
3501    else
3502      read_length = cell_info->length - 8;
3503
3504
3505    if(read_length > regfi_calc_maxsize(file, cell_info->offset))
3506    {
3507      regfi_log_add(REGFI_LOG_WARN, "A chunk exceeded the maxsize "
3508                    "while constructing big data at offset 0x%.8X "
3509                    "(chunk offset 0x%.8X).", offset, cell_info->offset);
3510      goto fail;
3511    }
3512
3513    if(!regfi_lock(file, &file->cb_lock, "regfi_load_big_data"))
3514      goto fail;
3515
3516    if(regfi_seek(file->cb, cell_info->offset+sizeof(uint32_t), SEEK_SET) == -1)
3517    {
3518      regfi_log_add(REGFI_LOG_WARN, "Could not seek to chunk while "
3519                    "constructing big data at offset 0x%.8X "
3520                    "(chunk offset 0x%.8X).", offset, cell_info->offset);
3521      goto fail_locked;
3522    }
3523
3524    tmp_len = read_length;
3525    if(regfi_read(file->cb, ret_val.buf+(data_length-data_left), 
3526                  &read_length) != 0 || (read_length != tmp_len))
3527    {
3528      regfi_log_add(REGFI_LOG_WARN, "Could not read data chunk while"
3529                    " constructing big data at offset 0x%.8X"
3530                    " (chunk offset 0x%.8X).", offset, cell_info->offset);
3531      goto fail_locked;
3532    }
3533
3534    if(!regfi_unlock(file, &file->cb_lock, "regfi_load_big_data"))
3535      goto fail;
3536
3537    if(used_ranges != NULL)
3538      if(!range_list_add(used_ranges, cell_info->offset,cell_info->length,NULL))
3539        goto fail;
3540
3541    data_left -= read_length;
3542  }
3543  range_list_free(bd_cells);
3544
3545  ret_val.len = data_length-data_left;
3546  return ret_val;
3547
3548 fail_locked:
3549  regfi_unlock(file, &file->cb_lock, "regfi_load_big_data");
3550 fail:
3551  talloc_free(ret_val.buf);
3552  talloc_free(indirect_ptrs);
3553  if(bd_cells != NULL)
3554    range_list_free(bd_cells);
3555  ret_val.buf = NULL;
3556  ret_val.len = 0;
3557  return ret_val;
3558}
3559
3560
3561range_list* regfi_parse_unalloc_cells(REGFI_FILE* file)
3562{
3563  range_list* ret_val;
3564  REGFI_HBIN* hbin;
3565  const range_list_element* hbins_elem;
3566  uint32_t i, num_hbins, curr_off, cell_len;
3567  bool is_unalloc;
3568
3569  ret_val = range_list_new();
3570  if(ret_val == NULL)
3571    return NULL;
3572
3573  if(!regfi_read_lock(file, &file->hbins_lock, "regfi_parse_unalloc_cells"))
3574  {
3575    range_list_free(ret_val);
3576    return NULL;
3577  }
3578
3579  num_hbins = range_list_size(file->hbins);
3580  for(i=0; i<num_hbins; i++)
3581  {
3582    hbins_elem = range_list_get(file->hbins, i);
3583    if(hbins_elem == NULL)
3584      break;
3585    hbin = (REGFI_HBIN*)hbins_elem->data;
3586
3587    curr_off = REGFI_HBIN_HEADER_SIZE;
3588    while(curr_off < hbin->block_size)
3589    {
3590      if(!regfi_lock(file, &file->cb_lock, "regfi_parse_unalloc_cells"))
3591        break;
3592
3593      if(!regfi_parse_cell(file->cb, hbin->file_off+curr_off, NULL, 0,
3594                           &cell_len, &is_unalloc))
3595      {
3596        regfi_unlock(file, &file->cb_lock, "regfi_parse_unalloc_cells");
3597        break;
3598      }
3599
3600      if(!regfi_unlock(file, &file->cb_lock, "regfi_parse_unalloc_cells"))
3601        break;
3602
3603      if((cell_len == 0) || ((cell_len & 0x00000007) != 0))
3604      {
3605        regfi_log_add(REGFI_LOG_ERROR, "Bad cell length encountered"
3606                      " while parsing unallocated cells at offset 0x%.8X.",
3607                      hbin->file_off+curr_off);
3608        break;
3609      }
3610
3611      /* for some reason the record_size of the last record in
3612         an hbin block can extend past the end of the block
3613         even though the record fits within the remaining
3614         space....aaarrrgggghhhhhh */ 
3615      if(curr_off + cell_len >= hbin->block_size)
3616        cell_len = hbin->block_size - curr_off;
3617     
3618      if(is_unalloc)
3619        range_list_add(ret_val, hbin->file_off+curr_off, 
3620                       cell_len, NULL);
3621     
3622      curr_off = curr_off+cell_len;
3623    }
3624  }
3625
3626  if(!regfi_rw_unlock(file, &file->hbins_lock, "regfi_parse_unalloc_cells"))
3627  {
3628    range_list_free(ret_val);
3629    return NULL;
3630  }
3631
3632  return ret_val;
3633}
3634
3635
3636/* From lib/time.c */
3637
3638/****************************************************************************
3639 Put a 8 byte filetime from a time_t
3640 This takes real GMT as input and converts to kludge-GMT
3641****************************************************************************/
3642void regfi_unix2nt_time(REGFI_NTTIME *nt, time_t t)
3643{
3644  double d;
3645 
3646  if (t==0) 
3647  {
3648    nt->low = 0;
3649    nt->high = 0;
3650    return;
3651  }
3652 
3653  if (t == TIME_T_MAX) 
3654  {
3655    nt->low = 0xffffffff;
3656    nt->high = 0x7fffffff;
3657    return;
3658  }             
3659 
3660  if (t == -1) 
3661  {
3662    nt->low = 0xffffffff;
3663    nt->high = 0xffffffff;
3664    return;
3665  }             
3666 
3667  /* this converts GMT to kludge-GMT */
3668  /* XXX: This was removed due to difficult dependency requirements. 
3669   *      So far, times appear to be correct without this adjustment, but
3670   *      that may be proven wrong with adequate testing.
3671   */
3672  /* t -= TimeDiff(t) - get_serverzone(); */
3673 
3674  d = (double)(t);
3675  d += TIME_FIXUP_CONSTANT;
3676  d *= 1.0e7;
3677 
3678  nt->high = (uint32_t)(d * (1.0/(4.0*(double)(1<<30))));
3679  nt->low  = (uint32_t)(d - ((double)nt->high)*4.0*(double)(1<<30));
3680}
3681
3682
3683/****************************************************************************
3684 Interpret an 8 byte "filetime" structure to a time_t
3685 It's originally in "100ns units since jan 1st 1601"
3686
3687 An 8 byte value of 0xffffffffffffffff will be returned as (time_t)0.
3688
3689 It appears to be kludge-GMT (at least for file listings). This means
3690 its the GMT you get by taking a localtime and adding the
3691 serverzone. This is NOT the same as GMT in some cases. This routine
3692 converts this to real GMT.
3693****************************************************************************/
3694double regfi_nt2unix_time(const REGFI_NTTIME* nt)
3695{
3696  double ret_val;
3697
3698  /* The next two lines are a fix needed for the
3699     broken SCO compiler. JRA. */
3700  time_t l_time_min = TIME_T_MIN;
3701  time_t l_time_max = TIME_T_MAX;
3702 
3703  if (nt->high == 0 || (nt->high == 0xffffffff && nt->low == 0xffffffff))
3704    return(0);
3705 
3706  ret_val = ((double)nt->high)*4.0*(double)(1<<30);
3707  ret_val += nt->low;
3708  ret_val *= 1.0e-7;
3709 
3710  /* now adjust by 369 years to make the secs since 1970 */
3711  ret_val -= TIME_FIXUP_CONSTANT;
3712 
3713  /* XXX: should these sanity checks be removed? */
3714  if (ret_val <= l_time_min)
3715    return (l_time_min);
3716 
3717  if (ret_val >= l_time_max)
3718    return (l_time_max);
3719 
3720  /* this takes us from kludge-GMT to real GMT */
3721  /* XXX: This was removed due to difficult dependency requirements. 
3722   *      So far, times appear to be correct without this adjustment, but
3723   *      that may be proven wrong with adequate testing.
3724   */
3725  /*
3726    ret -= get_serverzone();
3727    ret += LocTimeDiff(ret);
3728  */
3729
3730  return ret_val;
3731}
3732
3733/* End of stuff from lib/time.c */
Note: See TracBrowser for help on using the repository browser.