source: trunk/lib/regfio.c @ 30

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

Added initial version of regfio interface, borrowed from Samba project.

Library has all write capability stripped, and all Samba dependency has
either been removed, or included in the smb_deps code.

  • Property svn:keywords set to Id
File size: 32.7 KB
RevLine 
[30]1/*
2 * Branched from Samba project Subversion repository, version #7470:
3 *   http://websvn.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c
4 *
5 * Unix SMB/CIFS implementation.
6 * Windows NT registry I/O library
7 *
8 * Copyright (C) 2005 Timothy D. Morgan
9 * Copyright (C) 2005 Gerald (Jerry) Carter
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
23 *
24 * $Id: regfio.c 30 2005-07-16 14:31:27Z 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 Intialize the newly created REGF_BLOCK in *file and write the
1016 block header to disk
1017*******************************************************************/
1018static bool init_regf_block( REGF_FILE *file )
1019{       
1020        prs_struct ps;
1021        bool result = true;
1022       
1023        if ( !prs_init( &ps, REGF_BLOCKSIZE, file->mem_ctx, MARSHALL ) )
1024                return false;
1025               
1026        memcpy( file->header, "regf", REGF_HDR_SIZE );
1027        file->data_offset = 0x20;
1028        file->last_block  = 0x1000;
1029       
1030        /* set mod time */
1031       
1032        unix_to_nt_time( &file->mtime, time(NULL) );
1033       
1034        /* hard coded values...no diea what these are ... maybe in time */
1035       
1036        file->unknown1 = 0x2;
1037        file->unknown2 = 0x1;
1038        file->unknown3 = 0x3;
1039        file->unknown4 = 0x0;
1040        file->unknown5 = 0x1;
1041        file->unknown6 = 0x1;
1042       
1043        /* write header to the buffer */
1044       
1045        if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) {
1046                result = false;
1047                goto out;
1048        }
1049       
1050        /* calculate the checksum, re-marshall data (to include the checksum)
1051           and write to disk */
1052       
1053        file->checksum = regf_block_checksum( &ps );
1054        prs_set_offset( &ps, 0 );
1055        if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) {
1056                result = false;
1057                goto out;
1058        }
1059               
1060out:
1061        if(ps.is_dynamic)
1062          SAFE_FREE(ps.data_p);
1063        ps.is_dynamic = false;
1064        ps.buffer_size = 0;
1065        ps.data_offset = 0;
1066
1067        return result;
1068}
1069
1070
1071/*******************************************************************
1072 Open the registry file and then read in the REGF block to get the
1073 first hbin offset.
1074*******************************************************************/
1075REGF_FILE* regfio_open( const char *filename )
1076{
1077        REGF_FILE *rb;
1078        int flags = O_RDONLY;
1079
1080        if ( !(rb = (REGF_FILE*)malloc(sizeof(REGF_FILE))) ) {
1081                DEBUG(0,("ERROR allocating memory\n"));
1082                return NULL;
1083        }
1084        zerop( rb );
1085        rb->fd = -1;
1086       
1087        /*      if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) )
1088        {
1089          regfio_close( rb );
1090          return NULL;
1091        }
1092        */
1093        rb->open_flags = flags;
1094       
1095        /* open and existing file */
1096
1097        if ( (rb->fd = open(filename, flags)) == -1 ) {
1098                DEBUG(0,("regfio_open: failure to open %s (%s)\n", filename, strerror(errno)));
1099                regfio_close( rb );
1100                return NULL;
1101        }
1102       
1103        /* check if we are creating a new file or overwriting an existing one */
1104               
1105        if ( flags & (O_CREAT|O_TRUNC) ) {
1106                if ( !init_regf_block( rb ) ) {
1107                        DEBUG(0,("regfio_open: Failed to read initial REGF block\n"));
1108                        regfio_close( rb );
1109                        return NULL;
1110                }
1111               
1112                /* success */
1113                return rb;
1114        }
1115       
1116        /* read in an existing file */
1117       
1118        if ( !read_regf_block( rb ) ) {
1119                DEBUG(0,("regfio_open: Failed to read initial REGF block\n"));
1120                regfio_close( rb );
1121                return NULL;
1122        }
1123       
1124        /* success */
1125       
1126        return rb;
1127}
1128
1129
1130/*******************************************************************
1131*******************************************************************/
1132static void regfio_mem_free( REGF_FILE *file )
1133{
1134        /* free any zalloc()'d memory */
1135       
1136  /*    if ( file && file->mem_ctx )
1137                free(file->mem_ctx);
1138  */
1139}
1140
1141
1142/*******************************************************************
1143*******************************************************************/
1144int regfio_close( REGF_FILE *file )
1145{
1146        int fd;
1147
1148        regfio_mem_free( file );
1149
1150        /* nothing to do if there is no open file */
1151
1152        if ( !file || (file->fd == -1) )
1153                return 0;
1154               
1155        fd = file->fd;
1156        file->fd = -1;
1157        SAFE_FREE( file );
1158
1159        return close( fd );
1160}
1161
1162
1163/*******************************************************************
1164 There should be only *one* root key in the registry file based
1165 on my experience.  --jerry
1166*******************************************************************/
1167REGF_NK_REC* regfio_rootkey( REGF_FILE *file )
1168{
1169        REGF_NK_REC *nk;
1170        REGF_HBIN   *hbin;
1171        uint32      offset = REGF_BLOCKSIZE;
1172        bool        found = false;
1173        bool        eob;
1174       
1175        if ( !file )
1176                return NULL;
1177               
1178        if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
1179                DEBUG(0,("regfio_rootkey: zalloc() failed!\n"));
1180                return NULL;
1181        }
1182       
1183        /* scan through the file on HBIN block at a time looking
1184           for an NK record with a type == 0x002c.
1185           Normally this is the first nk record in the first hbin
1186           block (but I'm not assuming that for now) */
1187       
1188        while ( (hbin = read_hbin_block( file, offset )) ) {
1189                eob = false;
1190
1191                while ( !eob) {
1192                        if ( next_nk_record( file, hbin, nk, &eob ) ) {
1193                                if ( nk->key_type == NK_TYPE_ROOTKEY ) {
1194                                        found = true;
1195                                        break;
1196                                }
1197                        }
1198                        if(hbin->ps.is_dynamic)
1199                          SAFE_FREE(hbin->ps.data_p);
1200                        hbin->ps.is_dynamic = false;
1201                        hbin->ps.buffer_size = 0;
1202                        hbin->ps.data_offset = 0;
1203                }
1204               
1205                if ( found ) 
1206                        break;
1207
1208                offset += hbin->block_size;
1209        }
1210       
1211        if ( !found ) {
1212                DEBUG(0,("regfio_rootkey: corrupt registry file ?  No root key record located\n"));
1213                return NULL;
1214        }
1215
1216        DLIST_ADD( file->block_list, hbin );
1217
1218        return nk;             
1219}
1220
1221
1222/*******************************************************************
1223 This acts as an interator over the subkeys defined for a given
1224 NK record.  Remember that offsets are from the *first* HBIN block.
1225*******************************************************************/
1226REGF_NK_REC* regfio_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk )
1227{
1228        REGF_NK_REC *subkey;
1229        REGF_HBIN   *hbin;
1230        uint32      nk_offset;
1231
1232        /* see if there is anything left to report */
1233       
1234        if ( !nk || (nk->subkeys_off==REGF_OFFSET_NONE) || (nk->subkey_index >= nk->num_subkeys) )
1235                return NULL;
1236
1237        /* find the HBIN block which should contain the nk record */
1238       
1239        if ( !(hbin = lookup_hbin_block( file, nk->subkeys.hashes[nk->subkey_index].nk_off )) ) {
1240                DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n", 
1241                        nk->subkeys.hashes[nk->subkey_index].nk_off));
1242                return NULL;
1243        }
1244       
1245        nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off;
1246        if ( !prs_set_offset( &hbin->ps, (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off) ) )
1247                return NULL;
1248               
1249        nk->subkey_index++;
1250        if (!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
1251                return NULL;
1252
1253        if ( !hbin_prs_key( file, hbin, subkey ) )
1254                return NULL;
1255       
1256        return subkey;
1257}
Note: See TracBrowser for help on using the repository browser.