~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/registry/regfio.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
34
 
static 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
 
 
72
 
static 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
 
 
147
 
static 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
 
 
173
 
static 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
 
 
197
 
static 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
 
 
257
 
static 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
 
 
292
 
static 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
 
 
398
 
static 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
 
 
419
 
static 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
 
 
449
 
static 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
 
 
540
 
static 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
 
 
556
 
static 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
 
 
595
 
static 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
 
 
611
 
static 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->hashes = PRS_ALLOC_MEM( &hbin->ps, REGF_HASH_REC, lf->num_keys )) )
646
 
                        return False;
647
 
        }
648
 
 
649
 
        for ( i=0; i<lf->num_keys; i++ ) {
650
 
                if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) )
651
 
                        return False;
652
 
        }
653
 
 
654
 
        end_off = prs_offset( &hbin->ps );
655
 
 
656
 
        /* data_size must be divisible by 8 and large enough to hold the original record */
657
 
 
658
 
        data_size = ((start_off - end_off) & 0xfffffff8 );
659
 
        if ( data_size > lf->rec_size )
660
 
                DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));
661
 
 
662
 
        if ( MARSHALLING(&hbin->ps) )
663
 
                hbin->dirty = True;
664
 
 
665
 
        return True;
666
 
}
667
 
 
668
 
/*******************************************************************
669
 
*******************************************************************/
670
 
 
671
 
static BOOL hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
672
 
{
673
 
        prs_struct *ps = &hbin->ps;
674
 
        uint16 tag = 0xFFFF;
675
 
        uint32 data_size, start_off, end_off;
676
 
 
677
 
 
678
 
        prs_debug(ps, depth, desc, "hbin_prs_sk_rec");
679
 
        depth++;
680
 
 
681
 
        if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
682
 
                return False;
683
 
 
684
 
        /* backup and get the data_size */
685
 
        
686
 
        if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) )
687
 
                return False;
688
 
        start_off = prs_offset( &hbin->ps );
689
 
        if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size ))
690
 
                return False;
691
 
 
692
 
        if ( !prs_uint8s( True, "header", ps, depth, (uint8*)sk->header, sizeof( sk->header )) )
693
 
                return False;
694
 
        if ( !prs_uint16( "tag", ps, depth, &tag))
695
 
                return False;
696
 
 
697
 
        if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off))
698
 
                return False;
699
 
        if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off))
700
 
                return False;
701
 
        if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count))
702
 
                return False;
703
 
        if ( !prs_uint32( "size", ps, depth, &sk->size))
704
 
                return False;
705
 
 
706
 
        if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 
707
 
                return False;
708
 
 
709
 
        end_off = prs_offset( &hbin->ps );
710
 
 
711
 
        /* data_size must be divisible by 8 and large enough to hold the original record */
712
 
 
713
 
        data_size = ((start_off - end_off) & 0xfffffff8 );
714
 
        if ( data_size > sk->rec_size )
715
 
                DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));
716
 
 
717
 
        if ( MARSHALLING(&hbin->ps) )
718
 
                hbin->dirty = True;
719
 
 
720
 
        return True;
721
 
}
722
 
 
723
 
/*******************************************************************
724
 
*******************************************************************/
725
 
 
726
 
static BOOL hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_VK_REC *vk, REGF_FILE *file )
727
 
{
728
 
        uint32 offset;
729
 
        uint16 name_length;
730
 
        prs_struct *ps = &hbin->ps;
731
 
        uint32 data_size, start_off, end_off;
732
 
 
733
 
        prs_debug(ps, depth, desc, "prs_vk_rec");
734
 
        depth++;
735
 
 
736
 
        /* backup and get the data_size */
737
 
        
738
 
        if ( !prs_set_offset( &hbin->ps, prs_offset(&hbin->ps)-sizeof(uint32)) )
739
 
                return False;
740
 
        start_off = prs_offset( &hbin->ps );
741
 
        if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size ))
742
 
                return False;
743
 
 
744
 
        if ( !prs_uint8s( True, "header", ps, depth, (uint8*)vk->header, sizeof( vk->header )) )
745
 
                return False;
746
 
 
747
 
        if ( MARSHALLING(&hbin->ps) )
748
 
                name_length = strlen(vk->valuename);
749
 
 
750
 
        if ( !prs_uint16( "name_length", ps, depth, &name_length ))
751
 
                return False;
752
 
        if ( !prs_uint32( "data_size", ps, depth, &vk->data_size ))
753
 
                return False;
754
 
        if ( !prs_uint32( "data_off", ps, depth, &vk->data_off ))
755
 
                return False;
756
 
        if ( !prs_uint32( "type", ps, depth, &vk->type))
757
 
                return False;
758
 
        if ( !prs_uint16( "flag", ps, depth, &vk->flag))
759
 
                return False;
760
 
 
761
 
        offset = prs_offset( ps );
762
 
        offset += 2;    /* skip 2 bytes */
763
 
        prs_set_offset( ps, offset );
764
 
 
765
 
        /* get the name */
766
 
 
767
 
        if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
768
 
 
769
 
                if ( UNMARSHALLING(&hbin->ps) ) {
770
 
                        if ( !(vk->valuename = PRS_ALLOC_MEM( ps, char, name_length+1 )))
771
 
                                return False;
772
 
                }
773
 
                if ( !prs_uint8s( True, "name", ps, depth, (uint8*)vk->valuename, name_length ) )
774
 
                        return False;
775
 
        }
776
 
 
777
 
        end_off = prs_offset( &hbin->ps );
778
 
 
779
 
        /* get the data if necessary */
780
 
 
781
 
        if ( vk->data_size != 0 ) {
782
 
                BOOL charmode = False;
783
 
 
784
 
                if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
785
 
                        charmode = True;
786
 
 
787
 
                /* the data is stored in the offset if the size <= 4 */
788
 
 
789
 
                if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) {
790
 
                        REGF_HBIN *hblock = hbin;
791
 
                        uint32 data_rec_size;
792
 
 
793
 
                        if ( UNMARSHALLING(&hbin->ps) ) {
794
 
                                if ( !(vk->data = PRS_ALLOC_MEM( ps, uint8, vk->data_size) ) )
795
 
                                        return False;
796
 
                        }
797
 
 
798
 
                        /* this data can be in another hbin */
799
 
                        if ( !hbin_contains_offset( hbin, vk->data_off ) ) {
800
 
                                if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
801
 
                                        return False;
802
 
                        }
803
 
                        if ( !(prs_set_offset( &hblock->ps, (vk->data_off+HBIN_HDR_SIZE-hblock->first_hbin_off)-sizeof(uint32) )) )
804
 
                                return False;
805
 
 
806
 
                        if ( MARSHALLING(&hblock->ps) ) {
807
 
                                data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
808
 
                                data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF;
809
 
                        }
810
 
                        if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size ))
