source: trunk/lib/regfio.c @ 46

Last change on this file since 46 was 41, checked in by tim, 19 years ago

Added full printing of values, as with old code.

renamed type conversion functions to follow precedent.

  • Property svn:keywords set to Id
File size: 33.8 KB
RevLine 
[30]1/*
2 * Branched from Samba project Subversion repository, version #7470:
3 *   http://websvn.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c
4 *
5 * Unix SMB/CIFS implementation.
6 * Windows NT registry I/O library
7 *
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 41 2005-08-01 01:13:15Z 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"    },
[41]42  { REG_BINARY,                    "BINARY"       },
[32]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 */
[41]56const char* regfio_type_val2str(unsigned int val)
[32]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 */
[41]69int regfio_type_str2val(const char* str)
[32]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.