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