811
 
                                return False;
812
 
                        if ( !prs_uint8s( charmode, "data", &hblock->ps, depth, vk->data, vk->data_size) )
813
 
                                return False;
814
 
 
815
 
                        if ( MARSHALLING(&hblock->ps) )
816
 
                                hblock->dirty = True;
817
 
                }
818
 
                else {
819
 
                        if ( !(vk->data = PRS_ALLOC_MEM( ps, uint8, 4 ) ) )
820
 
                                return False;
821
 
                        SIVAL( vk->data, 0, vk->data_off );
822
 
                }
823
 
                
824
 
        }
825
 
 
826
 
        /* data_size must be divisible by 8 and large enough to hold the original record */
827
 
 
828
 
        data_size = ((start_off - end_off ) & 0xfffffff8 );
829
 
        if ( data_size !=  vk->rec_size )
830
 
                DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));
831
 
 
832
 
        if ( MARSHALLING(&hbin->ps) )
833
 
                hbin->dirty = True;
834
 
 
835
 
        return True;
836
 
}
837
 
 
838
 
/*******************************************************************
839
 
 read a VK record which is contained in the HBIN block stored 
840
 
 in the prs_struct *ps.
841
 
*******************************************************************/
842
 
 
843
 
static BOOL hbin_prs_vk_records( const char *desc, REGF_HBIN *hbin, int depth, REGF_NK_REC *nk, REGF_FILE *file )
844
 
{
845
 
        int i;
846
 
        uint32 record_size;
847
 
 
848
 
        prs_debug(&hbin->ps, depth, desc, "prs_vk_records");
849
 
        depth++;
850
 
        
851
 
        /* check if we have anything to do first */
852
 
        
853
 
        if ( nk->num_values == 0 )
854
 
                return True;
855
 
                
856
 
        if ( UNMARSHALLING(&hbin->ps) ) {
857
 
                if ( !(nk->values = PRS_ALLOC_MEM( &hbin->ps, REGF_VK_REC, nk->num_values ) ) )
858
 
                        return False;
859
 
        }
860
 
        
861
 
        /* convert the offset to something relative to this HBIN block */
862
 
        
863
 
        if ( !prs_set_offset( &hbin->ps, nk->values_off+HBIN_HDR_SIZE-hbin->first_hbin_off-sizeof(uint32)) )
864
 
                return False;
865
 
 
866
 
        if ( MARSHALLING( &hbin->ps) ) { 
867
 
                record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
868
 
                record_size = (record_size - 1) ^ 0xFFFFFFFF;
869
 
        }
870
 
 
871
 
        if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
872
 
                return False;
873
 
                
874
 
        for ( i=0; i<nk->num_values; i++ ) {
875
 
                if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
876
 
                        return False;
877
 
        }
878
 
 
879
 
        for ( i=0; i<nk->num_values; i++ ) {
880
 
                REGF_HBIN *sub_hbin = hbin;
881
 
                uint32 new_offset;
882
 
        
883
 
                if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) {
884
 
                        sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
885
 
                        if ( !sub_hbin ) {
886
 
                                DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n", 
887
 
                                        nk->values[i].hbin_off));
888
 
                                return False;
889
 
                        }
890
 
                }
891
 
                
892
 
                new_offset = nk->values[i].rec_off + HBIN_HDR_SIZE - sub_hbin->first_hbin_off;
893
 
                if ( !prs_set_offset( &sub_hbin->ps, new_offset ) )
894
 
                        return False;
895
 
                if ( !hbin_prs_vk_rec( "vk_rec", sub_hbin, depth, &nk->values[i], file ) )
896
 
                        return False;
897
 
        }
898
 
 
899
 
        if ( MARSHALLING(&hbin->ps) )
900
 
                hbin->dirty = True;
901
 
 
902
 
 
903
 
        return True;
904
 
}
905
 
 
906
 
 
907
 
/*******************************************************************
908
 
*******************************************************************/
909
 
 
910
 
static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
911
 
{
912
 
        REGF_SK_REC *p_sk;
913
 
        
914
 
        for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) {
915
 
                if ( p_sk->sk_off == offset ) 
916
 
                        return p_sk;
917
 
        }
918
 
        
919
 
        return NULL;
920
 
}
921
 
 
922
 
/*******************************************************************
923
 
*******************************************************************/
924
 
 
925
 
static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
926
 
{
927
 
        REGF_SK_REC *p;
928
 
 
929
 
        for ( p=file->sec_desc_list; p; p=p->next ) {
930
 
                if ( sec_desc_equal( p->sec_desc, sd ) )
931
 
                        return p;
932
 
        }
933
 
 
934
 
        /* failure */
935
 
 
936
 
        return NULL;
937
 
}
938
 
 
939
 
/*******************************************************************
940
 
*******************************************************************/
941
 
 
942
 
static BOOL hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
943
 
{
944
 
        int depth = 0;
945
 
        REGF_HBIN *sub_hbin;
946
 
        
947
 
        prs_debug(&hbin->ps, depth, "", "fetch_key");
948
 
        depth++;
949
 
 
950
 
        /* get the initial nk record */
951
 
        
952
 
        if ( !prs_nk_rec( "nk_rec", &hbin->ps, depth, nk ))
953
 
                return False;
954
 
 
955
 
        /* fill in values */
956
 
        
957
 
        if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) {
958
 
                sub_hbin = hbin;
959
 
                if ( !hbin_contains_offset( hbin, nk->values_off ) ) {
960
 
                        sub_hbin = lookup_hbin_block( file, nk->values_off );
961
 
                        if ( !sub_hbin ) {
962
 
                                DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n", 
963
 
                                        nk->values_off));
964
 
                                return False;
965
 
                        }
966
 
                }
967
 
                
968
 
                if ( !hbin_prs_vk_records( "vk_rec", sub_hbin, depth, nk, file ))
969
 
                        return False;
970
 
        }
971
 
                
972
 
        /* now get subkeys */
973
 
        
974
 
        if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) {
975
 
                sub_hbin = hbin;
976
 
                if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) {
977
 
                        sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
978
 
                        if ( !sub_hbin ) {
979
 
                                DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n", 
980
 
                                        nk->subkeys_off));
981
 
                                return False;
982
 
                        }
983
 
                }
984
 
                
985
 
                if ( !hbin_prs_lf_records( "lf_rec", sub_hbin, depth, nk ))
986
 
                        return False;
987
 
        }
988
 
 
989
 
        /* get the to the security descriptor.  First look if we have already parsed it */
