source: trunk/lib/regfi.c @ 224

Last change on this file since 224 was 224, checked in by tim, 14 years ago

added new regfi API function to help manage memory better
fixed reference loop problems in pyregfi

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