source: trunk/lib/regfi.c @ 252

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

updated pyregfi to work with regfi changes
renamed some functions for more clarity
fixed some issues related to talloc_reference

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