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
RevLine 
[30]1/*
2 * Branched from Samba project Subversion repository, version #7470:
[84]3 * http://viewcvs.samba.org/cgi-bin/viewcvs.cgi/trunk/source/registry/regfio.c?rev=7470&view=auto
[30]4 *
5 * Unix SMB/CIFS implementation.
6 * Windows NT registry I/O library
7 *
[81]8 * Copyright (C) 2005-2007 Timothy D. Morgan
[30]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
[81]27#include "../include/regfi.h"
[30]28
29
[32]30/* Registry types mapping */
[78]31const unsigned int regfi_num_reg_types = 12;
32static const char* regfi_type_names[] =
[65]33 {"NONE", "SZ", "EXPAND_SZ", "BINARY", "DWORD", "DWORD_BE", "LINK",
[72]34 "MULTI_SZ", "RSRC_LIST", "RSRC_DESC", "RSRC_REQ_LIST", "QWORD"};
[30]35
[32]36
37/* Returns NULL on error */
[78]38const char* regfi_type_val2str(unsigned int val)
[32]39{
[61]40 if(val == REG_KEY)
41 return "KEY";
42
[78]43 if(val >= regfi_num_reg_types)
[61]44 return NULL;
45
[78]46 return regfi_type_names[val];
[32]47}
48
49
[61]50/* Returns -1 on error */
[78]51int regfi_type_str2val(const char* str)
[32]52{
53 int i;
54
[61]55 if(strcmp("KEY", str) == 0)
56 return REG_KEY;
[32]57
[78]58 for(i=0; i < regfi_num_reg_types; i++)
59 if (strcmp(regfi_type_names[i], str) == 0)
[61]60 return i;
61
62 if(strcmp("DWORD_LE", str) == 0)
63 return REG_DWORD_LE;
64
65 return -1;
[32]66}
67
68
[53]69/* Security descriptor parsing functions */
70
[78]71const char* regfi_ace_type2str(uint8 type)
[53]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
[76]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 */
[78]91char* regfi_ace_flags2str(uint8 flags)
[53]92{
[76]93 static const char* flag_map[32] =
[87]94 { "OI", /* Object Inherit */
95 "CI", /* Container Inherit */
96 "NP", /* Non-Propagate */
97 "IO", /* Inherit Only */
98 "IA", /* Inherited ACE */
[76]99 NULL,
100 NULL,
101 NULL,
102 };
[53]103
[76]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)
[53]110 return NULL;
111
[76]112 fo[0] = '\0';
[53]113 if (!flags)
[76]114 return ret_val;
[53]115
[76]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 }
[53]126 }
[76]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...
[53]138 if (flags == 0xF) {
139 if (some) strcat(flg_output, " ");
140 some = 1;
141 strcat(flg_output, "VI");
142 }
[76]143 */
[53]144
[76]145 return ret_val;
[53]146}
147
148
[78]149char* regfi_ace_perms2str(uint32 perms)
[53]150{
[76]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
[53]200 if(ret_val == NULL)
201 return NULL;
202
[76]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);
[53]219
[76]220 /* Chop off the last space if we've written anything to ret_val */
221 if(r != ret_val)
222 r[-1] = '\0';
223
[53]224 return ret_val;
225}
226
227
[78]228char* regfi_sid2str(DOM_SID* sid)
[53]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
[78]250char* regfi_get_acl(SEC_ACL* acl)
[53]251{
252 uint32 i, extra, size = 0;
253 const char* type_str;
254 char* flags_str;
255 char* perms_str;
256 char* sid_str;
[61]257 char* ace_delim = "";
[53]258 char* ret_val = NULL;
[61]259 char* tmp_val = NULL;
260 bool failed = false;
[53]261 char field_delim = ':';
262
[61]263 for (i = 0; i < acl->num_aces && !failed; i++)
[53]264 {
[78]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);
[53]269
[61]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);
[53]277
[61]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);
[53]303 }
304
305 return ret_val;
306}
307
308
[78]309char* regfi_get_sacl(SEC_DESC *sec_desc)
[53]310{
311 if (sec_desc->sacl)
[78]312 return regfi_get_acl(sec_desc->sacl);
[53]313 else
314 return NULL;
315}
316
317
[78]318char* regfi_get_dacl(SEC_DESC *sec_desc)
[53]319{
320 if (sec_desc->dacl)
[78]321 return regfi_get_acl(sec_desc->dacl);
[53]322 else
323 return NULL;
324}
325
326
[78]327char* regfi_get_owner(SEC_DESC *sec_desc)
[53]328{
[78]329 return regfi_sid2str(sec_desc->owner_sid);
[53]330}
331
332
[78]333char* regfi_get_group(SEC_DESC *sec_desc)
[53]334{
[78]335 return regfi_sid2str(sec_desc->grp_sid);
[53]336}
337
338
339
[30]340/*******************************************************************
[31]341 *******************************************************************/
[30]342static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset,
343 uint32 block_size )
344{
[61]345 const int hdr_size = 0x20;
[31]346 int bytes_read, returned;
347 char *buffer;
348 SMB_STRUCT_STAT sbuf;
[30]349
[31]350 /* check for end of file */
[30]351
[31]352 if ( fstat( file->fd, &sbuf ) ) {
353 /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
354 return -1;
355 }
[30]356
[31]357 if ( (size_t)file_offset >= sbuf.st_size )
358 return -1;
[30]359
[31]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 */
[30]362
[31]363 if ( block_size == 0 ) {
364 uint8 hdr[0x20];
[30]365
[31]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 }
[30]370
[61]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;
[31]385 }
[30]386
[31]387 /* make sure this is an hbin header */
[30]388
[53]389 if ( strncmp( (char*)hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
[31]390 /*DEBUG(0,("read_block: invalid block header!\n"));*/
391 return -1;
392 }
[30]393
[31]394 block_size = IVAL( hdr, 0x08 );
395 }
[30]396
[31]397 /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
[30]398
[31]399 /* set the offset, initialize the buffer, and read the block from disk */
[30]400
[31]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 }
[30]405
[31]406 prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
407 buffer = ps->data_p;
408 bytes_read = returned = 0;
[30]409
[32]410 while ( bytes_read < block_size )
411 {
[61]412 returned = read(file->fd, buffer+bytes_read, block_size-bytes_read);
413 if(returned == -1 && errno != EINTR && errno != EAGAIN)
[32]414 {
[31]415 /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
[61]416 return -1;
[31]417 }
[61]418
[32]419 if ((returned == 0) && (bytes_read < block_size))
420 {
[31]421 /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
[61]422 return -1;
[31]423 }
[32]424
[31]425 bytes_read += returned;
426 }
[30]427
[31]428 return bytes_read;
[30]429}
430
431
432/*******************************************************************
[31]433 *******************************************************************/
[53]434static bool prs_regf_block(const char *desc, prs_struct *ps,
435 int depth, REGF_FILE *file)
[30]436{
[31]437 depth++;
[30]438
[84]439 if(!prs_uint8s("header", ps, depth, file->header, sizeof(file->header)))
[31]440 return false;
[30]441
[31]442 /* yes, these values are always identical so store them only once */
[30]443
[31]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;
[30]448
[31]449 /* get the modtime */
[30]450
[31]451 if ( !prs_set_offset( ps, 0x0c ) )
452 return false;
453 if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
454 return false;
[30]455
[31]456 /* constants */
[30]457
[31]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;
[30]466
[31]467 /* get file offsets */
[30]468
[31]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;
[30]475
[31]476 /* one more constant */
[30]477
[31]478 if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
479 return false;
[30]480
[31]481 /* get the checksum */
[30]482
[31]483 if ( !prs_set_offset( ps, 0x01fc ) )
484 return false;
485 if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
486 return false;
[30]487
[31]488 return true;
[30]489}
490
491
492/*******************************************************************
[31]493 *******************************************************************/
[53]494static bool prs_hbin_block(const char *desc, prs_struct *ps,
495 int depth, REGF_HBIN *hbin)
[30]496{
[31]497 uint32 block_size2;
[30]498
[31]499 depth++;
[30]500
[84]501 if(!prs_uint8s("header", ps, depth, hbin->header, sizeof(hbin->header)))
[31]502 return false;
[30]503
[31]504 if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
505 return false;
[30]506
[31]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 */
[30]510
[31]511 if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
512 return false;
[30]513
[31]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;
[30]518
[31]519 if ( !ps->io )
520 hbin->dirty = true;
[30]521
522
[31]523 return true;
[30]524}
525
526
527/*******************************************************************
[31]528 *******************************************************************/
[33]529static bool prs_nk_rec( const char *desc, prs_struct *ps,
530 int depth, REGF_NK_REC *nk )
[30]531{
[31]532 uint16 class_length, name_length;
533 uint32 start;
534 uint32 data_size, start_off, end_off;
535 uint32 unknown_off = REGF_OFFSET_NONE;
[30]536
[31]537 nk->hbin_off = ps->data_offset;
538 start = nk->hbin_off;
[30]539
[31]540 depth++;
[30]541
[33]542 /* back up and get the data_size */
[31]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;
[30]548
[84]549 if (!prs_uint8s("header", ps, depth, nk->header, sizeof(nk->header)))
[31]550 return false;
[30]551
[31]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;
[30]556
[31]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;
[30]563
[31]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;
[30]570
[31]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;
[30]581
[33]582 if (!prs_uint32("max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
[31]583 return false;
[33]584 if ( !prs_uint32( "max_bytes_subkeyclassname", ps,
585 depth, &nk->max_bytes_subkeyclassname))
586 { return false; }
[31]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;
[30]593
[31]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;
[30]600
[33]601 if ( class_length )
602 {
[80]603 /* XXX: why isn't this parsed? */
[31]604 ;;
605 }
[30]606
[33]607 if ( name_length )
608 {
609 if(ps->io && !(nk->keyname = (char*)zcalloc(sizeof(char), name_length+1)))
[31]610 return false;
[30]611
[84]612 if(!prs_uint8s("name", ps, depth, (uint8*)nk->keyname, name_length))
[31]613 return false;
[30]614
[53]615 if(ps->io)
[31]616 nk->keyname[name_length] = '\0';
617 }
[30]618
[31]619 end_off = ps->data_offset;
[30]620
[33]621 /* data_size must be divisible by 8 and large enough to hold
622 the original record */
[30]623
[31]624 data_size = ((start_off - end_off) & 0xfffffff8 );
[33]625 /*if ( data_size > nk->rec_size )
626 DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
[30]627
[33]628 if ( !ps->io )
629 nk->hbin->dirty = true;
630
[31]631 return true;
[30]632}
633
634
635/*******************************************************************
[31]636 *******************************************************************/
[30]637static uint32 regf_block_checksum( prs_struct *ps )
638{
[31]639 char *buffer = ps->data_p;
640 uint32 checksum, x;
641 int i;
[30]642
[31]643 /* XOR of all bytes 0x0000 - 0x01FB */
[30]644
[31]645 checksum = x = 0;
[30]646
[31]647 for ( i=0; i<0x01FB; i+=4 ) {
648 x = IVAL(buffer, i );
649 checksum ^= x;
650 }
[30]651
[31]652 return checksum;
[30]653}
654
655
656/*******************************************************************
[31]657 *******************************************************************/
[30]658static bool read_regf_block( REGF_FILE *file )
659{
[31]660 prs_struct ps;
661 uint32 checksum;
[30]662
[31]663 /* grab the first block from the file */
[30]664
[31]665 if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
666 return false;
[30]667
[31]668 /* parse the block and verify the checksum */
[30]669
[31]670 if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
671 return false;
[30]672
[31]673 checksum = regf_block_checksum( &ps );
[30]674
[31]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;
[30]680
[31]681 if ( file->checksum != checksum ) {
682 /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
683 return false;
684 }
[30]685
[31]686 return true;
[30]687}
688
689
690/*******************************************************************
[31]691 *******************************************************************/
[30]692static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
693{
[31]694 REGF_HBIN *hbin;
695 uint32 record_size, curr_off, block_size, header;
[30]696
[31]697 if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) )
698 return NULL;
699 hbin->file_off = offset;
700 hbin->free_off = -1;
[30]701
[31]702 if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
703 return NULL;
[30]704
[31]705 if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
706 return NULL;
[30]707
[31]708 /* this should be the same thing as hbin->block_size but just in case */
[30]709
[31]710 block_size = hbin->ps.buffer_size;
[30]711
[31]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. */
[30]717
[31]718 /* remember that the record_size is in the 4 bytes preceeding the record itself */
[30]719
[31]720 if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
721 return false;
[30]722
[31]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 */
[30]728
[31]729 curr_off = curr_off+record_size;
[30]730
[31]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 */
[30]735
[31]736 if ( curr_off >= block_size ) {
737 record_size = -1;
738 curr_off = -1;
739 break;
740 }
[30]741
[31]742 if ( !prs_set_offset( &hbin->ps, curr_off) )
743 return false;
[30]744
[31]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;
[30]749
[31]750 assert( record_size != 0 );
[30]751
[31]752 if ( record_size & 0x80000000 ) {
753 /* absolute_value(record_size) */
754 record_size = (record_size ^ 0xffffffff) + 1;
755 }
756 }
[30]757
[31]758 /* save the free space offset */
[30]759
[31]760 if ( header == 0xffffffff ) {
[30]761
[31]762 /* account for the fact that the curr_off is 4 bytes behind the actual
763 record header */
[30]764
[31]765 hbin->free_off = curr_off + sizeof(uint32);
766 hbin->free_size = record_size;
767 }
[30]768
[31]769 /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
[30]770
[31]771 if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE ) )
772 return false;
[30]773
[31]774 return hbin;
[30]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{
[31]784 if ( !hbin )
785 return false;
[30]786
[31]787 if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
788 return true;
[30]789
[31]790 return false;
[30]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{
[31]800 REGF_HBIN *hbin = NULL;
801 uint32 block_off;
[30]802
[31]803 /* start with the open list */
[30]804
[31]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 }
[30]810
[31]811 if ( !hbin ) {
812 /* start at the beginning */
[30]813
[31]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 }
[30]825
[31]826 hbin = read_hbin_block( file, block_off );
[30]827
[31]828 if ( hbin )
829 block_off = hbin->file_off + hbin->block_size;
[30]830
[31]831 } while ( hbin && !hbin_contains_offset( hbin, offset ) );
832 }
[30]833
[31]834 if ( hbin )
[80]835 /* XXX: this kind of caching needs to be re-evaluated */
[31]836 DLIST_ADD( file->block_list, hbin );
[30]837
[31]838 return hbin;
[30]839}
840
841
842/*******************************************************************
[31]843 *******************************************************************/
[30]844static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
845{
[31]846 depth++;
[30]847
[31]848 if ( !prs_uint32( "nk_off", ps, depth, &hash->nk_off ))
849 return false;
[84]850 if ( !prs_uint8s("keycheck", ps, depth, hash->keycheck, sizeof( hash->keycheck )) )
[31]851 return false;
[30]852
[31]853 return true;
[30]854}
855
856
857/*******************************************************************
[31]858 *******************************************************************/
[53]859static bool hbin_prs_lf_records(const char *desc, REGF_HBIN *hbin,
860 int depth, REGF_NK_REC *nk)
[30]861{
[31]862 int i;
863 REGF_LF_REC *lf = &nk->subkeys;
864 uint32 data_size, start_off, end_off;
[30]865
[31]866 depth++;
[30]867
[31]868 /* check if we have anything to do first */
[30]869
[31]870 if ( nk->num_subkeys == 0 )
871 return true;
[30]872
[31]873 /* move to the LF record */
[30]874
[31]875 if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
876 return false;
[30]877
[31]878 /* backup and get the data_size */
[30]879
[31]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;
[30]885
[84]886 if(!prs_uint8s("header", &hbin->ps, depth,
[53]887 lf->header, sizeof(lf->header)))
[31]888 return false;
[30]889
[31]890 if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
891 return false;
[30]892
[31]893 if ( hbin->ps.io ) {
894 if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
895 return false;
896 }
[30]897
[31]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 }
[30]902
[31]903 end_off = hbin->ps.data_offset;
[30]904
[31]905 /* data_size must be divisible by 8 and large enough to hold the original record */
[30]906
[31]907 data_size = ((start_off - end_off) & 0xfffffff8 );
[33]908 /* if ( data_size > lf->rec_size )*/
[31]909 /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
[30]910
[33]911 if ( !hbin->ps.io )
912 hbin->dirty = true;
[30]913
[31]914 return true;
[30]915}
916
917
918/*******************************************************************
[31]919 *******************************************************************/
[30]920static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
921{
[31]922 prs_struct *ps = &hbin->ps;
923 uint16 tag = 0xFFFF;
924 uint32 data_size, start_off, end_off;
[30]925
926
[31]927 depth++;
[30]928
[31]929 if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
930 return false;
[30]931
[31]932 /* backup and get the data_size */
[30]933
[31]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;
[30]939
[84]940 if (!prs_uint8s("header", ps, depth, sk->header, sizeof(sk->header)))
[31]941 return false;
942 if ( !prs_uint16( "tag", ps, depth, &tag))
943 return false;
[30]944
[31]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;
[30]953
[31]954 if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth ))
955 return false;
[30]956
[31]957 end_off = hbin->ps.data_offset;
[30]958
[31]959 /* data_size must be divisible by 8 and large enough to hold the original record */
[30]960
[31]961 data_size = ((start_off - end_off) & 0xfffffff8 );
[33]962 /* if ( data_size > sk->rec_size )*/
[31]963 /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
[30]964
[33]965 if ( !hbin->ps.io )
966 hbin->dirty = true;
[30]967
[31]968 return true;
[30]969}
970
971
972/*******************************************************************
[31]973 *******************************************************************/
[30]974static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth,
975 REGF_VK_REC *vk, REGF_FILE *file )
976{
[31]977 uint32 offset;
978 uint16 name_length;
979 prs_struct *ps = &hbin->ps;
980 uint32 data_size, start_off, end_off;
[30]981
[31]982 depth++;
[30]983
[31]984 /* backup and get the data_size */
[30]985
[31]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;
[30]991
[84]992 if ( !prs_uint8s("header", ps, depth, vk->header, sizeof( vk->header )) )
[31]993 return false;
[30]994
[31]995 if ( !hbin->ps.io )
996 name_length = strlen(vk->valuename);
[30]997
[31]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;
[30]1008
[31]1009 offset = ps->data_offset;
1010 offset += 2; /* skip 2 bytes */
1011 prs_set_offset( ps, offset );
[30]1012
[31]1013 /* get the name */
[30]1014
[31]1015 if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
[30]1016
[31]1017 if ( hbin->ps.io ) {
1018 if ( !(vk->valuename = (char*)zcalloc(sizeof(char), name_length+1 )))
1019 return false;
1020 }
[84]1021 if ( !prs_uint8s("name", ps, depth,
[53]1022 (uint8*)vk->valuename, name_length) )
[31]1023 return false;
1024 }
[30]1025
[31]1026 end_off = hbin->ps.data_offset;
[30]1027
[31]1028 /* get the data if necessary */
[30]1029
[32]1030 if ( vk->data_size != 0 )
1031 {
[31]1032 /* the data is stored in the offset if the size <= 4 */
[32]1033 if ( !(vk->data_size & VK_DATA_IN_OFFSET) )
1034 {
[31]1035 REGF_HBIN *hblock = hbin;
1036 uint32 data_rec_size;
[30]1037
[32]1038 if ( hbin->ps.io )
1039 {
[31]1040 if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
1041 return false;
1042 }
[30]1043
[31]1044 /* this data can be in another hbin */
[32]1045 if ( !hbin_contains_offset( hbin, vk->data_off ) )
1046 {
[31]1047 if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
1048 return false;
1049 }
[32]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; }
[30]1056
[32]1057 if ( !hblock->ps.io )
1058 {
[31]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;
[84]1064 if(!prs_uint8s("data", &hblock->ps, depth,
[32]1065 vk->data, vk->data_size))
[31]1066 return false;
[30]1067
[31]1068 if ( !hblock->ps.io )
1069 hblock->dirty = true;
1070 }
[32]1071 else
1072 {
1073 if(!(vk->data = zcalloc(sizeof(uint8), 4)))
[31]1074 return false;
1075 SIVAL( vk->data, 0, vk->data_off );
1076 }
[30]1077
[31]1078 }
[30]1079
[31]1080 /* data_size must be divisible by 8 and large enough to hold the original record */
[30]1081
[31]1082 data_size = ((start_off - end_off ) & 0xfffffff8 );
[77]1083 /* XXX: should probably print a warning here */
[32]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));*/
[30]1086
[32]1087 if ( !hbin->ps.io )
1088 hbin->dirty = true;
[30]1089
[31]1090 return true;
[30]1091}
1092
1093
1094/*******************************************************************
1095 read a VK record which is contained in the HBIN block stored
1096 in the prs_struct *ps.
1097*******************************************************************/
[32]1098static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin,
1099 int depth, REGF_NK_REC *nk, REGF_FILE *file)
[30]1100{
[31]1101 int i;
1102 uint32 record_size;
[30]1103
[31]1104 depth++;
[80]1105
[31]1106 /* check if we have anything to do first */
[32]1107 if(nk->num_values == 0)
[31]1108 return true;
[80]1109
[32]1110 if(hbin->ps.io)
1111 {
1112 if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC),
1113 nk->num_values )))
[31]1114 return false;
1115 }
[80]1116
[31]1117 /* convert the offset to something relative to this HBIN block */
[32]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; }
[30]1124
[32]1125 if ( !hbin->ps.io )
1126 {
[31]1127 record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
1128 record_size = (record_size - 1) ^ 0xFFFFFFFF;
1129 }
[30]1130
[31]1131 if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
1132 return false;
[80]1133
[32]1134 for ( i=0; i<nk->num_values; i++ )
1135 {
[31]1136 if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
1137 return false;
1138 }
[30]1139
[32]1140 for ( i=0; i<nk->num_values; i++ )
1141 {
[31]1142 REGF_HBIN *sub_hbin = hbin;
1143 uint32 new_offset;
[30]1144
[32]1145 if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) )
1146 {
[31]1147 sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
[32]1148 if ( !sub_hbin )
1149 {
[31]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 }
[80]1155
[32]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))
[31]1161 return false;
[32]1162 if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
[31]1163 return false;
1164 }
[30]1165
[31]1166 if ( !hbin->ps.io )
1167 hbin->dirty = true;
[30]1168
[31]1169 return true;
[30]1170}
1171
1172
1173/*******************************************************************
[31]1174 *******************************************************************/
[30]1175static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
1176{
[31]1177 REGF_SK_REC *p_sk;
[80]1178
[31]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 }
[80]1183
[31]1184 return NULL;
[30]1185}
1186
[32]1187
[30]1188/*******************************************************************
[31]1189 *******************************************************************/
[30]1190static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
1191{
[31]1192 REGF_SK_REC *p;
[30]1193
[31]1194 for ( p=file->sec_desc_list; p; p=p->next ) {
1195 if ( sec_desc_equal( p->sec_desc, sd ) )
1196 return p;
1197 }
[30]1198
[31]1199 /* failure */
[30]1200
[31]1201 return NULL;
[30]1202}
1203
[32]1204
[30]1205/*******************************************************************
[31]1206 *******************************************************************/
[30]1207static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
1208{
[31]1209 int depth = 0;
1210 REGF_HBIN *sub_hbin;
[80]1211
[31]1212 depth++;
[30]1213
[31]1214 /* get the initial nk record */
[33]1215 if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
[31]1216 return false;
[30]1217
[31]1218 /* fill in values */
[32]1219 if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) )
1220 {
[31]1221 sub_hbin = hbin;
[32]1222 if ( !hbin_contains_offset( hbin, nk->values_off ) )
1223 {
[31]1224 sub_hbin = lookup_hbin_block( file, nk->values_off );
[32]1225 if ( !sub_hbin )
1226 {
[31]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 }
[30]1232
[32]1233 if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
[31]1234 return false;
1235 }
[30]1236
[31]1237 /* now get subkeys */
[32]1238 if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) )
1239 {
[31]1240 sub_hbin = hbin;
[32]1241 if ( !hbin_contains_offset( hbin, nk->subkeys_off ) )
1242 {
[31]1243 sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
[32]1244 if ( !sub_hbin )
1245 {
[31]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 }
[30]1251
[32]1252 if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
[31]1253 return false;
1254 }
[30]1255
[31]1256 /* get the to the security descriptor. First look if we have already parsed it */
[30]1257
[32]1258 if ((nk->sk_off!=REGF_OFFSET_NONE)
1259 && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
1260 {
[31]1261 sub_hbin = hbin;
[32]1262 if (!hbin_contains_offset(hbin, nk->sk_off))
1263 {
[31]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 }
[30]1271
[31]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;
[30]1277
[31]1278 /* add to the list of security descriptors (ref_count has been read from the files) */
[30]1279
[31]1280 nk->sec_desc->sk_off = nk->sk_off;
[80]1281 /* XXX: this kind of caching needs to be re-evaluated */
[31]1282 DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1283 }
[30]1284
[31]1285 return true;
[30]1286}
1287
[32]1288
[30]1289/*******************************************************************
[31]1290 *******************************************************************/
[30]1291static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
1292{
[53]1293 uint8 header[REC_HDR_SIZE] = "";
[31]1294 uint32 record_size;
1295 uint32 curr_off, block_size;
1296 bool found = false;
1297 prs_struct *ps = &hbin->ps;
[30]1298
[31]1299 curr_off = ps->data_offset;
1300 if ( curr_off == 0 )
1301 prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
[30]1302
[31]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);
[30]1306
[31]1307 block_size = ps->buffer_size;
1308 record_size = 0;
[32]1309 while ( !found )
1310 {
[31]1311 curr_off = curr_off+record_size;
1312 if ( curr_off >= block_size )
1313 break;
[30]1314
[31]1315 if ( !prs_set_offset( &hbin->ps, curr_off) )
1316 return false;
[30]1317
[31]1318 if ( !prs_uint32( "record_size", ps, 0, &record_size ) )
1319 return false;
[84]1320 if ( !prs_uint8s("header", ps, 0, header, REC_HDR_SIZE ) )
[31]1321 return false;
[30]1322
[31]1323 if ( record_size & 0x80000000 ) {
1324 /* absolute_value(record_size) */
1325 record_size = (record_size ^ 0xffffffff) + 1;
1326 }
[30]1327
[31]1328 if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1329 found = true;
1330 curr_off += sizeof(uint32);
1331 }
1332 }
[30]1333
[31]1334 /* mark prs_struct as done ( at end ) if no more SK records */
[32]1335 /* mark end-of-block as true */
1336 if ( !found )
[31]1337 {
1338 prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
1339 *eob = true;
1340 return false;
1341 }
[32]1342
1343 if (!prs_set_offset(ps, curr_off))
[31]1344 return false;
[30]1345
[31]1346 return true;
[30]1347}
1348
1349
1350/*******************************************************************
[31]1351 *******************************************************************/
[32]1352static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin,
1353 REGF_NK_REC *nk, bool *eob)
[30]1354{
[32]1355 if (next_record(hbin, "nk", eob)
1356 && hbin_prs_key(file, hbin, nk))
[31]1357 return true;
[30]1358
[31]1359 return false;
[30]1360}
1361
1362
1363/*******************************************************************
1364 Open the registry file and then read in the REGF block to get the
1365 first hbin offset.
1366*******************************************************************/
[78]1367REGF_FILE* regfi_open( const char *filename )
[30]1368{
[31]1369 REGF_FILE *rb;
1370 int flags = O_RDONLY;
[30]1371
[31]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;
[30]1378
[31]1379 /* if ( !(rb->mem_ctx = talloc_init( "read_regf_block" )) )
1380 {
[78]1381 regfi_close( rb );
[31]1382 return NULL;
1383 }
1384 */
1385 rb->open_flags = flags;
[30]1386
[31]1387 /* open and existing file */
[30]1388
[31]1389 if ( (rb->fd = open(filename, flags)) == -1 ) {
[78]1390 /* DEBUG(0,("regfi_open: failure to open %s (%s)\n", filename, strerror(errno)));*/
1391 regfi_close( rb );
[31]1392 return NULL;
1393 }
[30]1394
[31]1395 /* read in an existing file */
[30]1396
[31]1397 if ( !read_regf_block( rb ) ) {
[78]1398 /* DEBUG(0,("regfi_open: Failed to read initial REGF block\n"));*/
1399 regfi_close( rb );
[31]1400 return NULL;
1401 }
[30]1402
[31]1403 /* success */
[30]1404
[31]1405 return rb;
[30]1406}
1407
1408
1409/*******************************************************************
[80]1410XXX: should this be nuked?
[31]1411 *******************************************************************/
[78]1412static void regfi_mem_free( REGF_FILE *file )
[30]1413{
[31]1414 /* free any zalloc()'d memory */
[30]1415
1416 /* if ( file && file->mem_ctx )
[31]1417 free(file->mem_ctx);
[30]1418 */
1419}
1420
1421
1422/*******************************************************************
[31]1423 *******************************************************************/
[78]1424int regfi_close( REGF_FILE *file )
[30]1425{
[31]1426 int fd;
[30]1427
[78]1428 regfi_mem_free( file );
[30]1429
[31]1430 /* nothing to do if there is no open file */
[30]1431
[31]1432 if ( !file || (file->fd == -1) )
1433 return 0;
[30]1434
[31]1435 fd = file->fd;
1436 file->fd = -1;
1437 SAFE_FREE( file );
[30]1438
[31]1439 return close( fd );
[30]1440}
1441
1442
[80]1443/******************************************************************************
1444 * There should be only *one* root key in the registry file based
1445 * on my experience. --jerry
1446 *****************************************************************************/
[78]1447REGF_NK_REC* regfi_rootkey( REGF_FILE *file )
[30]1448{
[31]1449 REGF_NK_REC *nk;
1450 REGF_HBIN *hbin;
1451 uint32 offset = REGF_BLOCKSIZE;
1452 bool found = false;
1453 bool eob;
[30]1454
[31]1455 if ( !file )
1456 return NULL;
[30]1457
[31]1458 if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
[78]1459 /*DEBUG(0,("regfi_rootkey: zalloc() failed!\n"));*/
[31]1460 return NULL;
1461 }
[30]1462
[31]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) */
[30]1467
[31]1468 while ( (hbin = read_hbin_block( file, offset )) ) {
1469 eob = false;
[30]1470
[31]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 }
[30]1484
[31]1485 if ( found )
1486 break;
[30]1487
[31]1488 offset += hbin->block_size;
1489 }
[30]1490
[31]1491 if ( !found ) {
[78]1492 /*DEBUG(0,("regfi_rootkey: corrupt registry file ? No root key record located\n"));*/
[31]1493 return NULL;
1494 }
[30]1495
[80]1496 /* XXX: this kind of caching needs to be re-evaluated */
[31]1497 DLIST_ADD( file->block_list, hbin );
[30]1498
[80]1499 return nk;
[30]1500}
1501
1502
[80]1503/******************************************************************************
1504 *****************************************************************************/
1505void regfi_key_free(REGF_NK_REC* nk)
[30]1506{
[80]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++)
[81]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 }
[80]1518 free(nk->values);
1519 }
[30]1520
[80]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
[81]1541 root = regfi_rootkey(fh);
[80]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
[84]1597 subkey = (REGF_NK_REC*)regfi_iterator_cur_subkey(i);
[80]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 */
[84]1664 subkey = (REGF_NK_REC*)regfi_iterator_first_subkey(i);
[80]1665 while((subkey != NULL) && (found == false))
1666 {
1667 if(subkey->keyname != NULL
1668 && strcasecmp(subkey->keyname, subkey_name) == 0)
1669 found = true;
[82]1670 else
1671 {
1672 regfi_key_free(subkey);
[84]1673 subkey = (REGF_NK_REC*)regfi_iterator_next_subkey(i);
[82]1674 }
[80]1675 }
1676
1677 if(found == false)
1678 {
1679 i->cur_subkey = old_subkey;
1680 return false;
1681 }
1682
[82]1683 regfi_key_free(subkey);
[80]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 *****************************************************************************/
[84]1715const REGF_NK_REC* regfi_iterator_cur_key(REGFI_ITERATOR* i)
[80]1716{
1717 return i->cur_key;
1718}
1719
1720
1721/******************************************************************************
1722 *****************************************************************************/
[84]1723const REGF_NK_REC* regfi_iterator_first_subkey(REGFI_ITERATOR* i)
[80]1724{
1725 i->cur_subkey = 0;
1726 return regfi_iterator_cur_subkey(i);
1727}
1728
1729
1730/******************************************************************************
1731 *****************************************************************************/
[84]1732const REGF_NK_REC* regfi_iterator_cur_subkey(REGFI_ITERATOR* i)
[80]1733{
1734 REGF_NK_REC* subkey;
1735 REGF_HBIN* hbin;
1736 uint32 nk_offset;
1737
[31]1738 /* see if there is anything left to report */
[80]1739 if (!(i->cur_key) || (i->cur_key->subkeys_off==REGF_OFFSET_NONE)
1740 || (i->cur_subkey >= i->cur_key->num_subkeys))
[31]1741 return NULL;
[30]1742
[80]1743 nk_offset = i->cur_key->subkeys.hashes[i->cur_subkey].nk_off;
1744
[31]1745 /* find the HBIN block which should contain the nk record */
[80]1746 hbin = lookup_hbin_block(i->f, nk_offset);
1747 if(!hbin)
[31]1748 {
[80]1749 /* XXX: should print out some kind of error message every time here */
[31]1750 /*DEBUG(0,("hbin_prs_key: Failed to find HBIN block containing offset [0x%x]\n",
[80]1751 i->cur_key->subkeys.hashes[i->cur_subkey].nk_off));*/
[31]1752 return NULL;
1753 }
[78]1754
[32]1755 if(!prs_set_offset(&hbin->ps,
[80]1756 HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off))
[31]1757 return NULL;
[30]1758
[32]1759 if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
[31]1760 return NULL;
[30]1761
[80]1762 if(!hbin_prs_key(i->f, hbin, subkey))
1763 {
1764 regfi_key_free(subkey);
[31]1765 return NULL;
[80]1766 }
[32]1767
[31]1768 return subkey;
[30]1769}
[80]1770
1771
1772/******************************************************************************
1773 *****************************************************************************/
1774/* XXX: some way of indicating reason for failure should be added. */
[84]1775const REGF_NK_REC* regfi_iterator_next_subkey(REGFI_ITERATOR* i)
[80]1776{
[84]1777 const REGF_NK_REC* subkey;
[80]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{
[84]1793 const REGF_VK_REC* cur;
[80]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;
[96]1808 else
1809 cur = regfi_iterator_next_value(i);
[80]1810 }
1811
[96]1812 return found;
[80]1813}
1814
1815
1816/******************************************************************************
1817 *****************************************************************************/
[84]1818const REGF_VK_REC* regfi_iterator_first_value(REGFI_ITERATOR* i)
[80]1819{
1820 i->cur_value = 0;
1821 return regfi_iterator_cur_value(i);
1822}
1823
1824
1825/******************************************************************************
1826 *****************************************************************************/
[84]1827const REGF_VK_REC* regfi_iterator_cur_value(REGFI_ITERATOR* i)
[80]1828{
1829 REGF_VK_REC* ret_val = NULL;
1830 if(i->cur_value < i->cur_key->num_values)
[81]1831 ret_val = &(i->cur_key->values[i->cur_value]);
[80]1832
1833 return ret_val;
1834}
1835
1836
1837/******************************************************************************
1838 *****************************************************************************/
[84]1839const REGF_VK_REC* regfi_iterator_next_value(REGFI_ITERATOR* i)
[80]1840{
[84]1841 const REGF_VK_REC* ret_val;
[80]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.