source: trunk/lib/regfio.c @ 39

Last change on this file since 39 was 33, checked in by tim, 19 years ago

Fixed some bugs.

rewrote testing code to allow for a path filter expression.

  • Property svn:keywords set to Id
File size: 33.7 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 *
8 * Copyright (C) 2005 Timothy D. Morgan
9 * Copyright (C) 2005 Gerald (Jerry) Carter
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
23 *
24 * $Id: regfio.c 33 2005-07-17 19:03:02Z tim $
25 */
26
27#include "../include/regfio.h"
28
29
30
31/*******************************************************************
32 *
33 * TODO : Right now this code basically ignores classnames.
34 *
35 ******************************************************************/
36
[32]37/* Registry types mapping */
38const VAL_STR reg_type_names[] = 
39{
40  { REG_SZ,                        "SZ"           },
41  { REG_EXPAND_SZ,                 "EXPAND_SZ"    },
42  { REG_BINARY,                    "BIN"          },
43  { REG_DWORD,                     "DWORD"        },
44  { REG_DWORD_BE,                  "DWORD_BE"     },
45  { REG_LINK,                      "LINK"         },
46  { REG_MULTI_SZ,                  "MULTI_SZ"     },
47  { REG_RESOURCE_LIST,             "RSRC_LIST"    },
48  { REG_FULL_RESOURCE_DESCRIPTOR,  "RSRC_DESC"    },
49  { REG_RESOURCE_REQUIREMENTS_LIST,"RSRC_REQ_LIST"},
50  { REG_KEY,                       "KEY"          },
51  { 0,                             NULL           },
52};
[30]53
[32]54
55/* Returns NULL on error */
56const char* type_val2str(unsigned int val)
57{
58  int i;
59
60  for(i=0; reg_type_names[i].val && reg_type_names[i].str; i++)
61    if (reg_type_names[i].val == val) 
62      return reg_type_names[i].str;
63
64  return NULL;
65}
66
67
68/* Returns 0 on error */
69int type_str2val(const char* str)
70{
71  int i;
72
73  for(i=0; reg_type_names[i].val && reg_type_names[i].str; i++) 
74    if (strcmp(reg_type_names[i].str, str) == 0) 
75      return reg_type_names[i].val;
76
77  return 0;
78}
79
80
[30]81/*******************************************************************
[31]82 *******************************************************************/
[30]83static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, 
84                       uint32 block_size )
85{
[31]86  int bytes_read, returned;
87  char *buffer;
88  SMB_STRUCT_STAT sbuf;
[30]89
[31]90  /* check for end of file */
[30]91
[31]92  if ( fstat( file->fd, &sbuf ) ) {
93    /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
94    return -1;
95  }
[30]96
[31]97  if ( (size_t)file_offset >= sbuf.st_size )
98    return -1;
[30]99       
[31]100  /* if block_size == 0, we are parsnig HBIN records and need
101     to read some of the header to get the block_size from there */
[30]102           
[31]103  if ( block_size == 0 ) {
104    uint8 hdr[0x20];
[30]105
[31]106    if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
107      /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
108      return -1;
109    }
[30]110
[31]111    returned = read( file->fd, hdr, 0x20 );
112    if ( (returned == -1) || (returned < 0x20) ) {
113      /*DEBUG(0,("read_block: failed to read in HBIN header. Is the file corrupt?\n"));*/
114      return -1;
115    }
[30]116
[31]117    /* make sure this is an hbin header */
[30]118
[31]119    if ( strncmp( hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
120      /*DEBUG(0,("read_block: invalid block header!\n"));*/
121      return -1;
122    }
[30]123
[31]124    block_size = IVAL( hdr, 0x08 );
125  }
[30]126
[31]127  /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
[30]128
[31]129  /* set the offset, initialize the buffer, and read the block from disk */
[30]130
[31]131  if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
132    /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
133    return -1;
134  }
[30]135       
[31]136  prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
137  buffer = ps->data_p;
138  bytes_read = returned = 0;
[30]139
[32]140  while ( bytes_read < block_size ) 
141  {
142    if((returned = 
143        read(file->fd, buffer+bytes_read, block_size-bytes_read)) == -1)
144    {
[31]145      /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
146      return false;
147    }
[32]148    if ((returned == 0) && (bytes_read < block_size)) 
149    {
[31]150      /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
151      return false;
152    }   
[32]153
[31]154    bytes_read += returned;
155  }
[30]156       
[31]157  return bytes_read;
[30]158}
159
160
161/*******************************************************************
[31]162 *******************************************************************/
[30]163static bool prs_regf_block( const char *desc, prs_struct *ps, int depth, REGF_FILE *file )
164{
[31]165  depth++;
[30]166       
[31]167  if ( !prs_uint8s( true, "header", ps, depth, file->header, sizeof( file->header )) )
168    return false;
[30]169       
[31]170  /* yes, these values are always identical so store them only once */
[30]171       
[31]172  if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 ))
173    return false;
174  if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 ))
175    return false;
[30]176
[31]177  /* get the modtime */
[30]178       
[31]179  if ( !prs_set_offset( ps, 0x0c ) )
180    return false;
181  if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
182    return false;
[30]183
[31]184  /* constants */
[30]185       
[31]186  if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 ))
187    return false;
188  if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 ))
189    return false;
190  if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 ))
191    return false;
192  if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 ))
193    return false;
[30]194
[31]195  /* get file offsets */
[30]196       
[31]197  if ( !prs_set_offset( ps, 0x24 ) )
198    return false;
199  if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset ))
200    return false;
201  if ( !prs_uint32( "last_block", ps, depth, &file->last_block ))
202    return false;
[30]203               
[31]204  /* one more constant */
[30]205       
[31]206  if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
207    return false;
[30]208               
[31]209  /* get the checksum */
[30]210       
[31]211  if ( !prs_set_offset( ps, 0x01fc ) )
212    return false;
213  if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
214    return false;
[30]215       
[31]216  return true;
[30]217}
218
219
220/*******************************************************************
[31]221 *******************************************************************/
[30]222static bool prs_hbin_block( const char *desc, prs_struct *ps, int depth, REGF_HBIN *hbin )
223{
[31]224  uint32 block_size2;
[30]225
[31]226  depth++;
[30]227       
[31]228  if ( !prs_uint8s( true, "header", ps, depth, hbin->header, sizeof( hbin->header )) )
229    return false;
[30]230
[31]231  if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
232    return false;
[30]233
[31]234  /* The dosreg.cpp comments say that the block size is at 0x1c.
235     According to a WINXP NTUSER.dat file, this is wrong.  The block_size
236     is at 0x08 */
[30]237
[31]238  if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
239    return false;
[30]240
[31]241  block_size2 = hbin->block_size;
242  prs_set_offset( ps, 0x1c );
243  if ( !prs_uint32( "block_size2", ps, depth, &block_size2 ))
244    return false;
[30]245
[31]246  if ( !ps->io )
247    hbin->dirty = true;
[30]248       
249
[31]250  return true;
[30]251}
252
253
254/*******************************************************************
[31]255 *******************************************************************/
[33]256static bool prs_nk_rec( const char *desc, prs_struct *ps, 
257                        int depth, REGF_NK_REC *nk )
[30]258{
[31]259  uint16 class_length, name_length;
260  uint32 start;
261  uint32 data_size, start_off, end_off;
262  uint32 unknown_off = REGF_OFFSET_NONE;
[30]263
[31]264  nk->hbin_off = ps->data_offset;
265  start = nk->hbin_off;
[30]266       
[31]267  depth++;
[30]268       
[33]269  /* back up and get the data_size */   
[31]270  if ( !prs_set_offset( ps, ps->data_offset-sizeof(uint32)) )
271    return false;
272  start_off = ps->data_offset;
273  if ( !prs_uint32( "rec_size", ps, depth, &nk->rec_size ))
274    return false;
[30]275       
[33]276  if (!prs_uint8s(true, "header", ps, depth, nk->header, sizeof(nk->header)))
[31]277    return false;
[30]278               
[31]279  if ( !prs_uint16( "key_type", ps, depth, &nk->key_type ))
280    return false;
281  if ( !smb_io_time( "mtime", &nk->mtime, ps, depth ))
282    return false;
[30]283               
[31]284  if ( !prs_set_offset( ps, start+0x0010 ) )
285    return false;
286  if ( !prs_uint32( "parent_off", ps, depth, &nk->parent_off ))
287    return false;
288  if ( !prs_uint32( "num_subkeys", ps, depth, &nk->num_subkeys ))
289    return false;
[30]290               
[31]291  if ( !prs_set_offset( ps, start+0x001c ) )
292    return false;
293  if ( !prs_uint32( "subkeys_off", ps, depth, &nk->subkeys_off ))
294    return false;
295  if ( !prs_uint32( "unknown_off", ps, depth, &unknown_off) )
296    return false;
[30]297               
[31]298  if ( !prs_set_offset( ps, start+0x0024 ) )
299    return false;
300  if ( !prs_uint32( "num_values", ps, depth, &nk->num_values ))
301    return false;
302  if ( !prs_uint32( "values_off", ps, depth, &nk->values_off ))
303    return false;
304  if ( !prs_uint32( "sk_off", ps, depth, &nk->sk_off ))
305    return false;
306  if ( !prs_uint32( "classname_off", ps, depth, &nk->classname_off ))
307    return false;
[30]308
[33]309  if (!prs_uint32("max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
[31]310    return false;
[33]311  if ( !prs_uint32( "max_bytes_subkeyclassname", ps, 
312                    depth, &nk->max_bytes_subkeyclassname))
313  { return false; }
[31]314  if ( !prs_uint32( "max_bytes_valuename", ps, depth, &nk->max_bytes_valuename))
315    return false;
316  if ( !prs_uint32( "max_bytes_value", ps, depth, &nk->max_bytes_value))
317    return false;
318  if ( !prs_uint32( "unknown index", ps, depth, &nk->unk_index))
319    return false;
[30]320
[31]321  name_length = nk->keyname ? strlen(nk->keyname) : 0 ;
322  class_length = nk->classname ? strlen(nk->classname) : 0 ;
323  if ( !prs_uint16( "name_length", ps, depth, &name_length ))
324    return false;
325  if ( !prs_uint16( "class_length", ps, depth, &class_length ))
326    return false;       
[30]327               
[33]328  if ( class_length ) 
329  {
[31]330    ;;
331  }
[30]332       
[33]333  if ( name_length ) 
334  {
335    if(ps->io && !(nk->keyname = (char*)zcalloc(sizeof(char), name_length+1)))
[31]336        return false;
[30]337
[31]338    if ( !prs_uint8s( true, "name", ps, depth, nk->keyname, name_length) )
339      return false;
[30]340
[31]341    if ( ps->io ) 
342      nk->keyname[name_length] = '\0';
343  }
[30]344
[31]345  end_off = ps->data_offset;
[30]346
[33]347  /* data_size must be divisible by 8 and large enough to hold
348     the original record */
[30]349
[31]350  data_size = ((start_off - end_off) & 0xfffffff8 );
[33]351  /*if ( data_size > nk->rec_size )
352      DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
[30]353
[33]354  if ( !ps->io )
355    nk->hbin->dirty = true;
356 
357  nk->subkey_index = 0;
[31]358  return true;
[30]359}
360
361
362/*******************************************************************
[31]363 *******************************************************************/
[30]364static uint32 regf_block_checksum( prs_struct *ps )
365{
[31]366  char *buffer = ps->data_p;
367  uint32 checksum, x;
368  int i;
[30]369
[31]370  /* XOR of all bytes 0x0000 - 0x01FB */
[30]371               
[31]372  checksum = x = 0;
[30]373       
[31]374  for ( i=0; i<0x01FB; i+=4 ) {
375    x = IVAL(buffer, i );
376    checksum ^= x;
377  }
[30]378       
[31]379  return checksum;
[30]380}
381
382
383/*******************************************************************
[31]384 *******************************************************************/
[30]385static bool read_regf_block( REGF_FILE *file )
386{
[31]387  prs_struct ps;
388  uint32 checksum;
[30]389       
[31]390  /* grab the first block from the file */
[30]391               
[31]392  if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
393    return false;
[30]394       
[31]395  /* parse the block and verify the checksum */
[30]396       
[31]397  if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
398    return false;       
[30]399               
[31]400  checksum = regf_block_checksum( &ps );
[30]401       
[31]402  if(ps.is_dynamic)
403    SAFE_FREE(ps.data_p);
404  ps.is_dynamic = false;
405  ps.buffer_size = 0;
406  ps.data_offset = 0;
[30]407
[31]408  if ( file->checksum !=  checksum ) {
409    /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
410    return false;
411  }
[30]412
[31]413  return true;
[30]414}
415
416
417/*******************************************************************
[31]418 *******************************************************************/
[30]419static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
420{
[31]421  REGF_HBIN *hbin;
422  uint32 record_size, curr_off, block_size, header;
[30]423       
[31]424  if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) ) 
425    return NULL;
426  hbin->file_off = offset;
427  hbin->free_off = -1;
[30]428               
[31]429  if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
430    return NULL;
[30]431       
[31]432  if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
433    return NULL;       
[30]434
[31]435  /* this should be the same thing as hbin->block_size but just in case */
[30]436
[31]437  block_size = hbin->ps.buffer_size;
[30]438
[31]439  /* Find the available free space offset.  Always at the end,
440     so walk the record list and stop when you get to the end.
441     The end is defined by a record header of 0xffffffff.  The
442     previous 4 bytes contains the amount of free space remaining
443     in the hbin block. */
[30]444
[31]445  /* remember that the record_size is in the 4 bytes preceeding the record itself */
[30]446
[31]447  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
448    return false;
[30]449
[31]450  record_size = 0;
451  curr_off = hbin->ps.data_offset;
452  while ( header != 0xffffffff ) {
453    /* not done yet so reset the current offset to the
454       next record_size field */
[30]455
[31]456    curr_off = curr_off+record_size;
[30]457
[31]458    /* for some reason the record_size of the last record in
459       an hbin block can extend past the end of the block
460       even though the record fits within the remaining
461       space....aaarrrgggghhhhhh */
[30]462
[31]463    if ( curr_off >= block_size ) {
464      record_size = -1;
465      curr_off = -1;
466      break;
467    }
[30]468
[31]469    if ( !prs_set_offset( &hbin->ps, curr_off) )
470      return false;
[30]471
[31]472    if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) )
473      return false;
474    if ( !prs_uint32( "header", &hbin->ps, 0, &header ) )
475      return false;
[30]476               
[31]477    assert( record_size != 0 );
[30]478
[31]479    if ( record_size & 0x80000000 ) {
480      /* absolute_value(record_size) */
481      record_size = (record_size ^ 0xffffffff) + 1;
482    }
483  }
[30]484
[31]485  /* save the free space offset */
[30]486
[31]487  if ( header == 0xffffffff ) {
[30]488
[31]489    /* account for the fact that the curr_off is 4 bytes behind the actual
490       record header */
[30]491
[31]492    hbin->free_off = curr_off + sizeof(uint32);
493    hbin->free_size = record_size;
494  }
[30]495
[31]496  /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
[30]497
[31]498  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE )  )
499    return false;
[30]500       
[31]501  return hbin;
[30]502}
503
504
505/*******************************************************************
506 Input a randon offset and receive the correpsonding HBIN
507 block for it
508*******************************************************************/
509static bool hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
510{
[31]511  if ( !hbin )
512    return false;
[30]513       
[31]514  if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
515    return true;
[30]516               
[31]517  return false;
[30]518}
519
520
521/*******************************************************************
522 Input a randon offset and receive the correpsonding HBIN
523 block for it
524*******************************************************************/
525static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset )
526{
[31]527  REGF_HBIN *hbin = NULL;
528  uint32 block_off;
[30]529
[31]530  /* start with the open list */
[30]531
[31]532  for ( hbin=file->block_list; hbin; hbin=hbin->next ) {
533    /* DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%x]\n", hbin->file_off, (uint32)hbin ));*/
534    if ( hbin_contains_offset( hbin, offset ) )
535      return hbin;
536  }
[30]537       
[31]538  if ( !hbin ) {
539    /* start at the beginning */
[30]540
[31]541    block_off = REGF_BLOCKSIZE;
542    do {
543      /* cleanup before the next round */
544      if ( hbin )
545      {
546        if(hbin->ps.is_dynamic)
547          SAFE_FREE(hbin->ps.data_p);
548        hbin->ps.is_dynamic = false;
549        hbin->ps.buffer_size = 0;
550        hbin->ps.data_offset = 0;
551      }
[30]552
[31]553      hbin = read_hbin_block( file, block_off );
[30]554
[31]555      if ( hbin ) 
556        block_off = hbin->file_off + hbin->block_size;
[30]557
[31]558    } while ( hbin && !hbin_contains_offset( hbin, offset ) );
559  }
[30]560
[31]561  if ( hbin )
562    DLIST_ADD( file->block_list, hbin );
[30]563
[31]564  return hbin;
[30]565}
566
567
568/*******************************************************************
[31]569 *******************************************************************/
[30]570static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
571{
[31]572  depth++;
[30]573
[31]574  if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off ))
575    return false;
576  if ( !prs_uint8s( true, "keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) )
577    return false;
[30]578       
[31]579  return true;
[30]580}
581
582
583/*******************************************************************
[31]584 *******************************************************************/
[30]585static bool hbin_prs_lf_records( const char *desc, REGF_HBIN *hbin, int depth, REGF_NK_REC *nk )
586{
[31]587  int i;
588  REGF_LF_REC *lf = &nk->subkeys;
589  uint32 data_size, start_off, end_off;
[30]590
[31]591  depth++;
[30]592
[31]593  /* check if we have anything to do first */
[30]594       
[31]595  if ( nk->num_subkeys == 0 )
596    return true;
[30]597
[31]598  /* move to the LF record */
[30]599
[31]600  if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
601    return false;
[30]602
[31]603  /* backup and get the data_size */
[30]604       
[31]605  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
606    return false;
607  start_off = hbin->ps.data_offset;
608  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &lf->rec_size ))
609    return false;
[30]610
[31]611  if ( !prs_uint8s( true, "header", &hbin->ps, depth, lf->header, sizeof( lf->header )) )
612    return false;
[30]613               
[31]614  if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
615    return false;
[30]616
[31]617  if ( hbin->ps.io ) {
618    if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
619      return false;
620  }
[30]621
[31]622  for ( i=0; i<lf->num_keys; i++ ) {
623    if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) )
624      return false;
625  }
[30]626
[31]627  end_off = hbin->ps.data_offset;
[30]628
[31]629  /* data_size must be divisible by 8 and large enough to hold the original record */
[30]630
[31]631  data_size = ((start_off - end_off) & 0xfffffff8 );
[33]632  /*  if ( data_size > lf->rec_size )*/
[31]633    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
[30]634
[33]635  if ( !hbin->ps.io )
636    hbin->dirty = true;
[30]637
[31]638  return true;
[30]639}
640
641
642/*******************************************************************
[31]643 *******************************************************************/
[30]644static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
645{
[31]646  prs_struct *ps = &hbin->ps;
647  uint16 tag = 0xFFFF;
648  uint32 data_size, start_off, end_off;
[30]649
650
[31]651  depth++;
[30]652
[31]653  if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
654    return false;
[30]655
[31]656  /* backup and get the data_size */
[30]657       
[31]658  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
659    return false;
660  start_off = hbin->ps.data_offset;
661  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size ))
662    return false;
[30]663
[31]664  if ( !prs_uint8s( true, "header", ps, depth, sk->header, sizeof( sk->header )) )
665    return false;
666  if ( !prs_uint16( "tag", ps, depth, &tag))
667    return false;
[30]668
[31]669  if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off))
670    return false;
671  if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off))
672    return false;
673  if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count))
674    return false;
675  if ( !prs_uint32( "size", ps, depth, &sk->size))
676    return false;
[30]677
[31]678  if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 
679    return false;
[30]680
[31]681  end_off = hbin->ps.data_offset;
[30]682
[31]683  /* data_size must be divisible by 8 and large enough to hold the original record */
[30]684
[31]685  data_size = ((start_off - end_off) & 0xfffffff8 );
[33]686  /*  if ( data_size > sk->rec_size )*/
[31]687    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
[30]688
[33]689  if ( !hbin->ps.io )
690    hbin->dirty = true;
[30]691
[31]692  return true;
[30]693}
694
695
696/*******************************************************************
[31]697 *******************************************************************/
[30]698static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, 
699                             REGF_VK_REC *vk, REGF_FILE *file )
700{
[31]701  uint32 offset;
702  uint16 name_length;
703  prs_struct *ps = &hbin->ps;
704  uint32 data_size, start_off, end_off;
[30]705
[31]706  depth++;
[30]707
[31]708  /* backup and get the data_size */
[30]709       
[31]710  if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
711    return false;
712  start_off = hbin->ps.data_offset;
713  if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size ))
714    return false;
[30]715
[31]716  if ( !prs_uint8s( true, "header", ps, depth, vk->header, sizeof( vk->header )) )
717    return false;
[30]718
[31]719  if ( !hbin->ps.io )
720    name_length = strlen(vk->valuename);
[30]721
[31]722  if ( !prs_uint16( "name_length", ps, depth, &name_length ))
723    return false;
724  if ( !prs_uint32( "data_size", ps, depth, &vk->data_size ))
725    return false;
726  if ( !prs_uint32( "data_off", ps, depth, &vk->data_off ))
727    return false;
728  if ( !prs_uint32( "type", ps, depth, &vk->type))
729    return false;
730  if ( !prs_uint16( "flag", ps, depth, &vk->flag))
731    return false;
[30]732
[31]733  offset = ps->data_offset;
734  offset += 2;  /* skip 2 bytes */
735  prs_set_offset( ps, offset );
[30]736
[31]737  /* get the name */
[30]738
[31]739  if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
[30]740
[31]741    if ( hbin->ps.io ) {
742      if ( !(vk->valuename = (char*)zcalloc(sizeof(char), name_length+1 )))
743        return false;
744    }
745    if ( !prs_uint8s( true, "name", ps, depth, vk->valuename, name_length ) )
746      return false;
747  }
[30]748
[31]749  end_off = hbin->ps.data_offset;
[30]750
[31]751  /* get the data if necessary */
[30]752
[32]753  if ( vk->data_size != 0 ) 
754  {
[31]755    bool charmode = false;
[30]756
[31]757    if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
758      charmode = true;
[30]759
[31]760    /* the data is stored in the offset if the size <= 4 */
[32]761    if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) 
762    {
[31]763      REGF_HBIN *hblock = hbin;
764      uint32 data_rec_size;
[30]765
[32]766      if ( hbin->ps.io ) 
767      {
[31]768        if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
769          return false;
770      }
[30]771
[31]772      /* this data can be in another hbin */
[32]773      if ( !hbin_contains_offset( hbin, vk->data_off ) ) 
774      {
[31]775        if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
776          return false;
777      }
[32]778      if (!(prs_set_offset(&hblock->ps, 
779                           (vk->data_off
780                            + HBIN_HDR_SIZE
781                            - hblock->first_hbin_off)
782                           - sizeof(uint32))))
783      { return false; }
[30]784
[32]785      if ( !hblock->ps.io ) 
786      {
[31]787        data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
788        data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF;
789      }
790      if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size ))
791        return false;
[32]792      if(!prs_uint8s(charmode, "data", &hblock->ps, depth, 
793                     vk->data, vk->data_size))
[31]794        return false;
[30]795
[31]796      if ( !hblock->ps.io )
797        hblock->dirty = true;
798    }
[32]799    else 
800    {
801      if(!(vk->data = zcalloc(sizeof(uint8), 4)))
[31]802        return false;
803      SIVAL( vk->data, 0, vk->data_off );
804    }
[30]805               
[31]806  }
[30]807
[31]808  /* data_size must be divisible by 8 and large enough to hold the original record */
[30]809
[31]810  data_size = ((start_off - end_off ) & 0xfffffff8 );
[32]811  /*if ( data_size !=  vk->rec_size )
812    DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));*/
[30]813
[32]814  if ( !hbin->ps.io )
815    hbin->dirty = true;
[30]816
[31]817  return true;
[30]818}
819
820
821/*******************************************************************
822 read a VK record which is contained in the HBIN block stored
823 in the prs_struct *ps.
824*******************************************************************/
[32]825static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin, 
826                                int depth, REGF_NK_REC *nk, REGF_FILE *file)
[30]827{
[31]828  int i;
829  uint32 record_size;
[30]830
[31]831  depth++;
[30]832       
[31]833  /* check if we have anything to do first */
[32]834  if(nk->num_values == 0)
[31]835    return true;
[30]836               
[32]837  if(hbin->ps.io)
838  {
839    if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC), 
840                                              nk->num_values )))
[31]841      return false;
842  }
[30]843       
[31]844  /* convert the offset to something relative to this HBIN block */
[32]845  if (!prs_set_offset(&hbin->ps, 
846                      nk->values_off
847                      + HBIN_HDR_SIZE
848                      - hbin->first_hbin_off
849                      - sizeof(uint32)))
850  { return false; }
[30]851
[32]852  if ( !hbin->ps.io ) 
853  { 
[31]854    record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
855    record_size = (record_size - 1) ^ 0xFFFFFFFF;
856  }
[30]857
[31]858  if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
859    return false;
[30]860               
[32]861  for ( i=0; i<nk->num_values; i++ ) 
862  {
[31]863    if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
864      return false;
865  }
[30]866
[32]867  for ( i=0; i<nk->num_values; i++ ) 
868  {
[31]869    REGF_HBIN *sub_hbin = hbin;
870    uint32 new_offset;
[30]871       
[32]872    if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) 
873    {
[31]874      sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
[32]875      if ( !sub_hbin ) 
876      {
[31]877        /*DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n",
878          nk->values[i].hbin_off));*/
879        return false;
880      }
881    }
[30]882               
[32]883    new_offset = nk->values[i].rec_off
884      + HBIN_HDR_SIZE
885      - sub_hbin->first_hbin_off;
886
887    if (!prs_set_offset(&sub_hbin->ps, new_offset))
[31]888      return false;
[32]889    if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
[31]890      return false;
891  }
[30]892
[31]893  if ( !hbin->ps.io )
894    hbin->dirty = true;
[30]895
[31]896  return true;
[30]897}
898
899
900/*******************************************************************
[31]901 *******************************************************************/
[30]902static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
903{
[31]904  REGF_SK_REC *p_sk;
[30]905       
[31]906  for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) {
907    if ( p_sk->sk_off == offset ) 
908      return p_sk;
909  }
[30]910       
[31]911  return NULL;
[30]912}
913
[32]914
[30]915/*******************************************************************
[31]916 *******************************************************************/
[30]917static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
918{
[31]919  REGF_SK_REC *p;
[30]920
[31]921  for ( p=file->sec_desc_list; p; p=p->next ) {
922    if ( sec_desc_equal( p->sec_desc, sd ) )
923      return p;
924  }
[30]925
[31]926  /* failure */
[30]927
[31]928  return NULL;
[30]929}
930
[32]931
[30]932/*******************************************************************
[31]933 *******************************************************************/
[30]934static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
935{
[31]936  int depth = 0;
937  REGF_HBIN *sub_hbin;
[30]938       
[31]939  depth++;
[30]940
[31]941  /* get the initial nk record */
[33]942  if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
[31]943    return false;
[30]944
[31]945  /* fill in values */
[32]946  if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) 
947  {
[31]948    sub_hbin = hbin;
[32]949    if ( !hbin_contains_offset( hbin, nk->values_off ) ) 
950    {
[31]951      sub_hbin = lookup_hbin_block( file, nk->values_off );
[32]952      if ( !sub_hbin ) 
953      {
[31]954        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n",
955          nk->values_off));*/
956        return false;
957      }
958    }
[30]959               
[32]960    if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
[31]961      return false;
962  }
[30]963               
[31]964  /* now get subkeys */
[32]965  if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) 
966  {
[31]967    sub_hbin = hbin;
[32]968    if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) 
969    {
[31]970      sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
[32]971      if ( !sub_hbin ) 
972      {
[31]973        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n",
974          nk->subkeys_off));*/
975        return false;
976      }
977    }
[30]978               
[32]979    if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
[31]980      return false;
981  }
[30]982
[31]983  /* get the to the security descriptor.  First look if we have already parsed it */
[30]984       
[32]985  if ((nk->sk_off!=REGF_OFFSET_NONE) 
986      && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
987  {
[31]988    sub_hbin = hbin;
[32]989    if (!hbin_contains_offset(hbin, nk->sk_off))
990    {
[31]991      sub_hbin = lookup_hbin_block( file, nk->sk_off );
992      if ( !sub_hbin ) {
993        /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n",
994          nk->subkeys_off));*/
995        return false;
996      }
997    }
[30]998               
[31]999    if ( !(nk->sec_desc = (REGF_SK_REC*)zalloc(sizeof(REGF_SK_REC) )) )
1000      return false;
1001    nk->sec_desc->sk_off = nk->sk_off;
1002    if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))
1003      return false;
[30]1004                       
[31]1005    /* add to the list of security descriptors (ref_count has been read from the files) */
[30]1006
[31]1007    nk->sec_desc->sk_off = nk->sk_off;
1008    DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1009  }
[30]1010               
[31]1011  return true;
[30]1012}
1013
[32]1014
[30]1015/*******************************************************************
[31]1016 *******************************************************************/
[30]1017static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
1018{
[31]1019  char header[REC_HDR_SIZE] = "";
1020  uint32 record_size;
1021  uint32 curr_off, block_size;
1022  bool found = false;
1023  prs_struct *ps = &hbin->ps;
[30]1024       
[31]1025  curr_off = ps->data_offset;
1026  if ( curr_off == 0 )
1027    prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
[30]1028
[31]1029  /* assume that the current offset is at the reacord header
1030     and we need to backup to read the record size */
1031  curr_off -= sizeof(uint32);
[30]1032
[31]1033  block_size = ps->buffer_size;
1034  record_size = 0;
[32]1035  while ( !found ) 
1036  {
[31]1037    curr_off = curr_off+record_size;
1038    if ( curr_off >= block_size ) 
1039      break;
[30]1040
[31]1041    if ( !prs_set_offset( &hbin->ps, curr_off) )
1042      return false;
[30]1043
[31]1044    if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
1045      return false;
1046    if ( !prs_uint8s( true, "header", ps, 0, header, REC_HDR_SIZE ) )
1047      return false;
[30]1048
[31]1049    if ( record_size & 0x80000000 ) {
1050      /* absolute_value(record_size) */
1051      record_size = (record_size ^ 0xffffffff) + 1;
1052    }
[30]1053
[31]1054    if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1055      found = true;
1056      curr_off += sizeof(uint32);
1057    }
1058  } 
[30]1059
[31]1060  /* mark prs_struct as done ( at end ) if no more SK records */
[32]1061  /* mark end-of-block as true */       
1062  if ( !found )
[31]1063  {
1064    prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
1065    *eob = true;
1066    return false;
1067  }
[32]1068
1069  if (!prs_set_offset(ps, curr_off))
[31]1070    return false;
[30]1071
[31]1072  return true;
[30]1073}
1074
1075
1076/*******************************************************************
[31]1077 *******************************************************************/
[32]1078static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin, 
1079                           REGF_NK_REC *nk, bool *eob)
[30]1080{
[32]1081  if (next_record(hbin, "nk", eob) 
1082      && hbin_prs_key(file, hbin, nk))
[31]1083    return true;
[30]1084       
[31]1085  return false;
[30]1086}
1087
1088
1089/*******************************************************************
1090 Open the registry file and then read in the REGF block to get the
1091 first hbin offset.
1092*******************************************************************/
1093REGF_FILE* regfio_open( const char *filename )
1094{
[31]1095  REGF_FILE *rb;
1096  int flags = O_RDONLY;
[30]1097
[31]1098  if ( !(rb = (REGF_FILE*)malloc(sizeof(REGF_FILE))) ) {
1099    /* DEBUG(0,("ERROR allocating memory\n")); */
1100    return NULL;
1101  }
1102  memset(rb, 0, sizeof(REGF_FILE));
1103  rb->fd = -1;
[30]1104       
[31]1105  /*    if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) )
1106    {
1107    regfio_close( rb );
1108    return NULL;
1109    }
1110  */
1111  rb->open_flags = flags;
[30]1112       
[31]1113  /* open and existing file */
[30]1114
[31]1115  if ( (rb->fd = open(filename, flags)) == -1 ) {
1116    /* DEBUG(0,("regfio_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
1117    regfio_close( rb );
1118    return NULL;
1119  }
[30]1120       
[31]1121  /* read in an existing file */
[30]1122       
[31]1123  if ( !read_regf_block( rb ) ) {
1124    /* DEBUG(0,("regfio_open: Failed to read initial REGF block\n"));*/
1125    regfio_close( rb );
1126    return NULL;
1127  }
[30]1128       
[31]1129  /* success */
[30]1130       
[31]1131  return rb;
[30]1132}
1133
1134
1135/*******************************************************************
[31]1136 *******************************************************************/
[30]1137static void regfio_mem_free( REGF_FILE *file )
1138{
[31]1139  /* free any zalloc()'d memory */
[30]1140       
1141  /*    if ( file && file->mem_ctx )
[31]1142    free(file->mem_ctx);
[30]1143  */
1144}
1145
1146
1147/*******************************************************************
[31]1148 *******************************************************************/
[30]1149int regfio_close( REGF_FILE *file )
1150{
[31]1151  int fd;
[30]1152
[31]1153  regfio_mem_free( file );
[30]1154
[31]1155  /* nothing to do if there is no open file */
[30]1156
[31]1157  if ( !file || (file->fd == -1) )
1158    return 0;
[30]1159               
[31]1160  fd = file->fd;
1161  file->fd = -1;
1162  SAFE_FREE( file );
[30]1163
[31]1164  return close( fd );
[30]1165}
1166
1167
1168/*******************************************************************
1169 There should be only *one* root key in the registry file based
1170 on my experience.  --jerry
1171*******************************************************************/
1172REGF_NK_REC* regfio_rootkey( REGF_FILE *file )
1173{
[31]1174  REGF_NK_REC *nk;
1175  REGF_HBIN   *hbin;
1176  uint32      offset = REGF_BLOCKSIZE;
1177  bool        found = false;
1178  bool        eob;
[30]1179       
[31]1180  if ( !file )
1181    return NULL;
[30]1182               
[31]1183  if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
1184    /*DEBUG(0,("regfio_rootkey: zalloc() failed!\n"));*/
1185    return NULL;
1186  }
[30]1187       
[31]1188  /* scan through the file on HBIN block at a time looking
1189     for an NK record with a type == 0x002c.
1190     Normally this is the first nk record in the first hbin
1191     block (but I'm not assuming that for now) */
[30]1192       
[31]1193  while ( (hbin = read_hbin_block( file, offset )) ) {
1194    eob = false;
[30]1195
[31]1196    while ( !eob) {
1197      if ( next_nk_record( file, hbin, nk, &eob ) ) {
1198        if ( nk->key_type == NK_TYPE_ROOTKEY ) {
1199          found = true;
1200          break;
1201        }
1202      }
1203      if(hbin->ps.is_dynamic)
1204        SAFE_FREE(hbin->ps.data_p);
1205      hbin->ps.is_dynamic = false;
1206      hbin->ps.buffer_size = 0;
1207      hbin->ps.data_offset = 0;
1208    }
[30]1209               
[31]1210    if ( found ) 
1211      break;
[30]1212
[31]1213    offset += hbin->block_size;
1214  }
[30]1215       
[31]1216  if ( !found ) {
1217    /*DEBUG(0,("regfio_rootkey: corrupt registry file ?  No root key record located\n"));*/
1218    return NULL;
1219  }
[30]1220
[31]1221  DLIST_ADD( file->block_list, hbin );
[30]1222
[31]1223  return nk;           
[30]1224}
1225
1226
[33]1227/* XXX: An interator struct should be used instead, and this function
1228 *   should operate on it, so the state of iteration isn't stored in the
1229 * REGF_NK_REC struct itself.
1230 */
[30]1231/*******************************************************************
1232 This acts as an interator over the subkeys defined for a given
1233 NK record.  Remember that offsets are from the *first* HBIN block.
1234*******************************************************************/
1235REGF_NK_REC* regfio_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk )
1236{
[31]1237  REGF_NK_REC *subkey;
1238  REGF_HBIN   *hbin;
1239  uint32      nk_offset;
[30]1240
[31]1241  /* see if there is anything left to report */
[32]1242  if (!nk || (nk->subkeys_off==REGF_OFFSET_NONE) 
1243      || (nk->subkey_index >= nk->num_subkeys))
[31]1244    return NULL;
[30]1245
[31]1246  /* find the HBIN block which should contain the nk record */
1247  if(!(hbin
1248       = lookup_hbin_block(file, nk->subkeys.hashes[nk->subkey_index].nk_off )))
1249  {
1250    /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n",
1251      nk->subkeys.hashes[nk->subkey_index].nk_off));*/
1252    return NULL;
1253  }
[30]1254       
[31]1255  nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off;
[32]1256  if(!prs_set_offset(&hbin->ps, 
1257                     (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off)))
[31]1258    return NULL;
[30]1259               
[31]1260  nk->subkey_index++;
[32]1261  if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
[31]1262    return NULL;
[30]1263
[32]1264  if(!hbin_prs_key(file, hbin, subkey))
[31]1265    return NULL;
[32]1266
[31]1267  return subkey;
[30]1268}
Note: See TracBrowser for help on using the repository browser.