LCOV - code coverage report
Current view: top level - source3/registry - regfio.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 466 992 47.0 %
Date: 2024-02-28 12:06:22 Functions: 25 40 62.5 %

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

Generated by: LCOV version 1.14