source: trunk/lib/regfio.c @ 33

Last change on this file since 33 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
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 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
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};
53
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
81/*******************************************************************
82 *******************************************************************/
83static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, 
84                       uint32 block_size )
85{
86  int bytes_read, returned;
87  char *buffer;
88  SMB_STRUCT_STAT sbuf;
89
90  /* check for end of file */
91
92  if ( fstat( file->fd, &sbuf ) ) {
93    /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
94    return -1;
95  }
96
97  if ( (size_t)file_offset >= sbuf.st_size )
98    return -1;
99       
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 */
102           
103  if ( block_size == 0 ) {
104    uint8 hdr[0x20];
105
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    }
110
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    }
116
117    /* make sure this is an hbin header */
118
119    if ( strncmp( hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
120      /*DEBUG(0,("read_block: invalid block header!\n"));*/
121      return -1;
122    }
123
124    block_size = IVAL( hdr, 0x08 );
125  }
126
127  /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
128
129  /* set the offset, initialize the buffer, and read the block from disk */
130
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  }
135       
136  prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
137  buffer = ps->data_p;
138  bytes_read = returned = 0;
139
140  while ( bytes_read < block_size ) 
141  {
142    if((returned = 
143        read(file->fd, buffer+bytes_read, block_size-bytes_read)) == -1)
144    {
145      /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
146      return false;
147    }
148    if ((returned == 0) && (bytes_read < block_size)) 
149    {
150      /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
151      return false;
152    }   
153
154    bytes_read += returned;
155  }
156       
157  return bytes_read;
158}
159
160
161/*******************************************************************
162 *******************************************************************/
163static bool prs_regf_block( const char *desc, prs_struct *ps, int depth, REGF_FILE *file )
164{
165  depth++;
166       
167  if ( !prs_uint8s( true, "header", ps, depth, file->header, sizeof( file->header )) )
168    return false;
169       
170  /* yes, these values are always identical so store them only once */
171       
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;
176
177  /* get the modtime */
178       
179  if ( !prs_set_offset( ps, 0x0c ) )
180    return false;
181  if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
182    return false;
183
184  /* constants */
185       
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;
194
195  /* get file offsets */
196       
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;
203               
204  /* one more constant */
205       
206  if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
207    return false;
208               
209  /* get the checksum */
210       
211  if ( !prs_set_offset( ps, 0x01fc ) )
212    return false;
213  if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
214    return false;
215       
216  return true;
217}
218
219
220/*******************************************************************
221 *******************************************************************/
222static bool prs_hbin_block( const char *desc, prs_struct *ps, int depth, REGF_HBIN *hbin )
223{
224  uint32 block_size2;
225
226  depth++;
227       
228  if ( !prs_uint8s( true, "header", ps, depth, hbin->header, sizeof( hbin->header )) )
229    return false;
230
231  if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
232    return false;
233
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 */
237
238  if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
239    return false;
240
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;
245
246  if ( !ps->io )
247    hbin->dirty = true;
248       
249
250  return true;
251}
252
253
254/*******************************************************************
255 *******************************************************************/
256static bool prs_nk_rec( const char *desc, prs_struct *ps, 
257                        int depth, REGF_NK_REC *nk )
258{
259  uint16 class_length, name_length;
260  uint32 start;
261  uint32 data_size, start_off, end_off;
262  uint32 unknown_off = REGF_OFFSET_NONE;
263
264  nk->hbin_off = ps->data_offset;
265  start = nk->hbin_off;
266       
267  depth++;
268       
269  /* back up and get the data_size */   
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;
275       
276  if (!prs_uint8s(true, "header", ps, depth, nk->header, sizeof(nk->header)))
277    return false;
278               
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;
283               
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;
290               
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;
297               
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;
308
309  if (!prs_uint32("max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
310    return false;
311  if ( !prs_uint32( "max_bytes_subkeyclassname", ps, 
312                    depth, &nk->max_bytes_subkeyclassname))
313  { return false; }
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;
320
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;       
327               
328  if ( class_length ) 
329  {
330    ;;
331  }
332       
333  if ( name_length ) 
334  {
335    if(ps->io && !(nk->keyname = (char*)zcalloc(sizeof(char), name_length+1)))
336        return false;
337
338    if ( !prs_uint8s( true, "name", ps, depth, nk->keyname, name_length) )
339      return false;
340
341    if ( ps->io ) 
342      nk->keyname[name_length] = '\0';
343  }
344
345  end_off = ps->data_offset;
346
347  /* data_size must be divisible by 8 and large enough to hold
348     the original record */
349
350  data_size = ((start_off - end_off) & 0xfffffff8 );
351  /*if ( data_size > nk->rec_size )
352      DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
353
354  if ( !ps->io )
355    nk->hbin->dirty = true;
356 
357  nk->subkey_index = 0;
358  return true;
359}
360
361
362/*******************************************************************
363 *******************************************************************/
364static uint32 regf_block_checksum( prs_struct *ps )
365{
366  char *buffer = ps->data_p;
367  uint32 checksum, x;
368  int i;
369
370  /* XOR of all bytes 0x0000 - 0x01FB */
371               
372  checksum = x = 0;
373       
374  for ( i=0; i<0x01FB; i+=4 ) {
375    x = IVAL(buffer, i );
376    checksum ^= x;
377  }
378       
379  return checksum;
380}
381
382
383/*******************************************************************
384 *******************************************************************/
385static bool read_regf_block( REGF_FILE *file )
386{
387  prs_struct ps;
388  uint32 checksum;
389       
390  /* grab the first block from the file */
391               
392  if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
393    return false;
394       
395  /* parse the block and verify the checksum */
396       
397  if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
398    return false;       
399               
400  checksum = regf_block_checksum( &ps );
401       
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;
407
408  if ( file->checksum !=  checksum ) {
409    /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
410    return false;
411  }
412
413  return true;
414}
415
416
417/*******************************************************************
418 *******************************************************************/
419static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
420{
421  REGF_HBIN *hbin;
422  uint32 record_size, curr_off, block_size, header;
423       
424  if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) ) 
425    return NULL;
426  hbin->file_off = offset;
427  hbin->free_off = -1;
428               
429  if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
430    return NULL;
431       
432  if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
433    return NULL;       
434
435  /* this should be the same thing as hbin->block_size but just in case */
436
437  block_size = hbin->ps.buffer_size;
438
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. */
444
445  /* remember that the record_size is in the 4 bytes preceeding the record itself */
446
447  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
448    return false;
449
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 */
455
456    curr_off = curr_off+record_size;
457
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 */
462
463    if ( curr_off >= block_size ) {
464      record_size = -1;
465      curr_off = -1;
466      break;
467    }
468
469    if ( !prs_set_offset( &hbin->ps, curr_off) )
470      return false;
471
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;
476               
477    assert( record_size != 0 );
478
479    if ( record_size & 0x80000000 ) {
480      /* absolute_value(record_size) */
481      record_size = (record_size ^ 0xffffffff) + 1;
482    }
483  }
484
485  /* save the free space offset */
486
487  if ( header == 0xffffffff ) {
488
489    /* account for the fact that the curr_off is 4 bytes behind the actual
490       record header */
491
492    hbin->free_off = curr_off + sizeof(uint32);
493    hbin->free_size = record_size;
494  }
495
496  /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
497
498  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE )  )
499    return false;
500       
501  return hbin;
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{
511  if ( !hbin )
512    return false;
513       
514  if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
515    return true;
516               
517  return false;
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{
527  REGF_HBIN *hbin = NULL;
528  uint32 block_off;
529
530  /* start with the open list */
531
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  }
537       
538  if ( !hbin ) {
539    /* start at the beginning */
540
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      }
552
553      hbin = read_hbin_block( file, block_off );
554
555      if ( hbin ) 
556        block_off = hbin->file_off + hbin->block_size;
557
558    } while ( hbin && !hbin_contains_offset( hbin, offset ) );
559  }
560
561  if ( hbin )
562    DLIST_ADD( file->block_list, hbin );
563
564  return hbin;
565}
566
567
568/*******************************************************************
569 *******************************************************************/
570static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
571{
572  depth++;
573
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;
578       
579  return true;
580}
581
582
583/*******************************************************************
584 *******************************************************************/
585static bool hbin_prs_lf_records( const char *desc, REGF_HBIN *hbin, int depth, REGF_NK_REC *nk )
586{
587  int i;
588  REGF_LF_REC *lf = &nk->subkeys;
589  uint32 data_size, start_off, end_off;
590
591  depth++;
592
593  /* check if we have anything to do first */
594       
595  if ( nk->num_subkeys == 0 )
596    return true;
597
598  /* move to the LF record */
599
600  if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
601    return false;
602
603  /* backup and get the data_size */
604       
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;
610
611  if ( !prs_uint8s( true, "header", &hbin->ps, depth, lf->header, sizeof( lf->header )) )
612    return false;
613               
614  if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
615    return false;
616
617  if ( hbin->ps.io ) {
618    if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
619      return false;
620  }
621
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  }
626
627  end_off = hbin->ps.data_offset;
628
629  /* data_size must be divisible by 8 and large enough to hold the original record */
630
631  data_size = ((start_off - end_off) & 0xfffffff8 );
632  /*  if ( data_size > lf->rec_size )*/
633    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
634
635  if ( !hbin->ps.io )
636    hbin->dirty = true;
637
638  return true;
639}
640
641
642/*******************************************************************
643 *******************************************************************/
644static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
645{
646  prs_struct *ps = &hbin->ps;
647  uint16 tag = 0xFFFF;
648  uint32 data_size, start_off, end_off;
649
650
651  depth++;
652
653  if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
654    return false;
655
656  /* backup and get the data_size */
657       
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;
663
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;
668
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;
677
678  if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 
679    return false;
680
681  end_off = hbin->ps.data_offset;
682
683  /* data_size must be divisible by 8 and large enough to hold the original record */
684
685  data_size = ((start_off - end_off) & 0xfffffff8 );
686  /*  if ( data_size > sk->rec_size )*/
687    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
688
689  if ( !hbin->ps.io )
690    hbin->dirty = true;
691
692  return true;
693}
694
695
696/*******************************************************************
697 *******************************************************************/
698static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, 
699                             REGF_VK_REC *vk, REGF_FILE *file )
700{
701  uint32 offset;
702  uint16 name_length;
703  prs_struct *ps = &hbin->ps;
704  uint32 data_size, start_off, end_off;
705
706  depth++;
707
708  /* backup and get the data_size */
709       
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;
715
716  if ( !prs_uint8s( true, "header", ps, depth, vk->header, sizeof( vk->header )) )
717    return false;
718
719  if ( !hbin->ps.io )
720    name_length = strlen(vk->valuename);
721
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;
732
733  offset = ps->data_offset;
734  offset += 2;  /* skip 2 bytes */
735  prs_set_offset( ps, offset );
736
737  /* get the name */
738
739  if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
740
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  }
748
749  end_off = hbin->ps.data_offset;
750
751  /* get the data if necessary */
752
753  if ( vk->data_size != 0 ) 
754  {
755    bool charmode = false;
756
757    if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
758      charmode = true;
759
760    /* the data is stored in the offset if the size <= 4 */
761    if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) 
762    {
763      REGF_HBIN *hblock = hbin;
764      uint32 data_rec_size;
765
766      if ( hbin->ps.io ) 
767      {
768        if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
769          return false;
770      }
771
772      /* this data can be in another hbin */
773      if ( !hbin_contains_offset( hbin, vk->data_off ) ) 
774      {
775        if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
776          return false;
777      }
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; }
784
785      if ( !hblock->ps.io ) 
786      {
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;
792      if(!prs_uint8s(charmode, "data", &hblock->ps, depth, 
793                     vk->data, vk->data_size))
794        return false;
795
796      if ( !hblock->ps.io )
797        hblock->dirty = true;
798    }
799    else 
800    {
801      if(!(vk->data = zcalloc(sizeof(uint8), 4)))
802        return false;
803      SIVAL( vk->data, 0, vk->data_off );
804    }
805               
806  }
807
808  /* data_size must be divisible by 8 and large enough to hold the original record */
809
810  data_size = ((start_off - end_off ) & 0xfffffff8 );
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));*/
813
814  if ( !hbin->ps.io )
815    hbin->dirty = true;
816
817  return true;
818}
819
820
821/*******************************************************************
822 read a VK record which is contained in the HBIN block stored
823 in the prs_struct *ps.
824*******************************************************************/
825static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin, 
826                                int depth, REGF_NK_REC *nk, REGF_FILE *file)
827{
828  int i;
829  uint32 record_size;
830
831  depth++;
832       
833  /* check if we have anything to do first */
834  if(nk->num_values == 0)
835    return true;
836               
837  if(hbin->ps.io)
838  {
839    if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC), 
840                                              nk->num_values )))
841      return false;
842  }
843       
844  /* convert the offset to something relative to this HBIN block */
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; }
851
852  if ( !hbin->ps.io ) 
853  { 
854    record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
855    record_size = (record_size - 1) ^ 0xFFFFFFFF;
856  }
857
858  if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
859    return false;
860               
861  for ( i=0; i<nk->num_values; i++ ) 
862  {
863    if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
864      return false;
865  }
866
867  for ( i=0; i<nk->num_values; i++ ) 
868  {
869    REGF_HBIN *sub_hbin = hbin;
870    uint32 new_offset;
871       
872    if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) 
873    {
874      sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
875      if ( !sub_hbin ) 
876      {
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    }
882               
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))
888      return false;
889    if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
890      return false;
891  }
892
893  if ( !hbin->ps.io )
894    hbin->dirty = true;
895
896  return true;
897}
898
899
900/*******************************************************************
901 *******************************************************************/
902static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
903{
904  REGF_SK_REC *p_sk;
905       
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  }
910       
911  return NULL;
912}
913
914
915/*******************************************************************
916 *******************************************************************/
917static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
918{
919  REGF_SK_REC *p;
920
921  for ( p=file->sec_desc_list; p; p=p->next ) {
922    if ( sec_desc_equal( p->sec_desc, sd ) )
923      return p;
924  }
925
926  /* failure */
927
928  return NULL;
929}
930
931
932/*******************************************************************
933 *******************************************************************/
934static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
935{
936  int depth = 0;
937  REGF_HBIN *sub_hbin;
938       
939  depth++;
940
941  /* get the initial nk record */
942  if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
943    return false;
944
945  /* fill in values */
946  if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) 
947  {
948    sub_hbin = hbin;
949    if ( !hbin_contains_offset( hbin, nk->values_off ) ) 
950    {
951      sub_hbin = lookup_hbin_block( file, nk->values_off );
952      if ( !sub_hbin ) 
953      {
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    }
959               
960    if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
961      return false;
962  }
963               
964  /* now get subkeys */
965  if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) 
966  {
967    sub_hbin = hbin;
968    if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) 
969    {
970      sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
971      if ( !sub_hbin ) 
972      {
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    }
978               
979    if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
980      return false;
981  }
982
983  /* get the to the security descriptor.  First look if we have already parsed it */
984       
985  if ((nk->sk_off!=REGF_OFFSET_NONE) 
986      && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
987  {
988    sub_hbin = hbin;
989    if (!hbin_contains_offset(hbin, nk->sk_off))
990    {
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    }
998               
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;
1004                       
1005    /* add to the list of security descriptors (ref_count has been read from the files) */
1006
1007    nk->sec_desc->sk_off = nk->sk_off;
1008    DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1009  }
1010               
1011  return true;
1012}
1013
1014
1015/*******************************************************************
1016 *******************************************************************/
1017static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
1018{
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;
1024       
1025  curr_off = ps->data_offset;
1026  if ( curr_off == 0 )
1027    prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
1028
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);
1032
1033  block_size = ps->buffer_size;
1034  record_size = 0;
1035  while ( !found ) 
1036  {
1037    curr_off = curr_off+record_size;
1038    if ( curr_off >= block_size ) 
1039      break;
1040
1041    if ( !prs_set_offset( &hbin->ps, curr_off) )
1042      return false;
1043
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;
1048
1049    if ( record_size & 0x80000000 ) {
1050      /* absolute_value(record_size) */
1051      record_size = (record_size ^ 0xffffffff) + 1;
1052    }
1053
1054    if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1055      found = true;
1056      curr_off += sizeof(uint32);
1057    }
1058  } 
1059
1060  /* mark prs_struct as done ( at end ) if no more SK records */
1061  /* mark end-of-block as true */       
1062  if ( !found )
1063  {
1064    prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
1065    *eob = true;
1066    return false;
1067  }
1068
1069  if (!prs_set_offset(ps, curr_off))
1070    return false;
1071
1072  return true;
1073}
1074
1075
1076/*******************************************************************
1077 *******************************************************************/
1078static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin, 
1079                           REGF_NK_REC *nk, bool *eob)
1080{
1081  if (next_record(hbin, "nk", eob) 
1082      && hbin_prs_key(file, hbin, nk))
1083    return true;
1084       
1085  return false;
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{
1095  REGF_FILE *rb;
1096  int flags = O_RDONLY;
1097
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;
1104       
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;
1112       
1113  /* open and existing file */
1114
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  }
1120       
1121  /* read in an existing file */
1122       
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  }
1128       
1129  /* success */
1130       
1131  return rb;
1132}
1133
1134
1135/*******************************************************************
1136 *******************************************************************/
1137static void regfio_mem_free( REGF_FILE *file )
1138{
1139  /* free any zalloc()'d memory */
1140       
1141  /*    if ( file && file->mem_ctx )
1142    free(file->mem_ctx);
1143  */
1144}
1145
1146
1147/*******************************************************************
1148 *******************************************************************/
1149int regfio_close( REGF_FILE *file )
1150{
1151  int fd;
1152
1153  regfio_mem_free( file );
1154
1155  /* nothing to do if there is no open file */
1156
1157  if ( !file || (file->fd == -1) )
1158    return 0;
1159               
1160  fd = file->fd;
1161  file->fd = -1;
1162  SAFE_FREE( file );
1163
1164  return close( fd );
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{
1174  REGF_NK_REC *nk;
1175  REGF_HBIN   *hbin;
1176  uint32      offset = REGF_BLOCKSIZE;
1177  bool        found = false;
1178  bool        eob;
1179       
1180  if ( !file )
1181    return NULL;
1182               
1183  if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
1184    /*DEBUG(0,("regfio_rootkey: zalloc() failed!\n"));*/
1185    return NULL;
1186  }
1187       
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) */
1192       
1193  while ( (hbin = read_hbin_block( file, offset )) ) {
1194    eob = false;
1195
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    }
1209               
1210    if ( found ) 
1211      break;
1212
1213    offset += hbin->block_size;
1214  }
1215       
1216  if ( !found ) {
1217    /*DEBUG(0,("regfio_rootkey: corrupt registry file ?  No root key record located\n"));*/
1218    return NULL;
1219  }
1220
1221  DLIST_ADD( file->block_list, hbin );
1222
1223  return nk;           
1224}
1225
1226
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 */
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{
1237  REGF_NK_REC *subkey;
1238  REGF_HBIN   *hbin;
1239  uint32      nk_offset;
1240
1241  /* see if there is anything left to report */
1242  if (!nk || (nk->subkeys_off==REGF_OFFSET_NONE) 
1243      || (nk->subkey_index >= nk->num_subkeys))
1244    return NULL;
1245
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  }
1254       
1255  nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off;
1256  if(!prs_set_offset(&hbin->ps, 
1257                     (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off)))
1258    return NULL;
1259               
1260  nk->subkey_index++;
1261  if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
1262    return NULL;
1263
1264  if(!hbin_prs_key(file, hbin, subkey))
1265    return NULL;
1266
1267  return subkey;
1268}
Note: See TracBrowser for help on using the repository browser.