source: releases/0.4.0/lib/regfi.c@ 293

Last change on this file since 293 was 96, checked in by tim, 18 years ago

last minute fixes for filter bugs

  • Property svn:keywords set to Id
File size: 46.9 KB
Line 
1/*
2 * Branched from Samba project Subversion repository, version #7470:
3 * http://viewcvs.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c?rev=7470&view=auto
4 *
5 * Unix SMB/CIFS implementation.
6 * Windows NT registry I/O library
7 *
8 * Copyright (C) 2005-2007 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: regfi.c 96 2007-03-29 01:41:33Z tim $
25 */
26
27#include "../include/regfi.h"
28
29
30/* Registry types mapping */
31const unsigned int regfi_num_reg_types = 12;
32static const char* regfi_type_names[] =
33 {"NONE", "SZ", "EXPAND_SZ", "BINARY", "DWORD", "DWORD_BE", "LINK",
34 "MULTI_SZ", "RSRC_LIST", "RSRC_DESC", "RSRC_REQ_LIST", "QWORD"};
35
36
37/* Returns NULL on error */
38const char* regfi_type_val2str(unsigned int val)
39{
40 if(val == REG_KEY)
41 return "KEY";
42
43 if(val >= regfi_num_reg_types)
44 return NULL;
45
46 return regfi_type_names[val];
47}
48
49
50/* Returns -1 on error */
51int regfi_type_str2val(const char* str)
52{
53 int i;
54
55 if(strcmp("KEY", str) == 0)
56 return REG_KEY;
57
58 for(i=0; i < regfi_num_reg_types; i++)
59 if (strcmp(regfi_type_names[i], str) == 0)
60 return i;
61
62 if(strcmp("DWORD_LE", str) == 0)
63 return REG_DWORD_LE;
64
65 return -1;
66}
67
68
69/* Security descriptor parsing functions */
70
71const char* regfi_ace_type2str(uint8 type)
72{
73 static const char* map[7]
74 = {"ALLOW", "DENY", "AUDIT", "ALARM",
75 "ALLOW CPD", "OBJ ALLOW", "OBJ DENY"};
76 if(type < 7)
77 return map[type];
78 else
79 /* XXX: would be nice to return the unknown integer value.
80 * However, as it is a const string, it can't be free()ed later on,
81 * so that would need to change.
82 */
83 return "UNKNOWN";
84}
85
86
87/* XXX: need a better reference on the meaning of each flag. */
88/* For more info, see:
89 * http://msdn2.microsoft.com/en-us/library/aa772242.aspx
90 */
91char* regfi_ace_flags2str(uint8 flags)
92{
93 static const char* flag_map[32] =
94 { "OI", /* Object Inherit */
95 "CI", /* Container Inherit */
96 "NP", /* Non-Propagate */
97 "IO", /* Inherit Only */
98 "IA", /* Inherited ACE */
99 NULL,
100 NULL,
101 NULL,
102 };
103
104 char* ret_val = malloc(35*sizeof(char));
105 char* fo = ret_val;
106 uint32 i;
107 uint8 f;
108
109 if(ret_val == NULL)
110 return NULL;
111
112 fo[0] = '\0';
113 if (!flags)
114 return ret_val;
115
116 for(i=0; i < 8; i++)
117 {
118 f = (1<<i);
119 if((flags & f) && (flag_map[i] != NULL))
120 {
121 strcpy(fo, flag_map[i]);
122 fo += strlen(flag_map[i]);
123 *(fo++) = ' ';
124 flags ^= f;
125 }
126 }
127
128 /* Any remaining unknown flags are added at the end in hex. */
129 if(flags != 0)
130 sprintf(fo, "0x%.2X ", flags);
131
132 /* Chop off the last space if we've written anything to ret_val */
133 if(fo != ret_val)
134 fo[-1] = '\0';
135
136 /* XXX: what was this old VI flag for??
137 XXX: Is this check right? 0xF == 1|2|4|8, which makes it redundant...
138 if (flags == 0xF) {
139 if (some) strcat(flg_output, " ");
140 some = 1;
141 strcat(flg_output, "VI");
142 }
143 */
144
145 return ret_val;
146}
147
148
149char* regfi_ace_perms2str(uint32 perms)
150{
151 uint32 i, p;
152 /* This is more than is needed by a fair margin. */
153 char* ret_val = malloc(350*sizeof(char));
154 char* r = ret_val;
155
156 /* Each represents one of 32 permissions bits. NULL is for undefined/reserved bits.
157 * For more information, see:
158 * http://msdn2.microsoft.com/en-gb/library/aa374892.aspx
159 * http://msdn2.microsoft.com/en-gb/library/ms724878.aspx
160 */
161 static const char* perm_map[32] =
162 {/* object-specific permissions (registry keys, in this case) */
163 "QRY_VAL", /* KEY_QUERY_VALUE */
164 "SET_VAL", /* KEY_SET_VALUE */
165 "CREATE_KEY", /* KEY_CREATE_SUB_KEY */
166 "ENUM_KEYS", /* KEY_ENUMERATE_SUB_KEYS */
167 "NOTIFY", /* KEY_NOTIFY */
168 "CREATE_LNK", /* KEY_CREATE_LINK - Reserved for system use. */
169 NULL,
170 NULL,
171 "WOW64_64", /* KEY_WOW64_64KEY */
172 "WOW64_32", /* KEY_WOW64_32KEY */
173 NULL,
174 NULL,
175 NULL,
176 NULL,
177 NULL,
178 NULL,
179 /* standard access rights */
180 "DELETE", /* DELETE */
181 "R_CONT", /* READ_CONTROL */
182 "W_DAC", /* WRITE_DAC */
183 "W_OWNER", /* WRITE_OWNER */
184 "SYNC", /* SYNCHRONIZE - Shouldn't be set in registries */
185 NULL,
186 NULL,
187 NULL,
188 /* other generic */
189 "SYS_SEC", /* ACCESS_SYSTEM_SECURITY */
190 "MAX_ALLWD", /* MAXIMUM_ALLOWED */
191 NULL,
192 NULL,
193 "GEN_A", /* GENERIC_ALL */
194 "GEN_X", /* GENERIC_EXECUTE */
195 "GEN_W", /* GENERIC_WRITE */
196 "GEN_R", /* GENERIC_READ */
197 };
198
199
200 if(ret_val == NULL)
201 return NULL;
202
203 r[0] = '\0';
204 for(i=0; i < 32; i++)
205 {
206 p = (1<<i);
207 if((perms & p) && (perm_map[i] != NULL))
208 {
209 strcpy(r, perm_map[i]);
210 r += strlen(perm_map[i]);
211 *(r++) = ' ';
212 perms ^= p;
213 }
214 }
215
216 /* Any remaining unknown permission bits are added at the end in hex. */
217 if(perms != 0)
218 sprintf(r, "0x%.8X ", perms);
219
220 /* Chop off the last space if we've written anything to ret_val */
221 if(r != ret_val)
222 r[-1] = '\0';
223
224 return ret_val;
225}
226
227
228char* regfi_sid2str(DOM_SID* sid)
229{
230 uint32 i, size = MAXSUBAUTHS*11 + 24;
231 uint32 left = size;
232 uint8 comps = sid->num_auths;
233 char* ret_val = malloc(size);
234
235 if(ret_val == NULL)
236 return NULL;
237
238 if(comps > MAXSUBAUTHS)
239 comps = MAXSUBAUTHS;
240
241 left -= sprintf(ret_val, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
242
243 for (i = 0; i < comps; i++)
244 left -= snprintf(ret_val+(size-left), left, "-%u", sid->sub_auths[i]);
245
246 return ret_val;
247}
248
249
250char* regfi_get_acl(SEC_ACL* acl)
251{
252 uint32 i, extra, size = 0;
253 const char* type_str;
254 char* flags_str;
255 char* perms_str;
256 char* sid_str;
257 char* ace_delim = "";
258 char* ret_val = NULL;
259 char* tmp_val = NULL;
260 bool failed = false;
261 char field_delim = ':';
262
263 for (i = 0; i < acl->num_aces && !failed; i++)
264 {
265 sid_str = regfi_sid2str(&acl->ace[i].trustee);
266 type_str = regfi_ace_type2str(acl->ace[i].type);
267 perms_str = regfi_ace_perms2str(acl->ace[i].info.mask);
268 flags_str = regfi_ace_flags2str(acl->ace[i].flags);
269
270 if(flags_str != NULL && perms_str != NULL
271 && type_str != NULL && sid_str != NULL)
272 {
273 /* XXX: this is slow */
274 extra = strlen(sid_str) + strlen(type_str)
275 + strlen(perms_str) + strlen(flags_str)+5;
276 tmp_val = realloc(ret_val, size+extra);
277
278 if(tmp_val == NULL)
279 {
280 free(ret_val);
281 failed = true;
282 }
283 else
284 {
285 ret_val = tmp_val;
286 size += snprintf(ret_val+size, extra, "%s%s%c%s%c%s%c%s",
287 ace_delim,sid_str,
288 field_delim,type_str,
289 field_delim,perms_str,
290 field_delim,flags_str);
291 ace_delim = "|";
292 }
293 }
294 else
295 failed = true;
296
297 if(sid_str != NULL)
298 free(sid_str);
299 if(sid_str != NULL)
300 free(perms_str);
301 if(sid_str != NULL)
302 free(flags_str);
303 }
304
305 return ret_val;
306}
307
308
309char* regfi_get_sacl(SEC_DESC *sec_desc)
310{
311 if (sec_desc->sacl)
312 return regfi_get_acl(sec_desc->sacl);
313 else
314 return NULL;
315}
316
317
318char* regfi_get_dacl(SEC_DESC *sec_desc)
319{
320 if (sec_desc->dacl)
321 return regfi_get_acl(sec_desc->dacl);
322 else
323 return NULL;
324}
325
326
327char* regfi_get_owner(SEC_DESC *sec_desc)
328{
329 return regfi_sid2str(sec_desc->owner_sid);
330}
331
332
333char* regfi_get_group(SEC_DESC *sec_desc)
334{
335 return regfi_sid2str(sec_desc->grp_sid);
336}
337
338
339
340/*******************************************************************
341 *******************************************************************/
342static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset,
343 uint32 block_size )
344{
345 const int hdr_size = 0x20;
346 int bytes_read, returned;
347 char *buffer;
348 SMB_STRUCT_STAT sbuf;
349
350 /* check for end of file */
351
352 if ( fstat( file->fd, &sbuf ) ) {
353 /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
354 return -1;
355 }
356
357 if ( (size_t)file_offset >= sbuf.st_size )
358 return -1;
359
360 /* if block_size == 0, we are parsnig HBIN records and need
361 to read some of the header to get the block_size from there */
362
363 if ( block_size == 0 ) {
364 uint8 hdr[0x20];
365
366 if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
367 /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
368 return -1;
369 }
370
371 bytes_read = returned = 0;
372 while (bytes_read < hdr_size)
373 {
374 returned = read(file->fd, hdr + bytes_read, hdr_size - bytes_read);
375 if(returned == -1 && errno != EINTR && errno != EAGAIN)
376 {
377 /*DEBUG(0,("read_block: read of hdr failed (%s)\n",strerror(errno)));*/
378 return -1;
379 }
380
381 if(returned == 0)
382 return -1;
383
384 bytes_read += returned;
385 }
386
387 /* make sure this is an hbin header */
388
389 if ( strncmp( (char*)hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
390 /*DEBUG(0,("read_block: invalid block header!\n"));*/
391 return -1;
392 }
393
394 block_size = IVAL( hdr, 0x08 );
395 }
396
397 /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
398
399 /* set the offset, initialize the buffer, and read the block from disk */
400
401 if ( lseek( file->fd, file_offset, SEEK_SET ) == -1 ) {
402 /*DEBUG(0,("read_block: lseek() failed! (%s)\n", strerror(errno) ));*/
403 return -1;
404 }
405
406 prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
407 buffer = ps->data_p;
408 bytes_read = returned = 0;
409
410 while ( bytes_read < block_size )
411 {
412 returned = read(file->fd, buffer+bytes_read, block_size-bytes_read);
413 if(returned == -1 && errno != EINTR && errno != EAGAIN)
414 {
415 /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
416 return -1;
417 }
418
419 if ((returned == 0) && (bytes_read < block_size))
420 {
421 /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
422 return -1;
423 }
424
425 bytes_read += returned;
426 }
427
428 return bytes_read;
429}
430
431
432/*******************************************************************
433 *******************************************************************/
434static bool prs_regf_block(const char *desc, prs_struct *ps,
435 int depth, REGF_FILE *file)
436{
437 depth++;
438
439 if(!prs_uint8s("header", ps, depth, file->header, sizeof(file->header)))
440 return false;
441
442 /* yes, these values are always identical so store them only once */
443
444 if ( !prs_uint32( "unknown1", ps, depth, &file->unknown1 ))
445 return false;
446 if ( !prs_uint32( "unknown1 (again)", ps, depth, &file->unknown1 ))
447 return false;
448
449 /* get the modtime */
450
451 if ( !prs_set_offset( ps, 0x0c ) )
452 return false;
453 if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
454 return false;
455
456 /* constants */
457
458 if ( !prs_uint32( "unknown2", ps, depth, &file->unknown2 ))
459 return false;
460 if ( !prs_uint32( "unknown3", ps, depth, &file->unknown3 ))
461 return false;
462 if ( !prs_uint32( "unknown4", ps, depth, &file->unknown4 ))
463 return false;
464 if ( !prs_uint32( "unknown5", ps, depth, &file->unknown5 ))
465 return false;
466
467 /* get file offsets */
468
469 if ( !prs_set_offset( ps, 0x24 ) )
470 return false;
471 if ( !prs_uint32( "data_offset", ps, depth, &file->data_offset ))
472 return false;
473 if ( !prs_uint32( "last_block", ps, depth, &file->last_block ))
474 return false;
475
476 /* one more constant */
477
478 if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
479 return false;
480
481 /* get the checksum */
482
483 if ( !prs_set_offset( ps, 0x01fc ) )
484 return false;
485 if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
486 return false;
487
488 return true;
489}
490
491
492/*******************************************************************
493 *******************************************************************/
494static bool prs_hbin_block(const char *desc, prs_struct *ps,
495 int depth, REGF_HBIN *hbin)
496{
497 uint32 block_size2;
498
499 depth++;
500
501 if(!prs_uint8s("header", ps, depth, hbin->header, sizeof(hbin->header)))
502 return false;
503
504 if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
505 return false;
506
507 /* The dosreg.cpp comments say that the block size is at 0x1c.
508 According to a WINXP NTUSER.dat file, this is wrong. The block_size
509 is at 0x08 */
510
511 if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
512 return false;
513
514 block_size2 = hbin->block_size;
515 prs_set_offset( ps, 0x1c );
516 if ( !prs_uint32( "block_size2", ps, depth, &block_size2 ))
517 return false;
518
519 if ( !ps->io )
520 hbin->dirty = true;
521
522
523 return true;
524}
525
526
527/*******************************************************************
528 *******************************************************************/
529static bool prs_nk_rec( const char *desc, prs_struct *ps,
530 int depth, REGF_NK_REC *nk )
531{
532 uint16 class_length, name_length;
533 uint32 start;
534 uint32 data_size, start_off, end_off;
535 uint32 unknown_off = REGF_OFFSET_NONE;
536
537 nk->hbin_off = ps->data_offset;
538 start = nk->hbin_off;
539
540 depth++;
541
542 /* back up and get the data_size */
543 if ( !prs_set_offset( ps, ps->data_offset-sizeof(uint32)) )
544 return false;
545 start_off = ps->data_offset;
546 if ( !prs_uint32( "rec_size", ps, depth, &nk->rec_size ))
547 return false;
548
549 if (!prs_uint8s("header", ps, depth, nk->header, sizeof(nk->header)))
550 return false;
551
552 if ( !prs_uint16( "key_type", ps, depth, &nk->key_type ))
553 return false;
554 if ( !smb_io_time( "mtime", &nk->mtime, ps, depth ))
555 return false;
556
557 if ( !prs_set_offset( ps, start+0x0010 ) )
558 return false;
559 if ( !prs_uint32( "parent_off", ps, depth, &nk->parent_off ))
560 return false;
561 if ( !prs_uint32( "num_subkeys", ps, depth, &nk->num_subkeys ))
562 return false;
563
564 if ( !prs_set_offset( ps, start+0x001c ) )
565 return false;
566 if ( !prs_uint32( "subkeys_off", ps, depth, &nk->subkeys_off ))
567 return false;
568 if ( !prs_uint32( "unknown_off", ps, depth, &unknown_off) )
569 return false;
570
571 if ( !prs_set_offset( ps, start+0x0024 ) )
572 return false;
573 if ( !prs_uint32( "num_values", ps, depth, &nk->num_values ))
574 return false;
575 if ( !prs_uint32( "values_off", ps, depth, &nk->values_off ))
576 return false;
577 if ( !prs_uint32( "sk_off", ps, depth, &nk->sk_off ))
578 return false;
579 if ( !prs_uint32( "classname_off", ps, depth, &nk->classname_off ))
580 return false;
581
582 if (!prs_uint32("max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
583 return false;
584 if ( !prs_uint32( "max_bytes_subkeyclassname", ps,
585 depth, &nk->max_bytes_subkeyclassname))
586 { return false; }
587 if ( !prs_uint32( "max_bytes_valuename", ps, depth, &nk->max_bytes_valuename))
588 return false;
589 if ( !prs_uint32( "max_bytes_value", ps, depth, &nk->max_bytes_value))
590 return false;
591 if ( !prs_uint32( "unknown index", ps, depth, &nk->unk_index))
592 return false;
593
594 name_length = nk->keyname ? strlen(nk->keyname) : 0 ;
595 class_length = nk->classname ? strlen(nk->classname) : 0 ;
596 if ( !prs_uint16( "name_length", ps, depth, &name_length ))
597 return false;
598 if ( !prs_uint16( "class_length", ps, depth, &class_length ))
599 return false;
600
601 if ( class_length )
602 {
603 /* XXX: why isn't this parsed? */
604 ;;
605 }
606
607 if ( name_length )
608 {
609 if(ps->io && !(nk->keyname = (char*)zcalloc(sizeof(char), name_length+1)))
610 return false;
611
612 if(!prs_uint8s("name", ps, depth, (uint8*)nk->keyname, name_length))
613 return false;
614
615 if(ps->io)
616 nk->keyname[name_length] = '\0';
617 }
618
619 end_off = ps->data_offset;
620
621 /* data_size must be divisible by 8 and large enough to hold
622 the original record */
623
624 data_size = ((start_off - end_off) & 0xfffffff8 );
625 /*if ( data_size > nk->rec_size )
626 DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
627
628 if ( !ps->io )
629 nk->hbin->dirty = true;
630
631 return true;
632}
633
634
635/*******************************************************************
636 *******************************************************************/
637static uint32 regf_block_checksum( prs_struct *ps )
638{
639 char *buffer = ps->data_p;
640 uint32 checksum, x;
641 int i;
642
643 /* XOR of all bytes 0x0000 - 0x01FB */
644
645 checksum = x = 0;
646
647 for ( i=0; i<0x01FB; i+=4 ) {
648 x = IVAL(buffer, i );
649 checksum ^= x;
650 }
651
652 return checksum;
653}
654
655
656/*******************************************************************
657 *******************************************************************/
658static bool read_regf_block( REGF_FILE *file )
659{
660 prs_struct ps;
661 uint32 checksum;
662
663 /* grab the first block from the file */
664
665 if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
666 return false;
667
668 /* parse the block and verify the checksum */
669
670 if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
671 return false;
672
673 checksum = regf_block_checksum( &ps );
674
675 if(ps.is_dynamic)
676 SAFE_FREE(ps.data_p);
677 ps.is_dynamic = false;
678 ps.buffer_size = 0;
679 ps.data_offset = 0;
680
681 if ( file->checksum != checksum ) {
682 /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
683 return false;
684 }
685
686 return true;
687}
688
689
690/*******************************************************************
691 *******************************************************************/
692static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
693{
694 REGF_HBIN *hbin;
695 uint32 record_size, curr_off, block_size, header;
696
697 if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) )
698 return NULL;
699 hbin->file_off = offset;
700 hbin->free_off = -1;
701
702 if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
703 return NULL;
704
705 if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
706 return NULL;
707
708 /* this should be the same thing as hbin->block_size but just in case */
709
710 block_size = hbin->ps.buffer_size;
711
712 /* Find the available free space offset. Always at the end,
713 so walk the record list and stop when you get to the end.
714 The end is defined by a record header of 0xffffffff. The
715 previous 4 bytes contains the amount of free space remaining
716 in the hbin block. */
717
718 /* remember that the record_size is in the 4 bytes preceeding the record itself */
719
720 if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
721 return false;
722
723 record_size = 0;
724 curr_off = hbin->ps.data_offset;
725 while ( header != 0xffffffff ) {
726 /* not done yet so reset the current offset to the
727 next record_size field */
728
729 curr_off = curr_off+record_size;
730
731 /* for some reason the record_size of the last record in
732 an hbin block can extend past the end of the block
733 even though the record fits within the remaining
734 space....aaarrrgggghhhhhh */
735
736 if ( curr_off >= block_size ) {
737 record_size = -1;
738 curr_off = -1;
739 break;
740 }
741
742 if ( !prs_set_offset( &hbin->ps, curr_off) )
743 return false;
744
745 if ( !prs_uint32( "rec_size", &hbin->ps, 0, &record_size ) )
746 return false;
747 if ( !prs_uint32( "header", &hbin->ps, 0, &header ) )
748 return false;
749
750 assert( record_size != 0 );
751
752 if ( record_size & 0x80000000 ) {
753 /* absolute_value(record_size) */
754 record_size = (record_size ^ 0xffffffff) + 1;
755 }
756 }
757
758 /* save the free space offset */
759
760 if ( header == 0xffffffff ) {
761
762 /* account for the fact that the curr_off is 4 bytes behind the actual
763 record header */
764
765 hbin->free_off = curr_off + sizeof(uint32);
766 hbin->free_size = record_size;
767 }
768
769 /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
770
771 if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE ) )
772 return false;
773
774 return hbin;
775}
776
777
778/*******************************************************************
779 Input a randon offset and receive the correpsonding HBIN
780 block for it
781*******************************************************************/
782static bool hbin_contains_offset( REGF_HBIN *hbin, uint32 offset )
783{
784 if ( !hbin )
785 return false;
786
787 if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
788 return true;
789
790 return false;
791}
792
793
794/*******************************************************************
795 Input a randon offset and receive the correpsonding HBIN
796 block for it
797*******************************************************************/
798static REGF_HBIN* lookup_hbin_block( REGF_FILE *file, uint32 offset )
799{
800 REGF_HBIN *hbin = NULL;
801 uint32 block_off;
802
803 /* start with the open list */
804
805 for ( hbin=file->block_list; hbin; hbin=hbin->next ) {
806 /* DEBUG(10,("lookup_hbin_block: address = 0x%x [0x%x]\n", hbin->file_off, (uint32)hbin ));*/
807 if ( hbin_contains_offset( hbin, offset ) )
808 return hbin;
809 }
810
811 if ( !hbin ) {
812 /* start at the beginning */
813
814 block_off = REGF_BLOCKSIZE;
815 do {
816 /* cleanup before the next round */
817 if ( hbin )
818 {
819 if(hbin->ps.is_dynamic)
820 SAFE_FREE(hbin->ps.data_p);
821 hbin->ps.is_dynamic = false;
822 hbin->ps.buffer_size = 0;
823 hbin->ps.data_offset = 0;
824 }
825
826 hbin = read_hbin_block( file, block_off );
827
828 if ( hbin )
829 block_off = hbin->file_off + hbin->block_size;
830
831 } while ( hbin && !hbin_contains_offset( hbin, offset ) );
832 }
833
834 if ( hbin )
835 /* XXX: this kind of caching needs to be re-evaluated */
836 DLIST_ADD( file->block_list, hbin );
837
838 return hbin;
839}
840
841
842/*******************************************************************
843 *******************************************************************/
844static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
845{
846 depth++;
847
848 if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off ))
849 return false;
850 if ( !prs_uint8s("keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) )
851 return false;
852
853 return true;
854}
855
856
857/*******************************************************************
858 *******************************************************************/
859static bool hbin_prs_lf_records(const char *desc, REGF_HBIN *hbin,
860 int depth, REGF_NK_REC *nk)
861{
862 int i;
863 REGF_LF_REC *lf = &nk->subkeys;
864 uint32 data_size, start_off, end_off;
865
866 depth++;
867
868 /* check if we have anything to do first */
869
870 if ( nk->num_subkeys == 0 )
871 return true;
872
873 /* move to the LF record */
874
875 if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
876 return false;
877
878 /* backup and get the data_size */
879
880 if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
881 return false;
882 start_off = hbin->ps.data_offset;
883 if ( !prs_uint32( "rec_size", &hbin->ps, depth, &lf->rec_size ))
884 return false;
885
886 if(!prs_uint8s("header", &hbin->ps, depth,
887 lf->header, sizeof(lf->header)))
888 return false;
889
890 if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
891 return false;
892
893 if ( hbin->ps.io ) {
894 if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
895 return false;
896 }
897
898 for ( i=0; i<lf->num_keys; i++ ) {
899 if ( !prs_hash_rec( "hash_rec", &hbin->ps, depth, &lf->hashes[i] ) )
900 return false;
901 }
902
903 end_off = hbin->ps.data_offset;
904
905 /* data_size must be divisible by 8 and large enough to hold the original record */
906
907 data_size = ((start_off - end_off) & 0xfffffff8 );
908 /* if ( data_size > lf->rec_size )*/
909 /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
910
911 if ( !hbin->ps.io )
912 hbin->dirty = true;
913
914 return true;
915}
916
917
918/*******************************************************************
919 *******************************************************************/
920static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
921{
922 prs_struct *ps = &hbin->ps;
923 uint16 tag = 0xFFFF;
924 uint32 data_size, start_off, end_off;
925
926
927 depth++;
928
929 if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
930 return false;
931
932 /* backup and get the data_size */
933
934 if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
935 return false;
936 start_off = hbin->ps.data_offset;
937 if ( !prs_uint32( "rec_size", &hbin->ps, depth, &sk->rec_size ))
938 return false;
939
940 if (!prs_uint8s("header", ps, depth, sk->header, sizeof(sk->header)))
941 return false;
942 if ( !prs_uint16( "tag", ps, depth, &tag))
943 return false;
944
945 if ( !prs_uint32( "prev_sk_off", ps, depth, &sk->prev_sk_off))
946 return false;
947 if ( !prs_uint32( "next_sk_off", ps, depth, &sk->next_sk_off))
948 return false;
949 if ( !prs_uint32( "ref_count", ps, depth, &sk->ref_count))
950 return false;
951 if ( !prs_uint32( "size", ps, depth, &sk->size))
952 return false;
953
954 if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth ))
955 return false;
956
957 end_off = hbin->ps.data_offset;
958
959 /* data_size must be divisible by 8 and large enough to hold the original record */
960
961 data_size = ((start_off - end_off) & 0xfffffff8 );
962 /* if ( data_size > sk->rec_size )*/
963 /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
964
965 if ( !hbin->ps.io )
966 hbin->dirty = true;
967
968 return true;
969}
970
971
972/*******************************************************************
973 *******************************************************************/
974static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth,
975 REGF_VK_REC *vk, REGF_FILE *file )
976{
977 uint32 offset;
978 uint16 name_length;
979 prs_struct *ps = &hbin->ps;
980 uint32 data_size, start_off, end_off;
981
982 depth++;
983
984 /* backup and get the data_size */
985
986 if ( !prs_set_offset( &hbin->ps, hbin->ps.data_offset-sizeof(uint32)) )
987 return false;
988 start_off = hbin->ps.data_offset;
989 if ( !prs_uint32( "rec_size", &hbin->ps, depth, &vk->rec_size ))
990 return false;
991
992 if ( !prs_uint8s("header", ps, depth, vk->header, sizeof( vk->header )) )
993 return false;
994
995 if ( !hbin->ps.io )
996 name_length = strlen(vk->valuename);
997
998 if ( !prs_uint16( "name_length", ps, depth, &name_length ))
999 return false;
1000 if ( !prs_uint32( "data_size", ps, depth, &vk->data_size ))
1001 return false;
1002 if ( !prs_uint32( "data_off", ps, depth, &vk->data_off ))
1003 return false;
1004 if ( !prs_uint32( "type", ps, depth, &vk->type))
1005 return false;
1006 if ( !prs_uint16( "flag", ps, depth, &vk->flag))
1007 return false;
1008
1009 offset = ps->data_offset;
1010 offset += 2; /* skip 2 bytes */
1011 prs_set_offset( ps, offset );
1012
1013 /* get the name */
1014
1015 if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
1016
1017 if ( hbin->ps.io ) {
1018 if ( !(vk->valuename = (char*)zcalloc(sizeof(char), name_length+1 )))
1019 return false;
1020 }
1021 if ( !prs_uint8s("name", ps, depth,
1022 (uint8*)vk->valuename, name_length) )
1023 return false;
1024 }
1025
1026 end_off = hbin->ps.data_offset;
1027
1028 /* get the data if necessary */
1029
1030 if ( vk->data_size != 0 )
1031 {
1032 /* the data is stored in the offset if the size <= 4 */
1033 if ( !(vk->data_size & VK_DATA_IN_OFFSET) )
1034 {
1035 REGF_HBIN *hblock = hbin;
1036 uint32 data_rec_size;
1037
1038 if ( hbin->ps.io )
1039 {
1040 if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
1041 return false;
1042 }
1043
1044 /* this data can be in another hbin */
1045 if ( !hbin_contains_offset( hbin, vk->data_off ) )
1046 {
1047 if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
1048 return false;
1049 }
1050 if (!(prs_set_offset(&hblock->ps,
1051 (vk->data_off
1052 + HBIN_HDR_SIZE
1053 - hblock->first_hbin_off)
1054 - sizeof(uint32))))
1055 { return false; }
1056
1057 if ( !hblock->ps.io )
1058 {
1059 data_rec_size = ( (vk->data_size+sizeof(uint32)) & 0xfffffff8 ) + 8;
1060 data_rec_size = ( data_rec_size - 1 ) ^ 0xFFFFFFFF;
1061 }
1062 if ( !prs_uint32( "data_rec_size", &hblock->ps, depth, &data_rec_size ))
1063 return false;
1064 if(!prs_uint8s("data", &hblock->ps, depth,
1065 vk->data, vk->data_size))
1066 return false;
1067
1068 if ( !hblock->ps.io )
1069 hblock->dirty = true;
1070 }
1071 else
1072 {
1073 if(!(vk->data = zcalloc(sizeof(uint8), 4)))
1074 return false;
1075 SIVAL( vk->data, 0, vk->data_off );
1076 }
1077
1078 }
1079
1080 /* data_size must be divisible by 8 and large enough to hold the original record */
1081
1082 data_size = ((start_off - end_off ) & 0xfffffff8 );
1083 /* XXX: should probably print a warning here */
1084 /*if ( data_size != vk->rec_size )
1085 DEBUG(10,("prs_vk_rec: data_size check failed (0x%x < 0x%x)\n", data_size, vk->rec_size));*/
1086
1087 if ( !hbin->ps.io )
1088 hbin->dirty = true;
1089
1090 return true;
1091}
1092
1093
1094/*******************************************************************
1095 read a VK record which is contained in the HBIN block stored
1096 in the prs_struct *ps.
1097*******************************************************************/
1098static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin,
1099 int depth, REGF_NK_REC *nk, REGF_FILE *file)
1100{
1101 int i;
1102 uint32 record_size;
1103
1104 depth++;
1105
1106 /* check if we have anything to do first */
1107 if(nk->num_values == 0)
1108 return true;
1109
1110 if(hbin->ps.io)
1111 {
1112 if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC),
1113 nk->num_values )))
1114 return false;
1115 }
1116
1117 /* convert the offset to something relative to this HBIN block */
1118 if (!prs_set_offset(&hbin->ps,
1119 nk->values_off
1120 + HBIN_HDR_SIZE
1121 - hbin->first_hbin_off
1122 - sizeof(uint32)))
1123 { return false; }
1124
1125 if ( !hbin->ps.io )
1126 {
1127 record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
1128 record_size = (record_size - 1) ^ 0xFFFFFFFF;
1129 }
1130
1131 if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
1132 return false;
1133
1134 for ( i=0; i<nk->num_values; i++ )
1135 {
1136 if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
1137 return false;
1138 }
1139
1140 for ( i=0; i<nk->num_values; i++ )
1141 {
1142 REGF_HBIN *sub_hbin = hbin;
1143 uint32 new_offset;
1144
1145 if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) )
1146 {
1147 sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
1148 if ( !sub_hbin )
1149 {
1150 /*DEBUG(0,("hbin_prs_vk_records: Failed to find HBIN block containing offset [0x%x]\n",
1151 nk->values[i].hbin_off));*/
1152 return false;
1153 }
1154 }
1155
1156 new_offset = nk->values[i].rec_off
1157 + HBIN_HDR_SIZE
1158 - sub_hbin->first_hbin_off;
1159
1160 if (!prs_set_offset(&sub_hbin->ps, new_offset))
1161 return false;
1162 if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
1163 return false;
1164 }
1165
1166 if ( !hbin->ps.io )
1167 hbin->dirty = true;
1168
1169 return true;
1170}
1171
1172
1173/*******************************************************************
1174 *******************************************************************/
1175static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
1176{
1177 REGF_SK_REC *p_sk;
1178
1179 for ( p_sk=file->sec_desc_list; p_sk; p_sk=p_sk->next ) {
1180 if ( p_sk->sk_off == offset )
1181 return p_sk;
1182 }
1183
1184 return NULL;
1185}
1186
1187
1188/*******************************************************************
1189 *******************************************************************/
1190static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
1191{
1192 REGF_SK_REC *p;
1193
1194 for ( p=file->sec_desc_list; p; p=p->next ) {
1195 if ( sec_desc_equal( p->sec_desc, sd ) )
1196 return p;
1197 }
1198
1199 /* failure */
1200
1201 return NULL;
1202}
1203
1204
1205/*******************************************************************
1206 *******************************************************************/
1207static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
1208{
1209 int depth = 0;
1210 REGF_HBIN *sub_hbin;
1211
1212 depth++;
1213
1214 /* get the initial nk record */
1215 if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
1216 return false;
1217
1218 /* fill in values */
1219 if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) )
1220 {
1221 sub_hbin = hbin;
1222 if ( !hbin_contains_offset( hbin, nk->values_off ) )
1223 {
1224 sub_hbin = lookup_hbin_block( file, nk->values_off );
1225 if ( !sub_hbin )
1226 {
1227 /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing value_list_offset [0x%x]\n",
1228 nk->values_off));*/
1229 return false;
1230 }
1231 }
1232
1233 if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
1234 return false;
1235 }
1236
1237 /* now get subkeys */
1238 if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) )
1239 {
1240 sub_hbin = hbin;
1241 if ( !hbin_contains_offset( hbin, nk->subkeys_off ) )
1242 {
1243 sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
1244 if ( !sub_hbin )
1245 {
1246 /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing subkey_offset [0x%x]\n",
1247 nk->subkeys_off));*/
1248 return false;
1249 }
1250 }
1251
1252 if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
1253 return false;
1254 }
1255
1256 /* get the to the security descriptor. First look if we have already parsed it */
1257
1258 if ((nk->sk_off!=REGF_OFFSET_NONE)
1259 && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
1260 {
1261 sub_hbin = hbin;
1262 if (!hbin_contains_offset(hbin, nk->sk_off))
1263 {
1264 sub_hbin = lookup_hbin_block( file, nk->sk_off );
1265 if ( !sub_hbin ) {
1266 /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing sk_offset [0x%x]\n",
1267 nk->subkeys_off));*/
1268 return false;
1269 }
1270 }
1271
1272 if ( !(nk->sec_desc = (REGF_SK_REC*)zalloc(sizeof(REGF_SK_REC) )) )
1273 return false;
1274 nk->sec_desc->sk_off = nk->sk_off;
1275 if ( !hbin_prs_sk_rec( "sk_rec", sub_hbin, depth, nk->sec_desc ))
1276 return false;
1277
1278 /* add to the list of security descriptors (ref_count has been read from the files) */
1279
1280 nk->sec_desc->sk_off = nk->sk_off;
1281 /* XXX: this kind of caching needs to be re-evaluated */
1282 DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1283 }
1284
1285 return true;
1286}
1287
1288
1289/*******************************************************************
1290 *******************************************************************/
1291static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
1292{
1293 uint8 header[REC_HDR_SIZE] = "";
1294 uint32 record_size;
1295 uint32 curr_off, block_size;
1296 bool found = false;
1297 prs_struct *ps = &hbin->ps;
1298
1299 curr_off = ps->data_offset;
1300 if ( curr_off == 0 )
1301 prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
1302
1303 /* assume that the current offset is at the reacord header
1304 and we need to backup to read the record size */
1305 curr_off -= sizeof(uint32);
1306
1307 block_size = ps->buffer_size;
1308 record_size = 0;
1309 while ( !found )
1310 {
1311 curr_off = curr_off+record_size;
1312 if ( curr_off >= block_size )
1313 break;
1314
1315 if ( !prs_set_offset( &hbin->ps, curr_off) )
1316 return false;
1317
1318 if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
1319 return false;
1320 if ( !prs_uint8s("header", ps, 0, header, REC_HDR_SIZE ) )
1321 return false;
1322
1323 if ( record_size & 0x80000000 ) {
1324 /* absolute_value(record_size) */
1325 record_size = (record_size ^ 0xffffffff) + 1;
1326 }
1327
1328 if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1329 found = true;
1330 curr_off += sizeof(uint32);
1331 }
1332 }
1333
1334 /* mark prs_struct as done ( at end ) if no more SK records */
1335 /* mark end-of-block as true */
1336 if ( !found )
1337 {
1338 prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
1339 *eob = true;
1340 return false;
1341 }
1342
1343 if (!prs_set_offset(ps, curr_off))
1344 return false;
1345
1346 return true;
1347}
1348
1349
1350/*******************************************************************
1351 *******************************************************************/
1352static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin,
1353 REGF_NK_REC *nk, bool *eob)
1354{
1355 if (next_record(hbin, "nk", eob)
1356 && hbin_prs_key(file, hbin, nk))
1357 return true;
1358
1359 return false;
1360}
1361
1362
1363/*******************************************************************
1364 Open the registry file and then read in the REGF block to get the
1365 first hbin offset.
1366*******************************************************************/
1367REGF_FILE* regfi_open( const char *filename )
1368{
1369 REGF_FILE *rb;
1370 int flags = O_RDONLY;
1371
1372 if ( !(rb = (REGF_FILE*)malloc(sizeof(REGF_FILE))) ) {
1373 /* DEBUG(0,("ERROR allocating memory\n")); */
1374 return NULL;
1375 }
1376 memset(rb, 0, sizeof(REGF_FILE));
1377 rb->fd = -1;
1378
1379 /* if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) )
1380 {
1381 regfi_close( rb );
1382 return NULL;
1383 }
1384 */
1385 rb->open_flags = flags;
1386
1387 /* open and existing file */
1388
1389 if ( (rb->fd = open(filename, flags)) == -1 ) {
1390 /* DEBUG(0,("regfi_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
1391 regfi_close( rb );
1392 return NULL;
1393 }
1394
1395 /* read in an existing file */
1396
1397 if ( !read_regf_block( rb ) ) {
1398 /* DEBUG(0,("regfi_open: Failed to read initial REGF block\n"));*/
1399 regfi_close( rb );
1400 return NULL;
1401 }
1402
1403 /* success */
1404
1405 return rb;
1406}
1407
1408
1409/*******************************************************************
1410XXX: should this be nuked?
1411 *******************************************************************/
1412static void regfi_mem_free( REGF_FILE *file )
1413{
1414 /* free any zalloc()'d memory */
1415
1416 /* if ( file && file->mem_ctx )
1417 free(file->mem_ctx);
1418 */
1419}
1420
1421
1422/*******************************************************************
1423 *******************************************************************/
1424int regfi_close( REGF_FILE *file )
1425{
1426 int fd;
1427
1428 regfi_mem_free( file );
1429
1430 /* nothing to do if there is no open file */
1431
1432 if ( !file || (file->fd == -1) )
1433 return 0;
1434
1435 fd = file->fd;
1436 file->fd = -1;
1437 SAFE_FREE( file );
1438
1439 return close( fd );
1440}
1441
1442
1443/******************************************************************************
1444 * There should be only *one* root key in the registry file based
1445 * on my experience. --jerry
1446 *****************************************************************************/
1447REGF_NK_REC* regfi_rootkey( REGF_FILE *file )
1448{
1449 REGF_NK_REC *nk;
1450 REGF_HBIN *hbin;
1451 uint32 offset = REGF_BLOCKSIZE;
1452 bool found = false;
1453 bool eob;
1454
1455 if ( !file )
1456 return NULL;
1457
1458 if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
1459 /*DEBUG(0,("regfi_rootkey: zalloc() failed!\n"));*/
1460 return NULL;
1461 }
1462
1463 /* scan through the file on HBIN block at a time looking
1464 for an NK record with a type == 0x002c.
1465 Normally this is the first nk record in the first hbin
1466 block (but I'm not assuming that for now) */
1467
1468 while ( (hbin = read_hbin_block( file, offset )) ) {
1469 eob = false;
1470
1471 while ( !eob) {
1472 if ( next_nk_record( file, hbin, nk, &eob ) ) {
1473 if ( nk->key_type == NK_TYPE_ROOTKEY ) {
1474 found = true;
1475 break;
1476 }
1477 }
1478 if(hbin->ps.is_dynamic)
1479 SAFE_FREE(hbin->ps.data_p);
1480 hbin->ps.is_dynamic = false;
1481 hbin->ps.buffer_size = 0;
1482 hbin->ps.data_offset = 0;
1483 }
1484
1485 if ( found )
1486 break;
1487
1488 offset += hbin->block_size;
1489 }
1490
1491 if ( !found ) {
1492 /*DEBUG(0,("regfi_rootkey: corrupt registry file ? No root key record located\n"));*/
1493 return NULL;
1494 }
1495
1496 /* XXX: this kind of caching needs to be re-evaluated */
1497 DLIST_ADD( file->block_list, hbin );
1498
1499 return nk;
1500}
1501
1502
1503/******************************************************************************
1504 *****************************************************************************/
1505void regfi_key_free(REGF_NK_REC* nk)
1506{
1507 uint32 i;
1508
1509 if((nk->values != NULL) && (nk->values_off!=REGF_OFFSET_NONE))
1510 {
1511 for(i=0; i < nk->num_values; i++)
1512 {
1513 if(nk->values[i].valuename != NULL)
1514 free(nk->values[i].valuename);
1515 if(nk->values[i].data != NULL)
1516 free(nk->values[i].data);
1517 }
1518 free(nk->values);
1519 }
1520
1521 if(nk->keyname != NULL)
1522 free(nk->keyname);
1523 if(nk->classname != NULL)
1524 free(nk->classname);
1525
1526 /* XXX: not freeing hbin because these are cached. This needs to be reviewed. */
1527 /* XXX: not freeing sec_desc because these are cached. This needs to be reviewed. */
1528 free(nk);
1529}
1530
1531
1532/******************************************************************************
1533 *****************************************************************************/
1534REGFI_ITERATOR* regfi_iterator_new(REGF_FILE* fh)
1535{
1536 REGF_NK_REC* root;
1537 REGFI_ITERATOR* ret_val = (REGFI_ITERATOR*)malloc(sizeof(REGFI_ITERATOR));
1538 if(ret_val == NULL)
1539 return NULL;
1540
1541 root = regfi_rootkey(fh);
1542 if(root == NULL)
1543 {
1544 free(ret_val);
1545 return NULL;
1546 }
1547
1548 ret_val->key_positions = void_stack_new(REGF_MAX_DEPTH);
1549 if(ret_val->key_positions == NULL)
1550 {
1551 free(ret_val);
1552 free(root);
1553 return NULL;
1554 }
1555
1556 ret_val->f = fh;
1557 ret_val->cur_key = root;
1558 ret_val->cur_subkey = 0;
1559 ret_val->cur_value = 0;
1560
1561 return ret_val;
1562}
1563
1564
1565/******************************************************************************
1566 *****************************************************************************/
1567void regfi_iterator_free(REGFI_ITERATOR* i)
1568{
1569 REGFI_ITER_POSITION* cur;
1570
1571 if(i->cur_key != NULL)
1572 regfi_key_free(i->cur_key);
1573
1574 while((cur = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions)) != NULL)
1575 {
1576 regfi_key_free(cur->nk);
1577 free(cur);
1578 }
1579
1580 free(i);
1581}
1582
1583
1584
1585/******************************************************************************
1586 *****************************************************************************/
1587/* XXX: some way of indicating reason for failure should be added. */
1588bool regfi_iterator_down(REGFI_ITERATOR* i)
1589{
1590 REGF_NK_REC* subkey;
1591 REGFI_ITER_POSITION* pos;
1592
1593 pos = (REGFI_ITER_POSITION*)malloc(sizeof(REGFI_ITER_POSITION));
1594 if(pos == NULL)
1595 return false;
1596
1597 subkey = (REGF_NK_REC*)regfi_iterator_cur_subkey(i);
1598 if(subkey == NULL)
1599 {
1600 free(pos);
1601 return false;
1602 }
1603
1604 pos->nk = i->cur_key;
1605 pos->cur_subkey = i->cur_subkey;
1606 if(!void_stack_push(i->key_positions, pos))
1607 {
1608 free(pos);
1609 regfi_key_free(subkey);
1610 return false;
1611 }
1612
1613 i->cur_key = subkey;
1614 i->cur_subkey = 0;
1615 i->cur_value = 0;
1616
1617 return true;
1618}
1619
1620
1621/******************************************************************************
1622 *****************************************************************************/
1623bool regfi_iterator_up(REGFI_ITERATOR* i)
1624{
1625 REGFI_ITER_POSITION* pos;
1626
1627 pos = (REGFI_ITER_POSITION*)void_stack_pop(i->key_positions);
1628 if(pos == NULL)
1629 return false;
1630
1631 regfi_key_free(i->cur_key);
1632 i->cur_key = pos->nk;
1633 i->cur_subkey = pos->cur_subkey;
1634 i->cur_value = 0;
1635 free(pos);
1636
1637 return true;
1638}
1639
1640
1641/******************************************************************************
1642 *****************************************************************************/
1643bool regfi_iterator_to_root(REGFI_ITERATOR* i)
1644{
1645 while(regfi_iterator_up(i))
1646 continue;
1647
1648 return true;
1649}
1650
1651
1652/******************************************************************************
1653 *****************************************************************************/
1654bool regfi_iterator_find_subkey(REGFI_ITERATOR* i, const char* subkey_name)
1655{
1656 REGF_NK_REC* subkey;
1657 bool found = false;
1658 uint32 old_subkey = i->cur_subkey;
1659
1660 if(subkey_name == NULL)
1661 return false;
1662
1663 /* XXX: this alloc/free of each sub key might be a bit excessive */
1664 subkey = (REGF_NK_REC*)regfi_iterator_first_subkey(i);
1665 while((subkey != NULL) && (found == false))
1666 {
1667 if(subkey->keyname != NULL
1668 && strcasecmp(subkey->keyname, subkey_name) == 0)
1669 found = true;
1670 else
1671 {
1672 regfi_key_free(subkey);
1673 subkey = (REGF_NK_REC*)regfi_iterator_next_subkey(i);
1674 }
1675 }
1676
1677 if(found == false)
1678 {
1679 i->cur_subkey = old_subkey;
1680 return false;
1681 }
1682
1683 regfi_key_free(subkey);
1684 return true;
1685}
1686
1687
1688/******************************************************************************
1689 *****************************************************************************/
1690bool regfi_iterator_walk_path(REGFI_ITERATOR* i, const char** path)
1691{
1692 uint32 x;
1693 if(path == NULL)
1694 return false;
1695
1696 for(x=0;
1697 ((path[x] != NULL) && regfi_iterator_find_subkey(i, path[x])
1698 && regfi_iterator_down(i));
1699 x++)
1700 { continue; }
1701
1702 if(path[x] == NULL)
1703 return true;
1704
1705 /* XXX: is this the right number of times? */
1706 for(; x > 0; x--)
1707 regfi_iterator_up(i);
1708
1709 return false;
1710}
1711
1712
1713/******************************************************************************
1714 *****************************************************************************/
1715const REGF_NK_REC* regfi_iterator_cur_key(REGFI_ITERATOR* i)
1716{
1717 return i->cur_key;
1718}
1719
1720
1721/******************************************************************************
1722 *****************************************************************************/
1723const REGF_NK_REC* regfi_iterator_first_subkey(REGFI_ITERATOR* i)
1724{
1725 i->cur_subkey = 0;
1726 return regfi_iterator_cur_subkey(i);
1727}
1728
1729
1730/******************************************************************************
1731 *****************************************************************************/
1732const REGF_NK_REC* regfi_iterator_cur_subkey(REGFI_ITERATOR* i)
1733{
1734 REGF_NK_REC* subkey;
1735 REGF_HBIN* hbin;
1736 uint32 nk_offset;
1737
1738 /* see if there is anything left to report */
1739 if (!(i->cur_key) || (i->cur_key->subkeys_off==REGF_OFFSET_NONE)
1740 || (i->cur_subkey >= i->cur_key->num_subkeys))
1741 return NULL;
1742
1743 nk_offset = i->cur_key->subkeys.hashes[i->cur_subkey].nk_off;
1744
1745 /* find the HBIN block which should contain the nk record */
1746 hbin = lookup_hbin_block(i->f, nk_offset);
1747 if(!hbin)
1748 {
1749 /* XXX: should print out some kind of error message every time here */
1750 /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n",
1751 i->cur_key->subkeys.hashes[i->cur_subkey].nk_off));*/
1752 return NULL;
1753 }
1754
1755 if(!prs_set_offset(&hbin->ps,
1756 HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off))
1757 return NULL;
1758
1759 if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
1760 return NULL;
1761
1762 if(!hbin_prs_key(i->f, hbin, subkey))
1763 {
1764 regfi_key_free(subkey);
1765 return NULL;
1766 }
1767
1768 return subkey;
1769}
1770
1771
1772/******************************************************************************
1773 *****************************************************************************/
1774/* XXX: some way of indicating reason for failure should be added. */
1775const REGF_NK_REC* regfi_iterator_next_subkey(REGFI_ITERATOR* i)
1776{
1777 const REGF_NK_REC* subkey;
1778
1779 i->cur_subkey++;
1780 subkey = regfi_iterator_cur_subkey(i);
1781
1782 if(subkey == NULL)
1783 i->cur_subkey--;
1784
1785 return subkey;
1786}
1787
1788
1789/******************************************************************************
1790 *****************************************************************************/
1791bool regfi_iterator_find_value(REGFI_ITERATOR* i, const char* value_name)
1792{
1793 const REGF_VK_REC* cur;
1794 bool found = false;
1795
1796 /* XXX: cur->valuename can be NULL in the registry.
1797 * Should we allow for a way to search for that?
1798 */
1799 if(value_name == NULL)
1800 return false;
1801
1802 cur = regfi_iterator_first_value(i);
1803 while((cur != NULL) && (found == false))
1804 {
1805 if((cur->valuename != NULL)
1806 && (strcasecmp(cur->valuename, value_name) == 0))
1807 found = true;
1808 else
1809 cur = regfi_iterator_next_value(i);
1810 }
1811
1812 return found;
1813}
1814
1815
1816/******************************************************************************
1817 *****************************************************************************/
1818const REGF_VK_REC* regfi_iterator_first_value(REGFI_ITERATOR* i)
1819{
1820 i->cur_value = 0;
1821 return regfi_iterator_cur_value(i);
1822}
1823
1824
1825/******************************************************************************
1826 *****************************************************************************/
1827const REGF_VK_REC* regfi_iterator_cur_value(REGFI_ITERATOR* i)
1828{
1829 REGF_VK_REC* ret_val = NULL;
1830 if(i->cur_value < i->cur_key->num_values)
1831 ret_val = &(i->cur_key->values[i->cur_value]);
1832
1833 return ret_val;
1834}
1835
1836
1837/******************************************************************************
1838 *****************************************************************************/
1839const REGF_VK_REC* regfi_iterator_next_value(REGFI_ITERATOR* i)
1840{
1841 const REGF_VK_REC* ret_val;
1842
1843 i->cur_value++;
1844 ret_val = regfi_iterator_cur_value(i);
1845 if(ret_val == NULL)
1846 i->cur_value--;
1847
1848 return ret_val;
1849}
Note: See TracBrowser for help on using the repository browser.