source: trunk/lib/regfi.c @ 255

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

fixed error condition deadlock in regfi
prevented early garbage collection of hive file handles
fixed module imports under python3

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