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

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

Moved security descriptor parsing functions into regfio.c

Improved malloc() mode of failure.

Eliminated some warnings in regfio.c

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