990
 
        
991
 
        if ( (nk->sk_off!=REGF_OFFSET_NONE) && !( nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )) ) {
992
 
 
993
 
                sub_hbin = hbin;
994
 
                if ( !hbin_contains_offset( hbin, nk->sk_off ) ) {
995
 
                        sub_hbin = lookup_hbin_block( file, nk->sk_off );
996
 
                        if ( !sub_hbin ) {
997
 
                                DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n", 
998
 
                                        nk->subkeys_off));
999
 
                                return False;
1000
 
                        }
1001
 
                }
1002
 
                
1003
 
                if ( !(nk->sec_desc = TALLOC_ZERO_P( file->mem_ctx, REGF_SK_REC )) )
1004
 
                        return False;
1005
 
                nk->sec_desc->sk_off = nk->sk_off;
1006
 
                if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))
1007
 
                        return False;
1008
 
                        
1009
 
                /* add to the list of security descriptors (ref_count has been read from the files) */
1010
 
 
1011
 
                nk->sec_desc->sk_off = nk->sk_off;
1012
 
                DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1013
 
        }
1014
 
                
1015
 
        return True;
1016
 
}
1017
 
 
1018
 
/*******************************************************************
1019
 
*******************************************************************/
1020
 
 
1021
 
static BOOL next_record( REGF_HBIN *hbin, const char *hdr, BOOL *eob )
1022
 
{
1023
 
        uint8 header[REC_HDR_SIZE];
1024
 
        uint32 record_size;
1025
 
        uint32 curr_off, block_size;
1026
 
        BOOL found = False;
1027
 
        prs_struct *ps = &hbin->ps;
1028
 
        
1029
 
        curr_off = prs_offset( ps );
1030
 
        if ( curr_off == 0 )
1031
 
                prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
1032
 
 
1033
 
        /* assume that the current offset is at the record header 
1034
 
           and we need to backup to read the record size */
1035
 
 
1036
 
        curr_off -= sizeof(uint32);
1037
 
 
1038
 
        block_size = prs_data_size( ps );
1039
 
        record_size = 0;
1040
 
        memset( header, 0x0, sizeof(uint8)*REC_HDR_SIZE );
1041
 
        while ( !found ) {
1042
 
 
1043
 
                curr_off = curr_off+record_size;
1044
 
                if ( curr_off >= block_size ) 
1045
 
                        break;
1046
 
 
1047
 
                if ( !prs_set_offset( &hbin->ps, curr_off) )
1048
 
                        return False;
1049
 
 
1050
 
                if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
1051
 
                        return False;
1052
 
                if ( !prs_uint8s( True, "header", ps, 0, header, REC_HDR_SIZE ) )
1053
 
                        return False;
1054
 
 
1055
 
                if ( record_size & 0x80000000 ) {
1056
 
                        /* absolute_value(record_size) */
1057
 
                        record_size = (record_size ^ 0xffffffff) + 1;
1058
 
                }
1059
 
 
1060
 
                if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1061
 
                        found = True;
1062
 
                        curr_off += sizeof(uint32);
1063
 
                }
1064
 
        } 
1065
 
 
1066
 
        /* mark prs_struct as done ( at end ) if no more SK records */
1067
 
        /* mark end-of-block as True */
1068
 
        
1069
 
        if ( !found ) {
1070
 
                prs_set_offset( &hbin->ps, prs_data_size(&hbin->ps) );
1071
 
                *eob = True;
1072
 
                return False;
1073
 
        }
1074
 
                
1075
 
        if ( !prs_set_offset( ps, curr_off ) )
1076
 
                return False;
1077
 
 
1078
 
        return True;
1079
 
}
1080
 
 
1081
 
/*******************************************************************
1082
 
*******************************************************************/
1083
 
 
1084
 
static BOOL next_nk_record( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk, BOOL *eob )
1085
 
{
1086
 
        if ( next_record( hbin, "nk", eob ) && hbin_prs_key( file, hbin, nk ) )
1087
 
                return True;
1088
 
        
1089
 
        return False;
1090
 
}
1091
 
 
1092
 
/*******************************************************************
1093
 
 Intialize the newly created REGF_BLOCK in *file and write the 
1094
 
 block header to disk 
1095
 
*******************************************************************/
1096
 
 
1097
 
static BOOL init_regf_block( REGF_FILE *file )
1098
 
{       
1099
 
        prs_struct ps;
1100
 
        BOOL result = True;
1101
 
        
1102
 
        if ( !prs_init( &ps, REGF_BLOCKSIZE, file->mem_ctx, MARSHALL ) )
1103
 
                return False;
1104
 
                
1105
 
        memcpy( file->header, "regf", REGF_HDR_SIZE );
1106
 
        file->data_offset = 0x20;
1107
 
        file->last_block  = 0x1000;
1108
 
        
1109
 
        /* set mod time */
1110
 
        
1111
 
        unix_to_nt_time( &file->mtime, time(NULL) );
1112
 
        
1113
 
        /* hard coded values...no diea what these are ... maybe in time */
1114
 
        
1115
 
        file->unknown1 = 0x2;
1116
 
        file->unknown2 = 0x1;
1117
 
        file->unknown3 = 0x3;
1118
 
        file->unknown4 = 0x0;
1119
 
        file->unknown5 = 0x1;
1120
 
        file->unknown6 = 0x1;
1121
 
        
1122
 
        /* write header to the buffer */
1123
 
        
1124
 
        if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) {
1125
 
                result = False;
1126
 
                goto out;
1127
 
        }
1128
 
        
1129
 
        /* calculate the checksum, re-marshall data (to include the checksum) 
1130
 
           and write to disk */
1131
 
        
1132
 
        file->checksum = regf_block_checksum( &ps );
1133
 
        prs_set_offset( &ps, 0 );
1134
 
        if ( !prs_regf_block( "regf_header", &ps, 0, file ) ) {
1135
 
                result = False;
1136
 
                goto out;
1137
 
        }
1138
 
                
1139
 
        if ( write_block( file, &ps, 0 ) == -1 ) {
1140
 
                DEBUG(0,("init_regf_block: Failed to initialize registry header block!\n"));
1141
 
                result = False;
1142
 
                goto out;
1143
 
        }
1144
 
        
1145
 
out:
1146
 
        prs_mem_free( &ps );
1147
 
 
1148
 
        return result;
1149
 
}
1150
 
/*******************************************************************
1151
 
 Open the registry file and then read in the REGF block to get the 
1152
 
 first hbin offset.
1153
 
*******************************************************************/
1154
 
 
1155
 
 REGF_FILE* regfio_open( const char *filename, int flags, int mode )
1156
 
