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