source: trunk/lib/regfio.c @ 59

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

Updated version

Code format cleanup, some comments added.

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