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