{
1157
 
        REGF_FILE *rb;
1158
 
        
1159
 
        if ( !(rb = SMB_MALLOC_P(REGF_FILE)) ) {
1160
 
                DEBUG(0,("ERROR allocating memory\n"));
1161
 
                return NULL;
1162
 
        }
1163
 
        ZERO_STRUCTP( rb );
1164
 
        rb->fd = -1;
1165
 
        
1166
 
        if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) ) {
1167
 
                regfio_close( rb );
1168
 
                return NULL;
1169
 
        }
1170
 
 
1171
 
        rb->open_flags = flags;
1172
 
        
1173
 
        /* open and existing file */
1174
 
 
1175
 
        if ( (rb->fd = open(filename, flags, mode)) == -1 ) {
1176
 
                DEBUG(0,("regfio_open: failure to open %s (%s)\n", filename, strerror(errno)));
1177
 
                regfio_close( rb );
1178
 
                return NULL;
1179
 
        }
1180
 
        
1181
 
        /* check if we are creating a new file or overwriting an existing one */
1182
 
                
1183
 
        if ( flags & (O_CREAT|O_TRUNC) ) {
1184
 
                if ( !init_regf_block( rb ) ) {
1185
 
                        DEBUG(0,("regfio_open: Failed to read initial REGF block\n"));
1186
 
                        regfio_close( rb );
1187
 
                        return NULL;
1188
 
                }
1189
 
                
1190
 
                /* success */
1191
 
                return rb;
1192
 
        }
1193
 
        
1194
 
        /* read in an existing file */
1195
 
        
1196
 
        if ( !read_regf_block( rb ) ) {
1197
 
                DEBUG(0,("regfio_open: Failed to read initial REGF block\n"));
1198
 
                regfio_close( rb );
1199
 
                return NULL;
1200
 
        }
1201
 
        
1202
 
        /* success */
1203
 
        
1204
 
        return rb;
1205
 
}
1206
 
 
1207
 
/*******************************************************************
1208
 
*******************************************************************/
1209
 
 
1210
 
static void regfio_mem_free( REGF_FILE *file )
1211
 
{
1212
 
        /* free any talloc()'d memory */
1213
 
        
1214
 
        if ( file && file->mem_ctx )
1215
 
                talloc_destroy( file->mem_ctx );        
1216
 
}
1217
 
 
1218
 
/*******************************************************************
1219
 
*******************************************************************/
1220
 
 
1221
 
 int regfio_close( REGF_FILE *file )
1222
 
{
1223
 
        int fd;
1224
 
 
1225
 
        /* cleanup for a file opened for write */
1226
 
 
1227
 
        if ( file->open_flags & (O_WRONLY|O_RDWR) ) {
1228
 
                prs_struct ps;
1229
 
                REGF_SK_REC *sk;
1230
 
 
1231
 
                /* write of sd list */
1232
 
 
1233
 
                for ( sk=file->sec_desc_list; sk; sk=sk->next ) {
1234
 
                        hbin_prs_sk_rec( "sk_rec", sk->hbin, 0, sk );
1235
 
                }
1236
 
 
1237
 
                /* flush any dirty blocks */
1238
 
 
1239
 
                while ( file->block_list ) {
1240
 
                        hbin_block_close( file, file->block_list );
1241
 
                } 
1242
 
 
1243
 
                ZERO_STRUCT( ps );
1244
 
 
1245
 
                unix_to_nt_time( &file->mtime, time(NULL) );
1246
 
 
1247
 
                if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) != -1 ) {
1248
 
                        /* now use for writing */
1249
 
                        prs_switch_type( &ps, MARSHALL );
1250
 
 
1251
 
                        /* stream the block once, generate the checksum, 
1252
 
                           and stream it again */
1253
 
                        prs_set_offset( &ps, 0 );
1254
 
                        prs_regf_block( "regf_blocK", &ps, 0, file );
1255
 
                        file->checksum = regf_block_checksum( &ps );
1256
 
                        prs_set_offset( &ps, 0 );
1257
 
                        prs_regf_block( "regf_blocK", &ps, 0, file );
1258
 
 
1259
 
                        /* now we are ready to write it to disk */
1260
 
                        if ( write_block( file, &ps, 0 ) == -1 )
1261
 
                                DEBUG(0,("regfio_close: failed to update the regf header block!\n"));
1262
 
                }
1263
 
 
1264
 
                prs_mem_free( &ps );
1265
 
        }
1266
 
        
1267
 
        regfio_mem_free( file );
1268
 
 
1269
 
        /* nothing tdo do if there is no open file */
1270
 
 
1271
 
        if ( !file || (file->fd == -1) )
1272
 
                return 0;
1273
 
                
1274
 
        fd = file->fd;
1275
 
        file->fd = -1;
1276
 
        SAFE_FREE( file );
1277
 
 
1278
 
        return close( fd );
1279
 
}
1280
 
 
1281
 
/*******************************************************************
1282
 
*******************************************************************/
1283
 
 
1284
 
static void regfio_flush( REGF_FILE *file )
1285
 
{
1286
 
        REGF_HBIN *hbin;
1287
 
 
1288
 
        for ( hbin=file->block_list; hbin; hbin=hbin->next ) {
1289
 
                write_hbin_block( file, hbin );
1290
 
        }
1291
 
}
1292
 
 
1293
 
/*******************************************************************
1294
 
 There should be only *one* root key in the registry file based 
1295
 
 on my experience.  --jerry
1296
 
*******************************************************************/
1297
 
 
1298
 
REGF_NK_REC* regfio_rootkey( REGF_FILE *file )
1299
 
{
1300
 
        REGF_NK_REC *nk;
1301
 
        REGF_HBIN   *hbin;
1302
 
        uint32      offset = REGF_BLOCKSIZE;
1303
 
        BOOL        found = False;
1304
 
        BOOL        eob;
1305
 
        
1306
 
        if ( !file )
1307
 
                return NULL;
1308
 
                
1309
 
        if ( !(nk = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) ) {
1310
 
                DEBUG(0,("regfio_rootkey: talloc() failed!\n"));
1311
 
                return NULL;
1312
 
        }
1313
 
        
1314
 
        /* scan through the file on HBIN block at a time looking 
1315
 
           for an NK record with a type == 0x002c.
1316
 
           Normally this is the first nk record in the first hbin 
1317
 
           block (but I'm not assuming that for now) */
1318
 
        
1319
 
        while ( (hbin = read_hbin_block( file, offset )) ) {
1320
 
                eob = False;
1321
 
 
1322
 
                while ( !eob) {
1323
 
                        if ( next_nk_record( file, hbin, nk, &eob ) ) {
1324
 
                                if ( nk->key_type == NK_TYPE_ROOTKEY ) {
1325
 
                                        found = True;
1326
 
                                        break;
1327
 
                                }
1328
 
                        }
1329
 
                        prs_mem_free( &hbin->ps );
1330
 
                }
1331
 
                
1332
 
                if ( found ) 
1333
 
                        break;
1334
 
 
1335
 
                offset += hbin->block_size;
1336
 
        }
1337
 
        
1338
 
        if ( !found ) {
1339
 
                DEBUG(0,("regfio_rootkey: corrupt registry file ?  No root key record located\n"));
1340
 
                return NULL;
1341
 
        }
1342
 
 
1343
 
        DLIST_ADD( file->block_list, hbin );
1344
 
 
1345
 
        return nk;              
1346
 
}
1347
 
 
1348
 
