source: trunk/lib/regfio.c @ 55

Last change on this file since 55 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
RevLine 
[30]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
[32]31/* Registry types mapping */
32const VAL_STR reg_type_names[] = 
33{
34  { REG_SZ,                        "SZ"           },
35  { REG_EXPAND_SZ,                 "EXPAND_SZ"    },
[41]36  { REG_BINARY,                    "BINARY"       },
[32]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};
[30]47
[32]48
49/* Returns NULL on error */
[41]50const char* regfio_type_val2str(unsigned int val)
[32]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 */
[41]63int regfio_type_str2val(const char* str)
[32]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
[53]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
[30]250/*******************************************************************
[31]251 *******************************************************************/
[30]252static int read_block( REGF_FILE *file, prs_struct *ps, uint32 file_offset, 
253                       uint32 block_size )
254{
[31]255  int bytes_read, returned;
256  char *buffer;
257  SMB_STRUCT_STAT sbuf;
[30]258
[31]259  /* check for end of file */
[30]260
[31]261  if ( fstat( file->fd, &sbuf ) ) {
262    /*DEBUG(0,("read_block: stat() failed! (%s)\n", strerror(errno)));*/
263    return -1;
264  }
[30]265
[31]266  if ( (size_t)file_offset >= sbuf.st_size )
267    return -1;
[30]268       
[31]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 */
[30]271           
[31]272  if ( block_size == 0 ) {
273    uint8 hdr[0x20];
[30]274
[31]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    }
[30]279
[31]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    }
[30]285
[31]286    /* make sure this is an hbin header */
[30]287
[53]288    if ( strncmp( (char*)hdr, "hbin", HBIN_HDR_SIZE ) != 0 ) {
[31]289      /*DEBUG(0,("read_block: invalid block header!\n"));*/
290      return -1;
291    }
[30]292
[31]293    block_size = IVAL( hdr, 0x08 );
294  }
[30]295
[31]296  /*DEBUG(10,("read_block: block_size == 0x%x\n", block_size ));*/
[30]297
[31]298  /* set the offset, initialize the buffer, and read the block from disk */
[30]299
[31]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  }
[30]304       
[31]305  prs_init( ps, block_size, file->mem_ctx, UNMARSHALL );
306  buffer = ps->data_p;
307  bytes_read = returned = 0;
[30]308
[32]309  while ( bytes_read < block_size ) 
310  {
311    if((returned = 
312        read(file->fd, buffer+bytes_read, block_size-bytes_read)) == -1)
313    {
[31]314      /*DEBUG(0,("read_block: read() failed (%s)\n", strerror(errno) ));*/
315      return false;
316    }
[32]317    if ((returned == 0) && (bytes_read < block_size)) 
318    {
[31]319      /*DEBUG(0,("read_block: not a vald registry file ?\n" ));*/
320      return false;
321    }   
[32]322
[31]323    bytes_read += returned;
324  }
[30]325       
[31]326  return bytes_read;
[30]327}
328
329
330/*******************************************************************
[31]331 *******************************************************************/
[53]332static bool prs_regf_block(const char *desc, prs_struct *ps, 
333                           int depth, REGF_FILE *file)
[30]334{
[31]335  depth++;
[30]336       
[53]337  if(!prs_uint8s(true, "header", ps, depth, file->header, sizeof(file->header)))
[31]338    return false;
[30]339       
[31]340  /* yes, these values are always identical so store them only once */
[30]341       
[31]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;
[30]346
[31]347  /* get the modtime */
[30]348       
[31]349  if ( !prs_set_offset( ps, 0x0c ) )
350    return false;
351  if ( !smb_io_time( "modtime", &file->mtime, ps, depth ) )
352    return false;
[30]353
[31]354  /* constants */
[30]355       
[31]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;
[30]364
[31]365  /* get file offsets */
[30]366       
[31]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;
[30]373               
[31]374  /* one more constant */
[30]375       
[31]376  if ( !prs_uint32( "unknown6", ps, depth, &file->unknown6 ))
377    return false;
[30]378               
[31]379  /* get the checksum */
[30]380       
[31]381  if ( !prs_set_offset( ps, 0x01fc ) )
382    return false;
383  if ( !prs_uint32( "checksum", ps, depth, &file->checksum ))
384    return false;
[30]385       
[31]386  return true;
[30]387}
388
389
390/*******************************************************************
[31]391 *******************************************************************/
[53]392static bool prs_hbin_block(const char *desc, prs_struct *ps, 
393                           int depth, REGF_HBIN *hbin)
[30]394{
[31]395  uint32 block_size2;
[30]396
[31]397  depth++;
[30]398       
[53]399  if(!prs_uint8s(true, "header", ps, depth, hbin->header, sizeof(hbin->header)))
[31]400    return false;
[30]401
[31]402  if ( !prs_uint32( "first_hbin_off", ps, depth, &hbin->first_hbin_off ))
403    return false;
[30]404
[31]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 */
[30]408
[31]409  if ( !prs_uint32( "block_size", ps, depth, &hbin->block_size ))
410    return false;
[30]411
[31]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;
[30]416
[31]417  if ( !ps->io )
418    hbin->dirty = true;
[30]419       
420
[31]421  return true;
[30]422}
423
424
425/*******************************************************************
[31]426 *******************************************************************/
[33]427static bool prs_nk_rec( const char *desc, prs_struct *ps, 
428                        int depth, REGF_NK_REC *nk )
[30]429{
[31]430  uint16 class_length, name_length;
431  uint32 start;
432  uint32 data_size, start_off, end_off;
433  uint32 unknown_off = REGF_OFFSET_NONE;
[30]434
[31]435  nk->hbin_off = ps->data_offset;
436  start = nk->hbin_off;
[30]437       
[31]438  depth++;
[30]439       
[33]440  /* back up and get the data_size */   
[31]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;
[30]446       
[33]447  if (!prs_uint8s(true, "header", ps, depth, nk->header, sizeof(nk->header)))
[31]448    return false;
[30]449               
[31]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;
[30]454               
[31]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;
[30]461               
[31]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;
[30]468               
[31]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;
[30]479
[33]480  if (!prs_uint32("max_bytes_subkeyname", ps, depth, &nk->max_bytes_subkeyname))
[31]481    return false;
[33]482  if ( !prs_uint32( "max_bytes_subkeyclassname", ps, 
483                    depth, &nk->max_bytes_subkeyclassname))
484  { return false; }
[31]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;
[30]491
[31]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;       
[30]498               
[33]499  if ( class_length ) 
500  {
[31]501    ;;
502  }
[30]503       
[33]504  if ( name_length ) 
505  {
506    if(ps->io && !(nk->keyname = (char*)zcalloc(sizeof(char), name_length+1)))
[31]507        return false;
[30]508
[53]509    if(!prs_uint8s(true, "name", ps, depth, (uint8*)nk->keyname, name_length))
[31]510      return false;
[30]511
[53]512    if(ps->io)
[31]513      nk->keyname[name_length] = '\0';
514  }
[30]515
[31]516  end_off = ps->data_offset;
[30]517
[33]518  /* data_size must be divisible by 8 and large enough to hold
519     the original record */
[30]520
[31]521  data_size = ((start_off - end_off) & 0xfffffff8 );
[33]522  /*if ( data_size > nk->rec_size )
523      DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, nk->rec_size));*/
[30]524
[33]525  if ( !ps->io )
526    nk->hbin->dirty = true;
527 
528  nk->subkey_index = 0;
[31]529  return true;
[30]530}
531
532
533/*******************************************************************
[31]534 *******************************************************************/
[30]535static uint32 regf_block_checksum( prs_struct *ps )
536{
[31]537  char *buffer = ps->data_p;
538  uint32 checksum, x;
539  int i;
[30]540
[31]541  /* XOR of all bytes 0x0000 - 0x01FB */
[30]542               
[31]543  checksum = x = 0;
[30]544       
[31]545  for ( i=0; i<0x01FB; i+=4 ) {
546    x = IVAL(buffer, i );
547    checksum ^= x;
548  }
[30]549       
[31]550  return checksum;
[30]551}
552
553
554/*******************************************************************
[31]555 *******************************************************************/
[30]556static bool read_regf_block( REGF_FILE *file )
557{
[31]558  prs_struct ps;
559  uint32 checksum;
[30]560       
[31]561  /* grab the first block from the file */
[30]562               
[31]563  if ( read_block( file, &ps, 0, REGF_BLOCKSIZE ) == -1 )
564    return false;
[30]565       
[31]566  /* parse the block and verify the checksum */
[30]567       
[31]568  if ( !prs_regf_block( "regf_header", &ps, 0, file ) )
569    return false;       
[30]570               
[31]571  checksum = regf_block_checksum( &ps );
[30]572       
[31]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;
[30]578
[31]579  if ( file->checksum !=  checksum ) {
580    /*DEBUG(0,("read_regf_block: invalid checksum\n" ));*/
581    return false;
582  }
[30]583
[31]584  return true;
[30]585}
586
587
588/*******************************************************************
[31]589 *******************************************************************/
[30]590static REGF_HBIN* read_hbin_block( REGF_FILE *file, off_t offset )
591{
[31]592  REGF_HBIN *hbin;
593  uint32 record_size, curr_off, block_size, header;
[30]594       
[31]595  if ( !(hbin = (REGF_HBIN*)zalloc(sizeof(REGF_HBIN))) ) 
596    return NULL;
597  hbin->file_off = offset;
598  hbin->free_off = -1;
[30]599               
[31]600  if ( read_block( file, &hbin->ps, offset, 0 ) == -1 )
601    return NULL;
[30]602       
[31]603  if ( !prs_hbin_block( "hbin", &hbin->ps, 0, hbin ) )
604    return NULL;       
[30]605
[31]606  /* this should be the same thing as hbin->block_size but just in case */
[30]607
[31]608  block_size = hbin->ps.buffer_size;
[30]609
[31]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. */
[30]615
[31]616  /* remember that the record_size is in the 4 bytes preceeding the record itself */
[30]617
[31]618  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE-sizeof(uint32) ) )
619    return false;
[30]620
[31]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 */
[30]626
[31]627    curr_off = curr_off+record_size;
[30]628
[31]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 */
[30]633
[31]634    if ( curr_off >= block_size ) {
635      record_size = -1;
636      curr_off = -1;
637      break;
638    }
[30]639
[31]640    if ( !prs_set_offset( &hbin->ps, curr_off) )
641      return false;
[30]642
[31]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;
[30]647               
[31]648    assert( record_size != 0 );
[30]649
[31]650    if ( record_size & 0x80000000 ) {
651      /* absolute_value(record_size) */
652      record_size = (record_size ^ 0xffffffff) + 1;
653    }
654  }
[30]655
[31]656  /* save the free space offset */
[30]657
[31]658  if ( header == 0xffffffff ) {
[30]659
[31]660    /* account for the fact that the curr_off is 4 bytes behind the actual
661       record header */
[30]662
[31]663    hbin->free_off = curr_off + sizeof(uint32);
664    hbin->free_size = record_size;
665  }
[30]666
[31]667  /*DEBUG(10,("read_hbin_block: free space offset == 0x%x\n", hbin->free_off));*/
[30]668
[31]669  if ( !prs_set_offset( &hbin->ps, file->data_offset+HBIN_HDR_SIZE )  )
670    return false;
[30]671       
[31]672  return hbin;
[30]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{
[31]682  if ( !hbin )
683    return false;
[30]684       
[31]685  if ( (offset > hbin->first_hbin_off) && (offset < (hbin->first_hbin_off+hbin->block_size)) )
686    return true;
[30]687               
[31]688  return false;
[30]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{
[31]698  REGF_HBIN *hbin = NULL;
699  uint32 block_off;
[30]700
[31]701  /* start with the open list */
[30]702
[31]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  }
[30]708       
[31]709  if ( !hbin ) {
710    /* start at the beginning */
[30]711
[31]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      }
[30]723
[31]724      hbin = read_hbin_block( file, block_off );
[30]725
[31]726      if ( hbin ) 
727        block_off = hbin->file_off + hbin->block_size;
[30]728
[31]729    } while ( hbin && !hbin_contains_offset( hbin, offset ) );
730  }
[30]731
[31]732  if ( hbin )
733    DLIST_ADD( file->block_list, hbin );
[30]734
[31]735  return hbin;
[30]736}
737
738
739/*******************************************************************
[31]740 *******************************************************************/
[30]741static bool prs_hash_rec( const char *desc, prs_struct *ps, int depth, REGF_HASH_REC *hash )
742{
[31]743  depth++;
[30]744
[31]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;
[30]749       
[31]750  return true;
[30]751}
752
753
754/*******************************************************************
[31]755 *******************************************************************/
[53]756static bool hbin_prs_lf_records(const char *desc, REGF_HBIN *hbin, 
757                                int depth, REGF_NK_REC *nk)
[30]758{
[31]759  int i;
760  REGF_LF_REC *lf = &nk->subkeys;
761  uint32 data_size, start_off, end_off;
[30]762
[31]763  depth++;
[30]764
[31]765  /* check if we have anything to do first */
[30]766       
[31]767  if ( nk->num_subkeys == 0 )
768    return true;
[30]769
[31]770  /* move to the LF record */
[30]771
[31]772  if ( !prs_set_offset( &hbin->ps, nk->subkeys_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
773    return false;
[30]774
[31]775  /* backup and get the data_size */
[30]776       
[31]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;
[30]782
[53]783  if(!prs_uint8s(true, "header", &hbin->ps, depth, 
784                 lf->header, sizeof(lf->header)))
[31]785    return false;
[30]786               
[31]787  if ( !prs_uint16( "num_keys", &hbin->ps, depth, &lf->num_keys))
788    return false;
[30]789
[31]790  if ( hbin->ps.io ) {
791    if ( !(lf->hashes = (REGF_HASH_REC*)zcalloc(sizeof(REGF_HASH_REC), lf->num_keys )) )
792      return false;
793  }
[30]794
[31]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  }
[30]799
[31]800  end_off = hbin->ps.data_offset;
[30]801
[31]802  /* data_size must be divisible by 8 and large enough to hold the original record */
[30]803
[31]804  data_size = ((start_off - end_off) & 0xfffffff8 );
[33]805  /*  if ( data_size > lf->rec_size )*/
[31]806    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, lf->rec_size));*/
[30]807
[33]808  if ( !hbin->ps.io )
809    hbin->dirty = true;
[30]810
[31]811  return true;
[30]812}
813
814
815/*******************************************************************
[31]816 *******************************************************************/
[30]817static bool hbin_prs_sk_rec( const char *desc, REGF_HBIN *hbin, int depth, REGF_SK_REC *sk )
818{
[31]819  prs_struct *ps = &hbin->ps;
820  uint16 tag = 0xFFFF;
821  uint32 data_size, start_off, end_off;
[30]822
823
[31]824  depth++;
[30]825
[31]826  if ( !prs_set_offset( &hbin->ps, sk->sk_off + HBIN_HDR_SIZE - hbin->first_hbin_off ) )
827    return false;
[30]828
[31]829  /* backup and get the data_size */
[30]830       
[31]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;
[30]836
[53]837  if (!prs_uint8s(true, "header", ps, depth, sk->header, sizeof(sk->header)))
[31]838    return false;
839  if ( !prs_uint16( "tag", ps, depth, &tag))
840    return false;
[30]841
[31]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;
[30]850
[31]851  if ( !sec_io_desc( "sec_desc", &sk->sec_desc, ps, depth )) 
852    return false;
[30]853
[31]854  end_off = hbin->ps.data_offset;
[30]855
[31]856  /* data_size must be divisible by 8 and large enough to hold the original record */
[30]857
[31]858  data_size = ((start_off - end_off) & 0xfffffff8 );
[33]859  /*  if ( data_size > sk->rec_size )*/
[31]860    /*DEBUG(10,("Encountered reused record (0x%x < 0x%x)\n", data_size, sk->rec_size));*/
[30]861
[33]862  if ( !hbin->ps.io )
863    hbin->dirty = true;
[30]864
[31]865  return true;
[30]866}
867
868
869/*******************************************************************
[31]870 *******************************************************************/
[30]871static bool hbin_prs_vk_rec( const char *desc, REGF_HBIN *hbin, int depth, 
872                             REGF_VK_REC *vk, REGF_FILE *file )
873{
[31]874  uint32 offset;
875  uint16 name_length;
876  prs_struct *ps = &hbin->ps;
877  uint32 data_size, start_off, end_off;
[30]878
[31]879  depth++;
[30]880
[31]881  /* backup and get the data_size */
[30]882       
[31]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;
[30]888
[31]889  if ( !prs_uint8s( true, "header", ps, depth, vk->header, sizeof( vk->header )) )
890    return false;
[30]891
[31]892  if ( !hbin->ps.io )
893    name_length = strlen(vk->valuename);
[30]894
[31]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;
[30]905
[31]906  offset = ps->data_offset;
907  offset += 2;  /* skip 2 bytes */
908  prs_set_offset( ps, offset );
[30]909
[31]910  /* get the name */
[30]911
[31]912  if ( vk->flag&VK_FLAG_NAME_PRESENT ) {
[30]913
[31]914    if ( hbin->ps.io ) {
915      if ( !(vk->valuename = (char*)zcalloc(sizeof(char), name_length+1 )))
916        return false;
917    }
[53]918    if ( !prs_uint8s(true, "name", ps, depth, 
919                     (uint8*)vk->valuename, name_length) )
[31]920      return false;
921  }
[30]922
[31]923  end_off = hbin->ps.data_offset;
[30]924
[31]925  /* get the data if necessary */
[30]926
[32]927  if ( vk->data_size != 0 ) 
928  {
[31]929    bool charmode = false;
[30]930
[31]931    if ( (vk->type == REG_SZ) || (vk->type == REG_MULTI_SZ) )
932      charmode = true;
[30]933
[31]934    /* the data is stored in the offset if the size <= 4 */
[32]935    if ( !(vk->data_size & VK_DATA_IN_OFFSET) ) 
936    {
[31]937      REGF_HBIN *hblock = hbin;
938      uint32 data_rec_size;
[30]939
[32]940      if ( hbin->ps.io ) 
941      {
[31]942        if ( !(vk->data = (uint8*)zcalloc(sizeof(uint8), vk->data_size) ) )
943          return false;
944      }
[30]945
[31]946      /* this data can be in another hbin */
[32]947      if ( !hbin_contains_offset( hbin, vk->data_off ) ) 
948      {
[31]949        if ( !(hblock = lookup_hbin_block( file, vk->data_off )) )
950          return false;
951      }
[32]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; }
[30]958
[32]959      if ( !hblock->ps.io ) 
960      {
[31]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;
[32]966      if(!prs_uint8s(charmode, "data", &hblock->ps, depth, 
967                     vk->data, vk->data_size))
[31]968        return false;
[30]969
[31]970      if ( !hblock->ps.io )
971        hblock->dirty = true;
972    }
[32]973    else 
974    {
975      if(!(vk->data = zcalloc(sizeof(uint8), 4)))
[31]976        return false;
977      SIVAL( vk->data, 0, vk->data_off );
978    }
[30]979               
[31]980  }
[30]981
[31]982  /* data_size must be divisible by 8 and large enough to hold the original record */
[30]983
[31]984  data_size = ((start_off - end_off ) & 0xfffffff8 );
[32]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));*/
[30]987
[32]988  if ( !hbin->ps.io )
989    hbin->dirty = true;
[30]990
[31]991  return true;
[30]992}
993
994
995/*******************************************************************
996 read a VK record which is contained in the HBIN block stored
997 in the prs_struct *ps.
998*******************************************************************/
[32]999static bool hbin_prs_vk_records(const char *desc, REGF_HBIN *hbin, 
1000                                int depth, REGF_NK_REC *nk, REGF_FILE *file)
[30]1001{
[31]1002  int i;
1003  uint32 record_size;
[30]1004
[31]1005  depth++;
[30]1006       
[31]1007  /* check if we have anything to do first */
[32]1008  if(nk->num_values == 0)
[31]1009    return true;
[30]1010               
[32]1011  if(hbin->ps.io)
1012  {
1013    if (!(nk->values = (REGF_VK_REC*)zcalloc(sizeof(REGF_VK_REC), 
1014                                              nk->num_values )))
[31]1015      return false;
1016  }
[30]1017       
[31]1018  /* convert the offset to something relative to this HBIN block */
[32]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; }
[30]1025
[32]1026  if ( !hbin->ps.io ) 
1027  { 
[31]1028    record_size = ( ( nk->num_values * sizeof(uint32) ) & 0xfffffff8 ) + 8;
1029    record_size = (record_size - 1) ^ 0xFFFFFFFF;
1030  }
[30]1031
[31]1032  if ( !prs_uint32( "record_size", &hbin->ps, depth, &record_size ) )
1033    return false;
[30]1034               
[32]1035  for ( i=0; i<nk->num_values; i++ ) 
1036  {
[31]1037    if ( !prs_uint32( "vk_off", &hbin->ps, depth, &nk->values[i].rec_off ) )
1038      return false;
1039  }
[30]1040
[32]1041  for ( i=0; i<nk->num_values; i++ ) 
1042  {
[31]1043    REGF_HBIN *sub_hbin = hbin;
1044    uint32 new_offset;
[30]1045       
[32]1046    if ( !hbin_contains_offset( hbin, nk->values[i].rec_off ) ) 
1047    {
[31]1048      sub_hbin = lookup_hbin_block( file, nk->values[i].rec_off );
[32]1049      if ( !sub_hbin ) 
1050      {
[31]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    }
[30]1056               
[32]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))
[31]1062      return false;
[32]1063    if (!hbin_prs_vk_rec("vk_rec", sub_hbin, depth, &nk->values[i], file))
[31]1064      return false;
1065  }
[30]1066
[31]1067  if ( !hbin->ps.io )
1068    hbin->dirty = true;
[30]1069
[31]1070  return true;
[30]1071}
1072
1073
1074/*******************************************************************
[31]1075 *******************************************************************/
[30]1076static REGF_SK_REC* find_sk_record_by_offset( REGF_FILE *file, uint32 offset )
1077{
[31]1078  REGF_SK_REC *p_sk;
[30]1079       
[31]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  }
[30]1084       
[31]1085  return NULL;
[30]1086}
1087
[32]1088
[30]1089/*******************************************************************
[31]1090 *******************************************************************/
[30]1091static REGF_SK_REC* find_sk_record_by_sec_desc( REGF_FILE *file, SEC_DESC *sd )
1092{
[31]1093  REGF_SK_REC *p;
[30]1094
[31]1095  for ( p=file->sec_desc_list; p; p=p->next ) {
1096    if ( sec_desc_equal( p->sec_desc, sd ) )
1097      return p;
1098  }
[30]1099
[31]1100  /* failure */
[30]1101
[31]1102  return NULL;
[30]1103}
1104
[32]1105
[30]1106/*******************************************************************
[31]1107 *******************************************************************/
[30]1108static bool hbin_prs_key( REGF_FILE *file, REGF_HBIN *hbin, REGF_NK_REC *nk )
1109{
[31]1110  int depth = 0;
1111  REGF_HBIN *sub_hbin;
[30]1112       
[31]1113  depth++;
[30]1114
[31]1115  /* get the initial nk record */
[33]1116  if (!prs_nk_rec("nk_rec", &hbin->ps, depth, nk))
[31]1117    return false;
[30]1118
[31]1119  /* fill in values */
[32]1120  if ( nk->num_values && (nk->values_off!=REGF_OFFSET_NONE) ) 
1121  {
[31]1122    sub_hbin = hbin;
[32]1123    if ( !hbin_contains_offset( hbin, nk->values_off ) ) 
1124    {
[31]1125      sub_hbin = lookup_hbin_block( file, nk->values_off );
[32]1126      if ( !sub_hbin ) 
1127      {
[31]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    }
[30]1133               
[32]1134    if(!hbin_prs_vk_records("vk_rec", sub_hbin, depth, nk, file))
[31]1135      return false;
1136  }
[30]1137               
[31]1138  /* now get subkeys */
[32]1139  if ( nk->num_subkeys && (nk->subkeys_off!=REGF_OFFSET_NONE) ) 
1140  {
[31]1141    sub_hbin = hbin;
[32]1142    if ( !hbin_contains_offset( hbin, nk->subkeys_off ) ) 
1143    {
[31]1144      sub_hbin = lookup_hbin_block( file, nk->subkeys_off );
[32]1145      if ( !sub_hbin ) 
1146      {
[31]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    }
[30]1152               
[32]1153    if (!hbin_prs_lf_records("lf_rec", sub_hbin, depth, nk))
[31]1154      return false;
1155  }
[30]1156
[31]1157  /* get the to the security descriptor.  First look if we have already parsed it */
[30]1158       
[32]1159  if ((nk->sk_off!=REGF_OFFSET_NONE) 
1160      && !(nk->sec_desc = find_sk_record_by_offset( file, nk->sk_off )))
1161  {
[31]1162    sub_hbin = hbin;
[32]1163    if (!hbin_contains_offset(hbin, nk->sk_off))
1164    {
[31]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    }
[30]1172               
[31]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;
[30]1178                       
[31]1179    /* add to the list of security descriptors (ref_count has been read from the files) */
[30]1180
[31]1181    nk->sec_desc->sk_off = nk->sk_off;
1182    DLIST_ADD( file->sec_desc_list, nk->sec_desc );
1183  }
[30]1184               
[31]1185  return true;
[30]1186}
1187
[32]1188
[30]1189/*******************************************************************
[31]1190 *******************************************************************/
[30]1191static bool next_record( REGF_HBIN *hbin, const char *hdr, bool *eob )
1192{
[53]1193  uint8 header[REC_HDR_SIZE] = "";
[31]1194  uint32 record_size;
1195  uint32 curr_off, block_size;
1196  bool found = false;
1197  prs_struct *ps = &hbin->ps;
[30]1198       
[31]1199  curr_off = ps->data_offset;
1200  if ( curr_off == 0 )
1201    prs_set_offset( ps, HBIN_HEADER_REC_SIZE );
[30]1202
[31]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);
[30]1206
[31]1207  block_size = ps->buffer_size;
1208  record_size = 0;
[32]1209  while ( !found ) 
1210  {
[31]1211    curr_off = curr_off+record_size;
1212    if ( curr_off >= block_size ) 
1213      break;
[30]1214
[31]1215    if ( !prs_set_offset( &hbin->ps, curr_off) )
1216      return false;
[30]1217
[31]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;
[30]1222
[31]1223    if ( record_size & 0x80000000 ) {
1224      /* absolute_value(record_size) */
1225      record_size = (record_size ^ 0xffffffff) + 1;
1226    }
[30]1227
[31]1228    if ( memcmp( header, hdr, REC_HDR_SIZE ) == 0 ) {
1229      found = true;
1230      curr_off += sizeof(uint32);
1231    }
1232  } 
[30]1233
[31]1234  /* mark prs_struct as done ( at end ) if no more SK records */
[32]1235  /* mark end-of-block as true */       
1236  if ( !found )
[31]1237  {
1238    prs_set_offset( &hbin->ps, hbin->ps.buffer_size );
1239    *eob = true;
1240    return false;
1241  }
[32]1242
1243  if (!prs_set_offset(ps, curr_off))
[31]1244    return false;
[30]1245
[31]1246  return true;
[30]1247}
1248
1249
1250/*******************************************************************
[31]1251 *******************************************************************/
[32]1252static bool next_nk_record(REGF_FILE *file, REGF_HBIN *hbin, 
1253                           REGF_NK_REC *nk, bool *eob)
[30]1254{
[32]1255  if (next_record(hbin, "nk", eob) 
1256      && hbin_prs_key(file, hbin, nk))
[31]1257    return true;
[30]1258       
[31]1259  return false;
[30]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{
[31]1269  REGF_FILE *rb;
1270  int flags = O_RDONLY;
[30]1271
[31]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;
[30]1278       
[31]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;
[30]1286       
[31]1287  /* open and existing file */
[30]1288
[31]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  }
[30]1294       
[31]1295  /* read in an existing file */
[30]1296       
[31]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  }
[30]1302       
[31]1303  /* success */
[30]1304       
[31]1305  return rb;
[30]1306}
1307
1308
1309/*******************************************************************
[31]1310 *******************************************************************/
[30]1311static void regfio_mem_free( REGF_FILE *file )
1312{
[31]1313  /* free any zalloc()'d memory */
[30]1314       
1315  /*    if ( file && file->mem_ctx )
[31]1316    free(file->mem_ctx);
[30]1317  */
1318}
1319
1320
1321/*******************************************************************
[31]1322 *******************************************************************/
[30]1323int regfio_close( REGF_FILE *file )
1324{
[31]1325  int fd;
[30]1326
[31]1327  regfio_mem_free( file );
[30]1328
[31]1329  /* nothing to do if there is no open file */
[30]1330
[31]1331  if ( !file || (file->fd == -1) )
1332    return 0;
[30]1333               
[31]1334  fd = file->fd;
1335  file->fd = -1;
1336  SAFE_FREE( file );
[30]1337
[31]1338  return close( fd );
[30]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{
[31]1348  REGF_NK_REC *nk;
1349  REGF_HBIN   *hbin;
1350  uint32      offset = REGF_BLOCKSIZE;
1351  bool        found = false;
1352  bool        eob;
[30]1353       
[31]1354  if ( !file )
1355    return NULL;
[30]1356               
[31]1357  if ( !(nk = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC) )) ) {
1358    /*DEBUG(0,("regfio_rootkey: zalloc() failed!\n"));*/
1359    return NULL;
1360  }
[30]1361       
[31]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) */
[30]1366       
[31]1367  while ( (hbin = read_hbin_block( file, offset )) ) {
1368    eob = false;
[30]1369
[31]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    }
[30]1383               
[31]1384    if ( found ) 
1385      break;
[30]1386
[31]1387    offset += hbin->block_size;
1388  }
[30]1389       
[31]1390  if ( !found ) {
1391    /*DEBUG(0,("regfio_rootkey: corrupt registry file ?  No root key record located\n"));*/
1392    return NULL;
1393  }
[30]1394
[31]1395  DLIST_ADD( file->block_list, hbin );
[30]1396
[31]1397  return nk;           
[30]1398}
1399
1400
[33]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 */
[30]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{
[31]1411  REGF_NK_REC *subkey;
1412  REGF_HBIN   *hbin;
1413  uint32      nk_offset;
[30]1414
[31]1415  /* see if there is anything left to report */
[32]1416  if (!nk || (nk->subkeys_off==REGF_OFFSET_NONE) 
1417      || (nk->subkey_index >= nk->num_subkeys))
[31]1418    return NULL;
[30]1419
[31]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  }
[30]1428       
[31]1429  nk_offset = nk->subkeys.hashes[nk->subkey_index].nk_off;
[32]1430  if(!prs_set_offset(&hbin->ps, 
1431                     (HBIN_HDR_SIZE + nk_offset - hbin->first_hbin_off)))
[31]1432    return NULL;
[30]1433               
[31]1434  nk->subkey_index++;
[32]1435  if(!(subkey = (REGF_NK_REC*)zalloc(sizeof(REGF_NK_REC))))
[31]1436    return NULL;
[30]1437
[32]1438  if(!hbin_prs_key(file, hbin, subkey))
[31]1439    return NULL;
[32]1440
[31]1441  return subkey;
[30]1442}
Note: See TracBrowser for help on using the repository browser.