source: releases/0.2.2/lib/regfio.c@ 293

Last change on this file since 293 was 59, checked in by tim, 20 years ago

Updated version

Code format cleanup, some comments added.

  • Property svn:keywords set to Id
File size: 37.2 KB
Line 
1/*
2 * Branched from Samba project Subversion repository, version #7470:
3 * http://websvn.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c
4 *
5 * Unix SMB/CIFS implementation.
6 * Windows NT registry I/O library
7 *
8 * Copyright (C) 2005 Timothy D. Morgan
9 * Copyright (C) 2005 Gerald (Jerry) Carter
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 * $Id: regfio.c 59 2005-10-03 01:26:12Z tim $
25 */
26
27#include "../include/regfio.h"
28
29
30
31/* Registry types mapping */
32const VAL_STR reg_type_names[] =
33{
34 { REG_SZ, "SZ" },
35 { REG_EXPAND_SZ, "EXPAND_SZ" },
36 { REG_BINARY, "BINARY" },
37 { REG_DWORD, "DWORD" },
38 { REG_DWORD_BE, "DWORD_BE" },
39 { REG_LINK, "LINK" },
40 { REG_MULTI_SZ, "MULTI_SZ" },
41 { REG_RESOURCE_LIST, "RSRC_LIST" },
42 { REG_FULL_RESOURCE_DESCRIPTOR, "RSRC_DESC" },
43 { REG_RESOURCE_REQUIREMENTS_LIST,"RSRC_REQ_LIST"},
44 { REG_KEY, "KEY" },
45 { 0, NULL },
46};
47
48
49/* Returns NULL on error */
50const char* regfio_type_val2str(unsigned int val)
51{
52 int i;
53
54 for(i=0; reg_type_names[i].val && reg_type_names[i].str; i++)
55 if (reg_type_names[i].val == val)
56 return reg_type_names[i].str;
57
58 return NULL;
59}
60
61
62/* Returns 0 on error */
63int regfio_type_str2val(const char* str)
64{
65 int i;
66
67 for(i=0; reg_type_names[i].val && reg_type_names[i].str; i++)
68 if (strcmp(reg_type_names[i].str, str) == 0)
69 return reg_type_names[i].val;
70
71 return 0;
72}
73
74
75/* Security descriptor parsing functions */
76
77const char* regfio_ace_type2str(uint8 type)
78{
79 static const char* map[7]
80 = {"ALLOW", "DENY", "AUDIT", "ALARM",
81 "ALLOW CPD", "OBJ ALLOW", "OBJ DENY"};
82 if(type < 7)
83 return map[type];
84 else
85 /* XXX: would be nice to return the unknown integer value.
86 * However, as it is a const string, it can't be free()ed later on,
87 * so that would need to change.
88 */
89 return "UNKNOWN";
90}
91
92
93/* XXX: this could probably be more efficient */
94char* regfio_ace_flags2str(uint8 flags)
95{
96 char* flg_output = malloc(21*sizeof(char));
97 int some = 0;
98
99 if(flg_output == NULL)
100 return NULL;
101
102 flg_output[0] = '\0';
103 if (!flags)
104 return flg_output;
105
106 if (flags & 0x01) {
107 if (some) strcat(flg_output, " ");
108 some = 1;
109 strcat(flg_output, "OI");
110 }
111 if (flags & 0x02) {
112 if (some) strcat(flg_output, " ");
113 some = 1;
114 strcat(flg_output, "CI");
115 }
116 if (flags & 0x04) {
117 if (some) strcat(flg_output, " ");
118 some = 1;
119 strcat(flg_output, "NP");
120 }
121 if (flags & 0x08) {
122 if (some) strcat(flg_output, " ");
123 some = 1;
124 strcat(flg_output, "IO");
125 }
126 if (flags & 0x10) {
127 if (some) strcat(flg_output, " ");
128 some = 1;
129 strcat(flg_output, "IA");
130 }
131 /* XXX: Is this check right? 0xF == 1|2|4|8, which makes it redundant... */
132 if (flags == 0xF) {
133 if (some) strcat(flg_output, " ");
134 some = 1;
135 strcat(flg_output, "VI");
136 }
137
138 return flg_output;
139}
140
141
142char* regfio_ace_perms2str(uint32 perms)
143{
144 char* ret_val = malloc(9*sizeof(char));
145 if(ret_val == NULL)
146 return NULL;
147
148 /* XXX: this should probably be parsed better */
149 sprintf(ret_val, "%.8X", perms);
150
151 return ret_val;
152}
153
154
155char* regfio_sid2str(DOM_SID* sid)
156{
157 uint32 i, size = MAXSUBAUTHS*11 + 24;
158 uint32 left = size;
159 uint8 comps = sid->num_auths;
160 char* ret_val = malloc(size);
161
162 if(ret_val == NULL)
163 return NULL;
164
165 if(comps > MAXSUBAUTHS)
166 comps = MAXSUBAUTHS;
167
168 left -= sprintf(ret_val, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
169
170 for (i = 0; i < comps; i++)
171 left -= snprintf(ret_val+(size-left), left, "-%u", sid->sub_auths[i]);
172
173 return ret_val;
174}
175
176
177char* regfio_get_acl(SEC_ACL* acl)
178{
179 uint32 i, extra, size = 0;
180 const char* type_str;
181 char* flags_str;
182 char* perms_str;
183 char* sid_str;
184 char* ret_val = NULL;
185 char* ace_delim = "";
186 char field_delim = ':';
187
188 for (i = 0; i < acl->num_aces; i++)
189 {
190 sid_str = regfio_sid2str(&acl->ace[i].trustee);
191 type_str = regfio_ace_type2str(acl->ace[i].type);
192 perms_str = regfio_ace_perms2str(acl->ace[i].info.mask);
193 flags_str = regfio_ace_flags2str(acl->ace[i].flags);
194
195 if(flags_str == NULL || perms_str == NULL
196 || type_str == NULL || sid_str == NULL)
197 return NULL;
198
199 /* XXX: this is slow */
200 extra = strlen(sid_str) + strlen(type_str)
201 + strlen(perms_str) + strlen(flags_str)+5;
202 ret_val = realloc(ret_val, size+extra);
203 if(ret_val == NULL)
204 return NULL;
205 size += snprintf(ret_val+size, extra, "%s%s%c%s%c%s%c%s",
206 ace_delim,sid_str,
207 field_delim,type_str,
208 field_delim,perms_str,
209 field_delim,flags_str);
210 ace_delim = "|";
211 free(sid_str);
212 free(perms_str);
213 free(flags_str);
214 }
215
216 return ret_val;
217}
218
219
220char* regfio_get_sacl(SEC_DESC *sec_desc)
221{
222 if (sec_desc->sacl)
223 return regfio_get_acl(sec_desc->sacl);
224 else
225 return NULL;
226}
227
228
229char* regfio_get_dacl(SEC_DESC *sec_desc)
230{
231 if (sec_desc->dacl)
232 return regfio_get_acl(sec_desc->dacl);
233 else
234 return NULL;
235}
236
237
238char* regfio_get_owner(SEC_DESC *sec_desc)
239{
240 return regfio_sid2str(sec_desc->owner_sid);
241}
242
243
244char* regfio_get_group(SEC_DESC *sec_desc)
245{
246 return regfio_sid2str(sec_desc->grp_sid);
247}
248
249
250
251/*******************************************************************
252 *******************************************************************/
253static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset,
254 uint32 block_size )
255{
256 int bytes_read, returned;
257 char *buffer;
258 SMB_STRUCT_STAT sbuf;
259
260 /* check for end of file */
261
262 if ( fstat( file->fd, &sbuf ) ) {
263 /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
264 return -1;
265 }
266
267 if ( (size_t)file_offset >= sbuf.st_size )
268 return -1;
269
270 /* if block_size == 0, we are parsnig HBIN records and need
271 to read some of the header to get the block_size from there */
272
273 if ( block_size == 0 ) {
274 uint8 hdr[0x20];
275
276 if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
277 /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
278 return -1;
279 }
280
281 returned = read( file->fd, hdr, 0x20 );
282 if ( (returned == -1) || (returned < 0x20) ) {
283 /*DEBUG(0,("read_block: failed to read in HBIN header. Is the file corrupt?\n"));*/
284 return -1;
285 }
286
287 /* make sure this is an hbin header */
288
289 if ( strncmp( (char*)hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
290 /*DEBUG(0,("read_block: invalid block header!\n"));*/
291 return -1;
292 }
293
294 block_size = IVAL( hdr, 0x08 );
295 }
296
297 /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
298
299 /* set the offset, initialize the buffer, and read the block from disk */
300
301 if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
302 /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
303 return -1;
304 }
305
306 prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
307 buffer = ps->data_p;
308 bytes_read = returned = 0;
309
310 while ( bytes_read < block_size )
311 {
312 if((returned =
313 read(file->fd, buffer+bytes_read, block_size-bytes_read)) == -1)
314 {
315 /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
316 return false;
317 }
318 if ((returned == 0) && (bytes_read < block_size))
319 {
320 /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
321 return false;
322 }
323
324 bytes_read += returned;
325 }
326
327 return bytes_read;
328}
329
330
331/*******************************************************************
332 *******************************************************************/
333static bool prs_regf_block(const char *desc, prs_struct *ps,
334 int depth, REGF_FILE *file)
335{
336 depth++;
337
338 if(!prs_uint8s(true, "header", ps, depth, file->header, sizeof(file->header)))
339 return false;
340
341 /* yes, these values are always identical so store them only once */
342
343 if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 ))
344 return false;
345 if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 ))
346 return false;
347
348 /* get the modtime */
349
350 if ( !prs_set_offset( ps, 0x0c ) )
351 return false;
352 if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
353 return false;
354
355 /* constants */
356
357 if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 ))
358 return false;
359 if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 ))
360 return false;
361 if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 ))
362 return false;
363 if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 ))
364 return false;
365
366 /* get file offsets */
367
368 if ( !prs_set_offset( ps, 0x24 ) )
369 return false;
370 if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset ))
371 return false;
372 if ( !prs_uint32( "last_block", ps, depth, &file->last_block ))
373 return false;
374
375 /* one more constant */
376
377 if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
378 return false;
379
380 /* get the checksum */
381
382 if ( !prs_set_offset( ps, 0x01fc ) )
383 return false;
384 if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
385 return false;
386
387 return true;
388}
389
390
391/*******************************************************************
392 *******************************************************************/
393static bool prs_hbin_block(const char *desc, prs_struct *ps,
394 int depth, REGF_HBIN *hbin)
395{
396 uint32 block_size2;
397
398 depth++;
399
400 if(!prs_uint8s(true, "header", ps, depth, hbin->header, sizeof(hbin->header)))
401 return false;
402
403 if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
404 return false;
405
406 /* The dosreg.cpp comments say that the block size is at 0x1c.
407 According to a WINXP NTUSER.dat file, this is wrong. The block_size
408 is at 0x08 */
409
410 if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
411 return false;
412
413 block_size2 = hbin->block_size;
414 prs_set_offset( ps, 0x1c );
415 if ( !prs_uint32( "block_size2", ps, depth, &block_size2 ))
416 return false;
417
418 if ( !ps->io )
419 hbin->dirty = true;
420
421
422 return true;
423}
424
425
426/*******************************************************************
427 *******************************************************************/
428static bool prs_nk_rec( const char *desc, prs_struct *ps,
429 int depth, REGF_NK_REC *nk )
430{
431 uint16 class_length, name_length;
432 uint32 start;
433 uint32 data_size, start_off, end_off;
434 uint32 unknown_off = REGF_OFFSET_NONE;
435
436 nk->hbin_off = ps->data_offset;
437 start = nk->hbin_off;
438
439 depth++;
440
441 /* back up and get the data_size */
442 if ( !prs_set_offset( ps, ps->data_offset-sizeof(uint32)) )
443 return false;
444 start_off = ps->data_offset;
445 if ( !prs_uint32( "rec_size", ps, depth, &nk->rec_size ))
446 return false;
447
448 if (!prs_uint8s(true, "header", ps, depth, nk->header, sizeof(nk->header)))
449 return false;
450
451 if ( !prs_uint16( "key_type", ps, depth, &nk->key_type ))
452 return false;
453 if ( !smb_io_time( "mtime", &nk->mtime, ps, depth ))
454 return false;
455
456 if ( !prs_set_offset( ps, start+0x0010 ) )
457 return false;
458 if ( !prs_uint32( "parent_off", ps, depth, &nk->parent_off ))
459 return false;
460 if ( !prs_uint32( "num_subkeys", ps, depth, &nk->num_subkeys ))
461 return false;
462
463 if ( !prs_set_offset( ps, start+0x001c ) )
464 return false;
465 if ( !prs_uint32( "subkeys_off", ps, depth, &nk->subkeys_off ))
466 return false;
467 if ( !prs_uint32( "unknown_off", ps, depth, &unknown_off) )
468 return false;
469
470 if ( !prs_set_offset( ps, start+0x0024 ) )
471 return false;
472 if ( !prs_uint32( "num_values", ps, depth, &nk->num_values ))
473 return false;
474 if ( !prs_uint32( "values_off", ps, depth, &nk->values_off ))
475 return false;
476 if ( !prs_uint32( "sk_off", ps, depth, &nk->sk_off ))
477 return false;
478 if ( !prs_uint32( "classname_off", ps, depth, &nk->classname_off ))
479 return false;
480
481 if (!prs_uint32("max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
482 return false;
483 if ( !prs_uint32( "max_bytes_subkeyclassname", ps,
484 depth, &nk->max_bytes_subkeyclassname))
485 { return false; }
486 if ( !prs_uint32( "max_bytes_valuename", ps, depth, &nk->max_bytes_valuename))
487 return false;
488 if ( !prs_uint32( "max_bytes_value", ps, depth, &nk->max_bytes_value))
489 return false;
490 if ( !prs_uint32( "unknown index", ps, depth, &nk->unk_index))
491 return false;
492
493 name_length = nk->keyname ? strlen(nk->keyname) : 0 ;
494 class_length = nk->classname ? strlen(nk->classname) : 0 ;
495 if ( !prs_uint16( "name_length", ps, depth, &name_length ))
496 return false;
497 if ( !prs_uint16( "class_length", ps, depth, &class_length ))
498 return false;
499
500 if ( class_length )
501 {
502 ;;
503 }
504
505 if ( name_length )
506 {
507 if(ps->io && !(nk->keyname = (char*)zcalloc(sizeof(char), name_length+1)))
508 return false;
509
510 if(!prs_uint8s(true, "name", ps, depth, (uint8*)nk->keyname, name_length))
511 return false;
512
513 if(ps->io)
514 nk->keyname[name_length] = '\0';
515 }
516
517 end_off = ps->data_offset;
518
519 /* data_size must be divisible by 8 and large enough to hold
520 the original record */
521
522 data_size = ((start_off - end_off) & 0xfffffff8 );
523 /*if ( data_size > nk->rec_size )
524 DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
525
526 if ( !ps->io )
527 nk->hbin->dirty = true;
528
529 nk->subkey_index = 0;
530 return true;
531}
532
533
534/*******************************************************************
535 *******************************************************************/
536static uint32 regf_block_checksum( prs_struct *ps )
537{
538 char *buffer = ps->data_p;
539 uint32 checksum, x;
540 int i;
541
542 /* XOR of all bytes 0x0000 - 0x01FB */
543
544 checksum = x = 0;
545
546 for ( i=0; i<0x01FB; i+=4 ) {
547 x = IVAL(buffer, i );
548 checksum ^= x;
549 }
550
551 return checksum;
552}
553
554
555/*******************************************************************
556 *******************************************************************/
557static bool read_regf_block( REGF_FILE *file )
558{
559 prs_struct ps;
560 uint32 checksum;
561
562 /* grab the first block from the file */
563
564 if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
565 return false;
566
567 /* parse the block and verify the checksum */
568
569 if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
570 return false;
571
572 checksum = regf_block_checksum( &ps );
573
574 if(ps.is_dynamic)
575 SAFE_FREE(ps.data_p);
576 ps.is_dynamic = false;
577 ps.buffer_size = 0;
578 ps.data_offset = 0;
579
580 if ( file->checksum != checksum ) {
581 /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
582 return false;
583 }
584
585 return true;
586}
587
588
589/*******************************************************************
590 *******************************************************************/
591static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
592{
593 REGF_HBIN *hbin;
594 uint32 record_size, curr_off, block_size, header;
595
596 if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) )
597 return NULL;
598 hbin->file_off = offset;
599 hbin->free_off = -1;
600
601 if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
602 return NULL;
603
604 if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
605 return NULL;
606
607 /* this should be the same thing as hbin->block_size but just in case */
608
609 block_size = hbin->ps.buffer_size;
610
611 /* Find the available free space offset. Always at the end,
612 so walk the record list and stop when you get to the end.
613 The end is defined by a record header of 0xffffffff. The
614 previous 4 bytes contains the amount of free space remaining
615 in the hbin block. */
616
617 /* remember that the record_size is in the 4 bytes preceeding the record itself */
618
619 if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
620 return false;
621
622 record_size = 0;
623 curr_off = hbin->ps.data_offset;
624 while ( header != 0xffffffff ) {
625 /* not done yet so reset the current offset to the
626 next record_size field */
627
628 curr_off = curr_off+record_size;
629
630 /* for some reason the record_size of the last record in
631 an hbin block can extend past the end of the block
632 even though the record fits within the remaining
633 space....aaarrrgggghhhhhh */
634
635 if ( curr_off >= block_size ) {
636 record_size = -1;
637 curr_off = -1;
638 break;
639 }
640
641 if ( !prs_set_offset( &hbin->ps, curr_off) )
642 return false;
643
644 if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) )
645 return false;
646 if ( !prs_uint32( "header", &hbin->ps, 0, &header ) )
647 return false;
648
649 assert( record_size != 0 );
650
651 if ( record_size & 0x80000000 ) {
652 /* absolute_value(record_size) */
653 record_size = (record_size ^ 0xffffffff) + 1;
654 }
655 }
656
657 /* save the free space offset */
658
659 if ( header == 0xffffffff ) {
660
661 /* account for the fact that the curr_off is 4 bytes behind the actual
662 record header */
663
664 hbin->free_off = curr_off + sizeof(uint32);
665 hbin->free_size = record_size;
666 }
667
668 /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
669
670 if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE ) )
671 return false;
672
673 return hbin;
674}
675
676
677/*******************************************************************
678 Input a randon offset and receive the correpsonding HBIN
679 block for it
680*******************************************************************/
681static bool hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
682{
683 if ( !hbin )
684 return false;
685
686 if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
687 return true;
688
689 return false;
690}
691
692
693/*******************************************************************
694 Input a randon offset and receive the correpsonding HBIN
695 block for it
696*******************************************************************/
697static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset )
698{
699 REGF_HBIN *hbin = NULL;
700 uint32 block_off;
701
702 /* start with the open list */
703
704 for ( hbin=file->block_list; hbin; hbin=hbin->next ) {
705 /* DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%x]\n", hbin->file_off, (uint32)hbin ));*/
706 if ( hbin_contains_offset( hbin, offset ) )
707 return hbin;
708 }
709
710 if ( !hbin ) {
711 /* start at the beginning */
712
713 block_off = REGF_BLOCKSIZE;
714 do {
715 /* cleanup before the next round */
716 if ( hbin )
717 {
718 if(hbin->ps.is_dynamic)
719 SAFE_FREE(hbin->ps.data_p);
720 hbin->ps.is_dynamic = false;
721 hbin->ps.buffer_size = 0;
722 hbin->ps.data_offset = 0;
723 }
724
725 hbin = read_hbin_block( file, block_off );
726
727 if ( hbin )
728 block_off = hbin->file_off + hbin->block_size;
729
730 } while ( hbin && !hbin_contains_offset( hbin, offset ) );
731 }
732
733 if ( hbin )
734 DLIST_ADD( file->block_list, hbin );
735
736 return hbin;
737}
738
739
740/*******************************************************************
741 *******************************************************************/
742static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
743{
744 depth++;
745
746 if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off ))
747 return false;
748 if ( !prs_uint8s( true, "keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) )
749 return false;
750
751 return true;
752}
753
754
755/*******************************************************************
756 *******************************************************************/
757static bool hbin_prs_lf_records(const char *desc, REGF_HBIN *hbin,
758 int depth, REGF_NK_REC *nk)
759{
760 int i;
761 REGF_LF_REC *lf = &nk->subkeys;
762 uint32 data_size, start_off, end_off;
763
764 depth++;
765
766 /* check if we have anything to do first */
767
768 if ( nk->num_subkeys == 0 )
769 return true;
770
771 /* move to the LF record */
772
773 if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
774 return false;
775
776 /* backup and get the data_size */
777
778 if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
779 return false;
780 start_off = hbin->ps.data_offset;
781 if ( !prs_uint32( "rec_size", &hbin->ps, depth, &lf->rec_size ))
782 return false;
783
784 if(!prs_uint8s(true, "header", &hbin->ps, depth,
785 lf->header, sizeof(lf->header)))
786 return false;
787
788 if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
789 return false;
790
791 if ( hbin->ps.io ) {
792 if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
793 return false;
794 }
795
796 for ( i=0; i<lf->num_keys; i++ ) {
797 if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) )
798 return false;
799 }
800
801 end_off = hbin->ps.data_offset;
802
803 /* data_size must be divisible by 8 and large enough to hold the original record */
804
805 data_size = ((start_off - end_off) & 0xfffffff8 );
806 /* if ( data_size > lf->rec_size )*/
807 /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
808
809 if ( !hbin->ps.io )
810 hbin->dirty = true;
811
812 return true;
813}
814
815
816/*******************************************************************
817 *******************************************************************/
818static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
819{
820 prs_struct *ps = &hbin->ps;
821 uint16 tag = 0xFFFF;
822 uint32 data_size, start_off, end_off;
823
824
825 depth++;
826
827 if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
828 return false;
829
830 /* backup and get the data_size */
831
832 if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
833 return false;
834 start_off = hbin->ps.data_offset;
835 if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size ))
836 return false;
837
838 if (!prs_uint8s(true, "header", ps, depth, sk->header, sizeof(sk->header)))
839 return false;
840 if ( !prs_uint16( "tag", ps, depth, &tag))
841 return false;
842
843 if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off))
844 return false;
845 if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off))
846 return false;
847 if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count))
848 return false;
849 if ( !prs_uint32( "size", ps, depth, &sk->size))
850 return false;
851
852 if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth ))
853 return false;
854
855 end_off = hbin->ps.data_offset;
856
857 /* data_size must be divisible by 8 and large enough to hold the original record */
858
859 data_size = ((start_off - end_off) & 0xfffffff8 );
860 /* if ( data_size > sk->rec_size )*/
861 /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
862
863 if ( !hbin->ps.io )
864 hbin->dirty = true;
865
866 return true;
867}
868
869
870/*******************************************************************
871 *******************************************************************/
872static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth,
873 REGF_VK_REC *vk, REGF_FILE *file )
874{
875 uint32 offset;
876 uint16 name_length;
877 prs_struct *ps = &hbin->ps;
878 uint32 data_size, start_off, end_off;
879
880 depth++;
881
882 /* backup and get the data_size */
883
884 if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
885 return false;
886 start_off = hbin->ps.data_offset;
887 if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size ))
888 return false;
889
890 if ( !prs_uint8s( true, "header", ps, depth, vk->header, sizeof( vk->header )) )
891 return false;
892
893 if ( !hbin->ps.io )
894 name_length = strlen(vk->valuename);
895
896 if ( !prs_uint16( "name_length", ps, depth, &name_length ))
897 return false;
898 if ( !prs_uint32( "data_size", ps, depth, &vk->data_size ))
899 return false;
900 if ( !prs_uint32( "data_off", ps, depth, &vk->data_off ))
901 return false;
902 if ( !prs_uint32( "type", ps, depth, &vk->type))
903 return false;
904 if ( !prs_uint16( "flag", ps, depth, &vk->flag))
905 return false;
906
907 offset = ps->data_offset;
908 offset += 2; /* skip 2 bytes */
909 prs_set_offset( ps, offset );
910
911 /* get the name */
912
913 if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
914
915 if ( hbin->ps.io ) {
916 if ( !(vk->valuename = (char*)zcalloc(sizeof(char), name_length+1 )))
917 return false;
918 }
919 if ( !prs_uint8s(true, "name", ps, depth,
920 (uint8*)vk->valuename, name_length) )
921 return false;
922 }
923
924 end_off = hbin->ps.data_offset;
925
926 /* get the data if necessary */
927
928 if ( vk->data_size != 0 )
929 {
930 bool charmode = false;
931
932 if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
933 charmode = true;
934
935 /* the data is stored in the offset if the size <= 4 */
936 if ( !(vk->data_size & VK_DATA_IN_OFFSET) )
937 {
938 REGF_HBIN *hblock = hbin;
939 uint32 data_rec_size;
940
941 if ( hbin->ps.io )
942 {
943 if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
944 return false;
945 }
946
947 /* this data can be in another hbin */
948 if ( !hbin_contains_offset( hbin, vk->data_off ) )
949 {
950 if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
951 return false;
952 }
953 if (!(prs_set_offset(&hblock->ps,
954 (vk->data_off
955 + HBIN_HDR_SIZE
956 - hblock->first_hbin_off)
957 - sizeof(uint32))))
958 { return false; }
959
960 if ( !hblock->ps.io )
961 {
962 data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
963 data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF;
964 }
965 if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size ))
966 return false;
967 if(!prs_uint8s(charmode, "data", &hblock->ps, depth,
968 vk->data, vk->data_size))
969 return false;
970
971 if ( !hblock->ps.io )
972 hblock->dirty = true;
973 }
974 else
975 {
976 if(!(vk->data = zcalloc(sizeof(uint8), 4)))
977 return false;
978 SIVAL( vk->data, 0, vk->data_off );
979 }
980
981 }
982
983 /* data_size must be divisible by 8 and large enough to hold the original record */
984
985 data_size = ((start_off - end_off ) & 0xfffffff8 );
986 /*if ( data_size != vk->rec_size )
987 DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));*/
988
989 if ( !hbin->ps.io )
990 hbin->dirty = true;
991
992 return true;
993}
994
995
996/*******************************************************************
997 read a VK record which is contained in the HBIN block stored
998 in the prs_struct *ps.
999*******************************************************************/
1000static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin,
1001 int depth, REGF_NK_REC *nk, REGF_FILE *file)
1002{
1003 int i;
1004 uint32 record_size;
1005
1006 depth++;
1007
1008 /* check if we have anything to do first */
1009 if(nk->num_values == 0)
1010 return true;
1011
1012 if(hbin->ps.io)
1013 {
1014 if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC),
1015 nk->num_values )))
1016 return false;
1017 }
1018
1019 /* convert the offset to something relative to this HBIN block */
1020 if (!prs_set_offset(&hbin->ps,
1021 nk->values_off
1022 + HBIN_HDR_SIZE
1023 - hbin->first_hbin_off
1024 - sizeof(uint32)))
1025 { return false; }
1026
1027 if ( !hbin->ps.io )
1028 {
1029 record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
1030 record_size = (record_size - 1) ^ 0xFFFFFFFF;
1031 }
1032
1033 if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
1034 return false;
1035
1036 for ( i=0; i<nk->num_values; i++ )
1037 {
1038 if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
1039 return false;
1040 }
1041
1042 for ( i=0; i<nk->num_values; i++ )
1043 {
1044 REGF_HBIN *sub_hbin = hbin;
1045 uint32 new_offset;
1046
1047 if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) )
1048 {
1049 sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
1050 if ( !sub_hbin )
1051 {
1052 /*DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n",
1053 nk->values[i].hbin_off));*/
1054 return false;
1055 }
1056 }
1057
1058 new_offset = nk->values[i].rec_off
1059 + HBIN_HDR_SIZE
1060 - sub_hbin->first_hbin_off;
1061
1062 if (!prs_set_offset(&sub_hbin->ps, new_offset))
1063 return false;
1064 if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
1065 return false;
1066 }
1067
1068 if ( !hbin->ps.io )
1069 hbin->dirty = true;
1070
1071 return true;
1072}
1073
1074
1075/*******************************************************************
1076 *******************************************************************/
1077static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
1078{
1079 REGF_SK_REC *p_sk;
1080
1081 for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) {
1082 if ( p_sk->sk_off == offset )
1083 return p_sk;
1084 }
1085
1086 return NULL;
1087}
1088
1089
1090/*******************************************************************
1091 *******************************************************************/
1092static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
1093{
1094 REGF_SK_REC *p;
1095
1096 for ( p=file->sec_desc_list; p; p=p->next ) {
1097 if ( sec_desc_equal( p->sec_desc, sd ) )
1098 return p;
1099 }
1100
1101 /* failure */
1102
1103 return NULL;
1104}
1105
1106
1107/*******************************************************************
1108 *******************************************************************/
1109static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
1110{
1111 int depth = 0;
1112 REGF_HBIN *sub_hbin;
1113
1114 depth++;
1115
1116 /* get the initial nk record */
1117 if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
1118 return false;
1119
1120 /* fill in values */
1121 if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) )
1122 {
1123 sub_hbin = hbin;
1124 if ( !hbin_contains_offset( hbin, nk->values_off ) )
1125 {
1126 sub_hbin = lookup_hbin_block( file, nk->values_off );
1127 if ( !sub_hbin )
1128 {
1129 /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n",
1130 nk->values_off));*/
1131 return false;
1132 }
1133 }
1134
1135 if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
1136 return false;
1137 }
1138
1139 /* now get subkeys */
1140 if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) )
1141 {
1142 sub_hbin = hbin;
1143 if ( !hbin_contains_offset( hbin, nk->subkeys_off ) )
1144 {
1145 sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
1146 if ( !sub_hbin )
1147 {
1148 /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n",
1149 nk->subkeys_off));*/
1150 return false;
1151 }
1152 }
1153
1154 if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
1155 return false;
1156 }
1157
1158 /* get the to the security descriptor. First look if we have already parsed it */
1159
1160 if ((nk->sk_off!=REGF_OFFSET_NONE)
1161 && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
1162 {
1163 sub_hbin = hbin;
1164 if (!hbin_contains_offset(hbin, nk->sk_off))
1165 {
1166 sub_hbin = lookup_hbin_block( file, nk->sk_off );
1167 if ( !sub_hbin ) {
1168 /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n",
1169 nk->subkeys_off));*/
1170 return false;
1171 }
1172 }
1173
1174 if ( !(nk->sec_desc = (REGF_SK_REC*)zalloc(sizeof(REGF_SK_REC) )) )
1175 return false;
1176 nk->sec_desc->sk_off = nk->sk_off;
1177 if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))
1178 return false;
1179
1180 /* add to the list of security descriptors (ref_count has been read from the files) */
1181
1182 nk->sec_desc->sk_off = nk->sk_off;
1183 DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1184 }
1185
1186 return true;
1187}
1188
1189
1190/*******************************************************************
1191 *******************************************************************/
1192static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
1193{
1194 uint8 header[REC_HDR_SIZE] = "";
1195 uint32 record_size;
1196 uint32 curr_off, block_size;
1197 bool found = false;
1198 prs_struct *ps = &hbin->ps;
1199
1200 curr_off = ps->data_offset;
1201 if ( curr_off == 0 )
1202 prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
1203
1204 /* assume that the current offset is at the reacord header
1205 and we need to backup to read the record size */
1206 curr_off -= sizeof(uint32);
1207
1208 block_size = ps->buffer_size;
1209 record_size = 0;
1210 while ( !found )
1211 {
1212 curr_off = curr_off+record_size;
1213 if ( curr_off >= block_size )
1214 break;
1215
1216 if ( !prs_set_offset( &hbin->ps, curr_off) )
1217 return false;
1218
1219 if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
1220 return false;
1221 if ( !prs_uint8s( true, "header", ps, 0, header, REC_HDR_SIZE ) )
1222 return false;
1223
1224 if ( record_size & 0x80000000 ) {
1225 /* absolute_value(record_size) */
1226 record_size = (record_size ^ 0xffffffff) + 1;
1227 }
1228
1229 if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1230 found = true;
1231 curr_off += sizeof(uint32);
1232 }
1233 }
1234
1235 /* mark prs_struct as done ( at end ) if no more SK records */
1236 /* mark end-of-block as true */
1237 if ( !found )
1238 {
1239 prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
1240 *eob = true;
1241 return false;
1242 }
1243
1244 if (!prs_set_offset(ps, curr_off))
1245 return false;
1246
1247 return true;
1248}
1249
1250
1251/*******************************************************************
1252 *******************************************************************/
1253static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin,
1254 REGF_NK_REC *nk, bool *eob)
1255{
1256 if (next_record(hbin, "nk", eob)
1257 && hbin_prs_key(file, hbin, nk))
1258 return true;
1259
1260 return false;
1261}
1262
1263
1264/*******************************************************************
1265 Open the registry file and then read in the REGF block to get the
1266 first hbin offset.
1267*******************************************************************/
1268REGF_FILE* regfio_open( const char *filename )
1269{
1270 REGF_FILE *rb;
1271 int flags = O_RDONLY;
1272
1273 if ( !(rb = (REGF_FILE*)malloc(sizeof(REGF_FILE))) ) {
1274 /* DEBUG(0,("ERROR allocating memory\n")); */
1275 return NULL;
1276 }
1277 memset(rb, 0, sizeof(REGF_FILE));
1278 rb->fd = -1;
1279
1280 /* if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) )
1281 {
1282 regfio_close( rb );
1283 return NULL;
1284 }
1285 */
1286 rb->open_flags = flags;
1287
1288 /* open and existing file */
1289
1290 if ( (rb->fd = open(filename, flags)) == -1 ) {
1291 /* DEBUG(0,("regfio_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
1292 regfio_close( rb );
1293 return NULL;
1294 }
1295
1296 /* read in an existing file */
1297
1298 if ( !read_regf_block( rb ) ) {
1299 /* DEBUG(0,("regfio_open: Failed to read initial REGF block\n"));*/
1300 regfio_close( rb );
1301 return NULL;
1302 }
1303
1304 /* success */
1305
1306 return rb;
1307}
1308
1309
1310/*******************************************************************
1311 *******************************************************************/
1312static void regfio_mem_free( REGF_FILE *file )
1313{
1314 /* free any zalloc()'d memory */
1315
1316 /* if ( file && file->mem_ctx )
1317 free(file->mem_ctx);
1318 */
1319}
1320
1321
1322/*******************************************************************
1323 *******************************************************************/
1324int regfio_close( REGF_FILE *file )
1325{
1326 int fd;
1327
1328 regfio_mem_free( file );
1329
1330 /* nothing to do if there is no open file */
1331
1332 if ( !file || (file->fd == -1) )
1333 return 0;
1334
1335 fd = file->fd;
1336 file->fd = -1;
1337 SAFE_FREE( file );
1338
1339 return close( fd );
1340}
1341
1342
1343/*******************************************************************
1344 There should be only *one* root key in the registry file based
1345 on my experience. --jerry
1346*******************************************************************/
1347REGF_NK_REC* regfio_rootkey( REGF_FILE *file )
1348{
1349 REGF_NK_REC *nk;
1350 REGF_HBIN *hbin;
1351 uint32 offset = REGF_BLOCKSIZE;
1352 bool found = false;
1353 bool eob;
1354
1355 if ( !file )
1356 return NULL;
1357
1358 if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
1359 /*DEBUG(0,("regfio_rootkey: zalloc() failed!\n"));*/
1360 return NULL;
1361 }
1362
1363 /* scan through the file on HBIN block at a time looking
1364 for an NK record with a type == 0x002c.
1365 Normally this is the first nk record in the first hbin
1366 block (but I'm not assuming that for now) */
1367
1368 while ( (hbin = read_hbin_block( file, offset )) ) {
1369 eob = false;
1370
1371 while ( !eob) {
1372 if ( next_nk_record( file, hbin, nk, &eob ) ) {
1373 if ( nk->key_type == NK_TYPE_ROOTKEY ) {
1374 found = true;
1375 break;
1376 }
1377 }
1378 if(hbin->ps.is_dynamic)
1379 SAFE_FREE(hbin->ps.data_p);
1380 hbin->ps.is_dynamic = false;
1381 hbin->ps.buffer_size = 0;
1382 hbin->ps.data_offset = 0;
1383 }
1384
1385 if ( found )
1386 break;
1387
1388 offset += hbin->block_size;
1389 }
1390
1391 if ( !found ) {
1392 /*DEBUG(0,("regfio_rootkey: corrupt registry file ? No root key record located\n"));*/
1393 return NULL;
1394 }
1395
1396 DLIST_ADD( file->block_list, hbin );
1397
1398 return nk;
1399}
1400
1401
1402/* XXX: An interator struct should be used instead, and this function
1403 * should operate on it, so the state of iteration isn't stored in the
1404 * REGF_NK_REC struct itself.
1405 */
1406/*******************************************************************
1407 This acts as an interator over the subkeys defined for a given
1408 NK record. Remember that offsets are from the *first* HBIN block.
1409*******************************************************************/
1410REGF_NK_REC* regfio_fetch_subkey( REGF_FILE *file, REGF_NK_REC *nk )
1411{
1412 REGF_NK_REC *subkey;
1413 REGF_HBIN *hbin;
1414 uint32 nk_offset;
1415
1416 /* see if there is anything left to report */
1417 if (!nk || (nk->subkeys_off==REGF_OFFSET_NONE)
1418 || (nk->subkey_index >= nk->num_subkeys))
1419 return NULL;
1420
1421 /* find the HBIN block which should contain the nk record */
1422 if(!(hbin
1423 = lookup_hbin_block(file, nk->subkeys.hashes[nk->subkey_index].nk_off )))
1424 {
1425 /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n",
1426 nk->subkeys.hashes[nk->subkey_index].nk_off));*/
1427 return NULL;
1428 }
1429
1430 nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off;
1431 if(!prs_set_offset(&hbin->ps,
1432 (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off)))
1433 return NULL;
1434
1435 nk->subkey_index++;
1436 if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
1437 return NULL;
1438
1439 if(!hbin_prs_key(file, hbin, subkey))
1440 return NULL;
1441
1442 return subkey;
1443}
Note: See TracBrowser for help on using the repository browser.