/*******************************************************************
1349
 
 This acts as an interator over the subkeys defined for a given 
1350
 
 NK record.  Remember that offsets are from the *first* HBIN block.
1351
 
*******************************************************************/
1352
 
 
1353
 
 REGF_NK_REC* regfio_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk )
1354
 
{
1355
 
        REGF_NK_REC *subkey;
1356
 
        REGF_HBIN   *hbin;
1357
 
        uint32      nk_offset;
1358
 
 
1359
 
        /* see if there is anything left to report */
1360
 
        
1361
 
        if ( !nk || (nk->subkeys_off==REGF_OFFSET_NONE) || (nk->subkey_index >= nk->num_subkeys) )
1362
 
                return NULL;
1363
 
 
1364
 
        /* find the HBIN block which should contain the nk record */
1365
 
        
1366
 
        if ( !(hbin = lookup_hbin_block( file, nk->subkeys.hashes[nk->subkey_index].nk_off )) ) {
1367
 
                DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n", 
1368
 
                        nk->subkeys.hashes[nk->subkey_index].nk_off));
1369
 
                return NULL;
1370
 
        }
1371
 
        
1372
 
        nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off;
1373
 
        if ( !prs_set_offset( &hbin->ps, (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off) ) )
1374
 
                return NULL;
1375
 
                
1376
 
        nk->subkey_index++;
1377
 
        if ( !(subkey = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) )
1378
 
                return NULL;
1379
 
                
1380
 
        if ( !hbin_prs_key( file, hbin, subkey ) )
1381
 
                return NULL;
1382
 
        
1383
 
        return subkey;
1384
 
}
1385
 
 
1386
 
 
1387
 
/*******************************************************************
1388
 
*******************************************************************/
1389
 
 
1390
 
static REGF_HBIN* regf_hbin_allocate( REGF_FILE *file, uint32 block_size )
1391
 
{
1392
 
        REGF_HBIN *hbin;
1393
 
        SMB_STRUCT_STAT sbuf;
1394
 
 
1395
 
        if ( !(hbin = TALLOC_ZERO_P( file->mem_ctx, REGF_HBIN )) )
1396
 
                return NULL;
1397
 
 
1398
 
        memcpy( hbin->header, "hbin", sizeof(HBIN_HDR_SIZE) );
1399
 
 
1400
 
 
1401
 
        if ( sys_fstat( file->fd, &sbuf ) ) {
1402
 
                DEBUG(0,("regf_hbin_allocate: stat() failed! (%s)\n", strerror(errno)));
1403
 
                return NULL;
1404
 
        }
1405
 
 
1406
 
        hbin->file_off       = sbuf.st_size;
1407
 
 
1408
 
        hbin->free_off       = HBIN_HEADER_REC_SIZE;
1409
 
        hbin->free_size      = block_size - hbin->free_off + sizeof(uint32);;
1410
 
 
1411
 
        hbin->block_size     = block_size;
1412
 
        hbin->first_hbin_off = hbin->file_off - REGF_BLOCKSIZE;
1413
 
 
1414
 
        if ( !prs_init( &hbin->ps, block_size, file->mem_ctx, MARSHALL ) )
1415
 
                return NULL;
1416
 
 
1417
 
        if ( !prs_hbin_block( "new_hbin", &hbin->ps, 0, hbin ) )
1418
 
                return NULL;
1419
 
 
1420
 
        if ( !write_hbin_block( file, hbin ) )
1421
 
                return NULL;
1422
 
 
1423
 
        file->last_block = hbin->file_off;
1424
 
 
1425
 
        return hbin;
1426
 
}
1427
 
 
1428
 
/*******************************************************************
1429
 
*******************************************************************/
1430
 
 
1431
 
static void update_free_space( REGF_HBIN *hbin, uint32 size_used )
1432
 
{
1433
 
        hbin->free_off  += size_used;
1434
 
        hbin->free_size -= size_used;
1435
 
 
1436
 
        if ( hbin->free_off >= hbin->block_size ) {
1437
 
                hbin->free_off = REGF_OFFSET_NONE;
1438
 
        }
1439
 
 
1440
 
        return;
1441
 
}
1442
 
 
1443
 
/*******************************************************************
1444
 
*******************************************************************/
1445
 
 
1446
 
static REGF_HBIN* find_free_space( REGF_FILE *file, uint32 size )
1447
 
