source: trunk/lib/regfi.c @ 81

Last change on this file since 81 was 81, checked in by tim, 18 years ago

Finished incorporating changes to reglookup to work with new regfi interface.

Compiles now, but is minimally tested.

  • Property svn:keywords set to Id
File size: 46.8 KB
Line 
1/*
2 * Branched from Samba project Subversion repository, version #7470:
3 *   http://websvn.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c
4 *
5 * Unix SMB/CIFS implementation.
6 * Windows NT registry I/O library
7 *
8 * Copyright (C) 2005-2007 Timothy D. Morgan
9 * Copyright (C) 2005 Gerald (Jerry) Carter
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
23 *
24 * $Id: regfi.c 81 2007-01-17 16:47:39Z tim $
25 */
26
27#include "../include/regfi.h"
28
29
30/* Registry types mapping */
31const unsigned int regfi_num_reg_types = 12;
32static const char* regfi_type_names[] =
33  {"NONE", "SZ", "EXPAND_SZ", "BINARY", "DWORD", "DWORD_BE", "LINK",
34   "MULTI_SZ", "RSRC_LIST", "RSRC_DESC", "RSRC_REQ_LIST", "QWORD"};
35
36
37/* Returns NULL on error */
38const char* regfi_type_val2str(unsigned int val)
39{
40  if(val == REG_KEY)
41    return "KEY";
42 
43  if(val >= regfi_num_reg_types)
44    return NULL;
45 
46  return regfi_type_names[val];
47}
48
49
50/* Returns -1 on error */
51int regfi_type_str2val(const char* str)
52{
53  int i;
54
55  if(strcmp("KEY", str) == 0)
56    return REG_KEY;
57
58  for(i=0; i < regfi_num_reg_types; i++)
59    if (strcmp(regfi_type_names[i], str) == 0) 
60      return i;
61
62  if(strcmp("DWORD_LE", str) == 0)
63    return REG_DWORD_LE;
64
65  return -1;
66}
67
68
69/* Security descriptor parsing functions  */
70
71const char* regfi_ace_type2str(uint8 type)
72{
73  static const char* map[7] 
74    = {"ALLOW", "DENY", "AUDIT", "ALARM", 
75       "ALLOW CPD", "OBJ ALLOW", "OBJ DENY"};
76  if(type < 7)
77    return map[type];
78  else
79    /* XXX: would be nice to return the unknown integer value. 
80     *      However, as it is a const string, it can't be free()ed later on,
81     *      so that would need to change.
82     */
83    return "UNKNOWN";
84}
85
86
87/* XXX: need a better reference on the meaning of each flag. */
88/* For more info, see:
89 *   http://msdn2.microsoft.com/en-us/library/aa772242.aspx
90 */
91char* regfi_ace_flags2str(uint8 flags)
92{
93  static const char* flag_map[32] = 
94    { "OI",
95      "CI",
96      "NP",
97      "IO",
98      "IA",
99      NULL,
100      NULL,
101      NULL,
102    };
103
104  char* ret_val = malloc(35*sizeof(char));
105  char* fo = ret_val;
106  uint32 i;
107  uint8 f;
108
109  if(ret_val == NULL)
110    return NULL;
111
112  fo[0] = '\0';
113  if (!flags)
114    return ret_val;
115
116  for(i=0; i < 8; i++)
117  {
118    f = (1<<i);
119    if((flags & f) && (flag_map[i] != NULL))
120    {
121      strcpy(fo, flag_map[i]);
122      fo += strlen(flag_map[i]);
123      *(fo++) = ' ';
124      flags ^= f;
125    }
126  }
127 
128  /* Any remaining unknown flags are added at the end in hex. */
129  if(flags != 0)
130    sprintf(fo, "0x%.2X ", flags);
131
132  /* Chop off the last space if we've written anything to ret_val */
133  if(fo != ret_val)
134    fo[-1] = '\0';
135
136  /* XXX: what was this old VI flag for??
137     XXX: Is this check right?  0xF == 1|2|4|8, which makes it redundant...
138  if (flags == 0xF) {
139    if (some) strcat(flg_output, " ");
140    some = 1;
141    strcat(flg_output, "VI");
142  }
143  */
144
145  return ret_val;
146}
147
148
149char* regfi_ace_perms2str(uint32 perms)
150{
151  uint32 i, p;
152  /* This is more than is needed by a fair margin. */
153  char* ret_val = malloc(350*sizeof(char));
154  char* r = ret_val;
155
156  /* Each represents one of 32 permissions bits.  NULL is for undefined/reserved bits.
157   * For more information, see:
158   *   http://msdn2.microsoft.com/en-gb/library/aa374892.aspx
159   *   http://msdn2.microsoft.com/en-gb/library/ms724878.aspx
160   */
161  static const char* perm_map[32] = 
162    {/* object-specific permissions (registry keys, in this case) */
163      "QRY_VAL",       /* KEY_QUERY_VALUE */
164      "SET_VAL",       /* KEY_SET_VALUE */
165      "CREATE_KEY",    /* KEY_CREATE_SUB_KEY */
166      "ENUM_KEYS",     /* KEY_ENUMERATE_SUB_KEYS */
167      "NOTIFY",        /* KEY_NOTIFY */
168      "CREATE_LNK",    /* KEY_CREATE_LINK - Reserved for system use. */
169      NULL,
170      NULL,
171      "WOW64_64",      /* KEY_WOW64_64KEY */
172      "WOW64_32",      /* KEY_WOW64_32KEY */
173      NULL,
174      NULL,
175      NULL,
176      NULL,
177      NULL,
178      NULL,
179      /* standard access rights */
180      "DELETE",        /* DELETE */
181      "R_CONT",        /* READ_CONTROL */
182      "W_DAC",         /* WRITE_DAC */
183      "W_OWNER",       /* WRITE_OWNER */
184      "SYNC",          /* SYNCHRONIZE - Shouldn't be set in registries */
185      NULL,
186      NULL,
187      NULL,
188      /* other generic */
189      "SYS_SEC",       /* ACCESS_SYSTEM_SECURITY */
190      "MAX_ALLWD",     /* MAXIMUM_ALLOWED */
191      NULL,
192      NULL,
193      "GEN_A",         /* GENERIC_ALL */
194      "GEN_X",         /* GENERIC_EXECUTE */
195      "GEN_W",         /* GENERIC_WRITE */
196      "GEN_R",         /* GENERIC_READ */
197    };
198
199
200  if(ret_val == NULL)
201    return NULL;
202
203  r[0] = '\0';
204  for(i=0; i < 32; i++)
205  {
206    p = (1<<i);
207    if((perms & p) && (perm_map[i] != NULL))
208    {
209      strcpy(r, perm_map[i]);
210      r += strlen(perm_map[i]);
211      *(r++) = ' ';
212      perms ^= p;
213    }
214  }
215 
216  /* Any remaining unknown permission bits are added at the end in hex. */
217  if(perms != 0)
218    sprintf(r, "0x%.8X ", perms);
219
220  /* Chop off the last space if we've written anything to ret_val */
221  if(r != ret_val)
222    r[-1] = '\0';
223
224  return ret_val;
225}
226
227
228char* regfi_sid2str(DOM_SID* sid)
229{
230  uint32 i, size = MAXSUBAUTHS*11 + 24;
231  uint32 left = size;
232  uint8 comps = sid->num_auths;
233  char* ret_val = malloc(size);
234 
235  if(ret_val == NULL)
236    return NULL;
237
238  if(comps > MAXSUBAUTHS)
239    comps = MAXSUBAUTHS;
240
241  left -= sprintf(ret_val, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
242
243  for (i = 0; i < comps; i++) 
244    left -= snprintf(ret_val+(size-left), left, "-%u", sid->sub_auths[i]);
245
246  return ret_val;
247}
248
249
250char* regfi_get_acl(SEC_ACL* acl)
251{
252  uint32 i, extra, size = 0;
253  const char* type_str;
254  char* flags_str;
255  char* perms_str;
256  char* sid_str;
257  char* ace_delim = "";
258  char* ret_val = NULL;
259  char* tmp_val = NULL;
260  bool failed = false;
261  char field_delim = ':';
262
263  for (i = 0; i < acl->num_aces && !failed; i++)
264  {
265    sid_str = regfi_sid2str(&acl->ace[i].trustee);
266    type_str = regfi_ace_type2str(acl->ace[i].type);
267    perms_str = regfi_ace_perms2str(acl->ace[i].info.mask);
268    flags_str = regfi_ace_flags2str(acl->ace[i].flags);
269   
270    if(flags_str != NULL && perms_str != NULL 
271       && type_str != NULL && sid_str != NULL)
272    {
273      /* XXX: this is slow */
274      extra = strlen(sid_str) + strlen(type_str) 
275        + strlen(perms_str) + strlen(flags_str)+5;
276      tmp_val = realloc(ret_val, size+extra);
277
278      if(tmp_val == NULL)
279      {
280        free(ret_val);
281        failed = true;
282      }
283      else
284      {
285        ret_val = tmp_val;
286        size += snprintf(ret_val+size, extra, "%s%s%c%s%c%s%c%s",
287                         ace_delim,sid_str,
288                         field_delim,type_str,
289                         field_delim,perms_str,
290                         field_delim,flags_str);
291        ace_delim = "|";
292      }
293    }
294    else
295      failed = true;
296
297    if(sid_str != NULL)
298      free(sid_str);
299    if(sid_str != NULL)
300      free(perms_str);
301    if(sid_str != NULL)
302      free(flags_str);
303  }
304
305  return ret_val;
306}
307
308
309char* regfi_get_sacl(SEC_DESC *sec_desc)
310{
311  if (sec_desc->sacl)
312    return regfi_get_acl(sec_desc->sacl);
313  else
314    return NULL;
315}
316
317
318char* regfi_get_dacl(SEC_DESC *sec_desc)
319{
320  if (sec_desc->dacl)
321    return regfi_get_acl(sec_desc->dacl);
322  else
323    return NULL;
324}
325
326
327char* regfi_get_owner(SEC_DESC *sec_desc)
328{
329  return regfi_sid2str(sec_desc->owner_sid);
330}
331
332
333char* regfi_get_group(SEC_DESC *sec_desc)
334{
335  return regfi_sid2str(sec_desc->grp_sid);
336}
337
338
339
340/*******************************************************************
341 *******************************************************************/
342static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, 
343                       uint32 block_size )
344{
345  const int hdr_size = 0x20;
346  int bytes_read, returned;
347  char *buffer;
348  SMB_STRUCT_STAT sbuf;
349
350  /* check for end of file */
351
352  if ( fstat( file->fd, &sbuf ) ) {
353    /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
354    return -1;
355  }
356
357  if ( (size_t)file_offset >= sbuf.st_size )
358    return -1;
359       
360  /* if block_size == 0, we are parsnig HBIN records and need
361     to read some of the header to get the block_size from there */
362           
363  if ( block_size == 0 ) {
364    uint8 hdr[0x20];
365
366    if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
367      /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
368      return -1;
369    }
370
371    bytes_read = returned = 0;
372    while (bytes_read < hdr_size)
373    {
374      returned = read(file->fd, hdr + bytes_read, hdr_size - bytes_read);
375      if(returned == -1 && errno != EINTR && errno != EAGAIN)
376      {
377        /*DEBUG(0,("read_block: read of hdr failed (%s)\n",strerror(errno)));*/
378        return -1;
379      }
380
381      if(returned == 0)
382        return -1;
383
384      bytes_read += returned;
385    }
386
387    /* make sure this is an hbin header */
388
389    if ( strncmp( (char*)hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
390      /*DEBUG(0,("read_block: invalid block header!\n"));*/
391      return -1;
392    }
393
394    block_size = IVAL( hdr, 0x08 );
395  }
396
397  /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
398
399  /* set the offset, initialize the buffer, and read the block from disk */
400
401  if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
402    /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
403    return -1;
404  }
405       
406  prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
407  buffer = ps->data_p;
408  bytes_read = returned = 0;
409
410  while ( bytes_read < block_size ) 
411  {
412    returned = read(file->fd, buffer+bytes_read, block_size-bytes_read);
413    if(returned == -1 && errno != EINTR && errno != EAGAIN)
414    {
415      /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
416      return -1;
417    }
418
419    if ((returned == 0) && (bytes_read < block_size)) 
420    {
421      /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
422      return -1;
423    }   
424
425    bytes_read += returned;
426  }
427       
428  return bytes_read;
429}
430
431
432/*******************************************************************
433 *******************************************************************/
434static bool prs_regf_block(const char *desc, prs_struct *ps, 
435                           int depth, REGF_FILE *file)
436{
437  depth++;
438       
439  if(!prs_uint8s(true, "header", ps, depth, file->header, sizeof(file->header)))
440    return false;
441       
442  /* yes, these values are always identical so store them only once */
443       
444  if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 ))
445    return false;
446  if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 ))
447    return false;
448
449  /* get the modtime */
450       
451  if ( !prs_set_offset( ps, 0x0c ) )
452    return false;
453  if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
454    return false;
455
456  /* constants */
457       
458  if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 ))
459    return false;
460  if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 ))
461    return false;
462  if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 ))
463    return false;
464  if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 ))
465    return false;
466
467  /* get file offsets */
468       
469  if ( !prs_set_offset( ps, 0x24 ) )
470    return false;
471  if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset ))
472    return false;
473  if ( !prs_uint32( "last_block", ps, depth, &file->last_block ))
474    return false;
475               
476  /* one more constant */
477       
478  if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
479    return false;
480               
481  /* get the checksum */
482       
483  if ( !prs_set_offset( ps, 0x01fc ) )
484    return false;
485  if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
486    return false;
487       
488  return true;
489}
490
491
492/*******************************************************************
493 *******************************************************************/
494static bool prs_hbin_block(const char *desc, prs_struct *ps, 
495                           int depth, REGF_HBIN *hbin)
496{
497  uint32 block_size2;
498
499  depth++;
500       
501  if(!prs_uint8s(true, "header", ps, depth, hbin->header, sizeof(hbin->header)))
502    return false;
503
504  if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
505    return false;
506
507  /* The dosreg.cpp comments say that the block size is at 0x1c.
508     According to a WINXP NTUSER.dat file, this is wrong.  The block_size
509     is at 0x08 */
510
511  if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
512    return false;
513
514  block_size2 = hbin->block_size;
515  prs_set_offset( ps, 0x1c );
516  if ( !prs_uint32( "block_size2", ps, depth, &block_size2 ))
517    return false;
518
519  if ( !ps->io )
520    hbin->dirty = true;
521       
522
523  return true;
524}
525
526
527/*******************************************************************
528 *******************************************************************/
529static bool prs_nk_rec( const char *desc, prs_struct *ps, 
530                        int depth, REGF_NK_REC *nk )
531{
532  uint16 class_length, name_length;
533  uint32 start;
534  uint32 data_size, start_off, end_off;
535  uint32 unknown_off = REGF_OFFSET_NONE;
536
537  nk->hbin_off = ps->data_offset;
538  start = nk->hbin_off;
539       
540  depth++;
541       
542  /* back up and get the data_size */   
543  if ( !prs_set_offset( ps, ps->data_offset-sizeof(uint32)) )
544    return false;
545  start_off = ps->data_offset;
546  if ( !prs_uint32( "rec_size", ps, depth, &nk->rec_size ))
547    return false;
548       
549  if (!prs_uint8s(true, "header", ps, depth, nk->header, sizeof(nk->header)))
550    return false;
551               
552  if ( !prs_uint16( "key_type", ps, depth, &nk->key_type ))
553    return false;
554  if ( !smb_io_time( "mtime", &nk->mtime, ps, depth ))
555    return false;
556               
557  if ( !prs_set_offset( ps, start+0x0010 ) )
558    return false;
559  if ( !prs_uint32( "parent_off", ps, depth, &nk->parent_off ))
560    return false;
561  if ( !prs_uint32( "num_subkeys", ps, depth, &nk->num_subkeys ))
562    return false;
563               
564  if ( !prs_set_offset( ps, start+0x001c ) )
565    return false;
566  if ( !prs_uint32( "subkeys_off", ps, depth, &nk->subkeys_off ))
567    return false;
568  if ( !prs_uint32( "unknown_off", ps, depth, &unknown_off) )
569    return false;
570               
571  if ( !prs_set_offset( ps, start+0x0024 ) )
572    return false;
573  if ( !prs_uint32( "num_values", ps, depth, &nk->num_values ))
574    return false;
575  if ( !prs_uint32( "values_off", ps, depth, &nk->values_off ))
576    return false;
577  if ( !prs_uint32( "sk_off", ps, depth, &nk->sk_off ))
578    return false;
579  if ( !prs_uint32( "classname_off", ps, depth, &nk->classname_off ))
580    return false;
581
582  if (!prs_uint32("max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
583    return false;
584  if ( !prs_uint32( "max_bytes_subkeyclassname", ps, 
585                    depth, &nk->max_bytes_subkeyclassname))
586  { return false; }
587  if ( !prs_uint32( "max_bytes_valuename", ps, depth, &nk->max_bytes_valuename))
588    return false;
589  if ( !prs_uint32( "max_bytes_value", ps, depth, &nk->max_bytes_value))
590    return false;
591  if ( !prs_uint32( "unknown index", ps, depth, &nk->unk_index))
592    return false;
593
594  name_length = nk->keyname ? strlen(nk->keyname) : 0 ;
595  class_length = nk->classname ? strlen(nk->classname) : 0 ;
596  if ( !prs_uint16( "name_length", ps, depth, &name_length ))
597    return false;
598  if ( !prs_uint16( "class_length", ps, depth, &class_length ))
599    return false;       
600               
601  if ( class_length ) 
602  {
603    /* XXX: why isn't this parsed? */
604    ;;
605  }
606       
607  if ( name_length ) 
608  {
609    if(ps->io && !(nk->keyname = (char*)zcalloc(sizeof(char), name_length+1)))
610        return false;
611
612    if(!prs_uint8s(true, "name", ps, depth, (uint8*)nk->keyname, name_length))
613      return false;
614
615    if(ps->io)
616      nk->keyname[name_length] = '\0';
617  }
618
619  end_off = ps->data_offset;
620
621  /* data_size must be divisible by 8 and large enough to hold
622     the original record */
623
624  data_size = ((start_off - end_off) & 0xfffffff8 );
625  /*if ( data_size > nk->rec_size )
626      DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
627
628  if ( !ps->io )
629    nk->hbin->dirty = true;
630 
631  return true;
632}
633
634
635/*******************************************************************
636 *******************************************************************/
637static uint32 regf_block_checksum( prs_struct *ps )
638{
639  char *buffer = ps->data_p;
640  uint32 checksum, x;
641  int i;
642
643  /* XOR of all bytes 0x0000 - 0x01FB */
644               
645  checksum = x = 0;
646       
647  for ( i=0; i<0x01FB; i+=4 ) {
648    x = IVAL(buffer, i );
649    checksum ^= x;
650  }
651       
652  return checksum;
653}
654
655
656/*******************************************************************
657 *******************************************************************/
658static bool read_regf_block( REGF_FILE *file )
659{
660  prs_struct ps;
661  uint32 checksum;
662       
663  /* grab the first block from the file */
664               
665  if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
666    return false;
667       
668  /* parse the block and verify the checksum */
669       
670  if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
671    return false;       
672               
673  checksum = regf_block_checksum( &ps );
674       
675  if(ps.is_dynamic)
676    SAFE_FREE(ps.data_p);
677  ps.is_dynamic = false;
678  ps.buffer_size = 0;
679  ps.data_offset = 0;
680
681  if ( file->checksum !=  checksum ) {
682    /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
683    return false;
684  }
685
686  return true;
687}
688
689
690/*******************************************************************
691 *******************************************************************/
692static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
693{
694  REGF_HBIN *hbin;
695  uint32 record_size, curr_off, block_size, header;
696       
697  if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) ) 
698    return NULL;
699  hbin->file_off = offset;
700  hbin->free_off = -1;
701               
702  if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
703    return NULL;
704       
705  if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
706    return NULL;       
707
708  /* this should be the same thing as hbin->block_size but just in case */
709
710  block_size = hbin->ps.buffer_size;
711
712  /* Find the available free space offset.  Always at the end,
713     so walk the record list and stop when you get to the end.
714     The end is defined by a record header of 0xffffffff.  The
715     previous 4 bytes contains the amount of free space remaining
716     in the hbin block. */
717
718  /* remember that the record_size is in the 4 bytes preceeding the record itself */
719
720  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
721    return false;
722
723  record_size = 0;
724  curr_off = hbin->ps.data_offset;
725  while ( header != 0xffffffff ) {
726    /* not done yet so reset the current offset to the
727       next record_size field */
728
729    curr_off = curr_off+record_size;
730
731    /* for some reason the record_size of the last record in
732       an hbin block can extend past the end of the block
733       even though the record fits within the remaining
734       space....aaarrrgggghhhhhh */
735
736    if ( curr_off >= block_size ) {
737      record_size = -1;
738      curr_off = -1;
739      break;
740    }
741
742    if ( !prs_set_offset( &hbin->ps, curr_off) )
743      return false;
744
745    if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) )
746      return false;
747    if ( !prs_uint32( "header", &hbin->ps, 0, &header ) )
748      return false;
749               
750    assert( record_size != 0 );
751
752    if ( record_size & 0x80000000 ) {
753      /* absolute_value(record_size) */
754      record_size = (record_size ^ 0xffffffff) + 1;
755    }
756  }
757
758  /* save the free space offset */
759
760  if ( header == 0xffffffff ) {
761
762    /* account for the fact that the curr_off is 4 bytes behind the actual
763       record header */
764
765    hbin->free_off = curr_off + sizeof(uint32);
766    hbin->free_size = record_size;
767  }
768
769  /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
770
771  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE )  )
772    return false;
773       
774  return hbin;
775}
776
777
778/*******************************************************************
779 Input a randon offset and receive the correpsonding HBIN
780 block for it
781*******************************************************************/
782static bool hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
783{
784  if ( !hbin )
785    return false;
786       
787  if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
788    return true;
789               
790  return false;
791}
792
793
794/*******************************************************************
795 Input a randon offset and receive the correpsonding HBIN
796 block for it
797*******************************************************************/
798static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset )
799{
800  REGF_HBIN *hbin = NULL;
801  uint32 block_off;
802
803  /* start with the open list */
804
805  for ( hbin=file->block_list; hbin; hbin=hbin->next ) {
806    /* DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%x]\n", hbin->file_off, (uint32)hbin ));*/
807    if ( hbin_contains_offset( hbin, offset ) )
808      return hbin;
809  }
810       
811  if ( !hbin ) {
812    /* start at the beginning */
813
814    block_off = REGF_BLOCKSIZE;
815    do {
816      /* cleanup before the next round */
817      if ( hbin )
818      {
819        if(hbin->ps.is_dynamic)
820          SAFE_FREE(hbin->ps.data_p);
821        hbin->ps.is_dynamic = false;
822        hbin->ps.buffer_size = 0;
823        hbin->ps.data_offset = 0;
824      }
825
826      hbin = read_hbin_block( file, block_off );
827
828      if ( hbin ) 
829        block_off = hbin->file_off + hbin->block_size;
830
831    } while ( hbin && !hbin_contains_offset( hbin, offset ) );
832  }
833
834  if ( hbin )
835    /* XXX: this kind of caching needs to be re-evaluated */
836    DLIST_ADD( file->block_list, hbin );
837
838  return hbin;
839}
840
841
842/*******************************************************************
843 *******************************************************************/
844static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
845{
846  depth++;
847
848  if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off ))
849    return false;
850  if ( !prs_uint8s( true, "keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) )
851    return false;
852       
853  return true;
854}
855
856
857/*******************************************************************
858 *******************************************************************/
859static bool hbin_prs_lf_records(const char *desc, REGF_HBIN *hbin, 
860                                int depth, REGF_NK_REC *nk)
861{
862  int i;
863  REGF_LF_REC *lf = &nk->subkeys;
864  uint32 data_size, start_off, end_off;
865
866  depth++;
867
868  /* check if we have anything to do first */
869       
870  if ( nk->num_subkeys == 0 )
871    return true;
872
873  /* move to the LF record */
874
875  if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
876    return false;
877
878  /* backup and get the data_size */
879       
880  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
881    return false;
882  start_off = hbin->ps.data_offset;
883  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &lf->rec_size ))
884    return false;
885
886  if(!prs_uint8s(true, "header", &hbin->ps, depth, 
887                 lf->header, sizeof(lf->header)))
888    return false;
889               
890  if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
891    return false;
892
893  if ( hbin->ps.io ) {
894    if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
895      return false;
896  }
897
898  for ( i=0; i<lf->num_keys; i++ ) {
899    if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) )
900      return false;
901  }
902
903  end_off = hbin->ps.data_offset;
904
905  /* data_size must be divisible by 8 and large enough to hold the original record */
906
907  data_size = ((start_off - end_off) & 0xfffffff8 );
908  /*  if ( data_size > lf->rec_size )*/
909    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
910
911  if ( !hbin->ps.io )
912    hbin->dirty = true;
913
914  return true;
915}
916
917
918/*******************************************************************
919 *******************************************************************/
920static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
921{
922  prs_struct *ps = &hbin->ps;
923  uint16 tag = 0xFFFF;
924  uint32 data_size, start_off, end_off;
925
926
927  depth++;
928
929  if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
930    return false;
931
932  /* backup and get the data_size */
933       
934  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
935    return false;
936  start_off = hbin->ps.data_offset;
937  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size ))
938    return false;
939
940  if (!prs_uint8s(true, "header", ps, depth, sk->header, sizeof(sk->header)))
941    return false;
942  if ( !prs_uint16( "tag", ps, depth, &tag))
943    return false;
944
945  if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off))
946    return false;
947  if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off))
948    return false;
949  if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count))
950    return false;
951  if ( !prs_uint32( "size", ps, depth, &sk->size))
952    return false;
953
954  if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 
955    return false;
956
957  end_off = hbin->ps.data_offset;
958
959  /* data_size must be divisible by 8 and large enough to hold the original record */
960
961  data_size = ((start_off - end_off) & 0xfffffff8 );
962  /*  if ( data_size > sk->rec_size )*/
963    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
964
965  if ( !hbin->ps.io )
966    hbin->dirty = true;
967
968  return true;
969}
970
971
972/*******************************************************************
973 *******************************************************************/
974static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, 
975                             REGF_VK_REC *vk, REGF_FILE *file )
976{
977  uint32 offset;
978  uint16 name_length;
979  prs_struct *ps = &hbin->ps;
980  uint32 data_size, start_off, end_off;
981
982  depth++;
983
984  /* backup and get the data_size */
985       
986  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
987    return false;
988  start_off = hbin->ps.data_offset;
989  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size ))
990    return false;
991
992  if ( !prs_uint8s( true, "header", ps, depth, vk->header, sizeof( vk->header )) )
993    return false;
994
995  if ( !hbin->ps.io )
996    name_length = strlen(vk->valuename);
997
998  if ( !prs_uint16( "name_length", ps, depth, &name_length ))
999    return false;
1000  if ( !prs_uint32( "data_size", ps, depth, &vk->data_size ))
1001    return false;
1002  if ( !prs_uint32( "data_off", ps, depth, &vk->data_off ))
1003    return false;
1004  if ( !prs_uint32( "type", ps, depth, &vk->type))
1005    return false;
1006  if ( !prs_uint16( "flag", ps, depth, &vk->flag))
1007    return false;
1008
1009  offset = ps->data_offset;
1010  offset += 2;  /* skip 2 bytes */
1011  prs_set_offset( ps, offset );
1012
1013  /* get the name */
1014
1015  if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
1016
1017    if ( hbin->ps.io ) {
1018      if ( !(vk->valuename = (char*)zcalloc(sizeof(char), name_length+1 )))
1019        return false;
1020    }
1021    if ( !prs_uint8s(true, "name", ps, depth, 
1022                     (uint8*)vk->valuename, name_length) )
1023      return false;
1024  }
1025
1026  end_off = hbin->ps.data_offset;
1027
1028  /* get the data if necessary */
1029
1030  if ( vk->data_size != 0 ) 
1031  {
1032    bool charmode = false;
1033
1034    if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
1035      charmode = true;
1036
1037    /* the data is stored in the offset if the size <= 4 */
1038    if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) 
1039    {
1040      REGF_HBIN *hblock = hbin;
1041      uint32 data_rec_size;
1042
1043      if ( hbin->ps.io ) 
1044      {
1045        if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
1046          return false;
1047      }
1048
1049      /* this data can be in another hbin */
1050      if ( !hbin_contains_offset( hbin, vk->data_off ) ) 
1051      {
1052        if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
1053          return false;
1054      }
1055      if (!(prs_set_offset(&hblock->ps, 
1056                           (vk->data_off
1057                            + HBIN_HDR_SIZE
1058                            - hblock->first_hbin_off)
1059                           - sizeof(uint32))))
1060      { return false; }
1061
1062      if ( !hblock->ps.io ) 
1063      {
1064        data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
1065        data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF;
1066      }
1067      if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size ))
1068        return false;
1069      if(!prs_uint8s(charmode, "data", &hblock->ps, depth, 
1070                     vk->data, vk->data_size))
1071        return false;
1072
1073      if ( !hblock->ps.io )
1074        hblock->dirty = true;
1075    }
1076    else 
1077    {
1078      if(!(vk->data = zcalloc(sizeof(uint8), 4)))
1079        return false;
1080      SIVAL( vk->data, 0, vk->data_off );
1081    }
1082               
1083  }
1084
1085  /* data_size must be divisible by 8 and large enough to hold the original record */
1086
1087  data_size = ((start_off - end_off ) & 0xfffffff8 );
1088  /* XXX: should probably print a warning here */
1089  /*if ( data_size !=  vk->rec_size )
1090    DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));*/
1091
1092  if ( !hbin->ps.io )
1093    hbin->dirty = true;
1094
1095  return true;
1096}
1097
1098
1099/*******************************************************************
1100 read a VK record which is contained in the HBIN block stored
1101 in the prs_struct *ps.
1102*******************************************************************/
1103static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin, 
1104                                int depth, REGF_NK_REC *nk, REGF_FILE *file)
1105{
1106  int i;
1107  uint32 record_size;
1108
1109  depth++;
1110 
1111  /* check if we have anything to do first */
1112  if(nk->num_values == 0)
1113    return true;
1114       
1115  if(hbin->ps.io)
1116  {
1117    if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC), 
1118                                              nk->num_values )))
1119      return false;
1120  }
1121 
1122  /* convert the offset to something relative to this HBIN block */
1123  if (!prs_set_offset(&hbin->ps, 
1124                      nk->values_off
1125                      + HBIN_HDR_SIZE
1126                      - hbin->first_hbin_off
1127                      - sizeof(uint32)))
1128  { return false; }
1129
1130  if ( !hbin->ps.io ) 
1131  { 
1132    record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
1133    record_size = (record_size - 1) ^ 0xFFFFFFFF;
1134  }
1135
1136  if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
1137    return false;
1138       
1139  for ( i=0; i<nk->num_values; i++ ) 
1140  {
1141    if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
1142      return false;
1143  }
1144
1145  for ( i=0; i<nk->num_values; i++ ) 
1146  {
1147    REGF_HBIN *sub_hbin = hbin;
1148    uint32 new_offset;
1149       
1150    if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) 
1151    {
1152      sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
1153      if ( !sub_hbin ) 
1154      {
1155        /*DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n",
1156          nk->values[i].hbin_off));*/
1157        return false;
1158      }
1159    }
1160       
1161    new_offset = nk->values[i].rec_off
1162      + HBIN_HDR_SIZE
1163      - sub_hbin->first_hbin_off;
1164
1165    if (!prs_set_offset(&sub_hbin->ps, new_offset))
1166      return false;
1167    if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
1168      return false;
1169  }
1170
1171  if ( !hbin->ps.io )
1172    hbin->dirty = true;
1173
1174  return true;
1175}
1176
1177
1178/*******************************************************************
1179 *******************************************************************/
1180static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
1181{
1182  REGF_SK_REC *p_sk;
1183 
1184  for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) {
1185    if ( p_sk->sk_off == offset ) 
1186      return p_sk;
1187  }
1188 
1189  return NULL;
1190}
1191
1192
1193/*******************************************************************
1194 *******************************************************************/
1195static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
1196{
1197  REGF_SK_REC *p;
1198
1199  for ( p=file->sec_desc_list; p; p=p->next ) {
1200    if ( sec_desc_equal( p->sec_desc, sd ) )
1201      return p;
1202  }
1203
1204  /* failure */
1205
1206  return NULL;
1207}
1208
1209
1210/*******************************************************************
1211 *******************************************************************/
1212static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
1213{
1214  int depth = 0;
1215  REGF_HBIN *sub_hbin;
1216 
1217  depth++;
1218
1219  /* get the initial nk record */
1220  if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
1221    return false;
1222
1223  /* fill in values */
1224  if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) 
1225  {
1226    sub_hbin = hbin;
1227    if ( !hbin_contains_offset( hbin, nk->values_off ) ) 
1228    {
1229      sub_hbin = lookup_hbin_block( file, nk->values_off );
1230      if ( !sub_hbin ) 
1231      {
1232        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n",
1233          nk->values_off));*/
1234        return false;
1235      }
1236    }
1237               
1238    if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
1239      return false;
1240  }
1241               
1242  /* now get subkeys */
1243  if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) 
1244  {
1245    sub_hbin = hbin;
1246    if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) 
1247    {
1248      sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
1249      if ( !sub_hbin ) 
1250      {
1251        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n",
1252          nk->subkeys_off));*/
1253        return false;
1254      }
1255    }
1256               
1257    if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
1258      return false;
1259  }
1260
1261  /* get the to the security descriptor.  First look if we have already parsed it */
1262       
1263  if ((nk->sk_off!=REGF_OFFSET_NONE) 
1264      && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
1265  {
1266    sub_hbin = hbin;
1267    if (!hbin_contains_offset(hbin, nk->sk_off))
1268    {
1269      sub_hbin = lookup_hbin_block( file, nk->sk_off );
1270      if ( !sub_hbin ) {
1271        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n",
1272          nk->subkeys_off));*/
1273        return false;
1274      }
1275    }
1276               
1277    if ( !(nk->sec_desc = (REGF_SK_REC*)zalloc(sizeof(REGF_SK_REC) )) )
1278      return false;
1279    nk->sec_desc->sk_off = nk->sk_off;
1280    if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))
1281      return false;
1282                       
1283    /* add to the list of security descriptors (ref_count has been read from the files) */
1284
1285    nk->sec_desc->sk_off = nk->sk_off;
1286    /* XXX: this kind of caching needs to be re-evaluated */
1287    DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1288  }
1289               
1290  return true;
1291}
1292
1293
1294/*******************************************************************
1295 *******************************************************************/
1296static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
1297{
1298  uint8 header[REC_HDR_SIZE] = "";
1299  uint32 record_size;
1300  uint32 curr_off, block_size;
1301  bool found = false;
1302  prs_struct *ps = &hbin->ps;
1303       
1304  curr_off = ps->data_offset;
1305  if ( curr_off == 0 )
1306    prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
1307
1308  /* assume that the current offset is at the reacord header
1309     and we need to backup to read the record size */
1310  curr_off -= sizeof(uint32);
1311
1312  block_size = ps->buffer_size;
1313  record_size = 0;
1314  while ( !found ) 
1315  {
1316    curr_off = curr_off+record_size;
1317    if ( curr_off >= block_size ) 
1318      break;
1319
1320    if ( !prs_set_offset( &hbin->ps, curr_off) )
1321      return false;
1322
1323    if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
1324      return false;
1325    if ( !prs_uint8s( true, "header", ps, 0, header, REC_HDR_SIZE ) )
1326      return false;
1327
1328    if ( record_size & 0x80000000 ) {
1329      /* absolute_value(record_size) */
1330      record_size = (record_size ^ 0xffffffff) + 1;
1331    }
1332
1333    if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1334      found = true;
1335      curr_off += sizeof(uint32);
1336    }
1337  } 
1338
1339  /* mark prs_struct as done ( at end ) if no more SK records */
1340  /* mark end-of-block as true */       
1341  if ( !found )
1342  {
1343    prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
1344    *eob = true;
1345    return false;
1346  }
1347
1348  if (!prs_set_offset(ps, curr_off))
1349    return false;
1350
1351  return true;
1352}
1353
1354
1355/*******************************************************************
1356 *******************************************************************/
1357static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin, 
1358                           REGF_NK_REC *nk, bool *eob)
1359{
1360  if (next_record(hbin, "nk", eob) 
1361      && hbin_prs_key(file, hbin, nk))
1362    return true;
1363       
1364  return false;
1365}
1366
1367
1368/*******************************************************************
1369 Open the registry file and then read in the REGF block to get the
1370 first hbin offset.
1371*******************************************************************/
1372REGF_FILE* regfi_open( const char *filename )
1373{
1374  REGF_FILE *rb;
1375  int flags = O_RDONLY;
1376
1377  if ( !(rb = (REGF_FILE*)malloc(sizeof(REGF_FILE))) ) {
1378    /* DEBUG(0,("ERROR allocating memory\n")); */
1379    return NULL;
1380  }
1381  memset(rb, 0, sizeof(REGF_FILE));
1382  rb->fd = -1;
1383       
1384  /*    if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) )
1385    {
1386    regfi_close( rb );
1387    return NULL;
1388    }
1389  */
1390  rb->open_flags = flags;
1391       
1392  /* open and existing file */
1393
1394  if ( (rb->fd = open(filename, flags)) == -1 ) {
1395    /* DEBUG(0,("regfi_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
1396    regfi_close( rb );
1397    return NULL;
1398  }
1399       
1400  /* read in an existing file */
1401       
1402  if ( !read_regf_block( rb ) ) {
1403    /* DEBUG(0,("regfi_open: Failed to read initial REGF block\n"));*/
1404    regfi_close( rb );
1405    return NULL;
1406  }
1407       
1408  /* success */
1409       
1410  return rb;
1411}
1412
1413
1414/*******************************************************************
1415XXX: should this be nuked?
1416 *******************************************************************/
1417static void regfi_mem_free( REGF_FILE *file )
1418{
1419  /* free any zalloc()'d memory */
1420       
1421  /*    if ( file && file->mem_ctx )
1422    free(file->mem_ctx);
1423  */
1424}
1425
1426
1427/*******************************************************************
1428 *******************************************************************/
1429int regfi_close( REGF_FILE *file )
1430{
1431  int fd;
1432
1433  regfi_mem_free( file );
1434
1435  /* nothing to do if there is no open file */
1436
1437  if ( !file || (file->fd == -1) )
1438    return 0;
1439               
1440  fd = file->fd;
1441  file->fd = -1;
1442  SAFE_FREE( file );
1443
1444  return close( fd );
1445}
1446
1447
1448/******************************************************************************
1449 * There should be only *one* root key in the registry file based
1450 * on my experience.  --jerry
1451 *****************************************************************************/
1452REGF_NK_REC* regfi_rootkey( REGF_FILE *file )
1453{
1454  REGF_NK_REC *nk;
1455  REGF_HBIN   *hbin;
1456  uint32      offset = REGF_BLOCKSIZE;
1457  bool        found = false;
1458  bool        eob;
1459       
1460  if ( !file )
1461    return NULL;
1462               
1463  if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
1464    /*DEBUG(0,("regfi_rootkey: zalloc() failed!\n"));*/
1465    return NULL;
1466  }
1467       
1468  /* scan through the file on HBIN block at a time looking
1469     for an NK record with a type == 0x002c.
1470     Normally this is the first nk record in the first hbin
1471     block (but I'm not assuming that for now) */
1472       
1473  while ( (hbin = read_hbin_block( file, offset )) ) {
1474    eob = false;
1475
1476    while ( !eob) {
1477      if ( next_nk_record( file, hbin, nk, &eob ) ) {
1478        if ( nk->key_type == NK_TYPE_ROOTKEY ) {
1479          found = true;
1480          break;
1481        }
1482      }
1483      if(hbin->ps.is_dynamic)
1484        SAFE_FREE(hbin->ps.data_p);
1485      hbin->ps.is_dynamic = false;
1486      hbin->ps.buffer_size = 0;
1487      hbin->ps.data_offset = 0;
1488    }
1489               
1490    if ( found ) 
1491      break;
1492
1493    offset += hbin->block_size;
1494  }
1495       
1496  if ( !found ) {
1497    /*DEBUG(0,("regfi_rootkey: corrupt registry file ?  No root key record located\n"));*/
1498    return NULL;
1499  }
1500
1501  /* XXX: this kind of caching needs to be re-evaluated */
1502  DLIST_ADD( file->block_list, hbin );
1503
1504  return nk;
1505}
1506
1507
1508/******************************************************************************
1509 *****************************************************************************/
1510void regfi_key_free(REGF_NK_REC* nk)
1511{
1512  uint32 i;
1513 
1514  if((nk->values != NULL) && (nk->values_off!=REGF_OFFSET_NONE))
1515  {
1516    for(i=0; i < nk->num_values; i++)
1517    {
1518      if(nk->values[i].valuename != NULL)
1519        free(nk->values[i].valuename);
1520      if(nk->values[i].data != NULL)
1521        free(nk->values[i].data);
1522    }
1523    free(nk->values);
1524  }
1525
1526  if(nk->keyname != NULL)
1527    free(nk->keyname);
1528  if(nk->classname != NULL)
1529    free(nk->classname);
1530
1531  /* XXX: not freeing hbin because these are cached.  This needs to be reviewed. */
1532  /* XXX: not freeing sec_desc because these are cached.  This needs to be reviewed. */
1533  free(nk);
1534}
1535
1536
1537/******************************************************************************
1538 *****************************************************************************/
1539REGFI_ITERATOR* regfi_iterator_new(REGF_FILE* fh)
1540{
1541  REGF_NK_REC* root;
1542  REGFI_ITERATOR* ret_val = (REGFI_ITERATOR*)malloc(sizeof(REGFI_ITERATOR));
1543  if(ret_val == NULL)
1544    return NULL;
1545
1546  root = regfi_rootkey(fh);
1547  if(root == NULL)
1548  {
1549    free(ret_val);
1550    return NULL;
1551  }
1552
1553  ret_val->key_positions = void_stack_new(REGF_MAX_DEPTH);
1554  if(ret_val->key_positions == NULL)
1555  {
1556    free(ret_val);
1557    free(root);
1558    return NULL;
1559  }
1560
1561  ret_val->f = fh;
1562  ret_val->cur_key = root;
1563  ret_val->cur_subkey = 0;
1564  ret_val->cur_value = 0;
1565
1566  return ret_val;
1567}
1568
1569
1570/******************************************************************************
1571 *****************************************************************************/
1572void regfi_iterator_free(REGFI_ITERATOR* i)
1573{
1574  REGFI_ITER_POSITION* cur;
1575
1576  if(i->cur_key != NULL)
1577    regfi_key_free(i->cur_key);
1578
1579  while((cur = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions)) != NULL)
1580  {
1581    regfi_key_free(cur->nk);
1582    free(cur);
1583  }
1584 
1585  free(i);
1586}
1587
1588
1589
1590/******************************************************************************
1591 *****************************************************************************/
1592/* XXX: some way of indicating reason for failure should be added. */
1593bool regfi_iterator_down(REGFI_ITERATOR* i)
1594{
1595  REGF_NK_REC* subkey;
1596  REGFI_ITER_POSITION* pos;
1597
1598  pos = (REGFI_ITER_POSITION*)malloc(sizeof(REGFI_ITER_POSITION));
1599  if(pos == NULL)
1600    return false;
1601
1602  subkey = regfi_iterator_cur_subkey(i);
1603  if(subkey == NULL)
1604  {
1605    free(pos);
1606    return false;
1607  }
1608
1609  pos->nk = i->cur_key;
1610  pos->cur_subkey = i->cur_subkey;
1611  if(!void_stack_push(i->key_positions, pos))
1612  {
1613    free(pos);
1614    regfi_key_free(subkey);
1615    return false;
1616  }
1617
1618  i->cur_key = subkey;
1619  i->cur_subkey = 0;
1620  i->cur_value = 0;
1621
1622  return true;
1623}
1624
1625
1626/******************************************************************************
1627 *****************************************************************************/
1628bool regfi_iterator_up(REGFI_ITERATOR* i)
1629{
1630  REGFI_ITER_POSITION* pos;
1631
1632  pos = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions);
1633  if(pos == NULL)
1634    return false;
1635
1636  regfi_key_free(i->cur_key);
1637  i->cur_key = pos->nk;
1638  i->cur_subkey = pos->cur_subkey;
1639  i->cur_value = 0;
1640  free(pos);
1641
1642  return true;
1643}
1644
1645
1646/******************************************************************************
1647 *****************************************************************************/
1648bool regfi_iterator_to_root(REGFI_ITERATOR* i)
1649{
1650  while(regfi_iterator_up(i))
1651    continue;
1652
1653  return true;
1654}
1655
1656
1657/******************************************************************************
1658 *****************************************************************************/
1659bool regfi_iterator_find_subkey(REGFI_ITERATOR* i, const char* subkey_name)
1660{
1661  REGF_NK_REC* subkey;
1662  bool found = false;
1663  uint32 old_subkey = i->cur_subkey;
1664 
1665  if(subkey_name == NULL)
1666    return false;
1667
1668  /* XXX: this alloc/free of each sub key might be a bit excessive */
1669  subkey = regfi_iterator_first_subkey(i);
1670  while((subkey != NULL) && (found == false))
1671  {
1672    if(subkey->keyname != NULL 
1673       && strcasecmp(subkey->keyname, subkey_name) == 0)
1674      found = true;
1675
1676    regfi_key_free(subkey);
1677    subkey = regfi_iterator_next_subkey(i);
1678  }
1679
1680  if(found == false)
1681  {
1682    i->cur_subkey = old_subkey;
1683    return false;
1684  }
1685
1686  return true;
1687}
1688
1689
1690/******************************************************************************
1691 *****************************************************************************/
1692bool regfi_iterator_walk_path(REGFI_ITERATOR* i, const char** path)
1693{
1694  uint32 x;
1695  if(path == NULL)
1696    return false;
1697
1698  for(x=0; 
1699      ((path[x] != NULL) && regfi_iterator_find_subkey(i, path[x])
1700       && regfi_iterator_down(i));
1701      x++)
1702  { continue; }
1703
1704  if(path[x] == NULL)
1705    return true;
1706 
1707  /* XXX: is this the right number of times? */
1708  for(; x > 0; x--)
1709    regfi_iterator_up(i);
1710 
1711  return false;
1712}
1713
1714
1715/******************************************************************************
1716 *****************************************************************************/
1717REGF_NK_REC* regfi_iterator_cur_key(REGFI_ITERATOR* i)
1718{
1719  return i->cur_key;
1720}
1721
1722
1723/******************************************************************************
1724 *****************************************************************************/
1725REGF_NK_REC* regfi_iterator_first_subkey(REGFI_ITERATOR* i)
1726{
1727  i->cur_subkey = 0;
1728  return regfi_iterator_cur_subkey(i);
1729}
1730
1731
1732/******************************************************************************
1733 *****************************************************************************/
1734REGF_NK_REC* regfi_iterator_cur_subkey(REGFI_ITERATOR* i)
1735{
1736  REGF_NK_REC* subkey;
1737  REGF_HBIN* hbin;
1738  uint32 nk_offset;
1739
1740  /* see if there is anything left to report */
1741  if (!(i->cur_key) || (i->cur_key->subkeys_off==REGF_OFFSET_NONE)
1742      || (i->cur_subkey >= i->cur_key->num_subkeys))
1743    return NULL;
1744
1745  nk_offset = i->cur_key->subkeys.hashes[i->cur_subkey].nk_off;
1746
1747  /* find the HBIN block which should contain the nk record */
1748  hbin = lookup_hbin_block(i->f, nk_offset);
1749  if(!hbin)
1750  {
1751    /* XXX: should print out some kind of error message every time here */
1752    /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n",
1753      i->cur_key->subkeys.hashes[i->cur_subkey].nk_off));*/
1754    return NULL;
1755  }
1756 
1757  if(!prs_set_offset(&hbin->ps, 
1758                     HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off))
1759    return NULL;
1760               
1761  if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
1762    return NULL;
1763
1764  if(!hbin_prs_key(i->f, hbin, subkey))
1765  {
1766    regfi_key_free(subkey);
1767    return NULL;
1768  }
1769
1770  return subkey;
1771}
1772
1773
1774/******************************************************************************
1775 *****************************************************************************/
1776/* XXX: some way of indicating reason for failure should be added. */
1777REGF_NK_REC* regfi_iterator_next_subkey(REGFI_ITERATOR* i)
1778{
1779  REGF_NK_REC* subkey;
1780
1781  i->cur_subkey++;
1782  subkey = regfi_iterator_cur_subkey(i);
1783
1784  if(subkey == NULL)
1785    i->cur_subkey--;
1786
1787  return subkey;
1788}
1789
1790
1791/******************************************************************************
1792 *****************************************************************************/
1793bool regfi_iterator_find_value(REGFI_ITERATOR* i, const char* value_name)
1794{
1795  REGF_VK_REC* cur;
1796  bool found = false;
1797
1798  /* XXX: cur->valuename can be NULL in the registry. 
1799   *      Should we allow for a way to search for that?
1800   */
1801  if(value_name == NULL)
1802    return false;
1803
1804  cur = regfi_iterator_first_value(i);
1805  while((cur != NULL) && (found == false))
1806  {
1807    if((cur->valuename != NULL)
1808       && (strcasecmp(cur->valuename, value_name) == 0))
1809      found = true;
1810    cur = regfi_iterator_next_value(i);
1811  }
1812
1813  if(cur == NULL)
1814    return false;
1815 
1816  return true;
1817}
1818
1819
1820/******************************************************************************
1821 *****************************************************************************/
1822REGF_VK_REC* regfi_iterator_first_value(REGFI_ITERATOR* i)
1823{
1824  i->cur_value = 0;
1825  return regfi_iterator_cur_value(i);
1826}
1827
1828
1829/******************************************************************************
1830 *****************************************************************************/
1831REGF_VK_REC* regfi_iterator_cur_value(REGFI_ITERATOR* i)
1832{
1833  REGF_VK_REC* ret_val = NULL;
1834  if(i->cur_value < i->cur_key->num_values)
1835    ret_val = &(i->cur_key->values[i->cur_value]);
1836
1837  return ret_val;
1838}
1839
1840
1841/******************************************************************************
1842 *****************************************************************************/
1843REGF_VK_REC* regfi_iterator_next_value(REGFI_ITERATOR* i)
1844{
1845  REGF_VK_REC* ret_val;
1846
1847  i->cur_value++;
1848  ret_val = regfi_iterator_cur_value(i);
1849  if(ret_val == NULL)
1850    i->cur_value--;
1851
1852  return ret_val;
1853}
Note: See TracBrowser for help on using the repository browser.