source: trunk/lib/regfio.c @ 41

Last change on this file since 41 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
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 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
37/* Registry types mapping */
38const VAL_STR reg_type_names[] = 
39{
40  { REG_SZ,                        "SZ"           },
41  { REG_EXPAND_SZ,                 "EXPAND_SZ"    },
42  { REG_BINARY,                    "BINARY"       },
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* regfio_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 regfio_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.