{
1448
 
        REGF_HBIN *hbin, *p_hbin;
1449
 
        uint32 block_off;
1450
 
        BOOL cached;
1451
 
 
1452
 
        /* check open block list */
1453
 
 
1454
 
        for ( hbin=file->block_list; hbin!=NULL; hbin=hbin->next ) {
1455
 
                /* only check blocks that actually have available space */
1456
 
 
1457
 
                if ( hbin->free_off == REGF_OFFSET_NONE )
1458
 
                        continue;
1459
 
 
1460
 
                /* check for a large enough available chunk */
1461
 
 
1462
 
                if ( (hbin->block_size - hbin->free_off) >= size ) {
1463
 
                        DLIST_PROMOTE( file->block_list, hbin );
1464
 
                        goto done;                      
1465
 
                }
1466
 
        }
1467
 
 
1468
 
        /* parse the file until we find a block with 
1469
 
           enough free space; save the last non-filled hbin */
1470
 
 
1471
 
        block_off = REGF_BLOCKSIZE;
1472
 
        do {
1473
 
                /* cleanup before the next round */
1474
 
                cached = False;
1475
 
                if ( hbin )
1476
 
                        prs_mem_free( &hbin->ps );
1477
 
 
1478
 
                hbin = read_hbin_block( file, block_off );
1479
 
 
1480
 
                if ( hbin ) {
1481
 
 
1482
 
                        /* make sure that we don't already have this block in memory */
1483
 
 
1484
 
                        for ( p_hbin=file->block_list; p_hbin!=NULL; p_hbin=p_hbin->next ) {
1485
 
                                if ( p_hbin->file_off == hbin->file_off ) {
1486
 
                                        cached = True;  
1487
 
                                        break;
1488
 
                                }
1489
 
                        }
1490
 
 
1491
 
                        block_off = hbin->file_off + hbin->block_size;
1492
 
 
1493
 
                        if ( cached ) {
1494
 
                                prs_mem_free( &hbin->ps );
1495
 
                                hbin = NULL;
1496
 
                                continue;
1497
 
                        }
1498
 
                }
1499
 
        /* if (cached block or (new block and not enough free space)) then continue looping */
1500
 
        } while ( cached || (hbin && (hbin->free_size < size)) );
1501
 
        
1502
 
        /* no free space; allocate a new one */
1503
 
 
1504
 
        if ( !hbin ) {
1505
 
                uint32 alloc_size;
1506
 
 
1507
 
                /* allocate in multiples of REGF_ALLOC_BLOCK; make sure (size + hbin_header) fits */
1508
 
 
1509
 
                alloc_size = (((size+HBIN_HEADER_REC_SIZE) / REGF_ALLOC_BLOCK ) + 1 ) * REGF_ALLOC_BLOCK;
1510
 
 
1511
 
                if ( !(hbin = regf_hbin_allocate( file, alloc_size )) ) {
1512
 
                        DEBUG(0,("find_free_space: regf_hbin_allocate() failed!\n"));
1513
 
                        return NULL;
1514
 
                }
1515
 
                DLIST_ADD( file->block_list, hbin );
1516
 
        }
1517
 
 
1518
 
done:
1519
 
        /* set the offset to be ready to write */
1520
 
 
1521
 
        if ( !prs_set_offset( &hbin->ps, hbin->free_off-sizeof(uint32) ) )
1522
 
                return NULL;
1523
 
 
1524
 
        /* write the record size as a placeholder for now, it should be
1525
 
           probably updated by the caller once it all of the data necessary 
1526
 
           for the record */
1527
 
 
1528
 
        if ( !prs_uint32("allocated_size", &hbin->ps, 0, &size) )
1529
 
                return False;
1530
 
 
1531
 
        update_free_space( hbin, size );
1532
 
        
1533
 
        return hbin;
1534
 
}
1535
 
 
1536
 
/*******************************************************************
1537
 
*******************************************************************/
1538
 
 
1539
 
static uint32 sk_record_data_size( SEC_DESC * sd )
1540
 
{
1541
 
        uint32 size, size_mod8;
1542
 
 
1543
 
        size_mod8 = 0;
1544
 
 
1545
 
        /* the record size is sizeof(hdr) + name + static members + data_size_field */
1546
 
 
1547
 
        size = sizeof(uint32)*5 + sec_desc_size( sd ) + sizeof(uint32);
1548
 
 
1549
 
        /* multiple of 8 */
1550
 
        size_mod8 = size & 0xfffffff8;
1551
 
        if ( size_mod8 < size )
1552
 
                size_mod8 += 8;
1553
 
 
1554
 
        return size_mod8;
1555
 
}
1556
 
 
1557
 
/*******************************************************************
1558
 
*******************************************************************/
1559
 
 
1560
 
static uint32 vk_record_data_size( REGF_VK_REC *vk )
1561
 
{
1562
 
        uint32 size, size_mod8;
1563
 
 
1564
 
        size_mod8 = 0;
1565
 
 
1566
 
        /* the record size is sizeof(hdr) + name + static members + data_size_field */
1567
 
 
1568
 
        size = REC_HDR_SIZE + (sizeof(uint16)*3) + (sizeof(uint32)*3) + sizeof(uint32);
1569
 
 
1570
 
        if ( vk->valuename )
1571
 
                size += strlen(vk->valuename);
1572
 
 
1573
 
        /* multiple of 8 */
1574
 
        size_mod8 = size & 0xfffffff8;
1575
 
        if ( size_mod8 < size )
1576
 
                size_mod8 += 8;
1577
 
 
1578
 
        return size_mod8;
1579
 
}
1580
 
 
1581
 
/*******************************************************************
1582
 
*******************************************************************/
1583
 
 
1584
 
static uint32 lf_record_data_size( uint32 num_keys )
1585
 
{
1586
 
        uint32 size, size_mod8;
1587
 
 
1588
 
        size_mod8 = 0;
1589
 
 
1590
 
        /* the record size is sizeof(hdr) + num_keys + sizeof of hash_array + data_size_uint32 */
1591
 
 
1592
 
        size = REC_HDR_SIZE + sizeof(uint16) + (sizeof(REGF_HASH_REC) * num_keys) + sizeof(uint32);
1593
 
 
1594
 
        /* multiple of 8 */
1595
 
        size_mod8 = size & 0xfffffff8;
1596
 
        if ( size_mod8 < size )
1597
 
                size_mod8 += 8;
1598
 
 
1599
 
        return size_mod8;
1600
 
}
1601
 
 
1602
 
/*******************************************************************
1603
 
*******************************************************************/
1604
 
 
1605
 
static uint32 nk_record_data_size( REGF_NK_REC *nk )
1606
 
{
1607
 
        uint32 size, size_mod8;
1608
 
 
1609
 
        size_mod8 = 0;
1610
 
 
1611
 
        /* the record size is static + length_of_keyname + length_of_classname + data_size_uint32 */
1612
 
 
1613
 
        size = 0x4c + strlen(nk->keyname) + sizeof(uint32);
1614
 
 
1615
 
        if ( nk->classname )
1616
 
                size += strlen( nk->classname );
1617
 
 
1618
 
        /* multiple of 8 */
1619
 
        size_mod8 = size & 0xfffffff8;
1620
 
        if ( size_mod8 < size )
1621
 
                size_mod8 += 8;
1622
 
 
1623
 
        return size_mod8;
1624
 
}
1625
 
 
1626
 
/*******************************************************************
1627
 
*******************************************************************/
1628
 
 
1629
 
static BOOL create_vk_record( REGF_FILE *file, REGF_VK_REC *vk, REGISTRY_VALUE *value )
1630
 
