source: trunk/lib/regfi.c @ 87

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

added minor documentation on ACE flags to regfi.c

vastly expanded output documentation in reglookup man page.

  • Property svn:keywords set to Id
File size: 46.9 KB
Line 
1/*
2 * Branched from Samba project Subversion repository, version #7470:
3 *   http://viewcvs.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c?rev=7470&view=auto
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 87 2007-02-04 01:55:18Z 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", /* Object Inherit */
95      "CI", /* Container Inherit */
96      "NP", /* Non-Propagate */
97      "IO", /* Inherit Only */
98      "IA", /* Inherited ACE */
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("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("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("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("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("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("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("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("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("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    /* the data is stored in the offset if the size <= 4 */
1033    if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) 
1034    {
1035      REGF_HBIN *hblock = hbin;
1036      uint32 data_rec_size;
1037
1038      if ( hbin->ps.io ) 
1039      {
1040        if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
1041          return false;
1042      }
1043
1044      /* this data can be in another hbin */
1045      if ( !hbin_contains_offset( hbin, vk->data_off ) ) 
1046      {
1047        if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
1048          return false;
1049      }
1050      if (!(prs_set_offset(&hblock->ps, 
1051                           (vk->data_off
1052                            + HBIN_HDR_SIZE
1053                            - hblock->first_hbin_off)
1054                           - sizeof(uint32))))
1055      { return false; }
1056
1057      if ( !hblock->ps.io ) 
1058      {
1059        data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
1060        data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF;
1061      }
1062      if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size ))
1063        return false;
1064      if(!prs_uint8s("data", &hblock->ps, depth, 
1065                     vk->data, vk->data_size))
1066        return false;
1067
1068      if ( !hblock->ps.io )
1069        hblock->dirty = true;
1070    }
1071    else 
1072    {
1073      if(!(vk->data = zcalloc(sizeof(uint8), 4)))
1074        return false;
1075      SIVAL( vk->data, 0, vk->data_off );
1076    }
1077               
1078  }
1079
1080  /* data_size must be divisible by 8 and large enough to hold the original record */
1081
1082  data_size = ((start_off - end_off ) & 0xfffffff8 );
1083  /* XXX: should probably print a warning here */
1084  /*if ( data_size !=  vk->rec_size )
1085    DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));*/
1086
1087  if ( !hbin->ps.io )
1088    hbin->dirty = true;
1089
1090  return true;
1091}
1092
1093
1094/*******************************************************************
1095 read a VK record which is contained in the HBIN block stored
1096 in the prs_struct *ps.
1097*******************************************************************/
1098static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin, 
1099                                int depth, REGF_NK_REC *nk, REGF_FILE *file)
1100{
1101  int i;
1102  uint32 record_size;
1103
1104  depth++;
1105 
1106  /* check if we have anything to do first */
1107  if(nk->num_values == 0)
1108    return true;
1109       
1110  if(hbin->ps.io)
1111  {
1112    if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC), 
1113                                              nk->num_values )))
1114      return false;
1115  }
1116 
1117  /* convert the offset to something relative to this HBIN block */
1118  if (!prs_set_offset(&hbin->ps, 
1119                      nk->values_off
1120                      + HBIN_HDR_SIZE
1121                      - hbin->first_hbin_off
1122                      - sizeof(uint32)))
1123  { return false; }
1124
1125  if ( !hbin->ps.io ) 
1126  { 
1127    record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
1128    record_size = (record_size - 1) ^ 0xFFFFFFFF;
1129  }
1130
1131  if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
1132    return false;
1133       
1134  for ( i=0; i<nk->num_values; i++ ) 
1135  {
1136    if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
1137      return false;
1138  }
1139
1140  for ( i=0; i<nk->num_values; i++ ) 
1141  {
1142    REGF_HBIN *sub_hbin = hbin;
1143    uint32 new_offset;
1144       
1145    if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) 
1146    {
1147      sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
1148      if ( !sub_hbin ) 
1149      {
1150        /*DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n",
1151          nk->values[i].hbin_off));*/
1152        return false;
1153      }
1154    }
1155       
1156    new_offset = nk->values[i].rec_off
1157      + HBIN_HDR_SIZE
1158      - sub_hbin->first_hbin_off;
1159
1160    if (!prs_set_offset(&sub_hbin->ps, new_offset))
1161      return false;
1162    if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
1163      return false;
1164  }
1165
1166  if ( !hbin->ps.io )
1167    hbin->dirty = true;
1168
1169  return true;
1170}
1171
1172
1173/*******************************************************************
1174 *******************************************************************/
1175static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
1176{
1177  REGF_SK_REC *p_sk;
1178 
1179  for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) {
1180    if ( p_sk->sk_off == offset ) 
1181      return p_sk;
1182  }
1183 
1184  return NULL;
1185}
1186
1187
1188/*******************************************************************
1189 *******************************************************************/
1190static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
1191{
1192  REGF_SK_REC *p;
1193
1194  for ( p=file->sec_desc_list; p; p=p->next ) {
1195    if ( sec_desc_equal( p->sec_desc, sd ) )
1196      return p;
1197  }
1198
1199  /* failure */
1200
1201  return NULL;
1202}
1203
1204
1205/*******************************************************************
1206 *******************************************************************/
1207static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
1208{
1209  int depth = 0;
1210  REGF_HBIN *sub_hbin;
1211 
1212  depth++;
1213
1214  /* get the initial nk record */
1215  if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
1216    return false;
1217
1218  /* fill in values */
1219  if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) 
1220  {
1221    sub_hbin = hbin;
1222    if ( !hbin_contains_offset( hbin, nk->values_off ) ) 
1223    {
1224      sub_hbin = lookup_hbin_block( file, nk->values_off );
1225      if ( !sub_hbin ) 
1226      {
1227        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n",
1228          nk->values_off));*/
1229        return false;
1230      }
1231    }
1232               
1233    if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
1234      return false;
1235  }
1236               
1237  /* now get subkeys */
1238  if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) 
1239  {
1240    sub_hbin = hbin;
1241    if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) 
1242    {
1243      sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
1244      if ( !sub_hbin ) 
1245      {
1246        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n",
1247          nk->subkeys_off));*/
1248        return false;
1249      }
1250    }
1251               
1252    if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
1253      return false;
1254  }
1255
1256  /* get the to the security descriptor.  First look if we have already parsed it */
1257       
1258  if ((nk->sk_off!=REGF_OFFSET_NONE) 
1259      && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
1260  {
1261    sub_hbin = hbin;
1262    if (!hbin_contains_offset(hbin, nk->sk_off))
1263    {
1264      sub_hbin = lookup_hbin_block( file, nk->sk_off );
1265      if ( !sub_hbin ) {
1266        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n",
1267          nk->subkeys_off));*/
1268        return false;
1269      }
1270    }
1271               
1272    if ( !(nk->sec_desc = (REGF_SK_REC*)zalloc(sizeof(REGF_SK_REC) )) )
1273      return false;
1274    nk->sec_desc->sk_off = nk->sk_off;
1275    if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))
1276      return false;
1277                       
1278    /* add to the list of security descriptors (ref_count has been read from the files) */
1279
1280    nk->sec_desc->sk_off = nk->sk_off;
1281    /* XXX: this kind of caching needs to be re-evaluated */
1282    DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1283  }
1284               
1285  return true;
1286}
1287
1288
1289/*******************************************************************
1290 *******************************************************************/
1291static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
1292{
1293  uint8 header[REC_HDR_SIZE] = "";
1294  uint32 record_size;
1295  uint32 curr_off, block_size;
1296  bool found = false;
1297  prs_struct *ps = &hbin->ps;
1298       
1299  curr_off = ps->data_offset;
1300  if ( curr_off == 0 )
1301    prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
1302
1303  /* assume that the current offset is at the reacord header
1304     and we need to backup to read the record size */
1305  curr_off -= sizeof(uint32);
1306
1307  block_size = ps->buffer_size;
1308  record_size = 0;
1309  while ( !found ) 
1310  {
1311    curr_off = curr_off+record_size;
1312    if ( curr_off >= block_size ) 
1313      break;
1314
1315    if ( !prs_set_offset( &hbin->ps, curr_off) )
1316      return false;
1317
1318    if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
1319      return false;
1320    if ( !prs_uint8s("header", ps, 0, header, REC_HDR_SIZE ) )
1321      return false;
1322
1323    if ( record_size & 0x80000000 ) {
1324      /* absolute_value(record_size) */
1325      record_size = (record_size ^ 0xffffffff) + 1;
1326    }
1327
1328    if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1329      found = true;
1330      curr_off += sizeof(uint32);
1331    }
1332  } 
1333
1334  /* mark prs_struct as done ( at end ) if no more SK records */
1335  /* mark end-of-block as true */       
1336  if ( !found )
1337  {
1338    prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
1339    *eob = true;
1340    return false;
1341  }
1342
1343  if (!prs_set_offset(ps, curr_off))
1344    return false;
1345
1346  return true;
1347}
1348
1349
1350/*******************************************************************
1351 *******************************************************************/
1352static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin, 
1353                           REGF_NK_REC *nk, bool *eob)
1354{
1355  if (next_record(hbin, "nk", eob) 
1356      && hbin_prs_key(file, hbin, nk))
1357    return true;
1358       
1359  return false;
1360}
1361
1362
1363/*******************************************************************
1364 Open the registry file and then read in the REGF block to get the
1365 first hbin offset.
1366*******************************************************************/
1367REGF_FILE* regfi_open( const char *filename )
1368{
1369  REGF_FILE *rb;
1370  int flags = O_RDONLY;
1371
1372  if ( !(rb = (REGF_FILE*)malloc(sizeof(REGF_FILE))) ) {
1373    /* DEBUG(0,("ERROR allocating memory\n")); */
1374    return NULL;
1375  }
1376  memset(rb, 0, sizeof(REGF_FILE));
1377  rb->fd = -1;
1378       
1379  /*    if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) )
1380    {
1381    regfi_close( rb );
1382    return NULL;
1383    }
1384  */
1385  rb->open_flags = flags;
1386       
1387  /* open and existing file */
1388
1389  if ( (rb->fd = open(filename, flags)) == -1 ) {
1390    /* DEBUG(0,("regfi_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
1391    regfi_close( rb );
1392    return NULL;
1393  }
1394       
1395  /* read in an existing file */
1396       
1397  if ( !read_regf_block( rb ) ) {
1398    /* DEBUG(0,("regfi_open: Failed to read initial REGF block\n"));*/
1399    regfi_close( rb );
1400    return NULL;
1401  }
1402       
1403  /* success */
1404       
1405  return rb;
1406}
1407
1408
1409/*******************************************************************
1410XXX: should this be nuked?
1411 *******************************************************************/
1412static void regfi_mem_free( REGF_FILE *file )
1413{
1414  /* free any zalloc()'d memory */
1415       
1416  /*    if ( file && file->mem_ctx )
1417    free(file->mem_ctx);
1418  */
1419}
1420
1421
1422/*******************************************************************
1423 *******************************************************************/
1424int regfi_close( REGF_FILE *file )
1425{
1426  int fd;
1427
1428  regfi_mem_free( file );
1429
1430  /* nothing to do if there is no open file */
1431
1432  if ( !file || (file->fd == -1) )
1433    return 0;
1434               
1435  fd = file->fd;
1436  file->fd = -1;
1437  SAFE_FREE( file );
1438
1439  return close( fd );
1440}
1441
1442
1443/******************************************************************************
1444 * There should be only *one* root key in the registry file based
1445 * on my experience.  --jerry
1446 *****************************************************************************/
1447REGF_NK_REC* regfi_rootkey( REGF_FILE *file )
1448{
1449  REGF_NK_REC *nk;
1450  REGF_HBIN   *hbin;
1451  uint32      offset = REGF_BLOCKSIZE;
1452  bool        found = false;
1453  bool        eob;
1454       
1455  if ( !file )
1456    return NULL;
1457               
1458  if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
1459    /*DEBUG(0,("regfi_rootkey: zalloc() failed!\n"));*/
1460    return NULL;
1461  }
1462       
1463  /* scan through the file on HBIN block at a time looking
1464     for an NK record with a type == 0x002c.
1465     Normally this is the first nk record in the first hbin
1466     block (but I'm not assuming that for now) */
1467       
1468  while ( (hbin = read_hbin_block( file, offset )) ) {
1469    eob = false;
1470
1471    while ( !eob) {
1472      if ( next_nk_record( file, hbin, nk, &eob ) ) {
1473        if ( nk->key_type == NK_TYPE_ROOTKEY ) {
1474          found = true;
1475          break;
1476        }
1477      }
1478      if(hbin->ps.is_dynamic)
1479        SAFE_FREE(hbin->ps.data_p);
1480      hbin->ps.is_dynamic = false;
1481      hbin->ps.buffer_size = 0;
1482      hbin->ps.data_offset = 0;
1483    }
1484               
1485    if ( found ) 
1486      break;
1487
1488    offset += hbin->block_size;
1489  }
1490       
1491  if ( !found ) {
1492    /*DEBUG(0,("regfi_rootkey: corrupt registry file ?  No root key record located\n"));*/
1493    return NULL;
1494  }
1495
1496  /* XXX: this kind of caching needs to be re-evaluated */
1497  DLIST_ADD( file->block_list, hbin );
1498
1499  return nk;
1500}
1501
1502
1503/******************************************************************************
1504 *****************************************************************************/
1505void regfi_key_free(REGF_NK_REC* nk)
1506{
1507  uint32 i;
1508 
1509  if((nk->values != NULL) && (nk->values_off!=REGF_OFFSET_NONE))
1510  {
1511    for(i=0; i < nk->num_values; i++)
1512    {
1513      if(nk->values[i].valuename != NULL)
1514        free(nk->values[i].valuename);
1515      if(nk->values[i].data != NULL)
1516        free(nk->values[i].data);
1517    }
1518    free(nk->values);
1519  }
1520
1521  if(nk->keyname != NULL)
1522    free(nk->keyname);
1523  if(nk->classname != NULL)
1524    free(nk->classname);
1525
1526  /* XXX: not freeing hbin because these are cached.  This needs to be reviewed. */
1527  /* XXX: not freeing sec_desc because these are cached.  This needs to be reviewed. */
1528  free(nk);
1529}
1530
1531
1532/******************************************************************************
1533 *****************************************************************************/
1534REGFI_ITERATOR* regfi_iterator_new(REGF_FILE* fh)
1535{
1536  REGF_NK_REC* root;
1537  REGFI_ITERATOR* ret_val = (REGFI_ITERATOR*)malloc(sizeof(REGFI_ITERATOR));
1538  if(ret_val == NULL)
1539    return NULL;
1540
1541  root = regfi_rootkey(fh);
1542  if(root == NULL)
1543  {
1544    free(ret_val);
1545    return NULL;
1546  }
1547
1548  ret_val->key_positions = void_stack_new(REGF_MAX_DEPTH);
1549  if(ret_val->key_positions == NULL)
1550  {
1551    free(ret_val);
1552    free(root);
1553    return NULL;
1554  }
1555
1556  ret_val->f = fh;
1557  ret_val->cur_key = root;
1558  ret_val->cur_subkey = 0;
1559  ret_val->cur_value = 0;
1560
1561  return ret_val;
1562}
1563
1564
1565/******************************************************************************
1566 *****************************************************************************/
1567void regfi_iterator_free(REGFI_ITERATOR* i)
1568{
1569  REGFI_ITER_POSITION* cur;
1570
1571  if(i->cur_key != NULL)
1572    regfi_key_free(i->cur_key);
1573
1574  while((cur = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions)) != NULL)
1575  {
1576    regfi_key_free(cur->nk);
1577    free(cur);
1578  }
1579 
1580  free(i);
1581}
1582
1583
1584
1585/******************************************************************************
1586 *****************************************************************************/
1587/* XXX: some way of indicating reason for failure should be added. */
1588bool regfi_iterator_down(REGFI_ITERATOR* i)
1589{
1590  REGF_NK_REC* subkey;
1591  REGFI_ITER_POSITION* pos;
1592
1593  pos = (REGFI_ITER_POSITION*)malloc(sizeof(REGFI_ITER_POSITION));
1594  if(pos == NULL)
1595    return false;
1596
1597  subkey = (REGF_NK_REC*)regfi_iterator_cur_subkey(i);
1598  if(subkey == NULL)
1599  {
1600    free(pos);
1601    return false;
1602  }
1603
1604  pos->nk = i->cur_key;
1605  pos->cur_subkey = i->cur_subkey;
1606  if(!void_stack_push(i->key_positions, pos))
1607  {
1608    free(pos);
1609    regfi_key_free(subkey);
1610    return false;
1611  }
1612
1613  i->cur_key = subkey;
1614  i->cur_subkey = 0;
1615  i->cur_value = 0;
1616
1617  return true;
1618}
1619
1620
1621/******************************************************************************
1622 *****************************************************************************/
1623bool regfi_iterator_up(REGFI_ITERATOR* i)
1624{
1625  REGFI_ITER_POSITION* pos;
1626
1627  pos = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions);
1628  if(pos == NULL)
1629    return false;
1630
1631  regfi_key_free(i->cur_key);
1632  i->cur_key = pos->nk;
1633  i->cur_subkey = pos->cur_subkey;
1634  i->cur_value = 0;
1635  free(pos);
1636
1637  return true;
1638}
1639
1640
1641/******************************************************************************
1642 *****************************************************************************/
1643bool regfi_iterator_to_root(REGFI_ITERATOR* i)
1644{
1645  while(regfi_iterator_up(i))
1646    continue;
1647
1648  return true;
1649}
1650
1651
1652/******************************************************************************
1653 *****************************************************************************/
1654bool regfi_iterator_find_subkey(REGFI_ITERATOR* i, const char* subkey_name)
1655{
1656  REGF_NK_REC* subkey;
1657  bool found = false;
1658  uint32 old_subkey = i->cur_subkey;
1659 
1660  if(subkey_name == NULL)
1661    return false;
1662
1663  /* XXX: this alloc/free of each sub key might be a bit excessive */
1664  subkey = (REGF_NK_REC*)regfi_iterator_first_subkey(i);
1665  while((subkey != NULL) && (found == false))
1666  {
1667    if(subkey->keyname != NULL 
1668       && strcasecmp(subkey->keyname, subkey_name) == 0)
1669      found = true;
1670    else
1671    {
1672      regfi_key_free(subkey);
1673      subkey = (REGF_NK_REC*)regfi_iterator_next_subkey(i);
1674    }
1675  }
1676
1677  if(found == false)
1678  {
1679    i->cur_subkey = old_subkey;
1680    return false;
1681  }
1682
1683  regfi_key_free(subkey);
1684  return true;
1685}
1686
1687
1688/******************************************************************************
1689 *****************************************************************************/
1690bool regfi_iterator_walk_path(REGFI_ITERATOR* i, const char** path)
1691{
1692  uint32 x;
1693  if(path == NULL)
1694    return false;
1695
1696  for(x=0; 
1697      ((path[x] != NULL) && regfi_iterator_find_subkey(i, path[x])
1698       && regfi_iterator_down(i));
1699      x++)
1700  { continue; }
1701
1702  if(path[x] == NULL)
1703    return true;
1704 
1705  /* XXX: is this the right number of times? */
1706  for(; x > 0; x--)
1707    regfi_iterator_up(i);
1708 
1709  return false;
1710}
1711
1712
1713/******************************************************************************
1714 *****************************************************************************/
1715const REGF_NK_REC* regfi_iterator_cur_key(REGFI_ITERATOR* i)
1716{
1717  return i->cur_key;
1718}
1719
1720
1721/******************************************************************************
1722 *****************************************************************************/
1723const REGF_NK_REC* regfi_iterator_first_subkey(REGFI_ITERATOR* i)
1724{
1725  i->cur_subkey = 0;
1726  return regfi_iterator_cur_subkey(i);
1727}
1728
1729
1730/******************************************************************************
1731 *****************************************************************************/
1732const REGF_NK_REC* regfi_iterator_cur_subkey(REGFI_ITERATOR* i)
1733{
1734  REGF_NK_REC* subkey;
1735  REGF_HBIN* hbin;
1736  uint32 nk_offset;
1737
1738  /* see if there is anything left to report */
1739  if (!(i->cur_key) || (i->cur_key->subkeys_off==REGF_OFFSET_NONE)
1740      || (i->cur_subkey >= i->cur_key->num_subkeys))
1741    return NULL;
1742
1743  nk_offset = i->cur_key->subkeys.hashes[i->cur_subkey].nk_off;
1744
1745  /* find the HBIN block which should contain the nk record */
1746  hbin = lookup_hbin_block(i->f, nk_offset);
1747  if(!hbin)
1748  {
1749    /* XXX: should print out some kind of error message every time here */
1750    /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n",
1751      i->cur_key->subkeys.hashes[i->cur_subkey].nk_off));*/
1752    return NULL;
1753  }
1754 
1755  if(!prs_set_offset(&hbin->ps, 
1756                     HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off))
1757    return NULL;
1758               
1759  if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
1760    return NULL;
1761
1762  if(!hbin_prs_key(i->f, hbin, subkey))
1763  {
1764    regfi_key_free(subkey);
1765    return NULL;
1766  }
1767
1768  return subkey;
1769}
1770
1771
1772/******************************************************************************
1773 *****************************************************************************/
1774/* XXX: some way of indicating reason for failure should be added. */
1775const REGF_NK_REC* regfi_iterator_next_subkey(REGFI_ITERATOR* i)
1776{
1777  const REGF_NK_REC* subkey;
1778
1779  i->cur_subkey++;
1780  subkey = regfi_iterator_cur_subkey(i);
1781
1782  if(subkey == NULL)
1783    i->cur_subkey--;
1784
1785  return subkey;
1786}
1787
1788
1789/******************************************************************************
1790 *****************************************************************************/
1791bool regfi_iterator_find_value(REGFI_ITERATOR* i, const char* value_name)
1792{
1793  const REGF_VK_REC* cur;
1794  bool found = false;
1795
1796  /* XXX: cur->valuename can be NULL in the registry. 
1797   *      Should we allow for a way to search for that?
1798   */
1799  if(value_name == NULL)
1800    return false;
1801
1802  cur = regfi_iterator_first_value(i);
1803  while((cur != NULL) && (found == false))
1804  {
1805    if((cur->valuename != NULL)
1806       && (strcasecmp(cur->valuename, value_name) == 0))
1807      found = true;
1808    cur = regfi_iterator_next_value(i);
1809  }
1810
1811  if(cur == NULL)
1812    return false;
1813 
1814  return true;
1815}
1816
1817
1818/******************************************************************************
1819 *****************************************************************************/
1820const REGF_VK_REC* regfi_iterator_first_value(REGFI_ITERATOR* i)
1821{
1822  i->cur_value = 0;
1823  return regfi_iterator_cur_value(i);
1824}
1825
1826
1827/******************************************************************************
1828 *****************************************************************************/
1829const REGF_VK_REC* regfi_iterator_cur_value(REGFI_ITERATOR* i)
1830{
1831  REGF_VK_REC* ret_val = NULL;
1832  if(i->cur_value < i->cur_key->num_values)
1833    ret_val = &(i->cur_key->values[i->cur_value]);
1834
1835  return ret_val;
1836}
1837
1838
1839/******************************************************************************
1840 *****************************************************************************/
1841const REGF_VK_REC* regfi_iterator_next_value(REGFI_ITERATOR* i)
1842{
1843  const REGF_VK_REC* ret_val;
1844
1845  i->cur_value++;
1846  ret_val = regfi_iterator_cur_value(i);
1847  if(ret_val == NULL)
1848    i->cur_value--;
1849
1850  return ret_val;
1851}
Note: See TracBrowser for help on using the repository browser.