1/* 2 * Unix SMB/CIFS implementation. 3 * Windows NT registry I/O library 4 * Copyright (c) Gerald (Jerry) Carter 2005 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21#include "includes.h" 22#include "regfio.h" 23 24/******************************************************************* 25 * 26 * TODO : Right now this code basically ignores classnames. 27 * 28 ******************************************************************/ 29 30 31/******************************************************************* 32*******************************************************************/ 33 34static int write_block( REGF_FILE *file, prs_struct *ps, uint32 offset ) 35{ 36 int bytes_written, returned; 37 char *buffer = prs_data_p( ps ); 38 uint32 buffer_size = prs_data_size( ps ); 39 SMB_STRUCT_STAT sbuf; 40 41 if ( file->fd == -1 ) 42 return -1; 43 44 /* check for end of file */ 45 46 if ( sys_fstat( file->fd, &sbuf ) ) { 47 DEBUG(0,("write_block: stat() failed! (%s)\n", strerror(errno))); 48 return -1; 49 } 50 51 if ( lseek( file->fd, offset, SEEK_SET ) == -1 ) { 52 DEBUG(0,("write_block: lseek() failed! (%s)\n", strerror(errno) )); 53 return -1; 54 } 55 56 bytes_written = returned = 0; 57 while ( bytes_written < buffer_size ) { 58 if ( (returned = write( file->fd, buffer+bytes_written, buffer_size-bytes_written )) == -1 ) { 59 DEBUG(0,("write_block: write() failed! (%s)\n", strerror(errno) )); 60 return False; 61 } 62 63 bytes_written += returned; 64 } 65 66 return bytes_written; 67} 68 69/******************************************************************* 70*******************************************************************/ 71 72static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, uint32 block_size ) 73{ 74 int bytes_read, returned; 75 char *buffer; 76 SMB_STRUCT_STAT sbuf; 77 78 /* check for end of file */ 79 80 if ( sys_fstat( file->fd, &sbuf ) ) { 81 DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno))); 82 return -1; 83 } 84 85 if ( (size_t)file_offset >= sbuf.st_size ) 86 return -1; 87 88 /* if block_size == 0, we are parsing HBIN records and need 89 to read some of the header to get the block_size from there */ 90 91 if ( block_size == 0 ) { 92 char hdr[0x20]; 93 94 if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) { 95 DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) )); 96 return -1; 97 } 98 99 returned = read( file->fd, hdr, 0x20 ); 100 if ( (returned == -1) || (returned < 0x20) ) { 101 DEBUG(0,("read_block: failed to read in HBIN header. Is the file corrupt?\n")); 102 return -1; 103 } 104 105 /* make sure this is an hbin header */ 106 107 if ( strncmp( hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) { 108 DEBUG(0,("read_block: invalid block header!\n")); 109 return -1; 110 } 111 112 block_size = IVAL( hdr, 0x08 ); 113 } 114 115 DEBUG(10,("read_block: block_size == 0x%x\n", block_size )); 116 117 /* set the offset, initialize the buffer, and read the block from disk */ 118 119 if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) { 120 DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) )); 121 return -1; 122 } 123 124 prs_init( ps, block_size, file->mem_ctx, UNMARSHALL ); 125 buffer = prs_data_p( ps ); 126 bytes_read = returned = 0; 127 128 while ( bytes_read < block_size ) { 129 if ( (returned = read( file->fd, buffer+bytes_read, block_size-bytes_read )) == -1 ) { 130 DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) )); 131 return False; 132 } 133 if ( (returned == 0) && (bytes_read < block_size) ) { 134 DEBUG(0,("read_block: not a vald registry file ?\n" )); 135 return False; 136 } 137 138 bytes_read += returned; 139 } 140 141 return bytes_read; 142} 143 144/******************************************************************* 145*******************************************************************/ 146 147static BOOL write_hbin_block( REGF_FILE *file, REGF_HBIN *hbin ) 148{ 149 if ( !hbin->dirty ) 150 return True; 151 152 /* write free space record if any is available */ 153 154 if ( hbin->free_off != REGF_OFFSET_NONE ) { 155 uint32 header = 0xffffffff; 156 157 if ( !prs_set_offset( &hbin->ps, hbin->free_off-sizeof(uint32) ) ) 158 return False; 159 if ( !prs_uint32( "free_size", &hbin->ps, 0, &hbin->free_size ) ) 160 return False; 161 if ( !prs_uint32( "free_header", &hbin->ps, 0, &header ) ) 162 return False; 163 } 164 165 hbin->dirty = (write_block( file, &hbin->ps, hbin->file_off ) != -1); 166 167 return hbin->dirty; 168} 169 170/******************************************************************* 171*******************************************************************/ 172 173static BOOL hbin_block_close( REGF_FILE *file, REGF_HBIN *hbin ) 174{ 175 REGF_HBIN *p; 176 177 /* remove the block from the open list and flush it to disk */ 178 179 for ( p=file->block_list; p && p!=hbin; p=p->next ) 180 ;; 181 182 if ( p == hbin ) { 183 DLIST_REMOVE( file->block_list, hbin ); 184 } 185 else 186 DEBUG(0,("hbin_block_close: block not in open list!\n")); 187 188 if ( !write_hbin_block( file, hbin ) ) 189 return False; 190 191 return True; 192} 193 194/******************************************************************* 195*******************************************************************/ 196 197static BOOL prs_regf_block( const char *desc, prs_struct *ps, int depth, REGF_FILE *file ) 198{ 199 prs_debug(ps, depth, desc, "prs_regf_block"); 200 depth++; 201 202 if ( !prs_uint8s( True, "header", ps, depth, (uint8*)file->header, sizeof( file->header )) ) 203 return False; 204 205 /* yes, these values are always identical so store them only once */ 206 207 if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 )) 208 return False; 209 if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 )) 210 return False; 211 212 /* get the modtime */ 213 214 if ( !prs_set_offset( ps, 0x0c ) ) 215 return False; 216 if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) ) 217 return False; 218 219 /* constants */ 220 221 if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 )) 222 return False; 223 if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 )) 224 return False; 225 if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 )) 226 return False; 227 if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 )) 228 return False; 229 230 /* get file offsets */ 231 232 if ( !prs_set_offset( ps, 0x24 ) ) 233 return False; 234 if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset )) 235 return False; 236 if ( !prs_uint32( "last_block", ps, depth, &file->last_block )) 237 return False; 238 239 /* one more constant */ 240 241 if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 )) 242 return False; 243 244 /* get the checksum */ 245 246 if ( !prs_set_offset( ps, 0x01fc ) ) 247 return False; 248 if ( !prs_uint32( "checksum", ps, depth, &file->checksum )) 249 return False; 250 251 return True; 252} 253 254/******************************************************************* 255*******************************************************************/ 256 257static BOOL prs_hbin_block( const char *desc, prs_struct *ps, int depth, REGF_HBIN *hbin ) 258{ 259 uint32 block_size2; 260 261 prs_debug(ps, depth, desc, "prs_regf_block"); 262 depth++; 263 264 if ( !prs_uint8s( True, "header", ps, depth, (uint8*)hbin->header, sizeof( hbin->header )) ) 265 return False; 266 267 if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off )) 268 return False; 269 270 /* The dosreg.cpp comments say that the block size is at 0x1c. 271 According to a WINXP NTUSER.dat file, this is wrong. The block_size 272 is at 0x08 */ 273 274 if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size )) 275 return False; 276 277 block_size2 = hbin->block_size; 278 prs_set_offset( ps, 0x1c ); 279 if ( !prs_uint32( "block_size2", ps, depth, &block_size2 )) 280 return False; 281 282 if ( MARSHALLING(ps) ) 283 hbin->dirty = True; 284 285 286 return True; 287} 288 289/******************************************************************* 290*******************************************************************/ 291 292static BOOL prs_nk_rec( const char *desc, prs_struct *ps, int depth, REGF_NK_REC *nk ) 293{ 294 uint16 class_length, name_length; 295 uint32 start; 296 uint32 data_size, start_off, end_off; 297 uint32 unknown_off = REGF_OFFSET_NONE; 298 299 nk->hbin_off = prs_offset( ps ); 300 start = nk->hbin_off; 301 302 prs_debug(ps, depth, desc, "prs_nk_rec"); 303 depth++; 304 305 /* back up and get the data_size */ 306 307 if ( !prs_set_offset( ps, prs_offset(ps)-sizeof(uint32)) ) 308 return False; 309 start_off = prs_offset( ps ); 310 if ( !prs_uint32( "rec_size", ps, depth, &nk->rec_size )) 311 return False; 312 313 if ( !prs_uint8s( True, "header", ps, depth, (uint8*)nk->header, sizeof( nk->header )) ) 314 return False; 315 316 if ( !prs_uint16( "key_type", ps, depth, &nk->key_type )) 317 return False; 318 if ( !smb_io_time( "mtime", &nk->mtime, ps, depth )) 319 return False; 320 321 if ( !prs_set_offset( ps, start+0x0010 ) ) 322 return False; 323 if ( !prs_uint32( "parent_off", ps, depth, &nk->parent_off )) 324 return False; 325 if ( !prs_uint32( "num_subkeys", ps, depth, &nk->num_subkeys )) 326 return False; 327 328 if ( !prs_set_offset( ps, start+0x001c ) ) 329 return False; 330 if ( !prs_uint32( "subkeys_off", ps, depth, &nk->subkeys_off )) 331 return False; 332 if ( !prs_uint32( "unknown_off", ps, depth, &unknown_off) ) 333 return False; 334 335 if ( !prs_set_offset( ps, start+0x0024 ) ) 336 return False; 337 if ( !prs_uint32( "num_values", ps, depth, &nk->num_values )) 338 return False; 339 if ( !prs_uint32( "values_off", ps, depth, &nk->values_off )) 340 return False; 341 if ( !prs_uint32( "sk_off", ps, depth, &nk->sk_off )) 342 return False; 343 if ( !prs_uint32( "classname_off", ps, depth, &nk->classname_off )) 344 return False; 345 346 if ( !prs_uint32( "max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname)) 347 return False; 348 if ( !prs_uint32( "max_bytes_subkeyclassname", ps, depth, &nk->max_bytes_subkeyclassname)) 349 return False; 350 if ( !prs_uint32( "max_bytes_valuename", ps, depth, &nk->max_bytes_valuename)) 351 return False; 352 if ( !prs_uint32( "max_bytes_value", ps, depth, &nk->max_bytes_value)) 353 return False; 354 if ( !prs_uint32( "unknown index", ps, depth, &nk->unk_index)) 355 return False; 356 357 name_length = nk->keyname ? strlen(nk->keyname) : 0 ; 358 class_length = nk->classname ? strlen(nk->classname) : 0 ; 359 if ( !prs_uint16( "name_length", ps, depth, &name_length )) 360 return False; 361 if ( !prs_uint16( "class_length", ps, depth, &class_length )) 362 return False; 363 364 if ( class_length ) { 365 ;; 366 } 367 368 if ( name_length ) { 369 if ( UNMARSHALLING(ps) ) { 370 if ( !(nk->keyname = PRS_ALLOC_MEM( ps, char, name_length+1 )) ) 371 return False; 372 } 373 374 if ( !prs_uint8s( True, "name", ps, depth, (uint8*)nk->keyname, name_length) ) 375 return False; 376 377 if ( UNMARSHALLING(ps) ) 378 nk->keyname[name_length] = '\0'; 379 } 380 381 end_off = prs_offset( ps ); 382 383 /* data_size must be divisible by 8 and large enough to hold the original record */ 384 385 data_size = ((start_off - end_off) & 0xfffffff8 ); 386 if ( data_size > nk->rec_size ) 387 DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size)); 388 389 if ( MARSHALLING(ps) ) 390 nk->hbin->dirty = True; 391 392 return True; 393} 394 395/******************************************************************* 396*******************************************************************/ 397 398static uint32 regf_block_checksum( prs_struct *ps ) 399{ 400 char *buffer = prs_data_p( ps ); 401 uint32 checksum, x; 402 int i; 403 404 /* XOR of all bytes 0x0000 - 0x01FB */ 405 406 checksum = x = 0; 407 408 for ( i=0; i<0x01FB; i+=4 ) { 409 x = IVAL(buffer, i ); 410 checksum ^= x; 411 } 412 413 return checksum; 414} 415 416/******************************************************************* 417*******************************************************************/ 418 419static BOOL read_regf_block( REGF_FILE *file ) 420{ 421 prs_struct ps; 422 uint32 checksum; 423 424 /* grab the first block from the file */ 425 426 if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 ) 427 return False; 428 429 /* parse the block and verify the checksum */ 430 431 if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) 432 return False; 433 434 checksum = regf_block_checksum( &ps ); 435 436 prs_mem_free( &ps ); 437 438 if ( file->checksum != checksum ) { 439 DEBUG(0,("read_regf_block: invalid checksum\n" )); 440 return False; 441 } 442 443 return True; 444} 445 446/******************************************************************* 447*******************************************************************/ 448 449static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset ) 450{ 451 REGF_HBIN *hbin; 452 uint32 record_size, curr_off, block_size, header; 453 454 if ( !(hbin = TALLOC_ZERO_P(file->mem_ctx, REGF_HBIN)) ) 455 return NULL; 456 hbin->file_off = offset; 457 hbin->free_off = -1; 458 459 if ( read_block( file, &hbin->ps, offset, 0 ) == -1 ) 460 return NULL; 461 462 if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) ) 463 return NULL; 464 465 /* this should be the same thing as hbin->block_size but just in case */ 466 467 block_size = prs_data_size( &hbin->ps ); 468 469 /* Find the available free space offset. Always at the end, 470 so walk the record list and stop when you get to the end. 471 The end is defined by a record header of 0xffffffff. The 472 previous 4 bytes contains the amount of free space remaining 473 in the hbin block. */ 474 475 /* remember that the record_size is in the 4 bytes preceeding the record itself */ 476 477 if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) ) 478 return False; 479 480 record_size = 0; 481 header = 0; 482 curr_off = prs_offset( &hbin->ps ); 483 while ( header != 0xffffffff ) { 484 /* not done yet so reset the current offset to the 485 next record_size field */ 486 487 curr_off = curr_off+record_size; 488 489 /* for some reason the record_size of the last record in 490 an hbin block can extend past the end of the block 491 even though the record fits within the remaining 492 space....aaarrrgggghhhhhh */ 493 494 if ( curr_off >= block_size ) { 495 record_size = -1; 496 curr_off = -1; 497 break; 498 } 499 500 if ( !prs_set_offset( &hbin->ps, curr_off) ) 501 return False; 502 503 if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) ) 504 return False; 505 if ( !prs_uint32( "header", &hbin->ps, 0, &header ) ) 506 return False; 507 508 SMB_ASSERT( record_size != 0 ); 509 510 if ( record_size & 0x80000000 ) { 511 /* absolute_value(record_size) */ 512 record_size = (record_size ^ 0xffffffff) + 1; 513 } 514 } 515 516 /* save the free space offset */ 517 518 if ( header == 0xffffffff ) { 519 520 /* account for the fact that the curr_off is 4 bytes behind the actual 521 record header */ 522 523 hbin->free_off = curr_off + sizeof(uint32); 524 hbin->free_size = record_size; 525 } 526 527 DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off)); 528 529 if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE ) ) 530 return False; 531 532 return hbin; 533} 534 535/******************************************************************* 536 Input a random offset and receive the corresponding HBIN 537 block for it 538*******************************************************************/ 539 540static BOOL hbin_contains_offset( REGF_HBIN *hbin, uint32 offset ) 541{ 542 if ( !hbin ) 543 return False; 544 545 if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) ) 546 return True; 547 548 return False; 549} 550 551/******************************************************************* 552 Input a random offset and receive the corresponding HBIN 553 block for it 554*******************************************************************/ 555 556static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset ) 557{ 558 REGF_HBIN *hbin = NULL; 559 uint32 block_off; 560 561 /* start with the open list */ 562 563 for ( hbin=file->block_list; hbin; hbin=hbin->next ) { 564 DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%lx]\n", hbin->file_off, (unsigned long)hbin )); 565 if ( hbin_contains_offset( hbin, offset ) ) 566 return hbin; 567 } 568 569 if ( !hbin ) { 570 /* start at the beginning */ 571 572 block_off = REGF_BLOCKSIZE; 573 do { 574 /* cleanup before the next round */ 575 if ( hbin ) 576 prs_mem_free( &hbin->ps ); 577 578 hbin = read_hbin_block( file, block_off ); 579 580 if ( hbin ) 581 block_off = hbin->file_off + hbin->block_size; 582 583 } while ( hbin && !hbin_contains_offset( hbin, offset ) ); 584 } 585 586 if ( hbin ) 587 DLIST_ADD( file->block_list, hbin ); 588 589 return hbin; 590} 591 592/******************************************************************* 593*******************************************************************/ 594 595static BOOL prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash ) 596{ 597 prs_debug(ps, depth, desc, "prs_hash_rec"); 598 depth++; 599 600 if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off )) 601 return False; 602 if ( !prs_uint8s( True, "keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) ) 603 return False; 604 605 return True; 606} 607 608/******************************************************************* 609*******************************************************************/ 610 611static BOOL hbin_prs_lf_records( const char *desc, REGF_HBIN *hbin, int depth, REGF_NK_REC *nk ) 612{ 613 int i; 614 REGF_LF_REC *lf = &nk->subkeys; 615 uint32 data_size, start_off, end_off; 616 617 prs_debug(&hbin->ps, depth, desc, "prs_lf_records"); 618 depth++; 619 620 /* check if we have anything to do first */ 621 622 if ( nk->num_subkeys == 0 ) 623 return True; 624 625 /* move to the LF record */ 626 627 if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) ) 628 return False; 629 630 /* backup and get the data_size */ 631 632 if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) ) 633 return False; 634 start_off = prs_offset( &hbin->ps ); 635 if ( !prs_uint32( "rec_size", &hbin->ps, depth, &lf->rec_size )) 636 return False; 637 638 if ( !prs_uint8s( True, "header", &hbin->ps, depth, (uint8*)lf->header, sizeof( lf->header )) ) 639 return False; 640 641 if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys)) 642 return False; 643 644 if ( UNMARSHALLING(&hbin->ps) ) { 645 if (lf->num_keys) { 646 if ( !(lf->hashes = PRS_ALLOC_MEM( &hbin->ps, REGF_HASH_REC, lf->num_keys )) ) 647 return False; 648 } else { 649 lf->hashes = NULL; 650 } 651 } 652 653 for ( i=0; i<lf->num_keys; i++ ) { 654 if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) ) 655 return False; 656 } 657 658 end_off = prs_offset( &hbin->ps ); 659 660 /* data_size must be divisible by 8 and large enough to hold the original record */ 661 662 data_size = ((start_off - end_off) & 0xfffffff8 ); 663 if ( data_size > lf->rec_size ) 664 DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size)); 665 666 if ( MARSHALLING(&hbin->ps) ) 667 hbin->dirty = True; 668 669 return True; 670} 671 672/******************************************************************* 673*******************************************************************/ 674 675static BOOL hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk ) 676{ 677 prs_struct *ps = &hbin->ps; 678 uint16 tag = 0xFFFF; 679 uint32 data_size, start_off, end_off; 680 681 682 prs_debug(ps, depth, desc, "hbin_prs_sk_rec"); 683 depth++; 684 685 if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) ) 686 return False; 687 688 /* backup and get the data_size */ 689 690 if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) ) 691 return False; 692 start_off = prs_offset( &hbin->ps ); 693 if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size )) 694 return False; 695 696 if ( !prs_uint8s( True, "header", ps, depth, (uint8*)sk->header, sizeof( sk->header )) ) 697 return False; 698 if ( !prs_uint16( "tag", ps, depth, &tag)) 699 return False; 700 701 if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off)) 702 return False; 703 if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off)) 704 return False; 705 if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count)) 706 return False; 707 if ( !prs_uint32( "size", ps, depth, &sk->size)) 708 return False; 709 710 if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 711 return False; 712 713 end_off = prs_offset( &hbin->ps ); 714 715 /* data_size must be divisible by 8 and large enough to hold the original record */ 716 717 data_size = ((start_off - end_off) & 0xfffffff8 ); 718 if ( data_size > sk->rec_size ) 719 DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size)); 720 721 if ( MARSHALLING(&hbin->ps) ) 722 hbin->dirty = True; 723 724 return True; 725} 726 727/******************************************************************* 728*******************************************************************/ 729 730static BOOL hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_VK_REC *vk, REGF_FILE *file ) 731{ 732 uint32 offset; 733 uint16 name_length; 734 prs_struct *ps = &hbin->ps; 735 uint32 data_size, start_off, end_off; 736 737 prs_debug(ps, depth, desc, "prs_vk_rec"); 738 depth++; 739 740 /* backup and get the data_size */ 741 742 if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) ) 743 return False; 744 start_off = prs_offset( &hbin->ps ); 745 if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size )) 746 return False; 747 748 if ( !prs_uint8s( True, "header", ps, depth, (uint8*)vk->header, sizeof( vk->header )) ) 749 return False; 750 751 if ( MARSHALLING(&hbin->ps) ) 752 name_length = strlen(vk->valuename); 753 754 if ( !prs_uint16( "name_length", ps, depth, &name_length )) 755 return False; 756 if ( !prs_uint32( "data_size", ps, depth, &vk->data_size )) 757 return False; 758 if ( !prs_uint32( "data_off", ps, depth, &vk->data_off )) 759 return False; 760 if ( !prs_uint32( "type", ps, depth, &vk->type)) 761 return False; 762 if ( !prs_uint16( "flag", ps, depth, &vk->flag)) 763 return False; 764 765 offset = prs_offset( ps ); 766 offset += 2; /* skip 2 bytes */ 767 prs_set_offset( ps, offset ); 768 769 /* get the name */ 770 771 if ( vk->flag&VK_FLAG_NAME_PRESENT ) { 772 773 if ( UNMARSHALLING(&hbin->ps) ) { 774 if ( !(vk->valuename = PRS_ALLOC_MEM( ps, char, name_length+1 ))) 775 return False; 776 } 777 if ( !prs_uint8s( True, "name", ps, depth, (uint8*)vk->valuename, name_length ) ) 778 return False; 779 } 780 781 end_off = prs_offset( &hbin->ps ); 782 783 /* get the data if necessary */ 784 785 if ( vk->data_size != 0 ) { 786 BOOL charmode = False; 787 788 if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) ) 789 charmode = True; 790 791 /* the data is stored in the offset if the size <= 4 */ 792 793 if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) { 794 REGF_HBIN *hblock = hbin; 795 uint32 data_rec_size; 796 797 if ( UNMARSHALLING(&hbin->ps) ) { 798 if ( !(vk->data = PRS_ALLOC_MEM( ps, uint8, vk->data_size) ) ) 799 return False; 800 } 801 802 /* this data can be in another hbin */ 803 if ( !hbin_contains_offset( hbin, vk->data_off ) ) { 804 if ( !(hblock = lookup_hbin_block( file, vk->data_off )) ) 805 return False; 806 } 807 if ( !(prs_set_offset( &hblock->ps, (vk->data_off+HBIN_HDR_SIZE-hblock->first_hbin_off)-sizeof(uint32) )) ) 808 return False; 809 810 if ( MARSHALLING(&hblock->ps) ) { 811 data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8; 812 data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF; 813 } 814 if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size )) 815 return False; 816 if ( !prs_uint8s( charmode, "data", &hblock->ps, depth, vk->data, vk->data_size) ) 817 return False; 818 819 if ( MARSHALLING(&hblock->ps) ) 820 hblock->dirty = True; 821 } 822 else { 823 if ( !(vk->data = PRS_ALLOC_MEM( ps, uint8, 4 ) ) ) 824 return False; 825 SIVAL( vk->data, 0, vk->data_off ); 826 } 827 828 } 829 830 /* data_size must be divisible by 8 and large enough to hold the original record */ 831 832 data_size = ((start_off - end_off ) & 0xfffffff8 ); 833 if ( data_size != vk->rec_size ) 834 DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size)); 835 836 if ( MARSHALLING(&hbin->ps) ) 837 hbin->dirty = True; 838 839 return True; 840} 841 842/******************************************************************* 843 read a VK record which is contained in the HBIN block stored 844 in the prs_struct *ps. 845*******************************************************************/ 846 847static BOOL hbin_prs_vk_records( const char *desc, REGF_HBIN *hbin, int depth, REGF_NK_REC *nk, REGF_FILE *file ) 848{ 849 int i; 850 uint32 record_size; 851 852 prs_debug(&hbin->ps, depth, desc, "prs_vk_records"); 853 depth++; 854 855 /* check if we have anything to do first */ 856 857 if ( nk->num_values == 0 ) 858 return True; 859 860 if ( UNMARSHALLING(&hbin->ps) ) { 861 if ( !(nk->values = PRS_ALLOC_MEM( &hbin->ps, REGF_VK_REC, nk->num_values ) ) ) 862 return False; 863 } 864 865 /* convert the offset to something relative to this HBIN block */ 866 867 if ( !prs_set_offset( &hbin->ps, nk->values_off+HBIN_HDR_SIZE-hbin->first_hbin_off-sizeof(uint32)) ) 868 return False; 869 870 if ( MARSHALLING( &hbin->ps) ) { 871 record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8; 872 record_size = (record_size - 1) ^ 0xFFFFFFFF; 873 } 874 875 if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) ) 876 return False; 877 878 for ( i=0; i<nk->num_values; i++ ) { 879 if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) ) 880 return False; 881 } 882 883 for ( i=0; i<nk->num_values; i++ ) { 884 REGF_HBIN *sub_hbin = hbin; 885 uint32 new_offset; 886 887 if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) { 888 sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off ); 889 if ( !sub_hbin ) { 890 DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n", 891 nk->values[i].hbin_off)); 892 return False; 893 } 894 } 895 896 new_offset = nk->values[i].rec_off + HBIN_HDR_SIZE - sub_hbin->first_hbin_off; 897 if ( !prs_set_offset( &sub_hbin->ps, new_offset ) ) 898 return False; 899 if ( !hbin_prs_vk_rec( "vk_rec", sub_hbin, depth, &nk->values[i], file ) ) 900 return False; 901 } 902 903 if ( MARSHALLING(&hbin->ps) ) 904 hbin->dirty = True; 905 906 907 return True; 908} 909 910 911/******************************************************************* 912*******************************************************************/ 913 914static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset ) 915{ 916 REGF_SK_REC *p_sk; 917 918 for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) { 919 if ( p_sk->sk_off == offset ) 920 return p_sk; 921 } 922 923 return NULL; 924} 925 926/******************************************************************* 927*******************************************************************/ 928 929static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd ) 930{ 931 REGF_SK_REC *p; 932 933 for ( p=file->sec_desc_list; p; p=p->next ) { 934 if ( sec_desc_equal( p->sec_desc, sd ) ) 935 return p; 936 } 937 938 /* failure */ 939 940 return NULL; 941} 942 943/******************************************************************* 944*******************************************************************/ 945 946static BOOL hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk ) 947{ 948 int depth = 0; 949 REGF_HBIN *sub_hbin; 950 951 prs_debug(&hbin->ps, depth, "", "fetch_key"); 952 depth++; 953 954 /* get the initial nk record */ 955 956 if ( !prs_nk_rec( "nk_rec", &hbin->ps, depth, nk )) 957 return False; 958 959 /* fill in values */ 960 961 if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) { 962 sub_hbin = hbin; 963 if ( !hbin_contains_offset( hbin, nk->values_off ) ) { 964 sub_hbin = lookup_hbin_block( file, nk->values_off ); 965 if ( !sub_hbin ) { 966 DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n", 967 nk->values_off)); 968 return False; 969 } 970 } 971 972 if ( !hbin_prs_vk_records( "vk_rec", sub_hbin, depth, nk, file )) 973 return False; 974 } 975 976 /* now get subkeys */ 977 978 if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) { 979 sub_hbin = hbin; 980 if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) { 981 sub_hbin = lookup_hbin_block( file, nk->subkeys_off ); 982 if ( !sub_hbin ) { 983 DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n", 984 nk->subkeys_off)); 985 return False; 986 } 987 } 988 989 if ( !hbin_prs_lf_records( "lf_rec", sub_hbin, depth, nk )) 990 return False; 991 } 992 993 /* get the to the security descriptor. First look if we have already parsed it */ 994 995 if ( (nk->sk_off!=REGF_OFFSET_NONE) && !( nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )) ) { 996 997 sub_hbin = hbin; 998 if ( !hbin_contains_offset( hbin, nk->sk_off ) ) { 999 sub_hbin = lookup_hbin_block( file, nk->sk_off ); 1000 if ( !sub_hbin ) { 1001 DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n", 1002 nk->subkeys_off)); 1003 return False; 1004 } 1005 } 1006 1007 if ( !(nk->sec_desc = TALLOC_ZERO_P( file->mem_ctx, REGF_SK_REC )) ) 1008 return False; 1009 nk->sec_desc->sk_off = nk->sk_off; 1010 if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc )) 1011 return False; 1012 1013 /* add to the list of security descriptors (ref_count has been read from the files) */ 1014 1015 nk->sec_desc->sk_off = nk->sk_off; 1016 DLIST_ADD( file->sec_desc_list, nk->sec_desc ); 1017 } 1018 1019 return True; 1020} 1021 1022/******************************************************************* 1023*******************************************************************/ 1024 1025static BOOL next_record( REGF_HBIN *hbin, const char *hdr, BOOL *eob ) 1026{ 1027 uint8 header[REC_HDR_SIZE]; 1028 uint32 record_size; 1029 uint32 curr_off, block_size; 1030 BOOL found = False; 1031 prs_struct *ps = &hbin->ps; 1032 1033 curr_off = prs_offset( ps ); 1034 if ( curr_off == 0 ) 1035 prs_set_offset( ps, HBIN_HEADER_REC_SIZE ); 1036 1037 /* assume that the current offset is at the record header 1038 and we need to backup to read the record size */ 1039 1040 curr_off -= sizeof(uint32); 1041 1042 block_size = prs_data_size( ps ); 1043 record_size = 0; 1044 memset( header, 0x0, sizeof(uint8)*REC_HDR_SIZE ); 1045 while ( !found ) { 1046 1047 curr_off = curr_off+record_size; 1048 if ( curr_off >= block_size ) 1049 break; 1050 1051 if ( !prs_set_offset( &hbin->ps, curr_off) ) 1052 return False; 1053 1054 if ( !prs_uint32( "record_size", ps, 0, &record_size ) ) 1055 return False; 1056 if ( !prs_uint8s( True, "header", ps, 0, header, REC_HDR_SIZE ) ) 1057 return False; 1058 1059 if ( record_size & 0x80000000 ) { 1060 /* absolute_value(record_size) */ 1061 record_size = (record_size ^ 0xffffffff) + 1; 1062 } 1063 1064 if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) { 1065 found = True; 1066 curr_off += sizeof(uint32); 1067 } 1068 } 1069 1070 /* mark prs_struct as done ( at end ) if no more SK records */ 1071 /* mark end-of-block as True */ 1072 1073 if ( !found ) { 1074 prs_set_offset( &hbin->ps, prs_data_size(&hbin->ps) ); 1075 *eob = True; 1076 return False; 1077 } 1078 1079 if ( !prs_set_offset( ps, curr_off ) ) 1080 return False; 1081 1082 return True; 1083} 1084 1085/******************************************************************* 1086*******************************************************************/ 1087 1088static BOOL next_nk_record( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk, BOOL *eob ) 1089{ 1090 if ( next_record( hbin, "nk", eob ) && hbin_prs_key( file, hbin, nk ) ) 1091 return True; 1092 1093 return False; 1094} 1095 1096/******************************************************************* 1097 Intialize the newly created REGF_BLOCK in *file and write the 1098 block header to disk 1099*******************************************************************/ 1100 1101static BOOL init_regf_block( REGF_FILE *file ) 1102{ 1103 prs_struct ps; 1104 BOOL result = True; 1105 1106 if ( !prs_init( &ps, REGF_BLOCKSIZE, file->mem_ctx, MARSHALL ) ) 1107 return False; 1108 1109 memcpy( file->header, "regf", REGF_HDR_SIZE ); 1110 file->data_offset = 0x20; 1111 file->last_block = 0x1000; 1112 1113 /* set mod time */ 1114 1115 unix_to_nt_time( &file->mtime, time(NULL) ); 1116 1117 /* hard coded values...no diea what these are ... maybe in time */ 1118 1119 file->unknown1 = 0x2; 1120 file->unknown2 = 0x1; 1121 file->unknown3 = 0x3; 1122 file->unknown4 = 0x0; 1123 file->unknown5 = 0x1; 1124 file->unknown6 = 0x1; 1125 1126 /* write header to the buffer */ 1127 1128 if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) { 1129 result = False; 1130 goto out; 1131 } 1132 1133 /* calculate the checksum, re-marshall data (to include the checksum) 1134 and write to disk */ 1135 1136 file->checksum = regf_block_checksum( &ps ); 1137 prs_set_offset( &ps, 0 ); 1138 if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) { 1139 result = False; 1140 goto out; 1141 } 1142 1143 if ( write_block( file, &ps, 0 ) == -1 ) { 1144 DEBUG(0,("init_regf_block: Failed to initialize registry header block!\n")); 1145 result = False; 1146 goto out; 1147 } 1148 1149out: 1150 prs_mem_free( &ps ); 1151 1152 return result; 1153} 1154/******************************************************************* 1155 Open the registry file and then read in the REGF block to get the 1156 first hbin offset. 1157*******************************************************************/ 1158 1159 REGF_FILE* regfio_open( const char *filename, int flags, int mode ) 1160{ 1161 REGF_FILE *rb; 1162 1163 if ( !(rb = SMB_MALLOC_P(REGF_FILE)) ) { 1164 DEBUG(0,("ERROR allocating memory\n")); 1165 return NULL; 1166 } 1167 ZERO_STRUCTP( rb ); 1168 rb->fd = -1; 1169 1170 if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) ) { 1171 regfio_close( rb ); 1172 return NULL; 1173 } 1174 1175 rb->open_flags = flags; 1176 1177 /* open and existing file */ 1178 1179 if ( (rb->fd = open(filename, flags, mode)) == -1 ) { 1180 DEBUG(0,("regfio_open: failure to open %s (%s)\n", filename, strerror(errno))); 1181 regfio_close( rb ); 1182 return NULL; 1183 } 1184 1185 /* check if we are creating a new file or overwriting an existing one */ 1186 1187 if ( flags & (O_CREAT|O_TRUNC) ) { 1188 if ( !init_regf_block( rb ) ) { 1189 DEBUG(0,("regfio_open: Failed to read initial REGF block\n")); 1190 regfio_close( rb ); 1191 return NULL; 1192 } 1193 1194 /* success */ 1195 return rb; 1196 } 1197 1198 /* read in an existing file */ 1199 1200 if ( !read_regf_block( rb ) ) { 1201 DEBUG(0,("regfio_open: Failed to read initial REGF block\n")); 1202 regfio_close( rb ); 1203 return NULL; 1204 } 1205 1206 /* success */ 1207 1208 return rb; 1209} 1210 1211/******************************************************************* 1212*******************************************************************/ 1213 1214static void regfio_mem_free( REGF_FILE *file ) 1215{ 1216 /* free any talloc()'d memory */ 1217 1218 if ( file && file->mem_ctx ) 1219 talloc_destroy( file->mem_ctx ); 1220} 1221 1222/******************************************************************* 1223*******************************************************************/ 1224 1225 int regfio_close( REGF_FILE *file ) 1226{ 1227 int fd; 1228 1229 /* cleanup for a file opened for write */ 1230 1231 if ( file->open_flags & (O_WRONLY|O_RDWR) ) { 1232 prs_struct ps; 1233 REGF_SK_REC *sk; 1234 1235 /* write of sd list */ 1236 1237 for ( sk=file->sec_desc_list; sk; sk=sk->next ) { 1238 hbin_prs_sk_rec( "sk_rec", sk->hbin, 0, sk ); 1239 } 1240 1241 /* flush any dirty blocks */ 1242 1243 while ( file->block_list ) { 1244 hbin_block_close( file, file->block_list ); 1245 } 1246 1247 ZERO_STRUCT( ps ); 1248 1249 unix_to_nt_time( &file->mtime, time(NULL) ); 1250 1251 if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) != -1 ) { 1252 /* now use for writing */ 1253 prs_switch_type( &ps, MARSHALL ); 1254 1255 /* stream the block once, generate the checksum, 1256 and stream it again */ 1257 prs_set_offset( &ps, 0 ); 1258 prs_regf_block( "regf_blocK", &ps, 0, file ); 1259 file->checksum = regf_block_checksum( &ps ); 1260 prs_set_offset( &ps, 0 ); 1261 prs_regf_block( "regf_blocK", &ps, 0, file ); 1262 1263 /* now we are ready to write it to disk */ 1264 if ( write_block( file, &ps, 0 ) == -1 ) 1265 DEBUG(0,("regfio_close: failed to update the regf header block!\n")); 1266 } 1267 1268 prs_mem_free( &ps ); 1269 } 1270 1271 regfio_mem_free( file ); 1272 1273 /* nothing tdo do if there is no open file */ 1274 1275 if ( !file || (file->fd == -1) ) 1276 return 0; 1277 1278 fd = file->fd; 1279 file->fd = -1; 1280 SAFE_FREE( file ); 1281 1282 return close( fd ); 1283} 1284 1285/******************************************************************* 1286*******************************************************************/ 1287 1288static void regfio_flush( REGF_FILE *file ) 1289{ 1290 REGF_HBIN *hbin; 1291 1292 for ( hbin=file->block_list; hbin; hbin=hbin->next ) { 1293 write_hbin_block( file, hbin ); 1294 } 1295} 1296 1297/******************************************************************* 1298 There should be only *one* root key in the registry file based 1299 on my experience. --jerry 1300*******************************************************************/ 1301 1302REGF_NK_REC* regfio_rootkey( REGF_FILE *file ) 1303{ 1304 REGF_NK_REC *nk; 1305 REGF_HBIN *hbin; 1306 uint32 offset = REGF_BLOCKSIZE; 1307 BOOL found = False; 1308 BOOL eob; 1309 1310 if ( !file ) 1311 return NULL; 1312 1313 if ( !(nk = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) ) { 1314 DEBUG(0,("regfio_rootkey: talloc() failed!\n")); 1315 return NULL; 1316 } 1317 1318 /* scan through the file on HBIN block at a time looking 1319 for an NK record with a type == 0x002c. 1320 Normally this is the first nk record in the first hbin 1321 block (but I'm not assuming that for now) */ 1322 1323 while ( (hbin = read_hbin_block( file, offset )) ) { 1324 eob = False; 1325 1326 while ( !eob) { 1327 if ( next_nk_record( file, hbin, nk, &eob ) ) { 1328 if ( nk->key_type == NK_TYPE_ROOTKEY ) { 1329 found = True; 1330 break; 1331 } 1332 } 1333 prs_mem_free( &hbin->ps ); 1334 } 1335 1336 if ( found ) 1337 break; 1338 1339 offset += hbin->block_size; 1340 } 1341 1342 if ( !found ) { 1343 DEBUG(0,("regfio_rootkey: corrupt registry file ? No root key record located\n")); 1344 return NULL; 1345 } 1346 1347 DLIST_ADD( file->block_list, hbin ); 1348 1349 return nk; 1350} 1351 1352/******************************************************************* 1353 This acts as an interator over the subkeys defined for a given 1354 NK record. Remember that offsets are from the *first* HBIN block. 1355*******************************************************************/ 1356 1357 REGF_NK_REC* regfio_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk ) 1358{ 1359 REGF_NK_REC *subkey; 1360 REGF_HBIN *hbin; 1361 uint32 nk_offset; 1362 1363 /* see if there is anything left to report */ 1364 1365 if ( !nk || (nk->subkeys_off==REGF_OFFSET_NONE) || (nk->subkey_index >= nk->num_subkeys) ) 1366 return NULL; 1367 1368 /* find the HBIN block which should contain the nk record */ 1369 1370 if ( !(hbin = lookup_hbin_block( file, nk->subkeys.hashes[nk->subkey_index].nk_off )) ) { 1371 DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n", 1372 nk->subkeys.hashes[nk->subkey_index].nk_off)); 1373 return NULL; 1374 } 1375 1376 nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off; 1377 if ( !prs_set_offset( &hbin->ps, (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off) ) ) 1378 return NULL; 1379 1380 nk->subkey_index++; 1381 if ( !(subkey = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) ) 1382 return NULL; 1383 1384 if ( !hbin_prs_key( file, hbin, subkey ) ) 1385 return NULL; 1386 1387 return subkey; 1388} 1389 1390 1391/******************************************************************* 1392*******************************************************************/ 1393 1394static REGF_HBIN* regf_hbin_allocate( REGF_FILE *file, uint32 block_size ) 1395{ 1396 REGF_HBIN *hbin; 1397 SMB_STRUCT_STAT sbuf; 1398 1399 if ( !(hbin = TALLOC_ZERO_P( file->mem_ctx, REGF_HBIN )) ) 1400 return NULL; 1401 1402 memcpy( hbin->header, "hbin", sizeof(HBIN_HDR_SIZE) ); 1403 1404 1405 if ( sys_fstat( file->fd, &sbuf ) ) { 1406 DEBUG(0,("regf_hbin_allocate: stat() failed! (%s)\n", strerror(errno))); 1407 return NULL; 1408 } 1409 1410 hbin->file_off = sbuf.st_size; 1411 1412 hbin->free_off = HBIN_HEADER_REC_SIZE; 1413 hbin->free_size = block_size - hbin->free_off + sizeof(uint32);; 1414 1415 hbin->block_size = block_size; 1416 hbin->first_hbin_off = hbin->file_off - REGF_BLOCKSIZE; 1417 1418 if ( !prs_init( &hbin->ps, block_size, file->mem_ctx, MARSHALL ) ) 1419 return NULL; 1420 1421 if ( !prs_hbin_block( "new_hbin", &hbin->ps, 0, hbin ) ) 1422 return NULL; 1423 1424 if ( !write_hbin_block( file, hbin ) ) 1425 return NULL; 1426 1427 file->last_block = hbin->file_off; 1428 1429 return hbin; 1430} 1431 1432/******************************************************************* 1433*******************************************************************/ 1434 1435static void update_free_space( REGF_HBIN *hbin, uint32 size_used ) 1436{ 1437 hbin->free_off += size_used; 1438 hbin->free_size -= size_used; 1439 1440 if ( hbin->free_off >= hbin->block_size ) { 1441 hbin->free_off = REGF_OFFSET_NONE; 1442 } 1443 1444 return; 1445} 1446 1447/******************************************************************* 1448*******************************************************************/ 1449 1450static REGF_HBIN* find_free_space( REGF_FILE *file, uint32 size ) 1451{ 1452 REGF_HBIN *hbin, *p_hbin; 1453 uint32 block_off; 1454 BOOL cached; 1455 1456 /* check open block list */ 1457 1458 for ( hbin=file->block_list; hbin!=NULL; hbin=hbin->next ) { 1459 /* only check blocks that actually have available space */ 1460 1461 if ( hbin->free_off == REGF_OFFSET_NONE ) 1462 continue; 1463 1464 /* check for a large enough available chunk */ 1465 1466 if ( (hbin->block_size - hbin->free_off) >= size ) { 1467 DLIST_PROMOTE( file->block_list, hbin ); 1468 goto done; 1469 } 1470 } 1471 1472 /* parse the file until we find a block with 1473 enough free space; save the last non-filled hbin */ 1474 1475 block_off = REGF_BLOCKSIZE; 1476 do { 1477 /* cleanup before the next round */ 1478 cached = False; 1479 if ( hbin ) 1480 prs_mem_free( &hbin->ps ); 1481 1482 hbin = read_hbin_block( file, block_off ); 1483 1484 if ( hbin ) { 1485 1486 /* make sure that we don't already have this block in memory */ 1487 1488 for ( p_hbin=file->block_list; p_hbin!=NULL; p_hbin=p_hbin->next ) { 1489 if ( p_hbin->file_off == hbin->file_off ) { 1490 cached = True; 1491 break; 1492 } 1493 } 1494 1495 block_off = hbin->file_off + hbin->block_size; 1496 1497 if ( cached ) { 1498 prs_mem_free( &hbin->ps ); 1499 hbin = NULL; 1500 continue; 1501 } 1502 } 1503 /* if (cached block or (new block and not enough free space)) then continue looping */ 1504 } while ( cached || (hbin && (hbin->free_size < size)) ); 1505 1506 /* no free space; allocate a new one */ 1507 1508 if ( !hbin ) { 1509 uint32 alloc_size; 1510 1511 /* allocate in multiples of REGF_ALLOC_BLOCK; make sure (size + hbin_header) fits */ 1512 1513 alloc_size = (((size+HBIN_HEADER_REC_SIZE) / REGF_ALLOC_BLOCK ) + 1 ) * REGF_ALLOC_BLOCK; 1514 1515 if ( !(hbin = regf_hbin_allocate( file, alloc_size )) ) { 1516 DEBUG(0,("find_free_space: regf_hbin_allocate() failed!\n")); 1517 return NULL; 1518 } 1519 DLIST_ADD( file->block_list, hbin ); 1520 } 1521 1522done: 1523 /* set the offset to be ready to write */ 1524 1525 if ( !prs_set_offset( &hbin->ps, hbin->free_off-sizeof(uint32) ) ) 1526 return NULL; 1527 1528 /* write the record size as a placeholder for now, it should be 1529 probably updated by the caller once it all of the data necessary 1530 for the record */ 1531 1532 if ( !prs_uint32("allocated_size", &hbin->ps, 0, &size) ) 1533 return False; 1534 1535 update_free_space( hbin, size ); 1536 1537 return hbin; 1538} 1539 1540/******************************************************************* 1541*******************************************************************/ 1542 1543static uint32 sk_record_data_size( SEC_DESC * sd ) 1544{ 1545 uint32 size, size_mod8; 1546 1547 size_mod8 = 0; 1548 1549 /* the record size is sizeof(hdr) + name + static members + data_size_field */ 1550 1551 size = sizeof(uint32)*5 + sec_desc_size( sd ) + sizeof(uint32); 1552 1553 /* multiple of 8 */ 1554 size_mod8 = size & 0xfffffff8; 1555 if ( size_mod8 < size ) 1556 size_mod8 += 8; 1557 1558 return size_mod8; 1559} 1560 1561/******************************************************************* 1562*******************************************************************/ 1563 1564static uint32 vk_record_data_size( REGF_VK_REC *vk ) 1565{ 1566 uint32 size, size_mod8; 1567 1568 size_mod8 = 0; 1569 1570 /* the record size is sizeof(hdr) + name + static members + data_size_field */ 1571 1572 size = REC_HDR_SIZE + (sizeof(uint16)*3) + (sizeof(uint32)*3) + sizeof(uint32); 1573 1574 if ( vk->valuename ) 1575 size += strlen(vk->valuename); 1576 1577 /* multiple of 8 */ 1578 size_mod8 = size & 0xfffffff8; 1579 if ( size_mod8 < size ) 1580 size_mod8 += 8; 1581 1582 return size_mod8; 1583} 1584 1585/******************************************************************* 1586*******************************************************************/ 1587 1588static uint32 lf_record_data_size( uint32 num_keys ) 1589{ 1590 uint32 size, size_mod8; 1591 1592 size_mod8 = 0; 1593 1594 /* the record size is sizeof(hdr) + num_keys + sizeof of hash_array + data_size_uint32 */ 1595 1596 size = REC_HDR_SIZE + sizeof(uint16) + (sizeof(REGF_HASH_REC) * num_keys) + sizeof(uint32); 1597 1598 /* multiple of 8 */ 1599 size_mod8 = size & 0xfffffff8; 1600 if ( size_mod8 < size ) 1601 size_mod8 += 8; 1602 1603 return size_mod8; 1604} 1605 1606/******************************************************************* 1607*******************************************************************/ 1608 1609static uint32 nk_record_data_size( REGF_NK_REC *nk ) 1610{ 1611 uint32 size, size_mod8; 1612 1613 size_mod8 = 0; 1614 1615 /* the record size is static + length_of_keyname + length_of_classname + data_size_uint32 */ 1616 1617 size = 0x4c + strlen(nk->keyname) + sizeof(uint32); 1618 1619 if ( nk->classname ) 1620 size += strlen( nk->classname ); 1621 1622 /* multiple of 8 */ 1623 size_mod8 = size & 0xfffffff8; 1624 if ( size_mod8 < size ) 1625 size_mod8 += 8; 1626 1627 return size_mod8; 1628} 1629 1630/******************************************************************* 1631*******************************************************************/ 1632 1633static BOOL create_vk_record( REGF_FILE *file, REGF_VK_REC *vk, REGISTRY_VALUE *value ) 1634{ 1635 char *name = regval_name(value); 1636 REGF_HBIN *data_hbin; 1637 1638 ZERO_STRUCTP( vk ); 1639 1640 memcpy( vk->header, "vk", REC_HDR_SIZE ); 1641 1642 if ( name ) { 1643 vk->valuename = talloc_strdup( file->mem_ctx, regval_name(value) ); 1644 vk->flag = VK_FLAG_NAME_PRESENT; 1645 } 1646 1647 vk->data_size = regval_size( value ); 1648 vk->type = regval_type( value ); 1649 1650 if ( vk->data_size > sizeof(uint32) ) { 1651 uint32 data_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8; 1652 1653 vk->data = (uint8 *)TALLOC_MEMDUP( file->mem_ctx, 1654 regval_data_p(value), 1655 vk->data_size ); 1656 if (vk->data == NULL) { 1657 return False; 1658 } 1659 1660 /* go ahead and store the offset....we'll pick this hbin block back up when 1661 we stream the data */ 1662 1663 if ((data_hbin = find_free_space(file, data_size )) == NULL) { 1664 return False; 1665 } 1666 vk->data_off = prs_offset( &data_hbin->ps ) + data_hbin->first_hbin_off - HBIN_HDR_SIZE; 1667 } 1668 else { 1669 /* make sure we don't try to copy from a NULL value pointer */ 1670 1671 if ( vk->data_size != 0 ) 1672 memcpy( &vk->data_off, regval_data_p(value), sizeof(uint32) ); 1673 vk->data_size |= VK_DATA_IN_OFFSET; 1674 } 1675 1676 return True; 1677} 1678 1679/******************************************************************* 1680*******************************************************************/ 1681 1682static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 ) 1683{ 1684 return StrCaseCmp( h1->fullname, h2->fullname ); 1685} 1686 1687/******************************************************************* 1688*******************************************************************/ 1689 1690 REGF_NK_REC* regfio_write_key( REGF_FILE *file, const char *name, 1691 REGVAL_CTR *values, REGSUBKEY_CTR *subkeys, 1692 SEC_DESC *sec_desc, REGF_NK_REC *parent ) 1693{ 1694 REGF_NK_REC *nk; 1695 REGF_HBIN *vlist_hbin = NULL; 1696 uint32 size; 1697 1698 if ( !(nk = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) ) 1699 return NULL; 1700 1701 memcpy( nk->header, "nk", REC_HDR_SIZE ); 1702 1703 if ( !parent ) 1704 nk->key_type = NK_TYPE_ROOTKEY; 1705 else 1706 nk->key_type = NK_TYPE_NORMALKEY; 1707 1708 /* store the parent offset (or -1 if a the root key */ 1709 1710 nk->parent_off = parent ? (parent->hbin_off + parent->hbin->file_off - REGF_BLOCKSIZE - HBIN_HDR_SIZE ) : REGF_OFFSET_NONE; 1711 1712 /* no classname currently */ 1713 1714 nk->classname_off = REGF_OFFSET_NONE; 1715 nk->classname = NULL; 1716 nk->keyname = talloc_strdup( file->mem_ctx, name ); 1717 1718 /* current modification time */ 1719 1720 unix_to_nt_time( &nk->mtime, time(NULL) ); 1721 1722 /* allocate the record on disk */ 1723 1724 size = nk_record_data_size( nk ); 1725 nk->rec_size = ( size - 1 ) ^ 0XFFFFFFFF; 1726 if ((nk->hbin = find_free_space( file, size )) == NULL) { 1727 return NULL; 1728 } 1729 nk->hbin_off = prs_offset( &nk->hbin->ps ); 1730 1731 /* Update the hash record in the parent */ 1732 1733 if ( parent ) { 1734 REGF_HASH_REC *hash = &parent->subkeys.hashes[parent->subkey_index]; 1735 1736 hash->nk_off = prs_offset( &nk->hbin->ps ) + nk->hbin->first_hbin_off - HBIN_HDR_SIZE; 1737 memcpy( hash->keycheck, name, sizeof(uint32) ); 1738 hash->fullname = talloc_strdup( file->mem_ctx, name ); 1739 parent->subkey_index++; 1740 1741 /* sort the list by keyname */ 1742 1743 qsort( parent->subkeys.hashes, parent->subkey_index, sizeof(REGF_HASH_REC), QSORT_CAST hashrec_cmp ); 1744 1745 if ( !hbin_prs_lf_records( "lf_rec", parent->subkeys.hbin, 0, parent ) ) 1746 return False; 1747 } 1748 1749 /* write the security descriptor */ 1750 1751 nk->sk_off = REGF_OFFSET_NONE; 1752 if ( sec_desc ) { 1753 uint32 sk_size = sk_record_data_size( sec_desc ); 1754 REGF_HBIN *sk_hbin; 1755 1756 /* search for it in the existing list of sd's */ 1757 1758 if ( (nk->sec_desc = find_sk_record_by_sec_desc( file, sec_desc )) == NULL ) { 1759 /* not found so add it to the list */ 1760 1761 if (!(sk_hbin = find_free_space( file, sk_size ))) { 1762 return NULL; 1763 } 1764 1765 if ( !(nk->sec_desc = TALLOC_ZERO_P( file->mem_ctx, REGF_SK_REC )) ) 1766 return NULL; 1767 1768 /* now we have to store the security descriptor in the list and 1769 update the offsets */ 1770 1771 memcpy( nk->sec_desc->header, "sk", REC_HDR_SIZE ); 1772 nk->sec_desc->hbin = sk_hbin; 1773 nk->sec_desc->hbin_off = prs_offset( &sk_hbin->ps ); 1774 nk->sec_desc->sk_off = prs_offset( &sk_hbin->ps ) + sk_hbin->first_hbin_off - HBIN_HDR_SIZE; 1775 nk->sec_desc->rec_size = (sk_size-1) ^ 0xFFFFFFFF; 1776 1777 nk->sec_desc->sec_desc = sec_desc; 1778 nk->sec_desc->ref_count = 0; 1779 1780 /* size value must be self-inclusive */ 1781 nk->sec_desc->size = sec_desc_size(sec_desc) + sizeof(uint32); 1782 1783 DLIST_ADD_END( file->sec_desc_list, nk->sec_desc, REGF_SK_REC *); 1784 1785 /* update the offsets for us and the previous sd in the list. 1786 if this is the first record, then just set the next and prev 1787 offsets to ourself. */ 1788 1789 if ( nk->sec_desc->prev ) { 1790 REGF_SK_REC *prev = nk->sec_desc->prev; 1791 1792 nk->sec_desc->prev_sk_off = prev->hbin_off + prev->hbin->first_hbin_off - HBIN_HDR_SIZE; 1793 prev->next_sk_off = nk->sec_desc->sk_off; 1794 1795 /* the end must loop around to the front */ 1796 nk->sec_desc->next_sk_off = file->sec_desc_list->sk_off; 1797 1798 /* and first must loop around to the tail */ 1799 file->sec_desc_list->prev_sk_off = nk->sec_desc->sk_off; 1800 } else { 1801 nk->sec_desc->prev_sk_off = nk->sec_desc->sk_off; 1802 nk->sec_desc->next_sk_off = nk->sec_desc->sk_off; 1803 } 1804 } 1805 1806 /* bump the reference count +1 */ 1807 1808 nk->sk_off = nk->sec_desc->sk_off; 1809 nk->sec_desc->ref_count++; 1810 } 1811 1812 /* write the subkeys */ 1813 1814 nk->subkeys_off = REGF_OFFSET_NONE; 1815 if ( (nk->num_subkeys = regsubkey_ctr_numkeys( subkeys )) != 0 ) { 1816 uint32 lf_size = lf_record_data_size( nk->num_subkeys ); 1817 uint32 namelen; 1818 int i; 1819 1820 if (!(nk->subkeys.hbin = find_free_space( file, lf_size ))) { 1821 return NULL; 1822 } 1823 nk->subkeys.hbin_off = prs_offset( &nk->subkeys.hbin->ps ); 1824 nk->subkeys.rec_size = (lf_size-1) ^ 0xFFFFFFFF; 1825 nk->subkeys_off = prs_offset( &nk->subkeys.hbin->ps ) + nk->subkeys.hbin->first_hbin_off - HBIN_HDR_SIZE; 1826 1827 memcpy( nk->subkeys.header, "lf", REC_HDR_SIZE ); 1828 1829 nk->subkeys.num_keys = nk->num_subkeys; 1830 if (nk->subkeys.num_keys) { 1831 if ( !(nk->subkeys.hashes = TALLOC_ZERO_ARRAY( file->mem_ctx, REGF_HASH_REC, nk->subkeys.num_keys )) ) 1832 return NULL; 1833 } else { 1834 nk->subkeys.hashes = NULL; 1835 } 1836 nk->subkey_index = 0; 1837 1838 /* update the max_bytes_subkey{name,classname} fields */ 1839 for ( i=0; i<nk->num_subkeys; i++ ) { 1840 namelen = strlen( regsubkey_ctr_specific_key(subkeys, i) ); 1841 if ( namelen*2 > nk->max_bytes_subkeyname ) 1842 nk->max_bytes_subkeyname = namelen * 2; 1843 } 1844 } 1845 1846 /* write the values */ 1847 1848 nk->values_off = REGF_OFFSET_NONE; 1849 if ( (nk->num_values = regval_ctr_numvals( values )) != 0 ) { 1850 uint32 vlist_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8; 1851 int i; 1852 1853 if (!(vlist_hbin = find_free_space( file, vlist_size ))) { 1854 return NULL; 1855 } 1856 nk->values_off = prs_offset( &vlist_hbin->ps ) + vlist_hbin->first_hbin_off - HBIN_HDR_SIZE; 1857 1858 if (nk->num_values) { 1859 if ( !(nk->values = TALLOC_ARRAY( file->mem_ctx, REGF_VK_REC, nk->num_values )) ) 1860 return NULL; 1861 } else { 1862 nk->values = NULL; 1863 } 1864 1865 /* create the vk records */ 1866 1867 for ( i=0; i<nk->num_values; i++ ) { 1868 uint32 vk_size, namelen, datalen; 1869 REGISTRY_VALUE *r; 1870 1871 r = regval_ctr_specific_value( values, i ); 1872 create_vk_record( file, &nk->values[i], r ); 1873 vk_size = vk_record_data_size( &nk->values[i] ); 1874 nk->values[i].hbin = find_free_space( file, vk_size ); 1875 nk->values[i].hbin_off = prs_offset( &nk->values[i].hbin->ps ); 1876 nk->values[i].rec_size = ( vk_size - 1 ) ^ 0xFFFFFFFF; 1877 nk->values[i].rec_off = prs_offset( &nk->values[i].hbin->ps ) 1878 + nk->values[i].hbin->first_hbin_off 1879 - HBIN_HDR_SIZE; 1880 1881 /* update the max bytes fields if necessary */ 1882 1883 namelen = strlen( regval_name(r) ); 1884 if ( namelen*2 > nk->max_bytes_valuename ) 1885 nk->max_bytes_valuename = namelen * 2; 1886 1887 datalen = regval_size( r ); 1888 if ( datalen > nk->max_bytes_value ) 1889 nk->max_bytes_value = datalen; 1890 } 1891 } 1892 1893 /* stream the records */ 1894 1895 prs_set_offset( &nk->hbin->ps, nk->hbin_off ); 1896 if ( !prs_nk_rec( "nk_rec", &nk->hbin->ps, 0, nk ) ) 1897 return False; 1898 1899 if ( nk->num_values ) { 1900 if ( !hbin_prs_vk_records( "vk_records", vlist_hbin, 0, nk, file ) ) 1901 return False; 1902 } 1903 1904 1905 regfio_flush( file ); 1906 1907 return nk; 1908} 1909 1910