{
1631
 
        char *name = regval_name(value);
1632
 
        REGF_HBIN *data_hbin;
1633
 
 
1634
 
        ZERO_STRUCTP( vk );
1635
 
 
1636
 
        memcpy( vk->header, "vk", REC_HDR_SIZE );
1637
 
 
1638
 
        if ( name ) {
1639
 
                vk->valuename = talloc_strdup( file->mem_ctx, regval_name(value) );
1640
 
                vk->flag = VK_FLAG_NAME_PRESENT;
1641
 
        }
1642
 
 
1643
 
        vk->data_size = regval_size( value );
1644
 
        vk->type      = regval_type( value );
1645
 
 
1646
 
        if ( vk->data_size > sizeof(uint32) ) {
1647
 
                uint32 data_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
1648
 
 
1649
 
                vk->data = TALLOC_MEMDUP( file->mem_ctx, regval_data_p(value), vk->data_size );
1650
 
                if (vk->data == NULL) {
1651
 
                        return False;
1652
 
                }
1653
 
 
1654
 
                /* go ahead and store the offset....we'll pick this hbin block back up when 
1655
 
                   we stream the data */
1656
 
 
1657
 
                if ((data_hbin = find_free_space(file, data_size )) == NULL) {
1658
 
                        return False;
1659
 
                }
1660
 
                vk->data_off = prs_offset( &data_hbin->ps ) + data_hbin->first_hbin_off - HBIN_HDR_SIZE;
1661
 
        }
1662
 
        else {
1663
 
                /* make sure we don't try to copy from a NULL value pointer */
1664
 
 
1665
 
                if ( vk->data_size != 0 ) 
1666
 
                        memcpy( &vk->data_off, regval_data_p(value), sizeof(uint32) );
1667
 
                vk->data_size |= VK_DATA_IN_OFFSET;             
1668
 
        }
1669
 
 
1670
 
        return True;
1671
 
}
1672
 
 
1673
 
/*******************************************************************
1674
 
*******************************************************************/
1675
 
 
1676
 
static int hashrec_cmp( REGF_HASH_REC *h1, REGF_HASH_REC *h2 )
1677
 
{
1678
 
        return StrCaseCmp( h1->fullname, h2->fullname );
1679
 
}
1680
 
 
1681
 
/*******************************************************************
1682
 
*******************************************************************/
1683
 
 
1684
 
 REGF_NK_REC* regfio_write_key( REGF_FILE *file, const char *name, 
1685
 
                               REGVAL_CTR *values, REGSUBKEY_CTR *subkeys, 
1686
 
                               SEC_DESC *sec_desc, REGF_NK_REC *parent )
1687
 
