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
RevLine 
[30]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 *
[61]8 * Copyright (C) 2005-2006 Timothy D. Morgan
[30]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
[32]30/* Registry types mapping */
[78]31const unsigned int regfi_num_reg_types = 12;
32static const char* regfi_type_names[] =
[65]33  {"NONE", "SZ", "EXPAND_SZ", "BINARY", "DWORD", "DWORD_BE", "LINK",
[72]34   "MULTI_SZ", "RSRC_LIST", "RSRC_DESC", "RSRC_REQ_LIST", "QWORD"};
[30]35
[32]36
37/* Returns NULL on error */
[78]38const char* regfi_type_val2str(unsigned int val)
[32]39{
[61]40  if(val == REG_KEY)
41    return "KEY";
42 
[78]43  if(val >= regfi_num_reg_types)
[61]44    return NULL;
45 
[78]46  return regfi_type_names[val];
[32]47}
48
49
[61]50/* Returns -1 on error */
[78]51int regfi_type_str2val(const char* str)
[32]52{
53  int i;
54
[61]55  if(strcmp("KEY", str) == 0)
56    return REG_KEY;
[32]57
[78]58  for(i=0; i < regfi_num_reg_types; i++)
59    if (strcmp(regfi_type_names[i], str) == 0) 
[61]60      return i;
61
62  if(strcmp("DWORD_LE", str) == 0)
63    return REG_DWORD_LE;
64
65  return -1;
[32]66}
67
68
[53]69/* Security descriptor parsing functions  */
70
[78]71const char* regfi_ace_type2str(uint8 type)
[53]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
[76]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 */
[78]91char* regfi_ace_flags2str(uint8 flags)
[53]92{
[76]93  static const char* flag_map[32] = 
94    { "OI",
95      "CI",
96      "NP",
97      "IO",
98      "IA",
99      NULL,
100      NULL,
101      NULL,
102    };
[53]103
[76]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)
[53]110    return NULL;
111
[76]112  fo[0] = '\0';
[53]113  if (!flags)
[76]114    return ret_val;
[53]115
[76]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    }
[53]126  }
[76]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...
[53]138  if (flags == 0xF) {
139    if (some) strcat(flg_output, " ");
140    some = 1;
141    strcat(flg_output, "VI");
142  }
[76]143  */
[53]144
[76]145  return ret_val;
[53]146}
147
148
[78]149char* regfi_ace_perms2str(uint32 perms)
[53]150{
[76]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
[53]200  if(ret_val == NULL)
201    return NULL;
202
[76]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);
[53]219
[76]220  /* Chop off the last space if we've written anything to ret_val */
221  if(r != ret_val)
222    r[-1] = '\0';
223
[53]224  return ret_val;
225}
226
227
[78]228char* regfi_sid2str(DOM_SID* sid)
[53]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
[78]250char* regfi_get_acl(SEC_ACL* acl)
[53]251{
252  uint32 i, extra, size = 0;
253  const char* type_str;
254  char* flags_str;
255  char* perms_str;
256  char* sid_str;
[61]257  char* ace_delim = "";
[53]258  char* ret_val = NULL;
[61]259  char* tmp_val = NULL;
260  bool failed = false;
[53]261  char field_delim = ':';
262
[61]263  for (i = 0; i < acl->num_aces && !failed; i++)
[53]264  {
[78]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);
[53]269   
[61]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);
[53]277
[61]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);
[53]303  }
304
305  return ret_val;
306}
307
308
[78]309char* regfi_get_sacl(SEC_DESC *sec_desc)
[53]310{
311  if (sec_desc->sacl)
[78]312    return regfi_get_acl(sec_desc->sacl);
[53]313  else
314    return NULL;
315}
316
317
[78]318char* regfi_get_dacl(SEC_DESC *sec_desc)
[53]319{
320  if (sec_desc->dacl)
[78]321    return regfi_get_acl(sec_desc->dacl);
[53]322  else
323    return NULL;
324}
325
326
[78]327char* regfi_get_owner(SEC_DESC *sec_desc)
[53]328{
[78]329  return regfi_sid2str(sec_desc->owner_sid);
[53]330}
331
332
[78]333char* regfi_get_group(SEC_DESC *sec_desc)
[53]334{
[78]335  return regfi_sid2str(sec_desc->grp_sid);
[53]336}
337
338
339
[30]340/*******************************************************************
[31]341 *******************************************************************/
[30]342static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, 
343                       uint32 block_size )
344{
[61]345  const int hdr_size = 0x20;
[31]346  int bytes_read, returned;
347  char *buffer;
348  SMB_STRUCT_STAT sbuf;
[30]349
[31]350  /* check for end of file */
[30]351
[31]352  if ( fstat( file->fd, &sbuf ) ) {
353    /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
354    return -1;
355  }
[30]356
[31]357  if ( (size_t)file_offset >= sbuf.st_size )
358    return -1;
[30]359       
[31]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 */
[30]362           
[31]363  if ( block_size == 0 ) {
364    uint8 hdr[0x20];
[30]365
[31]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    }
[30]370
[61]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;
[31]385    }
[30]386
[31]387    /* make sure this is an hbin header */
[30]388
[53]389    if ( strncmp( (char*)hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
[31]390      /*DEBUG(0,("read_block: invalid block header!\n"));*/
391      return -1;
392    }
[30]393
[31]394    block_size = IVAL( hdr, 0x08 );
395  }
[30]396
[31]397  /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
[30]398
[31]399  /* set the offset, initialize the buffer, and read the block from disk */
[30]400
[31]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  }
[30]405       
[31]406  prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
407  buffer = ps->data_p;
408  bytes_read = returned = 0;
[30]409
[32]410  while ( bytes_read < block_size ) 
411  {
[61]412    returned = read(file->fd, buffer+bytes_read, block_size-bytes_read);
413    if(returned == -1 && errno != EINTR && errno != EAGAIN)
[32]414    {
[31]415      /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
[61]416      return -1;
[31]417    }
[61]418
[32]419    if ((returned == 0) && (bytes_read < block_size)) 
420    {
[31]421      /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
[61]422      return -1;
[31]423    }   
[32]424
[31]425    bytes_read += returned;
426  }
[30]427       
[31]428  return bytes_read;
[30]429}
430
431
432/*******************************************************************
[31]433 *******************************************************************/
[53]434static bool prs_regf_block(const char *desc, prs_struct *ps, 
435                           int depth, REGF_FILE *file)
[30]436{
[31]437  depth++;
[30]438       
[53]439  if(!prs_uint8s(true, "header", ps, depth, file->header, sizeof(file->header)))
[31]440    return false;
[30]441       
[31]442  /* yes, these values are always identical so store them only once */
[30]443       
[31]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;
[30]448
[31]449  /* get the modtime */
[30]450       
[31]451  if ( !prs_set_offset( ps, 0x0c ) )
452    return false;
453  if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
454    return false;
[30]455
[31]456  /* constants */
[30]457       
[31]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;
[30]466
[31]467  /* get file offsets */
[30]468       
[31]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;
[30]475               
[31]476  /* one more constant */
[30]477       
[31]478  if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
479    return false;
[30]480               
[31]481  /* get the checksum */
[30]482       
[31]483  if ( !prs_set_offset( ps, 0x01fc ) )
484    return false;
485  if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
486    return false;
[30]487       
[31]488  return true;
[30]489}
490
491
492/*******************************************************************
[31]493 *******************************************************************/
[53]494static bool prs_hbin_block(const char *desc, prs_struct *ps, 
495                           int depth, REGF_HBIN *hbin)
[30]496{
[31]497  uint32 block_size2;
[30]498
[31]499  depth++;
[30]500       
[53]501  if(!prs_uint8s(true, "header", ps, depth, hbin->header, sizeof(hbin->header)))
[31]502    return false;
[30]503
[31]504  if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
505    return false;
[30]506
[31]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 */
[30]510
[31]511  if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
512    return false;
[30]513
[31]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;
[30]518
[31]519  if ( !ps->io )
520    hbin->dirty = true;
[30]521       
522
[31]523  return true;
[30]524}
525
526
527/*******************************************************************
[31]528 *******************************************************************/
[33]529static bool prs_nk_rec( const char *desc, prs_struct *ps, 
530                        int depth, REGF_NK_REC *nk )
[30]531{
[31]532  uint16 class_length, name_length;
533  uint32 start;
534  uint32 data_size, start_off, end_off;
535  uint32 unknown_off = REGF_OFFSET_NONE;
[30]536
[31]537  nk->hbin_off = ps->data_offset;
538  start = nk->hbin_off;
[30]539       
[31]540  depth++;
[30]541       
[33]542  /* back up and get the data_size */   
[31]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;
[30]548       
[33]549  if (!prs_uint8s(true, "header", ps, depth, nk->header, sizeof(nk->header)))
[31]550    return false;
[30]551               
[31]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;
[30]556               
[31]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;
[30]563               
[31]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;
[30]570               
[31]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;
[30]581
[33]582  if (!prs_uint32("max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
[31]583    return false;
[33]584  if ( !prs_uint32( "max_bytes_subkeyclassname", ps, 
585                    depth, &nk->max_bytes_subkeyclassname))
586  { return false; }
[31]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;
[30]593
[31]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;       
[30]600               
[33]601  if ( class_length ) 
602  {
[80]603    /* XXX: why isn't this parsed? */
[31]604    ;;
605  }
[30]606       
[33]607  if ( name_length ) 
608  {
609    if(ps->io && !(nk->keyname = (char*)zcalloc(sizeof(char), name_length+1)))
[31]610        return false;
[30]611
[53]612    if(!prs_uint8s(true, "name", ps, depth, (uint8*)nk->keyname, name_length))
[31]613      return false;
[30]614
[53]615    if(ps->io)
[31]616      nk->keyname[name_length] = '\0';
617  }
[30]618
[31]619  end_off = ps->data_offset;
[30]620
[33]621  /* data_size must be divisible by 8 and large enough to hold
622     the original record */
[30]623
[31]624  data_size = ((start_off - end_off) & 0xfffffff8 );
[33]625  /*if ( data_size > nk->rec_size )
626      DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
[30]627
[33]628  if ( !ps->io )
629    nk->hbin->dirty = true;
630 
631  nk->subkey_index = 0;
[31]632  return true;
[30]633}
634
635
636/*******************************************************************
[31]637 *******************************************************************/
[30]638static uint32 regf_block_checksum( prs_struct *ps )
639{
[31]640  char *buffer = ps->data_p;
641  uint32 checksum, x;
642  int i;
[30]643
[31]644  /* XOR of all bytes 0x0000 - 0x01FB */
[30]645               
[31]646  checksum = x = 0;
[30]647       
[31]648  for ( i=0; i<0x01FB; i+=4 ) {
649    x = IVAL(buffer, i );
650    checksum ^= x;
651  }
[30]652       
[31]653  return checksum;
[30]654}
655
656
657/*******************************************************************
[31]658 *******************************************************************/
[30]659static bool read_regf_block( REGF_FILE *file )
660{
[31]661  prs_struct ps;
662  uint32 checksum;
[30]663       
[31]664  /* grab the first block from the file */
[30]665               
[31]666  if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
667    return false;
[30]668       
[31]669  /* parse the block and verify the checksum */
[30]670       
[31]671  if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
672    return false;       
[30]673               
[31]674  checksum = regf_block_checksum( &ps );
[30]675       
[31]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;
[30]681
[31]682  if ( file->checksum !=  checksum ) {
683    /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
684    return false;
685  }
[30]686
[31]687  return true;
[30]688}
689
690
691/*******************************************************************
[31]692 *******************************************************************/
[30]693static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
694{
[31]695  REGF_HBIN *hbin;
696  uint32 record_size, curr_off, block_size, header;
[30]697       
[31]698  if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) ) 
699    return NULL;
700  hbin->file_off = offset;
701  hbin->free_off = -1;
[30]702               
[31]703  if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
704    return NULL;
[30]705       
[31]706  if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
707    return NULL;       
[30]708
[31]709  /* this should be the same thing as hbin->block_size but just in case */
[30]710
[31]711  block_size = hbin->ps.buffer_size;
[30]712
[31]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. */
[30]718
[31]719  /* remember that the record_size is in the 4 bytes preceeding the record itself */
[30]720
[31]721  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
722    return false;
[30]723
[31]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 */
[30]729
[31]730    curr_off = curr_off+record_size;
[30]731
[31]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 */
[30]736
[31]737    if ( curr_off >= block_size ) {
738      record_size = -1;
739      curr_off = -1;
740      break;
741    }
[30]742
[31]743    if ( !prs_set_offset( &hbin->ps, curr_off) )
744      return false;
[30]745
[31]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;
[30]750               
[31]751    assert( record_size != 0 );
[30]752
[31]753    if ( record_size & 0x80000000 ) {
754      /* absolute_value(record_size) */
755      record_size = (record_size ^ 0xffffffff) + 1;
756    }
757  }
[30]758
[31]759  /* save the free space offset */
[30]760
[31]761  if ( header == 0xffffffff ) {
[30]762
[31]763    /* account for the fact that the curr_off is 4 bytes behind the actual
764       record header */
[30]765
[31]766    hbin->free_off = curr_off + sizeof(uint32);
767    hbin->free_size = record_size;
768  }
[30]769
[31]770  /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
[30]771
[31]772  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE )  )
773    return false;
[30]774       
[31]775  return hbin;
[30]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{
[31]785  if ( !hbin )
786    return false;
[30]787       
[31]788  if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
789    return true;
[30]790               
[31]791  return false;
[30]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{
[31]801  REGF_HBIN *hbin = NULL;
802  uint32 block_off;
[30]803
[31]804  /* start with the open list */
[30]805
[31]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  }
[30]811       
[31]812  if ( !hbin ) {
813    /* start at the beginning */
[30]814
[31]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      }
[30]826
[31]827      hbin = read_hbin_block( file, block_off );
[30]828
[31]829      if ( hbin ) 
830        block_off = hbin->file_off + hbin->block_size;
[30]831
[31]832    } while ( hbin && !hbin_contains_offset( hbin, offset ) );
833  }
[30]834
[31]835  if ( hbin )
[80]836    /* XXX: this kind of caching needs to be re-evaluated */
[31]837    DLIST_ADD( file->block_list, hbin );
[30]838
[31]839  return hbin;
[30]840}
841
842
843/*******************************************************************
[31]844 *******************************************************************/
[30]845static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
846{
[31]847  depth++;
[30]848
[31]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;
[30]853       
[31]854  return true;
[30]855}
856
857
858/*******************************************************************
[31]859 *******************************************************************/
[53]860static bool hbin_prs_lf_records(const char *desc, REGF_HBIN *hbin, 
861                                int depth, REGF_NK_REC *nk)
[30]862{
[31]863  int i;
864  REGF_LF_REC *lf = &nk->subkeys;
865  uint32 data_size, start_off, end_off;
[30]866
[31]867  depth++;
[30]868
[31]869  /* check if we have anything to do first */
[30]870       
[31]871  if ( nk->num_subkeys == 0 )
872    return true;
[30]873
[31]874  /* move to the LF record */
[30]875
[31]876  if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
877    return false;
[30]878
[31]879  /* backup and get the data_size */
[30]880       
[31]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;
[30]886
[53]887  if(!prs_uint8s(true, "header", &hbin->ps, depth, 
888                 lf->header, sizeof(lf->header)))
[31]889    return false;
[30]890               
[31]891  if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
892    return false;
[30]893
[31]894  if ( hbin->ps.io ) {
895    if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
896      return false;
897  }
[30]898
[31]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  }
[30]903
[31]904  end_off = hbin->ps.data_offset;
[30]905
[31]906  /* data_size must be divisible by 8 and large enough to hold the original record */
[30]907
[31]908  data_size = ((start_off - end_off) & 0xfffffff8 );
[33]909  /*  if ( data_size > lf->rec_size )*/
[31]910    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
[30]911
[33]912  if ( !hbin->ps.io )
913    hbin->dirty = true;
[30]914
[31]915  return true;
[30]916}
917
918
919/*******************************************************************
[31]920 *******************************************************************/
[30]921static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
922{
[31]923  prs_struct *ps = &hbin->ps;
924  uint16 tag = 0xFFFF;
925  uint32 data_size, start_off, end_off;
[30]926
927
[31]928  depth++;
[30]929
[31]930  if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
931    return false;
[30]932
[31]933  /* backup and get the data_size */
[30]934       
[31]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;
[30]940
[53]941  if (!prs_uint8s(true, "header", ps, depth, sk->header, sizeof(sk->header)))
[31]942    return false;
943  if ( !prs_uint16( "tag", ps, depth, &tag))
944    return false;
[30]945
[31]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;
[30]954
[31]955  if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 
956    return false;
[30]957
[31]958  end_off = hbin->ps.data_offset;
[30]959
[31]960  /* data_size must be divisible by 8 and large enough to hold the original record */
[30]961
[31]962  data_size = ((start_off - end_off) & 0xfffffff8 );
[33]963  /*  if ( data_size > sk->rec_size )*/
[31]964    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
[30]965
[33]966  if ( !hbin->ps.io )
967    hbin->dirty = true;
[30]968
[31]969  return true;
[30]970}
971
972
973/*******************************************************************
[31]974 *******************************************************************/
[30]975static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, 
976                             REGF_VK_REC *vk, REGF_FILE *file )
977{
[31]978  uint32 offset;
979  uint16 name_length;
980  prs_struct *ps = &hbin->ps;
981  uint32 data_size, start_off, end_off;
[30]982
[31]983  depth++;
[30]984
[31]985  /* backup and get the data_size */
[30]986       
[31]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;
[30]992
[31]993  if ( !prs_uint8s( true, "header", ps, depth, vk->header, sizeof( vk->header )) )
994    return false;
[30]995
[31]996  if ( !hbin->ps.io )
997    name_length = strlen(vk->valuename);
[30]998
[31]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;
[30]1009
[31]1010  offset = ps->data_offset;
1011  offset += 2;  /* skip 2 bytes */
1012  prs_set_offset( ps, offset );
[30]1013
[31]1014  /* get the name */
[30]1015
[31]1016  if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
[30]1017
[31]1018    if ( hbin->ps.io ) {
1019      if ( !(vk->valuename = (char*)zcalloc(sizeof(char), name_length+1 )))
1020        return false;
1021    }
[53]1022    if ( !prs_uint8s(true, "name", ps, depth, 
1023                     (uint8*)vk->valuename, name_length) )
[31]1024      return false;
1025  }
[30]1026
[31]1027  end_off = hbin->ps.data_offset;
[30]1028
[31]1029  /* get the data if necessary */
[30]1030
[32]1031  if ( vk->data_size != 0 ) 
1032  {
[31]1033    bool charmode = false;
[30]1034
[31]1035    if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
1036      charmode = true;
[30]1037
[31]1038    /* the data is stored in the offset if the size <= 4 */
[32]1039    if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) 
1040    {
[31]1041      REGF_HBIN *hblock = hbin;
1042      uint32 data_rec_size;
[30]1043
[32]1044      if ( hbin->ps.io ) 
1045      {
[31]1046        if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
1047          return false;
1048      }
[30]1049
[31]1050      /* this data can be in another hbin */
[32]1051      if ( !hbin_contains_offset( hbin, vk->data_off ) ) 
1052      {
[31]1053        if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
1054          return false;
1055      }
[32]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; }
[30]1062
[32]1063      if ( !hblock->ps.io ) 
1064      {
[31]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;
[32]1070      if(!prs_uint8s(charmode, "data", &hblock->ps, depth, 
1071                     vk->data, vk->data_size))
[31]1072        return false;
[30]1073
[31]1074      if ( !hblock->ps.io )
1075        hblock->dirty = true;
1076    }
[32]1077    else 
1078    {
1079      if(!(vk->data = zcalloc(sizeof(uint8), 4)))
[31]1080        return false;
1081      SIVAL( vk->data, 0, vk->data_off );
1082    }
[30]1083               
[31]1084  }
[30]1085
[31]1086  /* data_size must be divisible by 8 and large enough to hold the original record */
[30]1087
[31]1088  data_size = ((start_off - end_off ) & 0xfffffff8 );
[77]1089  /* XXX: should probably print a warning here */
[32]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));*/
[30]1092
[32]1093  if ( !hbin->ps.io )
1094    hbin->dirty = true;
[30]1095
[31]1096  return true;
[30]1097}
1098
1099
1100/*******************************************************************
1101 read a VK record which is contained in the HBIN block stored
1102 in the prs_struct *ps.
1103*******************************************************************/
[32]1104static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin, 
1105                                int depth, REGF_NK_REC *nk, REGF_FILE *file)
[30]1106{
[31]1107  int i;
1108  uint32 record_size;
[30]1109
[31]1110  depth++;
[80]1111 
[31]1112  /* check if we have anything to do first */
[32]1113  if(nk->num_values == 0)
[31]1114    return true;
[80]1115       
[32]1116  if(hbin->ps.io)
1117  {
1118    if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC), 
1119                                              nk->num_values )))
[31]1120      return false;
1121  }
[80]1122 
[31]1123  /* convert the offset to something relative to this HBIN block */
[32]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; }
[30]1130
[32]1131  if ( !hbin->ps.io ) 
1132  { 
[31]1133    record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
1134    record_size = (record_size - 1) ^ 0xFFFFFFFF;
1135  }
[30]1136
[31]1137  if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
1138    return false;
[80]1139       
[32]1140  for ( i=0; i<nk->num_values; i++ ) 
1141  {
[31]1142    if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
1143      return false;
1144  }
[30]1145
[32]1146  for ( i=0; i<nk->num_values; i++ ) 
1147  {
[31]1148    REGF_HBIN *sub_hbin = hbin;
1149    uint32 new_offset;
[30]1150       
[32]1151    if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) 
1152    {
[31]1153      sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
[32]1154      if ( !sub_hbin ) 
1155      {
[31]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    }
[80]1161       
[32]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))
[31]1167      return false;
[32]1168    if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
[31]1169      return false;
1170  }
[30]1171
[31]1172  if ( !hbin->ps.io )
1173    hbin->dirty = true;
[30]1174
[31]1175  return true;
[30]1176}
1177
1178
1179/*******************************************************************
[31]1180 *******************************************************************/
[30]1181static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
1182{
[31]1183  REGF_SK_REC *p_sk;
[80]1184 
[31]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  }
[80]1189 
[31]1190  return NULL;
[30]1191}
1192
[32]1193
[30]1194/*******************************************************************
[31]1195 *******************************************************************/
[30]1196static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
1197{
[31]1198  REGF_SK_REC *p;
[30]1199
[31]1200  for ( p=file->sec_desc_list; p; p=p->next ) {
1201    if ( sec_desc_equal( p->sec_desc, sd ) )
1202      return p;
1203  }
[30]1204
[31]1205  /* failure */
[30]1206
[31]1207  return NULL;
[30]1208}
1209
[32]1210
[30]1211/*******************************************************************
[31]1212 *******************************************************************/
[30]1213static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
1214{
[31]1215  int depth = 0;
1216  REGF_HBIN *sub_hbin;
[80]1217 
[31]1218  depth++;
[30]1219
[31]1220  /* get the initial nk record */
[33]1221  if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
[31]1222    return false;
[30]1223
[31]1224  /* fill in values */
[32]1225  if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) 
1226  {
[31]1227    sub_hbin = hbin;
[32]1228    if ( !hbin_contains_offset( hbin, nk->values_off ) ) 
1229    {
[31]1230      sub_hbin = lookup_hbin_block( file, nk->values_off );
[32]1231      if ( !sub_hbin ) 
1232      {
[31]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    }
[30]1238               
[32]1239    if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
[31]1240      return false;
1241  }
[30]1242               
[31]1243  /* now get subkeys */
[32]1244  if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) 
1245  {
[31]1246    sub_hbin = hbin;
[32]1247    if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) 
1248    {
[31]1249      sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
[32]1250      if ( !sub_hbin ) 
1251      {
[31]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    }
[30]1257               
[32]1258    if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
[31]1259      return false;
1260  }
[30]1261
[31]1262  /* get the to the security descriptor.  First look if we have already parsed it */
[30]1263       
[32]1264  if ((nk->sk_off!=REGF_OFFSET_NONE) 
1265      && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
1266  {
[31]1267    sub_hbin = hbin;
[32]1268    if (!hbin_contains_offset(hbin, nk->sk_off))
1269    {
[31]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    }
[30]1277               
[31]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;
[30]1283                       
[31]1284    /* add to the list of security descriptors (ref_count has been read from the files) */
[30]1285
[31]1286    nk->sec_desc->sk_off = nk->sk_off;
[80]1287    /* XXX: this kind of caching needs to be re-evaluated */
[31]1288    DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1289  }
[30]1290               
[31]1291  return true;
[30]1292}
1293
[32]1294
[30]1295/*******************************************************************
[31]1296 *******************************************************************/
[30]1297static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
1298{
[53]1299  uint8 header[REC_HDR_SIZE] = "";
[31]1300  uint32 record_size;
1301  uint32 curr_off, block_size;
1302  bool found = false;
1303  prs_struct *ps = &hbin->ps;
[30]1304       
[31]1305  curr_off = ps->data_offset;
1306  if ( curr_off == 0 )
1307    prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
[30]1308
[31]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);
[30]1312
[31]1313  block_size = ps->buffer_size;
1314  record_size = 0;
[32]1315  while ( !found ) 
1316  {
[31]1317    curr_off = curr_off+record_size;
1318    if ( curr_off >= block_size ) 
1319      break;
[30]1320
[31]1321    if ( !prs_set_offset( &hbin->ps, curr_off) )
1322      return false;
[30]1323
[31]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;
[30]1328
[31]1329    if ( record_size & 0x80000000 ) {
1330      /* absolute_value(record_size) */
1331      record_size = (record_size ^ 0xffffffff) + 1;
1332    }
[30]1333
[31]1334    if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1335      found = true;
1336      curr_off += sizeof(uint32);
1337    }
1338  } 
[30]1339
[31]1340  /* mark prs_struct as done ( at end ) if no more SK records */
[32]1341  /* mark end-of-block as true */       
1342  if ( !found )
[31]1343  {
1344    prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
1345    *eob = true;
1346    return false;
1347  }
[32]1348
1349  if (!prs_set_offset(ps, curr_off))
[31]1350    return false;
[30]1351
[31]1352  return true;
[30]1353}
1354
1355
1356/*******************************************************************
[31]1357 *******************************************************************/
[32]1358static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin, 
1359                           REGF_NK_REC *nk, bool *eob)
[30]1360{
[32]1361  if (next_record(hbin, "nk", eob) 
1362      && hbin_prs_key(file, hbin, nk))
[31]1363    return true;
[30]1364       
[31]1365  return false;
[30]1366}
1367
1368
1369/*******************************************************************
1370 Open the registry file and then read in the REGF block to get the
1371 first hbin offset.
1372*******************************************************************/
[78]1373REGF_FILE* regfi_open( const char *filename )
[30]1374{
[31]1375  REGF_FILE *rb;
1376  int flags = O_RDONLY;
[30]1377
[31]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;
[30]1384       
[31]1385  /*    if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) )
1386    {
[78]1387    regfi_close( rb );
[31]1388    return NULL;
1389    }
1390  */
1391  rb->open_flags = flags;
[30]1392       
[31]1393  /* open and existing file */
[30]1394
[31]1395  if ( (rb->fd = open(filename, flags)) == -1 ) {
[78]1396    /* DEBUG(0,("regfi_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
1397    regfi_close( rb );
[31]1398    return NULL;
1399  }
[30]1400       
[31]1401  /* read in an existing file */
[30]1402       
[31]1403  if ( !read_regf_block( rb ) ) {
[78]1404    /* DEBUG(0,("regfi_open: Failed to read initial REGF block\n"));*/
1405    regfi_close( rb );
[31]1406    return NULL;
1407  }
[30]1408       
[31]1409  /* success */
[30]1410       
[31]1411  return rb;
[30]1412}
1413
1414
1415/*******************************************************************
[80]1416XXX: should this be nuked?
[31]1417 *******************************************************************/
[78]1418static void regfi_mem_free( REGF_FILE *file )
[30]1419{
[31]1420  /* free any zalloc()'d memory */
[30]1421       
1422  /*    if ( file && file->mem_ctx )
[31]1423    free(file->mem_ctx);
[30]1424  */
1425}
1426
1427
1428/*******************************************************************
[31]1429 *******************************************************************/
[78]1430int regfi_close( REGF_FILE *file )
[30]1431{
[31]1432  int fd;
[30]1433
[78]1434  regfi_mem_free( file );
[30]1435
[31]1436  /* nothing to do if there is no open file */
[30]1437
[31]1438  if ( !file || (file->fd == -1) )
1439    return 0;
[30]1440               
[31]1441  fd = file->fd;
1442  file->fd = -1;
1443  SAFE_FREE( file );
[30]1444
[31]1445  return close( fd );
[30]1446}
1447
1448
[80]1449/******************************************************************************
1450 * There should be only *one* root key in the registry file based
1451 * on my experience.  --jerry
1452 *****************************************************************************/
[78]1453REGF_NK_REC* regfi_rootkey( REGF_FILE *file )
[30]1454{
[31]1455  REGF_NK_REC *nk;
1456  REGF_HBIN   *hbin;
1457  uint32      offset = REGF_BLOCKSIZE;
1458  bool        found = false;
1459  bool        eob;
[30]1460       
[31]1461  if ( !file )
1462    return NULL;
[30]1463               
[31]1464  if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
[78]1465    /*DEBUG(0,("regfi_rootkey: zalloc() failed!\n"));*/
[31]1466    return NULL;
1467  }
[30]1468       
[31]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) */
[30]1473       
[31]1474  while ( (hbin = read_hbin_block( file, offset )) ) {
1475    eob = false;
[30]1476
[31]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    }
[30]1490               
[31]1491    if ( found ) 
1492      break;
[30]1493
[31]1494    offset += hbin->block_size;
1495  }
[30]1496       
[31]1497  if ( !found ) {
[78]1498    /*DEBUG(0,("regfi_rootkey: corrupt registry file ?  No root key record located\n"));*/
[31]1499    return NULL;
1500  }
[30]1501
[80]1502  /* XXX: this kind of caching needs to be re-evaluated */
[31]1503  DLIST_ADD( file->block_list, hbin );
[30]1504
[80]1505  return nk;
[30]1506}
1507
1508
[80]1509/******************************************************************************
1510 *****************************************************************************/
1511void regfi_key_free(REGF_NK_REC* nk)
[30]1512{
[80]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  }
[30]1521
[80]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
[31]1753  /* see if there is anything left to report */
[80]1754  if (!(i->cur_key) || (i->cur_key->subkeys_off==REGF_OFFSET_NONE)
1755      || (i->cur_subkey >= i->cur_key->num_subkeys))
[31]1756    return NULL;
[30]1757
[80]1758  nk_offset = i->cur_key->subkeys.hashes[i->cur_subkey].nk_off;
1759
[31]1760  /* find the HBIN block which should contain the nk record */
[80]1761  hbin = lookup_hbin_block(i->f, nk_offset);
1762  if(!hbin)
[31]1763  {
[80]1764    /* XXX: should print out some kind of error message every time here */
[31]1765    /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n",
[80]1766      i->cur_key->subkeys.hashes[i->cur_subkey].nk_off));*/
[31]1767    return NULL;
1768  }
[78]1769 
[32]1770  if(!prs_set_offset(&hbin->ps, 
[80]1771                     HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off))
[31]1772    return NULL;
[30]1773               
[32]1774  if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
[31]1775    return NULL;
[30]1776
[80]1777  if(!hbin_prs_key(i->f, hbin, subkey))
1778  {
1779    regfi_key_free(subkey);
[31]1780    return NULL;
[80]1781  }
[32]1782
[31]1783  return subkey;
[30]1784}
[80]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.