source: trunk/lib/regfi.c @ 81

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

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

Compiles now, but is minimally tested.

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