source: trunk/lib/regfi.c @ 84

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

rearranged structure contents to reduce fragmentation on 64 bit systems.

make regfi interface return const structures to help enforce separation

removed a little cruft from some parsing functions

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