source: trunk/lib/regfio.c @ 31

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

Added new lightweight stack library

rewrote test program to use this instead of string concatenation/recursion.

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