source: trunk/lib/regfio.c @ 53

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

Moved security descriptor parsing functions into regfio.c

Improved malloc() mode of failure.

Eliminated some warnings in regfio.c

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