source: trunk/lib/regfi.c @ 80

Last change on this file since 80 was 80, checked in by tim, 17 years ago

Major API updates for regfi, and started porting reglookup to the API.

Code is non-functional, but should be soon.

  • Property svn:keywords set to Id
File size: 47.2 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-2006 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 80 2007-01-17 01:46:07Z tim $
25 */
26
27#include "../include/regfio.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  nk->subkey_index = 0;
632  return true;
633}
634
635
636/*******************************************************************
637 *******************************************************************/
638static uint32 regf_block_checksum( prs_struct *ps )
639{
640  char *buffer = ps->data_p;
641  uint32 checksum, x;
642  int i;
643
644  /* XOR of all bytes 0x0000 - 0x01FB */
645               
646  checksum = x = 0;
647       
648  for ( i=0; i<0x01FB; i+=4 ) {
649    x = IVAL(buffer, i );
650    checksum ^= x;
651  }
652       
653  return checksum;
654}
655
656
657/*******************************************************************
658 *******************************************************************/
659static bool read_regf_block( REGF_FILE *file )
660{
661  prs_struct ps;
662  uint32 checksum;
663       
664  /* grab the first block from the file */
665               
666  if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
667    return false;
668       
669  /* parse the block and verify the checksum */
670       
671  if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
672    return false;       
673               
674  checksum = regf_block_checksum( &ps );
675       
676  if(ps.is_dynamic)
677    SAFE_FREE(ps.data_p);
678  ps.is_dynamic = false;
679  ps.buffer_size = 0;
680  ps.data_offset = 0;
681
682  if ( file->checksum !=  checksum ) {
683    /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
684    return false;
685  }
686
687  return true;
688}
689
690
691/*******************************************************************
692 *******************************************************************/
693static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
694{
695  REGF_HBIN *hbin;
696  uint32 record_size, curr_off, block_size, header;
697       
698  if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) ) 
699    return NULL;
700  hbin->file_off = offset;
701  hbin->free_off = -1;
702               
703  if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
704    return NULL;
705       
706  if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
707    return NULL;       
708
709  /* this should be the same thing as hbin->block_size but just in case */
710
711  block_size = hbin->ps.buffer_size;
712
713  /* Find the available free space offset.  Always at the end,
714     so walk the record list and stop when you get to the end.
715     The end is defined by a record header of 0xffffffff.  The
716     previous 4 bytes contains the amount of free space remaining
717     in the hbin block. */
718
719  /* remember that the record_size is in the 4 bytes preceeding the record itself */
720
721  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
722    return false;
723
724  record_size = 0;
725  curr_off = hbin->ps.data_offset;
726  while ( header != 0xffffffff ) {
727    /* not done yet so reset the current offset to the
728       next record_size field */
729
730    curr_off = curr_off+record_size;
731
732    /* for some reason the record_size of the last record in
733       an hbin block can extend past the end of the block
734       even though the record fits within the remaining
735       space....aaarrrgggghhhhhh */
736
737    if ( curr_off >= block_size ) {
738      record_size = -1;
739      curr_off = -1;
740      break;
741    }
742
743    if ( !prs_set_offset( &hbin->ps, curr_off) )
744      return false;
745
746    if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) )
747      return false;
748    if ( !prs_uint32( "header", &hbin->ps, 0, &header ) )
749      return false;
750               
751    assert( record_size != 0 );
752
753    if ( record_size & 0x80000000 ) {
754      /* absolute_value(record_size) */
755      record_size = (record_size ^ 0xffffffff) + 1;
756    }
757  }
758
759  /* save the free space offset */
760
761  if ( header == 0xffffffff ) {
762
763    /* account for the fact that the curr_off is 4 bytes behind the actual
764       record header */
765
766    hbin->free_off = curr_off + sizeof(uint32);
767    hbin->free_size = record_size;
768  }
769
770  /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
771
772  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE )  )
773    return false;
774       
775  return hbin;
776}
777
778
779/*******************************************************************
780 Input a randon offset and receive the correpsonding HBIN
781 block for it
782*******************************************************************/
783static bool hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
784{
785  if ( !hbin )
786    return false;
787       
788  if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
789    return true;
790               
791  return false;
792}
793
794
795/*******************************************************************
796 Input a randon offset and receive the correpsonding HBIN
797 block for it
798*******************************************************************/
799static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset )
800{
801  REGF_HBIN *hbin = NULL;
802  uint32 block_off;
803
804  /* start with the open list */
805
806  for ( hbin=file->block_list; hbin; hbin=hbin->next ) {
807    /* DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%x]\n", hbin->file_off, (uint32)hbin ));*/
808    if ( hbin_contains_offset( hbin, offset ) )
809      return hbin;
810  }
811       
812  if ( !hbin ) {
813    /* start at the beginning */
814
815    block_off = REGF_BLOCKSIZE;
816    do {
817      /* cleanup before the next round */
818      if ( hbin )
819      {
820        if(hbin->ps.is_dynamic)
821          SAFE_FREE(hbin->ps.data_p);
822        hbin->ps.is_dynamic = false;
823        hbin->ps.buffer_size = 0;
824        hbin->ps.data_offset = 0;
825      }
826
827      hbin = read_hbin_block( file, block_off );
828
829      if ( hbin ) 
830        block_off = hbin->file_off + hbin->block_size;
831
832    } while ( hbin && !hbin_contains_offset( hbin, offset ) );
833  }
834
835  if ( hbin )
836    /* XXX: this kind of caching needs to be re-evaluated */
837    DLIST_ADD( file->block_list, hbin );
838
839  return hbin;
840}
841
842
843/*******************************************************************
844 *******************************************************************/
845static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
846{
847  depth++;
848
849  if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off ))
850    return false;
851  if ( !prs_uint8s( true, "keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) )
852    return false;
853       
854  return true;
855}
856
857
858/*******************************************************************
859 *******************************************************************/
860static bool hbin_prs_lf_records(const char *desc, REGF_HBIN *hbin, 
861                                int depth, REGF_NK_REC *nk)
862{
863  int i;
864  REGF_LF_REC *lf = &nk->subkeys;
865  uint32 data_size, start_off, end_off;
866
867  depth++;
868
869  /* check if we have anything to do first */
870       
871  if ( nk->num_subkeys == 0 )
872    return true;
873
874  /* move to the LF record */
875
876  if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
877    return false;
878
879  /* backup and get the data_size */
880       
881  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
882    return false;
883  start_off = hbin->ps.data_offset;
884  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &lf->rec_size ))
885    return false;
886
887  if(!prs_uint8s(true, "header", &hbin->ps, depth, 
888                 lf->header, sizeof(lf->header)))
889    return false;
890               
891  if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
892    return false;
893
894  if ( hbin->ps.io ) {
895    if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
896      return false;
897  }
898
899  for ( i=0; i<lf->num_keys; i++ ) {
900    if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) )
901      return false;
902  }
903
904  end_off = hbin->ps.data_offset;
905
906  /* data_size must be divisible by 8 and large enough to hold the original record */
907
908  data_size = ((start_off - end_off) & 0xfffffff8 );
909  /*  if ( data_size > lf->rec_size )*/
910    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
911
912  if ( !hbin->ps.io )
913    hbin->dirty = true;
914
915  return true;
916}
917
918
919/*******************************************************************
920 *******************************************************************/
921static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
922{
923  prs_struct *ps = &hbin->ps;
924  uint16 tag = 0xFFFF;
925  uint32 data_size, start_off, end_off;
926
927
928  depth++;
929
930  if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
931    return false;
932
933  /* backup and get the data_size */
934       
935  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
936    return false;
937  start_off = hbin->ps.data_offset;
938  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size ))
939    return false;
940
941  if (!prs_uint8s(true, "header", ps, depth, sk->header, sizeof(sk->header)))
942    return false;
943  if ( !prs_uint16( "tag", ps, depth, &tag))
944    return false;
945
946  if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off))
947    return false;
948  if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off))
949    return false;
950  if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count))
951    return false;
952  if ( !prs_uint32( "size", ps, depth, &sk->size))
953    return false;
954
955  if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 
956    return false;
957
958  end_off = hbin->ps.data_offset;
959
960  /* data_size must be divisible by 8 and large enough to hold the original record */
961
962  data_size = ((start_off - end_off) & 0xfffffff8 );
963  /*  if ( data_size > sk->rec_size )*/
964    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
965
966  if ( !hbin->ps.io )
967    hbin->dirty = true;
968
969  return true;
970}
971
972
973/*******************************************************************
974 *******************************************************************/
975static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, 
976                             REGF_VK_REC *vk, REGF_FILE *file )
977{
978  uint32 offset;
979  uint16 name_length;
980  prs_struct *ps = &hbin->ps;
981  uint32 data_size, start_off, end_off;
982
983  depth++;
984
985  /* backup and get the data_size */
986       
987  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
988    return false;
989  start_off = hbin->ps.data_offset;
990  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size ))
991    return false;
992
993  if ( !prs_uint8s( true, "header", ps, depth, vk->header, sizeof( vk->header )) )
994    return false;
995
996  if ( !hbin->ps.io )
997    name_length = strlen(vk->valuename);
998
999  if ( !prs_uint16( "name_length", ps, depth, &name_length ))
1000    return false;
1001  if ( !prs_uint32( "data_size", ps, depth, &vk->data_size ))
1002    return false;
1003  if ( !prs_uint32( "data_off", ps, depth, &vk->data_off ))
1004    return false;
1005  if ( !prs_uint32( "type", ps, depth, &vk->type))
1006    return false;
1007  if ( !prs_uint16( "flag", ps, depth, &vk->flag))
1008    return false;
1009
1010  offset = ps->data_offset;
1011  offset += 2;  /* skip 2 bytes */
1012  prs_set_offset( ps, offset );
1013
1014  /* get the name */
1015
1016  if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
1017
1018    if ( hbin->ps.io ) {
1019      if ( !(vk->valuename = (char*)zcalloc(sizeof(char), name_length+1 )))
1020        return false;
1021    }
1022    if ( !prs_uint8s(true, "name", ps, depth, 
1023                     (uint8*)vk->valuename, name_length) )
1024      return false;
1025  }
1026
1027  end_off = hbin->ps.data_offset;
1028
1029  /* get the data if necessary */
1030
1031  if ( vk->data_size != 0 ) 
1032  {
1033    bool charmode = false;
1034
1035    if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
1036      charmode = true;
1037
1038    /* the data is stored in the offset if the size <= 4 */
1039    if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) 
1040    {
1041      REGF_HBIN *hblock = hbin;
1042      uint32 data_rec_size;
1043
1044      if ( hbin->ps.io ) 
1045      {
1046        if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
1047          return false;
1048      }
1049
1050      /* this data can be in another hbin */
1051      if ( !hbin_contains_offset( hbin, vk->data_off ) ) 
1052      {
1053        if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
1054          return false;
1055      }
1056      if (!(prs_set_offset(&hblock->ps, 
1057                           (vk->data_off
1058                            + HBIN_HDR_SIZE
1059                            - hblock->first_hbin_off)
1060                           - sizeof(uint32))))
1061      { return false; }
1062
1063      if ( !hblock->ps.io ) 
1064      {
1065        data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
1066        data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF;
1067      }
1068      if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size ))
1069        return false;
1070      if(!prs_uint8s(charmode, "data", &hblock->ps, depth, 
1071                     vk->data, vk->data_size))
1072        return false;
1073
1074      if ( !hblock->ps.io )
1075        hblock->dirty = true;
1076    }
1077    else 
1078    {
1079      if(!(vk->data = zcalloc(sizeof(uint8), 4)))
1080        return false;
1081      SIVAL( vk->data, 0, vk->data_off );
1082    }
1083               
1084  }
1085
1086  /* data_size must be divisible by 8 and large enough to hold the original record */
1087
1088  data_size = ((start_off - end_off ) & 0xfffffff8 );
1089  /* XXX: should probably print a warning here */
1090  /*if ( data_size !=  vk->rec_size )
1091    DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));*/
1092
1093  if ( !hbin->ps.io )
1094    hbin->dirty = true;
1095
1096  return true;
1097}
1098
1099
1100/*******************************************************************
1101 read a VK record which is contained in the HBIN block stored
1102 in the prs_struct *ps.
1103*******************************************************************/
1104static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin, 
1105                                int depth, REGF_NK_REC *nk, REGF_FILE *file)
1106{
1107  int i;
1108  uint32 record_size;
1109
1110  depth++;
1111 
1112  /* check if we have anything to do first */
1113  if(nk->num_values == 0)
1114    return true;
1115       
1116  if(hbin->ps.io)
1117  {
1118    if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC), 
1119                                              nk->num_values )))
1120      return false;
1121  }
1122 
1123  /* convert the offset to something relative to this HBIN block */
1124  if (!prs_set_offset(&hbin->ps, 
1125                      nk->values_off
1126                      + HBIN_HDR_SIZE
1127                      - hbin->first_hbin_off
1128                      - sizeof(uint32)))
1129  { return false; }
1130
1131  if ( !hbin->ps.io ) 
1132  { 
1133    record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
1134    record_size = (record_size - 1) ^ 0xFFFFFFFF;
1135  }
1136
1137  if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
1138    return false;
1139       
1140  for ( i=0; i<nk->num_values; i++ ) 
1141  {
1142    if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
1143      return false;
1144  }
1145
1146  for ( i=0; i<nk->num_values; i++ ) 
1147  {
1148    REGF_HBIN *sub_hbin = hbin;
1149    uint32 new_offset;
1150       
1151    if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) 
1152    {
1153      sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
1154      if ( !sub_hbin ) 
1155      {
1156        /*DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n",
1157          nk->values[i].hbin_off));*/
1158        return false;
1159      }
1160    }
1161       
1162    new_offset = nk->values[i].rec_off
1163      + HBIN_HDR_SIZE
1164      - sub_hbin->first_hbin_off;
1165
1166    if (!prs_set_offset(&sub_hbin->ps, new_offset))
1167      return false;
1168    if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
1169      return false;
1170  }
1171
1172  if ( !hbin->ps.io )
1173    hbin->dirty = true;
1174
1175  return true;
1176}
1177
1178
1179/*******************************************************************
1180 *******************************************************************/
1181static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
1182{
1183  REGF_SK_REC *p_sk;
1184 
1185  for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) {
1186    if ( p_sk->sk_off == offset ) 
1187      return p_sk;
1188  }
1189 
1190  return NULL;
1191}
1192
1193
1194/*******************************************************************
1195 *******************************************************************/
1196static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
1197{
1198  REGF_SK_REC *p;
1199
1200  for ( p=file->sec_desc_list; p; p=p->next ) {
1201    if ( sec_desc_equal( p->sec_desc, sd ) )
1202      return p;
1203  }
1204
1205  /* failure */
1206
1207  return NULL;
1208}
1209
1210
1211/*******************************************************************
1212 *******************************************************************/
1213static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
1214{
1215  int depth = 0;
1216  REGF_HBIN *sub_hbin;
1217 
1218  depth++;
1219
1220  /* get the initial nk record */
1221  if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
1222    return false;
1223
1224  /* fill in values */
1225  if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) 
1226  {
1227    sub_hbin = hbin;
1228    if ( !hbin_contains_offset( hbin, nk->values_off ) ) 
1229    {
1230      sub_hbin = lookup_hbin_block( file, nk->values_off );
1231      if ( !sub_hbin ) 
1232      {
1233        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n",
1234          nk->values_off));*/
1235        return false;
1236      }
1237    }
1238               
1239    if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
1240      return false;
1241  }
1242               
1243  /* now get subkeys */
1244  if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) 
1245  {
1246    sub_hbin = hbin;
1247    if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) 
1248    {
1249      sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
1250      if ( !sub_hbin ) 
1251      {
1252        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n",
1253          nk->subkeys_off));*/
1254        return false;
1255      }
1256    }
1257               
1258    if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
1259      return false;
1260  }
1261
1262  /* get the to the security descriptor.  First look if we have already parsed it */
1263       
1264  if ((nk->sk_off!=REGF_OFFSET_NONE) 
1265      && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
1266  {
1267    sub_hbin = hbin;
1268    if (!hbin_contains_offset(hbin, nk->sk_off))
1269    {
1270      sub_hbin = lookup_hbin_block( file, nk->sk_off );
1271      if ( !sub_hbin ) {
1272        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n",
1273          nk->subkeys_off));*/
1274        return false;
1275      }
1276    }
1277               
1278    if ( !(nk->sec_desc = (REGF_SK_REC*)zalloc(sizeof(REGF_SK_REC) )) )
1279      return false;
1280    nk->sec_desc->sk_off = nk->sk_off;
1281    if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))
1282      return false;
1283                       
1284    /* add to the list of security descriptors (ref_count has been read from the files) */
1285
1286    nk->sec_desc->sk_off = nk->sk_off;
1287    /* XXX: this kind of caching needs to be re-evaluated */
1288    DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1289  }
1290               
1291  return true;
1292}
1293
1294
1295/*******************************************************************
1296 *******************************************************************/
1297static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
1298{
1299  uint8 header[REC_HDR_SIZE] = "";
1300  uint32 record_size;
1301  uint32 curr_off, block_size;
1302  bool found = false;
1303  prs_struct *ps = &hbin->ps;
1304       
1305  curr_off = ps->data_offset;
1306  if ( curr_off == 0 )
1307    prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
1308
1309  /* assume that the current offset is at the reacord header
1310     and we need to backup to read the record size */
1311  curr_off -= sizeof(uint32);
1312
1313  block_size = ps->buffer_size;
1314  record_size = 0;
1315  while ( !found ) 
1316  {
1317    curr_off = curr_off+record_size;
1318    if ( curr_off >= block_size ) 
1319      break;
1320
1321    if ( !prs_set_offset( &hbin->ps, curr_off) )
1322      return false;
1323
1324    if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
1325      return false;
1326    if ( !prs_uint8s( true, "header", ps, 0, header, REC_HDR_SIZE ) )
1327      return false;
1328
1329    if ( record_size & 0x80000000 ) {
1330      /* absolute_value(record_size) */
1331      record_size = (record_size ^ 0xffffffff) + 1;
1332    }
1333
1334    if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1335      found = true;
1336      curr_off += sizeof(uint32);
1337    }
1338  } 
1339
1340  /* mark prs_struct as done ( at end ) if no more SK records */
1341  /* mark end-of-block as true */       
1342  if ( !found )
1343  {
1344    prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
1345    *eob = true;
1346    return false;
1347  }
1348
1349  if (!prs_set_offset(ps, curr_off))
1350    return false;
1351
1352  return true;
1353}
1354
1355
1356/*******************************************************************
1357 *******************************************************************/
1358static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin, 
1359                           REGF_NK_REC *nk, bool *eob)
1360{
1361  if (next_record(hbin, "nk", eob) 
1362      && hbin_prs_key(file, hbin, nk))
1363    return true;
1364       
1365  return false;
1366}
1367
1368
1369/*******************************************************************
1370 Open the registry file and then read in the REGF block to get the
1371 first hbin offset.
1372*******************************************************************/
1373REGF_FILE* regfi_open( const char *filename )
1374{
1375  REGF_FILE *rb;
1376  int flags = O_RDONLY;
1377
1378  if ( !(rb = (REGF_FILE*)malloc(sizeof(REGF_FILE))) ) {
1379    /* DEBUG(0,("ERROR allocating memory\n")); */
1380    return NULL;
1381  }
1382  memset(rb, 0, sizeof(REGF_FILE));
1383  rb->fd = -1;
1384       
1385  /*    if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) )
1386    {
1387    regfi_close( rb );
1388    return NULL;
1389    }
1390  */
1391  rb->open_flags = flags;
1392       
1393  /* open and existing file */
1394
1395  if ( (rb->fd = open(filename, flags)) == -1 ) {
1396    /* DEBUG(0,("regfi_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
1397    regfi_close( rb );
1398    return NULL;
1399  }
1400       
1401  /* read in an existing file */
1402       
1403  if ( !read_regf_block( rb ) ) {
1404    /* DEBUG(0,("regfi_open: Failed to read initial REGF block\n"));*/
1405    regfi_close( rb );
1406    return NULL;
1407  }
1408       
1409  /* success */
1410       
1411  return rb;
1412}
1413
1414
1415/*******************************************************************
1416XXX: should this be nuked?
1417 *******************************************************************/
1418static void regfi_mem_free( REGF_FILE *file )
1419{
1420  /* free any zalloc()'d memory */
1421       
1422  /*    if ( file && file->mem_ctx )
1423    free(file->mem_ctx);
1424  */
1425}
1426
1427
1428/*******************************************************************
1429 *******************************************************************/
1430int regfi_close( REGF_FILE *file )
1431{
1432  int fd;
1433
1434  regfi_mem_free( file );
1435
1436  /* nothing to do if there is no open file */
1437
1438  if ( !file || (file->fd == -1) )
1439    return 0;
1440               
1441  fd = file->fd;
1442  file->fd = -1;
1443  SAFE_FREE( file );
1444
1445  return close( fd );
1446}
1447
1448
1449/******************************************************************************
1450 * There should be only *one* root key in the registry file based
1451 * on my experience.  --jerry
1452 *****************************************************************************/
1453REGF_NK_REC* regfi_rootkey( REGF_FILE *file )
1454{
1455  REGF_NK_REC *nk;
1456  REGF_HBIN   *hbin;
1457  uint32      offset = REGF_BLOCKSIZE;
1458  bool        found = false;
1459  bool        eob;
1460       
1461  if ( !file )
1462    return NULL;
1463               
1464  if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
1465    /*DEBUG(0,("regfi_rootkey: zalloc() failed!\n"));*/
1466    return NULL;
1467  }
1468       
1469  /* scan through the file on HBIN block at a time looking
1470     for an NK record with a type == 0x002c.
1471     Normally this is the first nk record in the first hbin
1472     block (but I'm not assuming that for now) */
1473       
1474  while ( (hbin = read_hbin_block( file, offset )) ) {
1475    eob = false;
1476
1477    while ( !eob) {
1478      if ( next_nk_record( file, hbin, nk, &eob ) ) {
1479        if ( nk->key_type == NK_TYPE_ROOTKEY ) {
1480          found = true;
1481          break;
1482        }
1483      }
1484      if(hbin->ps.is_dynamic)
1485        SAFE_FREE(hbin->ps.data_p);
1486      hbin->ps.is_dynamic = false;
1487      hbin->ps.buffer_size = 0;
1488      hbin->ps.data_offset = 0;
1489    }
1490               
1491    if ( found ) 
1492      break;
1493
1494    offset += hbin->block_size;
1495  }
1496       
1497  if ( !found ) {
1498    /*DEBUG(0,("regfi_rootkey: corrupt registry file ?  No root key record located\n"));*/
1499    return NULL;
1500  }
1501
1502  /* XXX: this kind of caching needs to be re-evaluated */
1503  DLIST_ADD( file->block_list, hbin );
1504
1505  return nk;
1506}
1507
1508
1509/******************************************************************************
1510 *****************************************************************************/
1511void regfi_key_free(REGF_NK_REC* nk)
1512{
1513  uint32 i;
1514 
1515  if((nk->values != NULL) && (nk->values_off!=REGF_OFFSET_NONE))
1516  {
1517    for(i=0; i < nk->num_values; i++)
1518      regfi_value_free(nk->values[i]);
1519    free(nk->values);
1520  }
1521
1522  if(nk->keyname != NULL)
1523    free(nk->keyname);
1524  if(nk->classname != NULL)
1525    free(nk->classname);
1526
1527  /* XXX: not freeing hbin because these are cached.  This needs to be reviewed. */
1528  /* XXX: not freeing sec_desc because these are cached.  This needs to be reviewed. */
1529  free(nk);
1530}
1531
1532
1533/******************************************************************************
1534 *****************************************************************************/
1535void regfi_value_free(REGF_VK_REC* vk)
1536{
1537  if(vk->valuename != NULL)
1538    free(vk->valuename);
1539  if(vk->data != NULL)
1540    free(vk->data); 
1541 
1542  /* XXX: not freeing hbin because these are cached.  This needs to be reviewed. */
1543  free(vk);
1544}
1545
1546
1547/******************************************************************************
1548 *****************************************************************************/
1549REGFI_ITERATOR* regfi_iterator_new(REGF_FILE* fh)
1550{
1551  REGF_NK_REC* root;
1552  REGFI_ITERATOR* ret_val = (REGFI_ITERATOR*)malloc(sizeof(REGFI_ITERATOR));
1553  if(ret_val == NULL)
1554    return NULL;
1555
1556  root = regfi_rootkey(f);
1557  if(root == NULL)
1558  {
1559    free(ret_val);
1560    return NULL;
1561  }
1562
1563  ret_val->key_positions = void_stack_new(REGF_MAX_DEPTH);
1564  if(ret_val->key_positions == NULL)
1565  {
1566    free(ret_val);
1567    free(root);
1568    return NULL;
1569  }
1570
1571  ret_val->f = fh;
1572  ret_val->cur_key = root;
1573  ret_val->cur_subkey = 0;
1574  ret_val->cur_value = 0;
1575
1576  return ret_val;
1577}
1578
1579
1580/******************************************************************************
1581 *****************************************************************************/
1582void regfi_iterator_free(REGFI_ITERATOR* i)
1583{
1584  REGFI_ITER_POSITION* cur;
1585
1586  if(i->cur_key != NULL)
1587    regfi_key_free(i->cur_key);
1588
1589  while((cur = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions)) != NULL)
1590  {
1591    regfi_key_free(cur->nk);
1592    free(cur);
1593  }
1594 
1595  free(i);
1596}
1597
1598
1599
1600/******************************************************************************
1601 *****************************************************************************/
1602/* XXX: some way of indicating reason for failure should be added. */
1603bool regfi_iterator_down(REGFI_ITERATOR* i)
1604{
1605  REGF_NK_REC* subkey;
1606  REGFI_ITER_POSITION* pos;
1607
1608  pos = (REGFI_ITER_POSITION*)malloc(sizeof(REGFI_ITER_POSITION));
1609  if(pos == NULL)
1610    return false;
1611
1612  subkey = regfi_iterator_cur_subkey(i);
1613  if(subkey == NULL)
1614  {
1615    free(pos);
1616    return false;
1617  }
1618
1619  pos->nk = i->cur_key;
1620  pos->cur_subkey = i->cur_subkey;
1621  if(!void_stack_push(i->key_positions, pos))
1622  {
1623    free(pos);
1624    regfi_key_free(subkey);
1625    return false;
1626  }
1627
1628  i->cur_key = subkey;
1629  i->cur_subkey = 0;
1630  i->cur_value = 0;
1631
1632  return true;
1633}
1634
1635
1636/******************************************************************************
1637 *****************************************************************************/
1638bool regfi_iterator_up(REGFI_ITERATOR* i)
1639{
1640  REGFI_ITER_POSITION* pos;
1641
1642  pos = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions);
1643  if(pos == NULL)
1644    return false;
1645
1646  regfi_key_free(i->cur_key);
1647  i->cur_key = pos->nk;
1648  i->cur_subkey = pos->cur_subkey;
1649  i->cur_value = 0;
1650  free(pos);
1651
1652  return true;
1653}
1654
1655
1656/******************************************************************************
1657 *****************************************************************************/
1658bool regfi_iterator_to_root(REGFI_ITERATOR* i)
1659{
1660  while(regfi_iterator_up(i))
1661    continue;
1662
1663  return true;
1664}
1665
1666
1667/******************************************************************************
1668 *****************************************************************************/
1669bool regfi_iterator_find_subkey(REGFI_ITERATOR* i, const char* subkey_name)
1670{
1671  REGF_NK_REC* subkey;
1672  bool found = false;
1673  uint32 old_subkey = i->cur_subkey;
1674 
1675  if(subkey_name == NULL)
1676    return false;
1677
1678  /* XXX: this alloc/free of each sub key might be a bit excessive */
1679  subkey = regfi_iterator_first_subkey(i);
1680  while((subkey != NULL) && (found == false))
1681  {
1682    if(subkey->keyname != NULL 
1683       && strcasecmp(subkey->keyname, subkey_name) == 0)
1684      found = true;
1685
1686    regfi_key_free(subkey);
1687    subkey = regfi_iterator_next_subkey(i);
1688  }
1689
1690  if(found == false)
1691  {
1692    i->cur_subkey = old_subkey;
1693    return false;
1694  }
1695
1696  return true;
1697}
1698
1699
1700/******************************************************************************
1701 *****************************************************************************/
1702bool regfi_iterator_walk_path(REGFI_ITERATOR* i, const char** path)
1703{
1704  uint32 x;
1705  if(path == NULL)
1706    return false;
1707
1708  for(x=0; 
1709      ((path[x] != NULL) && regfi_iterator_find_subkey(i, path[x])
1710       && regfi_iterator_down(i));
1711      x++)
1712  { continue; }
1713
1714  if(path[x] == NULL)
1715    return true;
1716 
1717  /* XXX: is this the right number of times? */
1718  for(; x > 0; x--)
1719    regfi_iterator_up(i);
1720 
1721  return false;
1722}
1723
1724
1725/******************************************************************************
1726 *****************************************************************************/
1727REGF_NK_REC* regfi_iterator_cur_key(REGFI_ITERATOR* i);
1728{
1729  return i->cur_key;
1730}
1731
1732
1733/******************************************************************************
1734 *****************************************************************************/
1735REGF_NK_REC* regfi_iterator_first_subkey(REGFI_ITERATOR* i)
1736{
1737  REGF_NK_REC* subkey;
1738  REGF_HBIN* hbin;
1739 
1740  i->cur_subkey = 0;
1741  return regfi_iterator_cur_subkey(i);
1742}
1743
1744
1745/******************************************************************************
1746 *****************************************************************************/
1747REGF_NK_REC* regfi_iterator_cur_subkey(REGFI_ITERATOR* i)
1748{
1749  REGF_NK_REC* subkey;
1750  REGF_HBIN* hbin;
1751  uint32 nk_offset;
1752
1753  /* see if there is anything left to report */
1754  if (!(i->cur_key) || (i->cur_key->subkeys_off==REGF_OFFSET_NONE)
1755      || (i->cur_subkey >= i->cur_key->num_subkeys))
1756    return NULL;
1757
1758  nk_offset = i->cur_key->subkeys.hashes[i->cur_subkey].nk_off;
1759
1760  /* find the HBIN block which should contain the nk record */
1761  hbin = lookup_hbin_block(i->f, nk_offset);
1762  if(!hbin)
1763  {
1764    /* XXX: should print out some kind of error message every time here */
1765    /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n",
1766      i->cur_key->subkeys.hashes[i->cur_subkey].nk_off));*/
1767    return NULL;
1768  }
1769 
1770  if(!prs_set_offset(&hbin->ps, 
1771                     HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off))
1772    return NULL;
1773               
1774  if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
1775    return NULL;
1776
1777  if(!hbin_prs_key(i->f, hbin, subkey))
1778  {
1779    regfi_key_free(subkey);
1780    return NULL;
1781  }
1782
1783  return subkey;
1784}
1785
1786
1787/******************************************************************************
1788 *****************************************************************************/
1789/* XXX: some way of indicating reason for failure should be added. */
1790REGF_NK_REC* regfi_iterator_next_subkey(REGFI_ITERATOR* i)
1791{
1792  REGF_NK_REC* subkey;
1793
1794  i->cur_subkey++;
1795  subkey = regfi_iterator_cur_subkey(i);
1796
1797  if(subkey == NULL)
1798    i->cur_subkey--;
1799
1800  return subkey;
1801}
1802
1803
1804/******************************************************************************
1805 *****************************************************************************/
1806bool regfi_iterator_find_value(REGFI_ITERATOR* i, const char* value_name)
1807{
1808  REGF_VK_REC* cur;
1809  bool found = false;
1810
1811  /* XXX: cur->valuename can be NULL in the registry. 
1812   *      Should we allow for a way to search for that?
1813   */
1814  if(value_name == NULL)
1815    return false;
1816
1817  cur = regfi_iterator_first_value(i);
1818  while((cur != NULL) && (found == false))
1819  {
1820    if((cur->valuename != NULL)
1821       && (strcasecmp(cur->valuename, value_name) == 0))
1822      found = true;
1823    cur = retfi_iterator_next_value(i);
1824  }
1825
1826  if(cur == NULL)
1827    return false;
1828 
1829  return true;
1830}
1831
1832
1833/******************************************************************************
1834 *****************************************************************************/
1835REGF_VK_REC* regfi_iterator_first_value(REGFI_ITERATOR* i)
1836{
1837  i->cur_value = 0;
1838  return regfi_iterator_cur_value(i);
1839}
1840
1841
1842/******************************************************************************
1843 *****************************************************************************/
1844REGF_VK_REC* regfi_iterator_cur_value(REGFI_ITERATOR* i)
1845{
1846  REGF_VK_REC* ret_val = NULL;
1847  if(i->cur_value < i->cur_key->num_values)
1848    ret_val = i->cur_key->values[i];
1849
1850  return ret_val;
1851}
1852
1853
1854/******************************************************************************
1855 *****************************************************************************/
1856REGF_VK_REC* regfi_iterator_next_value(REGFI_ITERATOR* i)
1857{
1858  REGF_VK_REC* ret_val;
1859
1860  i->cur_value++;
1861  ret_val = regfi_iterator_cur_value(i);
1862  if(ret_val == NULL)
1863    i->cur_value--;
1864
1865  return ret_val;
1866}
Note: See TracBrowser for help on using the repository browser.