{
1688
 
        REGF_NK_REC *nk;
1689
 
        REGF_HBIN *vlist_hbin = NULL;
1690
 
        uint32 size;
1691
 
 
1692
 
        if ( !(nk = TALLOC_ZERO_P( file->mem_ctx, REGF_NK_REC )) )
1693
 
                return NULL;
1694
 
 
1695
 
        memcpy( nk->header, "nk", REC_HDR_SIZE );
1696
 
 
1697
 
        if ( !parent )
1698
 
                nk->key_type = NK_TYPE_ROOTKEY;
1699
 
        else
1700
 
                nk->key_type = NK_TYPE_NORMALKEY;
1701
 
 
1702
 
        /* store the parent offset (or -1 if a the root key */
1703
 
 
1704
 
        nk->parent_off = parent ? (parent->hbin_off + parent->hbin->file_off - REGF_BLOCKSIZE - HBIN_HDR_SIZE ) : REGF_OFFSET_NONE;
1705
 
 
1706
 
        /* no classname currently */
1707
 
 
1708
 
        nk->classname_off = REGF_OFFSET_NONE;
1709
 
        nk->classname = NULL;
1710
 
        nk->keyname = talloc_strdup( file->mem_ctx, name );
1711
 
 
1712
 
        /* current modification time */
1713
 
 
1714
 
        unix_to_nt_time( &nk->mtime, time(NULL) );
1715
 
 
1716
 
        /* allocate the record on disk */
1717
 
 
1718
 
        size = nk_record_data_size( nk );
1719
 
        nk->rec_size = ( size - 1 ) ^ 0XFFFFFFFF;
1720
 
        if ((nk->hbin = find_free_space( file, size )) == NULL) {
1721
 
                return NULL;
1722
 
        }
1723
 
        nk->hbin_off = prs_offset( &nk->hbin->ps );
1724
 
 
1725
 
        /* Update the hash record in the parent */
1726
 
        
1727
 
        if ( parent ) {
1728
 
                REGF_HASH_REC *hash = &parent->subkeys.hashes[parent->subkey_index];
1729
 
 
1730
 
                hash->nk_off = prs_offset( &nk->hbin->ps ) + nk->hbin->first_hbin_off - HBIN_HDR_SIZE;
1731
 
                memcpy( hash->keycheck, name, sizeof(uint32) );
1732
 
                hash->fullname = talloc_strdup( file->mem_ctx, name );
1733
 
                parent->subkey_index++;
1734
 
 
1735
 
                /* sort the list by keyname */
1736
 
 
1737
 
                qsort( parent->subkeys.hashes, parent->subkey_index, sizeof(REGF_HASH_REC), QSORT_CAST hashrec_cmp );
1738
 
 
1739
 
                if ( !hbin_prs_lf_records( "lf_rec", parent->subkeys.hbin, 0, parent ) )
1740
 
                        return False;
1741
 
        }
1742
 
 
1743
 
        /* write the security descriptor */
1744
 
 
1745
 
        nk->sk_off = REGF_OFFSET_NONE;
1746
 
        if ( sec_desc ) {
1747
 
                uint32 sk_size = sk_record_data_size( sec_desc );
1748
 
                REGF_HBIN *sk_hbin;
1749
 
                REGF_SK_REC *tmp = NULL;
1750
 
 
1751
 
                /* search for it in the existing list of sd's */
1752
 
 
1753
 
                if ( (nk->sec_desc = find_sk_record_by_sec_desc( file, sec_desc )) == NULL ) {
1754
 
                        /* not found so add it to the list */
1755
 
 
1756
 
                        if (!(sk_hbin = find_free_space( file, sk_size ))) {
1757
 
                                return NULL;
1758
 
                        }
1759
 
 
1760
 
                        if ( !(nk->sec_desc = TALLOC_ZERO_P( file->mem_ctx, REGF_SK_REC )) )
1761
 
                                return NULL;
1762
 
        
1763
 
                        /* now we have to store the security descriptor in the list and 
1764
 
                           update the offsets */
1765
 
 
1766
 
                        memcpy( nk->sec_desc->header, "sk", REC_HDR_SIZE );
1767
 
                        nk->sec_desc->hbin      = sk_hbin;
1768
 
                        nk->sec_desc->hbin_off  = prs_offset( &sk_hbin->ps );
1769
 
                        nk->sec_desc->sk_off    = prs_offset( &sk_hbin->ps ) + sk_hbin->first_hbin_off - HBIN_HDR_SIZE;
1770
 
                        nk->sec_desc->rec_size  = (sk_size-1)  ^ 0xFFFFFFFF;
1771
 
 
1772
 
                        nk->sec_desc->sec_desc  = sec_desc;
1773
 
                        nk->sec_desc->ref_count = 0;
1774
 
                        
1775
 
                        /* size value must be self-inclusive */
1776
 
                        nk->sec_desc->size      = sec_desc_size(sec_desc) + sizeof(uint32);
1777
 
 
1778
 
                        DLIST_ADD_END( file->sec_desc_list, nk->sec_desc, tmp );
1779
 
 
1780
 
                        /* update the offsets for us and the previous sd in the list.
1781
 
                           if this is the first record, then just set the next and prev
1782
 
                           offsets to ourself. */
1783
 
 
1784
 
                        if ( nk->sec_desc->prev ) {
1785
 
                                REGF_SK_REC *prev = nk->sec_desc->prev;
1786
 
 
1787
 
                                nk->sec_desc->prev_sk_off = prev->hbin_off + prev->hbin->first_hbin_off - HBIN_HDR_SIZE;
1788
 
                                prev->next_sk_off = nk->sec_desc->sk_off;
1789
 
 
1790
 
                                /* the end must loop around to the front */
1791
 
                                nk->sec_desc->next_sk_off = file->sec_desc_list->sk_off;
1792
 
 
1793
 
                                /* and first must loop around to the tail */
1794
 
                                file->sec_desc_list->prev_sk_off = nk->sec_desc->sk_off;
1795
 
                        } else {
1796
 
                                nk->sec_desc->prev_sk_off = nk->sec_desc->sk_off;
1797
 
                                nk->sec_desc->next_sk_off = nk->sec_desc->sk_off;
1798
 
                        }
1799
 
                }
1800
 
 
1801
 
                /* bump the reference count +1 */
1802
 
 
1803
 
                nk->sk_off = nk->sec_desc->sk_off;
1804
 
                nk->sec_desc->ref_count++;
1805
 
        }
1806
 
 
1807
 
        /* write the subkeys */
1808
 
 
1809
 
        nk->subkeys_off = REGF_OFFSET_NONE;
1810
 
        if ( (nk->num_subkeys = regsubkey_ctr_numkeys( subkeys )) != 0 ) {
1811
 
                uint32 lf_size = lf_record_data_size( nk->num_subkeys );
1812
 
                uint32 namelen;
1813
 
                int i;
1814
 
                
1815
 
                if (!(nk->subkeys.hbin = find_free_space( file, lf_size ))) {
1816
 
                        return NULL;
1817
 
                }
1818
 
                nk->subkeys.hbin_off = prs_offset( &nk->subkeys.hbin->ps );
1819
 
                nk->subkeys.rec_size = (lf_size-1) ^ 0xFFFFFFFF;
1820
 
                nk->subkeys_off = prs_offset( &nk->subkeys.hbin->ps ) + nk->subkeys.hbin->first_hbin_off - HBIN_HDR_SIZE;
1821
 
 
1822
 
                memcpy( nk->subkeys.header, "lf", REC_HDR_SIZE );
1823
 
                
1824
 
                nk->subkeys.num_keys = nk->num_subkeys;
1825
 
                if ( !(nk->subkeys.hashes = TALLOC_ZERO_ARRAY( file->mem_ctx, REGF_HASH_REC, nk->subkeys.num_keys )) )
1826
 
                        return NULL;
1827
 
                nk->subkey_index = 0;
1828
 
 
1829
 
                /* update the max_bytes_subkey{name,classname} fields */
1830
 
                for ( i=0; i<nk->num_subkeys; i++ ) {
1831
 
                        namelen = strlen( regsubkey_ctr_specific_key(subkeys, i) );
1832
 
                        if ( namelen*2 > nk->max_bytes_subkeyname )
1833
 
                                nk->max_bytes_subkeyname = namelen * 2;
1834
 
                }
1835
 
        }
1836
 
 
1837
 
        /* write the values */
1838
 
 
1839
 
        nk->values_off = REGF_OFFSET_NONE;
1840
 
        if ( (nk->num_values = regval_ctr_numvals( values )) != 0 ) {
1841
 
                uint32 vlist_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
1842
 
                int i;
1843
 
                
1844
 
                if (!(vlist_hbin = find_free_space( file, vlist_size ))) {
1845
 
                        return NULL;
1846
 
                }
1847
 
                nk->values_off = prs_offset( &vlist_hbin->ps ) + vlist_hbin->first_hbin_off - HBIN_HDR_SIZE;
1848
 
        
1849
 
                if ( !(nk->values = TALLOC_ARRAY( file->mem_ctx, REGF_VK_REC, nk->num_values )) )
1850
 
                        return NULL;
1851
 
 
1852
 
                /* create the vk records */
1853
 
 
1854
 
                for ( i=0; i<nk->num_values; i++ ) {
1855
 
                        uint32 vk_size, namelen, datalen;
1856
 
                        REGISTRY_VALUE *r;
1857
 
 
1858
 
                        r = regval_ctr_specific_value( values, i );
1859
 
                        create_vk_record( file, &nk->values[i], r );
1860
 
                        vk_size = vk_record_data_size( &nk->values[i] );
1861
 
                        nk->values[i].hbin = find_free_space( file, vk_size );
1862
 
                        nk->values[i].hbin_off = prs_offset( &nk->values[i].hbin->ps );
1863
 
                        nk->values[i].rec_size = ( vk_size - 1 ) ^ 0xFFFFFFFF;
1864
 
                        nk->values[i].rec_off = prs_offset( &nk->values[i].hbin->ps ) 
1865
 
                                + nk->values[i].hbin->first_hbin_off 
1866
 
                                - HBIN_HDR_SIZE;
1867
 
 
1868
 
                        /* update the max bytes fields if necessary */
1869
 
 
1870
 
                        namelen = strlen( regval_name(r) );
1871
 
                        if ( namelen*2 > nk->max_bytes_valuename )
1872
 
                                nk->max_bytes_valuename = namelen * 2;
1873
 
 
1874
 
                        datalen = regval_size( r );
1875
 
                        if ( datalen > nk->max_bytes_value )
1876
 
                                nk->max_bytes_value = datalen;
1877
 
                }
1878
 
        }
1879
 
 
1880
 
        /* stream the records */        
1881
 
        
1882
 
        prs_set_offset( &nk->hbin->ps, nk->hbin_off );
1883
 
        if ( !prs_nk_rec( "nk_rec", &nk->hbin->ps, 0, nk ) )
1884
 
                return False;
1885
 
 
1886
 
        if ( nk->num_values ) {
1887
 
                if ( !hbin_prs_vk_records( "vk_records", vlist_hbin, 0, nk, file ) )
1888
 
                        return False;
1889
 
        }
1890
 
 
1891
 
 
1892
 
        regfio_flush( file );
1893
 
 
1894
 
        return nk;
1895
 
}
1896