source: releases/0.2/lib/regfio.c@ 209

Last change on this file since 209 was 41, checked in by tim, 20 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.