Changeset 99

Show
Ignore:
Timestamp:
12/11/06 06:23:07 (2 years ago)
Author:
kindlund
Message:

Still debugging registry/parser interactions.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • honeyclient/branches/bug/42/etc/honeyclient_log.conf

    r85 r99  
    6060 
    6161log4perl.rootLogger=DEBUG, Screen 
     62# Suppress Parser Debugging Messages 
     63log4perl.logger.HoneyClient.Agent.Integrity.Registry.Parser=INFO, Screen 
    6264log4perl.appender.Screen=Log::Log4perl::Appender::Screen 
    6365# If you want colorized logging to the screen, enable this line, instead. 
  • honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry.pm

    r97 r99  
    109109use HoneyClient::Util::Config qw(getVar); 
    110110 
     111# Include Registry Parsing Library 
     112use HoneyClient::Agent::Integrity::Registry::Parser; 
     113 
    111114# Use Dumper Library 
    112115use Data::Dumper; 
     
    248251use Filesys::CygwinPaths qw(:all); 
    249252 
     253# Make sure HoneyClient::Agent::Integrity::Registry::Parser loads 
     254BEGIN { use_ok('HoneyClient::Agent::Integrity::Registry::Parser') 
     255        or diag("Can't load HoneyClient::Agent::Integrity::Registry::Parser package. Check to make sure the package library is correctly listed within the path."); } 
     256require_ok('HoneyClient::Agent::Integrity::Registry::Parser'); 
     257use HoneyClient::Agent::Integrity::Registry::Parser; 
     258 
    250259=end testing 
    251260 
     
    315324 
    316325    # Baseline File Collection 
    317     # A hashtable of file handles, one file per hive name. 
     326    # A hashtable of file parsers, one parser per hive name. 
    318327    # (For internal use only.) 
    319     _baseline_files => { }, 
     328    _baseline_parsers => { }, 
    320329 
    321330    # Checkpoint File Collection 
    322     # A hashtable of file handles, one file per hive name. 
     331    # A hashtable of file parsers, one parser per hive name. 
    323332    # (For internal use only.) 
    324     _checkpoint_files => { },  
    325  
    326     # A hashtable of file names, where the hash key is the file handle 
     333    _checkpoint_parsers => { },  
     334 
     335    # A hashtable of file names, where the hash key is the file parser 
    327336    # and the hash value is the file name. 
    328337    # (For internal use only.) 
     
    330339 
    331340    # A hashtable of current key info objects, where the hash key is the 
    332     # file handle and the hash value is the info object. 
     341    # file parser and the hash value is the info object. 
    333342    # (For internal use only.) 
    334343    _currentKeys => { }, 
     
    336345    # A hashtable of counters, where each counter keeps track of 
    337346    # which entry was last read in from the current key.  The hash key 
    338     # is the file handle, and the hash value is the entry counter. 
     347    # is the file parser, and the hash value is the entry counter. 
    339348    _currentEntryIndex => { }, 
    340349); 
     
    354363    # Delete any temporary files created. 
    355364#    foreach my $hive (@{$self->{hives_to_check}}) { 
    356 #        my $fh = $self->{_baseline_files}->{$hive}; 
     365#        my $fh = $self->{_baseline_parsers}->{$hive}; 
    357366#        $LOG->debug("Deleting baseline of hive '" . $hive . "' in '" . 
    358367#                    $self->{_filenames}->{$fh} . "'."); 
     
    375384sub _snapshot { 
    376385    # Extract arguments. 
    377     my ($self, $file_collection) = @_; 
    378     my $fh = undef; 
     386    my ($self, $parser_collection) = @_; 
     387    my $parser = undef; 
    379388    my $fname = undef; 
     389    my $fname_tmp = undef; 
    380390    foreach my $hive (@{$self->{hives_to_check}}) { 
    381391        $fname = tmpnam();  
     392        $fname_tmp = tmpnam();  
    382393        $LOG->debug("Storing snapshot of hive '" . $hive . "' into '" . $fname . "'."); 
    383  
    384         if (system("regedit.exe /a \"" . fullwin32path($fname) . "\" \"$hive\"") != 0) { 
     394        $LOG->debug("Creating temporary file '" . $fname_tmp . "' to perform data conversion."); 
     395 
     396        # Dump registry.  Strip all '\r' characters. 
     397        if (system("regedit.exe /a \"" . fullwin32path($fname_tmp) . "\" \"$hive\" && 
     398                   cat " . $fname_tmp . " | sed -e 's/\r//g' > " . $fname) != 0) { 
    385399            $LOG->fatal("Error: Unable to write '" . $hive . "' hive data to '" . $fname ."'."); 
    386400            Carp::croak("Error: Unable to write '" . $hive . "' hive data to '" . $fname ."'."); 
    387401        } 
    388402 
    389         $fh = new IO::File($fname, 'r'); 
    390         if (!defined($fh)) { 
    391             $LOG->fatal("Error: Unable to read '" . $hive . "' hive data from '" . $fname ."'."); 
    392             Carp::croak("Error: Unable to read '" . $hive . "' hive data from '" . $fname ."'."); 
     403        # Delete the unconverted temporary file. 
     404        if (!unlink($fname_tmp)) { 
     405            $LOG->fatal("Error: Unable to unlink temporary file '" . $fname_tmp ."'."); 
     406            Carp::croak("Error: Unable to unlink temporary file '" . $fname_tmp ."'."); 
    393407        } 
    394408 
     409        $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $fname); 
     410 
    395411        # Preemptively unlink the file, to prevent any other process from mucking with it. 
    396 #        if (!unlink0($fh, $fname)) { 
     412        # XXX: Check if this can still be used. 
     413#        if (!unlink0($parser->getFileHandle(), $fname)) { 
    397414#            $LOG->fatal("Error: Unable to unlink '" . $hive . "' hive data in '" . $fname ."'."); 
    398415#            Carp::croak("Error: Unable to unlink '" . $hive . "' hive data in '" . $fname ."'."); 
    399416#        } 
    400417 
    401         $file_collection->{$hive} = $fh
    402         $self->{_filenames}->{$fh} = $fname; 
     418        $parser_collection->{$hive} = $parser
     419        $self->{_filenames}->{$parser} = $fname; 
    403420    } 
    404 } 
    405  
    406 # Helper function, designed to read a single key from the specified 
    407 # file descriptor. 
    408 # 
    409 # Inputs: HoneyClient::Agent::Integrity::Registry object, 
    410 #         file descriptor to read the key from 
    411 # 
    412 # Outputs: Returns undef on error, an empty hash reference if end 
    413 #          of file is encountered, our outputs the following 
    414 #          'info' hashtable: 
    415 # 
    416 #   { 
    417 #       'key' => "theName",          # name of key (with HKEY_...) 
    418 #       'status' => 'd' | 'n' | 'e', # d: deleted, n:new, e:existing 
    419 #       'entries' => [ {             # entries added/changed/deleted 
    420 #           'name' => "\"theName\"", # name of entry (maybe "@") 
    421 #           'value' => "hex:...",    # value (undef if deleted) 
    422 #           'oldValue' => "\"abc\"", # undef if unknown (maybe "new") 
    423 #       } ], 
    424 #   } 
    425 # 
    426 sub _readKey { 
    427     # Extract arguments. 
    428     my ($self, $fd) = @_; 
    429  
    430     my ($key, $stuff); 
    431  
    432     # Create a new info object to return. 
    433     my ($info) = {}; 
    434     my ($startLine, $currentLine); 
    435  
    436     # Boolean to keep track of whether the first line has been read. 
    437     my ($firstLine) = 1; 
    438  
    439     # While the file descriptor has more lines to read... 
    440     while (<$fd>) { 
    441         # Strip off any carriage returns. 
    442         $_ =~ s/\r$//; 
    443  
    444         # Skip the beginning 'REGEDIT4' header. 
    445         next if (/^REGEDIT4\s*$/ && $firstLine); 
    446  
    447         # Terminate early, if the info object is already populated. 
    448         if (/^\s*$/) { 
    449             last if (%$info); # non empty key 
    450             next; 
    451         } 
    452  
    453         # If we've gotten this far, then we're not on the first line. 
    454         $firstLine = 0; 
    455  
    456         # Read in the new registry key directory name. 
    457         #if (/^\[(.*)](.*)/) { 
    458         if (/^\[(.*)]/) { 
    459  
    460             # Emit error, if we've already created an info object and were about 
    461             # to create a new one, before reaching a blank line. 
    462             if (%$info) { 
    463                 $LOG->error("Error: (" . $. . ") - Registry keys not separated by blank line."); 
    464                 Carp::carp("Error: (" . $. . ") - Registry keys not separated by blank line."); 
    465                 return undef; 
    466             } 
    467  
    468             # Read in key name, along with any adjacent string. 
    469             #($key, $stuff) = ($1, $2); 
    470             $key = $1; 
    471  
    472             # Determine if the registry file we're reading has custom identifiers in the 
    473             # adjacent string, which would signify if the registry key is new, deleted, or 
    474             # already existed. 
    475             my ($status); 
    476             #if ($stuff =~ /^\s*$/) { 
    477             #   $status = 'e'; 
    478             #} elsif ($stuff =~ /^\s*-\s*$/) { 
    479             #   $status = 'd'; 
    480             #} elsif ($stuff =~ /^\s*\(new\)\s*$/) { 
    481             #   $status = 'n'; 
    482             #} else { 
    483             #   $LOG->error("Error: (" . $. . ") - Unrecognized data after registry key: " . $stuff); 
    484             #   Carp::carp("Error: (" . $. . ") - Unrecognized data after registry key: " . $stuff); 
    485             #   return undef; 
    486             #} 
    487  
    488             # Construct the info object. 
    489             $info->{'key'}     = $key; 
    490             $info->{'status'}  = $status; 
    491             $info->{'entries'} = []; 
    492             next; 
    493         } 
    494  
    495         # If we've gotten this far, then we must have already read the key directory name and 
    496         # the new text must correspond to a key entry. 
    497         if (!%$info) { 
    498             $LOG->error("Error: (" . $. . ") - Entry found outside of registry key."); 
    499             Carp::carp("Error: (" . $. . ") - Entry found outside of registry key."); 
    500             return undef; 
    501         } 
    502  
    503         # Read in the contents of the key entry, span multiple lines 
    504         # as long as we have a continuation marker (\) at the end of  
    505         # each line... 
    506         $startLine = $.; 
    507         #my $sofar = ''; 
    508         while (1) { 
    509  
    510             #if (/^(([^"\\]|\\\\|\\")+|"([^"\\]|\\\\|\\")*")*/) { 
    511             #    $sofar .= $&; 
    512             #    last if $' eq ''; 
    513             #    $_ = $'; 
    514             #} 
    515  
    516             chomp; # Kill off excess newlines from $_. 
    517  
    518             # Check to see if we're on a line that continues. 
    519             if (/^.*[^\\]$/) { 
    520                 last; 
    521             } 
    522  
    523             # Strip out continuation marker from $_. 
    524             $_ =~ s/\\$//; 
    525  
    526  
    527             # Kill off excess newlines. 
    528             chomp($currentLine = <$fd>); 
    529             $currentLine =~ s/\r$//; 
    530  
    531             # Sanity check. 
    532             if (!defined $currentLine) { 
    533                 $LOG->error("Error: (" . $. . ") - Hit EOF while looking for matching registry entry quote or non-continuation line (started at line " . $startLine . ")"); 
    534                 Carp::carp("Error: (" . $. . ") - Hit EOF while looking for matching registry entry quote or non-continuation line (started at line " . $startLine . ")"); 
    535                 return undef; 
    536             } 
    537             #if ($_ eq "\\\n") { 
    538             #    $_ = ''; 
    539                 $currentLine =~ s/^\s*//; 
    540             #} 
    541             $_ .= $currentLine; 
    542         } 
    543         #$_ = $sofar; 
    544         if ( 
    545 /^(\@|\"([^\\"]|\\"|\\\\)+")(|=(|(|stringz:|ustringz:)"([^\\"]|\\"|\\\\)*"|dword:[\da-fA-F]+|hex(|\([0-9a-fA-F]+\)):[\da-fA-F,]*))(|\s+\((.+)\))\s*$/ 
    546           ) 
    547         { 
    548             push(@{$info->{'entries'}}, 
    549                  {'name'     => $1, 
    550                   'value'    => $3 eq '' ? undef: $4, 
    551                   'oldValue' => $8 eq '' ? undef: $9,}); 
    552             next; 
    553         } 
    554         $LOG->error("Error: (" . $. . ") - Unable to extract registry entry name/value pairs."); 
    555         Carp::carp("Error: (" . $. . ") - Unable to extract registry entry name/value pairs."); 
    556         return undef; 
    557     } 
    558     return $info; 
    559 } 
    560  
    561 # Helper function, designed to print any info object created by 
    562 # the _readKey() function. 
    563 # 
    564 # Inputs: HoneyClient::Agent::Integrity::Registry object, 
    565 #         file descriptor to print to, 
    566 #         info object created by _readKey() 
    567 #  
    568 # Outputs: None 
    569 sub _printKey { 
    570     my ($self, $info) = @_; 
    571  
    572     return if !defined($info) || !%{$info}; 
    573  
    574     print '[', $info->{'key'}, ']'; 
    575 #    print "\t(new)" if ($info->{'status'} eq 'n'); 
    576 #    print '-'       if ($info->{'status'} eq 'd'); 
    577     print "\n"; 
    578     my $f; 
    579     foreach $f (@{$info->{'entries'}}) { 
    580         print $f->{'name'}; 
    581         print '=', $f->{'value'} if (defined $f->{'value'}); 
    582         print "\t(", $f->{'oldValue'}, ')' if (defined $f->{'oldValue'}); 
    583         print "\n"; 
    584     } 
    585     print "\n"; 
    586421} 
    587422 
     
    640475# name, out of the specified file. 
    641476# 
    642 # Inputs: HoneyClient::Agent::Integrity::Registry object, file descriptor to read 
     477# Inputs: HoneyClient::Agent::Integrity::Registry object, file parser to read 
    643478# 
    644479# Outputs: next registry key directory name; undef if no key directory names 
    645480#          are left to read 
    646481sub _nextKey { 
    647     my ($self, $file) = @_; 
     482    my ($self, $parser) = @_; 
    648483 
    649484    # Read the next key from the specified file. 
    650     $self->{_currentKeys}->{$file} = $self->_readKey($file); 
     485    $self->{_currentKeys}->{$parser} = $parser->nextGroup(); 
    651486 
    652487    # Check to make sure read was successful. 
    653     if (!defined($self->{_currentKeys}->{$file})) { 
     488    if (!defined($self->{_currentKeys}->{$parser})) { 
    654489        $LOG->fatal("Error: Unable to read registry keys from '" . 
    655                     $self->{_filenames}->{$file} . "'."); 
     490                    $self->{_filenames}->{$parser} . "'."); 
    656491        Carp::croak("Error: Unable to read registry keys from '" . 
    657                     $self->{_filenames}->{$file} . "'."); 
     492                    $self->{_filenames}->{$parser} . "'."); 
    658493    } 
    659494 
    660495    # Encountered empty hash ref, thus we are at 
    661496    # the end of the file. 
    662     if (!%{$self->{_currentKeys}->{$file}}) { 
     497    if (!%{$self->{_currentKeys}->{$parser}}) { 
    663498        return undef; 
    664499    } 
     
    666501    # Key read was successful, reset the entry index 
    667502    # for this file. 
    668     $self->{_currentEntryIndex}->{$file} = 0; 
     503    $self->{_currentEntryIndex}->{$parser} = 0; 
    669504 
    670505    # Return the corresponding key directory name. 
    671     return $self->{_currentKeys}->{$file}->{'key'}; 
     506    return $self->{_currentKeys}->{$parser}->{'key'}; 
    672507} 
    673508 
     
    675510# the last key directory that was fetched by _nextKey(). 
    676511# 
    677 # Inputs: HoneyClient::Agent::Integrity::Registry object, file descriptor to read 
     512# Inputs: HoneyClient::Agent::Integrity::Registry object, file parser to read 
    678513# 
    679514# Outputs: next entry (name, value) pair; undef if no entries were found that 
    680515#          correspond to the last key directory fetched by _nextKey() 
    681516sub _nextVal { 
    682     my ($self, $file) = @_; 
     517    my ($self, $parser) = @_; 
    683518 
    684519    # Read the last key object read from the specified file. 
    685     my ($k)    = $self->{_currentKeys}->{$file}; 
     520    my ($k) = $self->{_currentKeys}->{$parser}; 
    686521 
    687522    # Get the latest entry index associated with the latest key. 
    688     my ($i) = $self->{_currentEntryIndex}->{$file}; 
     523    my ($i) = $self->{_currentEntryIndex}->{$parser}; 
    689524 
    690525    # If the index is past our array of known entries, then return undef. 
     
    694529 
    695530    # There is an entry to be read, so increment the entry index. 
    696     $self->{_currentEntryIndex}->{$file} = $i + 1; 
     531    $self->{_currentEntryIndex}->{$parser} = $i + 1; 
    697532 
    698533    # Return the corresponding entry (name, value) pair. 
     
    782617 
    783618    # Perform registry baselining. 
    784     $self->_snapshot($self->{_baseline_files}); 
     619    $self->_snapshot($self->{_baseline_parsers}); 
    785620 
    786621    # Finally, return the blessed object. 
     
    848683 
    849684    # Checkpoint the registry. 
    850     $self->_snapshot($self->{_checkpoint_files}); 
     685    $self->_snapshot($self->{_checkpoint_parsers}); 
    851686 
    852687    my ($from, $to); 
     
    871706 
    872707$LOG->info("Checking '" . $hive . "' hive..."); 
    873 $from = $self->{_baseline_files}->{$hive}; 
    874 $to   = $self->{_checkpoint_files}->{$hive}; 
     708$from = $self->{_baseline_parsers}->{$hive}; 
     709$to   = $self->{_checkpoint_parsers}->{$hive}; 
    875710 
    876711    my $dellen = 99999; 
     
    888723#$LOG->debug("FROM: ". Dumper($fromkey)); 
    889724#$LOG->debug("TO: " . Dumper($tokey)); 
    890 $self->_printKey($self->{_currentKeys}->{$from}); 
     725print "FROM: ". Dumper($fromkey) . "\n"; 
     726print "TO: ". Dumper($tokey) . "\n\n"; 
     727#print Dumper($self->{_currentKeys}->{$from}) . "\n"; 
    891728 
    892729        # Figure out the length of the to key. 
  • honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.pm

    r97 r99  
    6969 
    7070  # Print each registry group found, until there are no more left. 
    71   my $registryGroup = undef
    72   while(defined($registryGroup = $parser->nextGroup())) { 
     71  my $registryGroup = $parser->nextGroup()
     72  while(scalar(keys(%{$registryGroup}))) { 
    7373      print Dumper($registryGroup); 
     74      $registryGroup = $parser->nextGroup(); 
    7475  } 
    7576 
     
    113114use IO::File; 
    114115 
     116# Use Seek Library. 
     117use Fcntl qw(:seek); 
     118 
    115119####################################################################### 
    116120# Module Initialization                                               # 
     
    198202require_ok('IO::File'); 
    199203use IO::File; 
     204 
     205# Make sure Fcntl loads 
     206BEGIN { use_ok('Fcntl') 
     207        or diag("Can't load Fcntl package. Check to make sure the package library is correctly listed within the path."); } 
     208require_ok('Fcntl'); 
     209use Fcntl qw(:seek); 
    200210 
    201211# Make sure HoneyClient::Agent::Integrity::Registry::Parser loads 
     
    344354         'registry', 0, 
    345355sub 
    346 #line 218 "Parser.yp" 
     356#line 228 "Parser.yp" 
    347357{ 
    348358            $LOG->debug("Reached end of input stream."); 
    349             # Finished parsing the entire file, return undef. 
    350             return undef
     359            # Finished parsing the entire file, return empty hash ref. 
     360            return { }
    351361        } 
    352362    ], 
     
    354364         'registry', 1, 
    355365sub 
    356 #line 223 "Parser.yp" 
     366#line 233 "Parser.yp" 
    357367{ 
    358368            $LOG->debug("Reached end of input stream."); 
    359             # Finished parsing the entire file, return undef. 
    360             return undef
     369            # Finished parsing the entire file, return empty hash ref. 
     370            return { }
    361371        } 
    362372    ], 
     
    364374         'registry', 2, 
    365375sub 
    366 #line 228 "Parser.yp" 
     376#line 238 "Parser.yp" 
    367377{ 
    368378            $LOG->debug("Reached end of input stream."); 
    369             # Finished parsing the entire file, return undef. 
    370             return undef
     379            # Finished parsing the entire file, return empty hash ref. 
     380            return { }
    371381        } 
    372382    ], 
     
    386396         'group', 2, 
    387397sub 
    388 #line 245 "Parser.yp" 
     398#line 255 "Parser.yp" 
    389399{ 
    390400            my $ret = { }; 
     
    405415         'group', 1, 
    406416sub 
    407 #line 259 "Parser.yp" 
     417#line 269 "Parser.yp" 
    408418{ 
    409419            my $ret = { }; 
     
    430440         'entry', 2, 
    431441sub 
    432 #line 283 "Parser.yp" 
     442#line 293 "Parser.yp" 
    433443{ 
    434444            my $entry = { 
     
    445455} 
    446456 
    447 #line 293 "Parser.yp" 
     457#line 303 "Parser.yp" 
    448458 
    449459 
     
    541551} 
    542552 
     553# Helper function, designed to index all groups, based upon beginning file 
     554# offsets. 
     555# 
     556# Inputs: parser 
     557# Outputs: None 
     558sub _index { 
     559    # Extract arguments. 
     560    my $self = shift; 
     561 
     562    $LOG->debug("Starting group index process."); 
     563 
     564    $self->YYData->{'group_index'} = [0, ]; 
     565 
     566    my $registryGroup = $self->nextGroup(); 
     567    while(scalar(keys(%{$registryGroup}))) { 
     568        $registryGroup = $self->nextGroup(); 
     569        push (@{$self->YYData->{'group_index'}}, $self->YYData->{'input_pos'}); 
     570    } 
     571 
     572    my $fh = $self->YYData->{'file_handle'}; 
     573    seek($fh, 0, SEEK_SET); 
     574 
     575    undef $/; 
     576    $self->YYData->{DATA} = <$fh>; 
     577 
     578    # Strip all CRs. 
     579    $self->YYData->{DATA} =~ s/\r//g; 
     580     
     581$self->YYData->{DATA} =~ m/\G.{73}/scg; 
     582    
     583 
     584    # Reinitialize helper variables. 
     585    # Hashtable, to represent the latest, extracted group chunk. 
     586    $self->YYData->{'latest_group'} = { }; 
     587 
     588    # Boolean, to indicate when we're parsing inside a group chunk. 
     589    $self->YYData->{'in_group'} = 0; 
     590 
     591    # Boolean, to indicate when we're parsing inside a value segment. 
     592    $self->YYData->{'in_value'} = 0; 
     593     
     594    # Regexp offset, used to record where the parser is within 
     595    # the file. 
     596    $self->YYData->{'input_pos'} = 0; 
     597 
     598    # Initialize statistics. 
     599    # Total number of directories parsed. 
     600    $self->YYData->{'dir_count'} = 0; 
     601 
     602    # Total number of key/value pairs parsed. 
     603    $self->YYData->{'entry_count'} = 0; 
     604 
     605    $LOG->debug("Finished group index process."); 
     606 
     607    print Dumper($self->YYData->{'group_index'}) . "\n"; 
     608} 
     609 
    543610####################################################################### 
    544611# Public Methods Implemented                                          # 
     
    551618The following functions have been implemented by any Parser object. 
    552619 
    553 =head2 HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $filename
     620=head2 HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $filename, index_groups => $perform_index
    554621 
    555622=over 4 
     
    560627I<Inputs>: 
    561628 B<$filename> is an required parameter, specifying the file to open for parsing. 
     629 B<$perform_index> is an optional parameter.  1 specifies that the parser should go 
     630ahead and scan the entire file, indexing the file offsets of where groups start and 
     631end.  Otherwise, this indexing process is not performed. 
    562632  
    563633I<Output>: The instantiated Parser B<$object>, fully initialized. 
     
    605675        Carp::croak("Error: Unable to read file '" . $args{'input_file'} . "'!\n"); 
    606676    } 
     677 
     678    # Save the file handle. 
     679    $parser->YYData->{'file_handle'} = $fh; 
     680 
    607681    undef $/; 
    608682    $parser->YYData->{DATA} = <$fh>; 
     
    625699    $parser->YYData->{'input_pos'} = 0; 
    626700 
     701    # Array to record where group boundaries occur. 
     702    $parser->YYData->{'group_index'} = [0, ]; 
     703 
    627704    # Initialize statistics. 
    628705    # Total number of directories parsed. 
     
    631708    # Total number of key/value pairs parsed. 
    632709    $parser->YYData->{'entry_count'} = 0; 
     710 
     711    # Perform group indexing, if specified. 
     712    if ($argsExist &&  
     713        exists($args{'index_groups'}) &&  
     714        defined($args{'index_groups'}) && 
     715        $args{'index_groups'}) { 
     716        $parser->_index(); 
     717    } 
    633718 
    634719    # Return parser object. 
     
    659744 
    660745I<Output>: A hashtable reference if the next group was parsed successfully; 
    661 returns undef, if the Parser B<$object> has reached the end of the input stream. 
     746returns an empty hash ref, if the Parser B<$object> has reached the end of 
     747the input stream. 
    662748 
    663749=back 
     
    670756 
    671757# Create a generic Parser object, with test state data. 
    672 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 
     758my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file, index_groups => 1); 
    673759 
    674760# Verify Test Group #1 
     
    804890# Verify Test Group #9 
    805891$nextGroup = $parser->nextGroup(); 
    806 is_deeply($nextGroup, undef, "nextGroup() - 9") or diag("The nextGroup() call failed."); 
     892is_deeply($nextGroup, { }, "nextGroup() - 9") or diag("The nextGroup() call failed."); 
    807893 
    808894=end testing 
     
    852938my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 
    853939 
    854 while(defined($nextGroup = $parser->nextGroup)) { 
     940$nextGroup = $parser->nextGroup(); 
     941while(scalar(keys(%{$nextGroup}))) { 
     942    $nextGroup = $parser->nextGroup(); 
    855943} 
    856944 
     
    897985my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 
    898986 
    899 while(defined($nextGroup = $parser->nextGroup)) { 
     987$nextGroup = $parser->nextGroup(); 
     988while(scalar(keys(%{$nextGroup}))) { 
     989    $nextGroup = $parser->nextGroup(); 
    900990} 
    901991 
     
    9191009} 
    9201010 
     1011=pod 
     1012 
     1013=head2 $object->getFileHandle() 
     1014 
     1015=over 4 
     1016 
     1017Returns the file handle associated with the current Parser B<$object>. 
     1018 
     1019I<Output>: Returns the file handle in use. 
     1020 
     1021=back 
     1022 
     1023=begin testing 
     1024 
     1025my ($handle); 
     1026my $test_registry_file = $ENV{PWD} . "/" . getVar(name      => "registry_file", 
     1027                                                  namespace => "HoneyClient::Agent::Integrity::Registry::Parser::Test"); 
     1028 
     1029# Create a generic Parser object, with test state data. 
     1030my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 
     1031 
     1032$handle = $parser->getFileHandle(); 
     1033 
     1034isa_ok($handle, 'IO::File', "getFileHandle()") or diag("The getFileHandle() call failed."); 
     1035 
     1036=end testing 
     1037 
     1038=cut 
     1039 
     1040sub getFileHandle { 
     1041    # Extract arguments. 
     1042    my ($self, %args) = @_; 
     1043 
     1044    # Log resolved arguments. 
     1045    # Make Dumper format more terse. 
     1046    $Data::Dumper::Terse = 1; 
     1047    $Data::Dumper::Indent = 0; 
     1048    $LOG->debug(Dumper(\%args)); 
     1049 
     1050    return $self->YYData->{'file_handle'};  
     1051} 
     1052 
    9211053####################################################################### 
    9221054# Additional Module Documentation                                     # 
  • honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.yp

    r97 r99  
    5252 
    5353  # Print each registry group found, until there are no more left. 
    54   my $registryGroup = undef
    55   while(defined($registryGroup = $parser->nextGroup())) { 
     54  my $registryGroup = $parser->nextGroup()
     55  while(scalar(keys(%{$registryGroup}))) { 
    5656      print Dumper($registryGroup); 
     57      $registryGroup = $parser->nextGroup(); 
    5758  } 
    5859 
     
    9697use IO::File; 
    9798 
     99# Use Seek Library. 
     100use Fcntl qw(:seek); 
     101 
    98102####################################################################### 
    99103# Module Initialization                                               # 
     
    182186use IO::File; 
    183187 
     188# Make sure Fcntl loads 
     189BEGIN { use_ok('Fcntl') 
     190        or diag("Can't load Fcntl package. Check to make sure the package library is correctly listed within the path."); } 
     191require_ok('Fcntl'); 
     192use Fcntl qw(:seek); 
     193 
    184194# Make sure HoneyClient::Agent::Integrity::Registry::Parser loads 
    185195BEGIN { use_ok('HoneyClient::Agent::Integrity::Registry::Parser') 
     
    218228               { 
    219229            $LOG->debug("Reached end of input stream."); 
    220             # Finished parsing the entire file, return undef. 
    221             return undef
     230            # Finished parsing the entire file, return empty hash ref. 
     231            return { }
    222232        } 
    223233    |   groups { 
    224234            $LOG->debug("Reached end of input stream."); 
    225             # Finished parsing the entire file, return undef. 
    226             return undef
     235            # Finished parsing the entire file, return empty hash ref. 
     236            return { }
    227237        } 
    228238    |   HEADER groups { 
    229239            $LOG->debug("Reached end of input stream."); 
    230             # Finished parsing the entire file, return undef. 
    231             return undef
     240            # Finished parsing the entire file, return empty hash ref. 
     241            return { }
    232242        } 
    233243; 
     
    386396} 
    387397 
     398# Helper function, designed to index all groups, based upon beginning file 
     399# offsets. 
     400# 
     401# Inputs: parser 
     402# Outputs: None 
     403sub _index { 
     404    # Extract arguments. 
     405    my $self = shift; 
     406 
     407    $LOG->debug("Starting group index process."); 
     408 
     409    $self->YYData->{'group_index'} = [0, ]; 
     410 
     411    my $registryGroup = $self->nextGroup(); 
     412    while(scalar(keys(%{$registryGroup}))) { 
     413        $registryGroup = $self->nextGroup(); 
     414        push (@{$self->YYData->{'group_index'}}, $self->YYData->{'input_pos'}); 
     415    } 
     416 
     417    my $fh = $self->YYData->{'file_handle'}; 
     418    seek($fh, 0, SEEK_SET); 
     419 
     420    undef $/; 
     421    $self->YYData->{DATA} = <$fh>; 
     422 
     423    # Strip all CRs. 
     424    $self->YYData->{DATA} =~ s/\r//g; 
     425     
     426$self->YYData->{DATA} =~ m/\G.{73}/scg; 
     427    
     428 
     429    # Reinitialize helper variables. 
     430    # Hashtable, to represent the latest, extracted group chunk. 
     431    $self->YYData->{'latest_group'} = { }; 
     432 
     433    # Boolean, to indicate when we're parsing inside a group chunk. 
     434    $self->YYData->{'in_group'} = 0; 
     435 
     436    # Boolean, to indicate when we're parsing inside a value segment. 
     437    $self->YYData->{'in_value'} = 0; 
     438     
     439    # Regexp offset, used to record where the parser is within 
     440    # the file. 
     441    $self->YYData->{'input_pos'} = 0; 
     442 
     443    # Initialize statistics. 
     444    # Total number of directories parsed. 
     445    $self->YYData->{'dir_count'} = 0; 
     446 
     447    # Total number of key/value pairs parsed. 
     448    $self->YYData->{'entry_count'} = 0; 
     449 
     450    $LOG->debug("Finished group index process."); 
     451 
     452    print Dumper($self->YYData->{'group_index'}) . "\n"; 
     453} 
     454 
    388455####################################################################### 
    389456# Public Methods Implemented                                          # 
     
    396463The following functions have been implemented by any Parser object. 
    397464 
    398 =head2 HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $filename
     465=head2 HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $filename, index_groups => $perform_index
    399466 
    400467=over 4 
     
    405472I<Inputs>: 
    406473 B<$filename> is an required parameter, specifying the file to open for parsing. 
     474 B<$perform_index> is an optional parameter.  1 specifies that the parser should go 
     475ahead and scan the entire file, indexing the file offsets of where groups start and 
     476end.  Otherwise, this indexing process is not performed. 
    407477  
    408478I<Output>: The instantiated Parser B<$object>, fully initialized. 
     
    450520        Carp::croak("Error: Unable to read file '" . $args{'input_file'} . "'!\n"); 
    451521    } 
     522 
     523    # Save the file handle. 
     524    $parser->YYData->{'file_handle'} = $fh; 
     525 
    452526    undef $/; 
    453527    $parser->YYData->{DATA} = <$fh>; 
     
    470544    $parser->YYData->{'input_pos'} = 0; 
    471545 
     546    # Array to record where group boundaries occur. 
     547    $parser->YYData->{'group_index'} = [0, ]; 
     548 
    472549    # Initialize statistics. 
    473550    # Total number of directories parsed. 
     
    476553    # Total number of key/value pairs parsed. 
    477554    $parser->YYData->{'entry_count'} = 0; 
     555 
     556    # Perform group indexing, if specified. 
     557    if ($argsExist &&  
     558        exists($args{'index_groups'}) &&  
     559        defined($args{'index_groups'}) && 
     560        $args{'index_groups'}) { 
     561        $parser->_index(); 
     562    } 
    478563 
    479564    # Return parser object. 
     
    504589 
    505590I<Output>: A hashtable reference if the next group was parsed successfully; 
    506 returns undef, if the Parser B<$object> has reached the end of the input stream. 
     591returns an empty hash ref, if the Parser B<$object> has reached the end of 
     592the input stream. 
    507593 
    508594=back 
     
    515601 
    516602# Create a generic Parser object, with test state data. 
    517 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 
     603my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file, index_groups => 1); 
    518604 
    519605# Verify Test Group #1 
     
    649735# Verify Test Group #9 
    650736$nextGroup = $parser->nextGroup(); 
    651 is_deeply($nextGroup, undef, "nextGroup() - 9") or diag("The nextGroup() call failed."); 
     737is_deeply($nextGroup, { }, "nextGroup() - 9") or diag("The nextGroup() call failed."); 
    652738 
    653739=end testing 
     
    697783my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 
    698784 
    699 while(defined($nextGroup = $parser->nextGroup)) { 
     785$nextGroup = $parser->nextGroup(); 
     786while(scalar(keys(%{$nextGroup}))) { 
     787    $nextGroup = $parser->nextGroup(); 
    700788} 
    701789 
     
    742830my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 
    743831 
    744 while(defined($nextGroup = $parser->nextGroup)) { 
     832$nextGroup = $parser->nextGroup(); 
     833while(scalar(keys(%{$nextGroup}))) { 
     834    $nextGroup = $parser->nextGroup(); 
    745835} 
    746836 
     
    764854} 
    765855 
     856=pod 
     857 
     858=head2 $object->getFileHandle() 
     859 
     860=over 4 
     861 
     862Returns the file handle associated with the current Parser B<$object>. 
     863 
     864I<Output>: Returns the file handle in use. 
     865 
     866=back 
     867 
     868=begin testing 
     869 
     870my ($handle); 
     871my $test_registry_file = $ENV{PWD} . "/" . getVar(name      => "registry_file", 
     872                                                  namespace => "HoneyClient::Agent::Integrity::Registry::Parser::Test"); 
     873 
     874# Create a generic Parser object, with test state data. 
     875my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 
     876 
     877$handle = $parser->getFileHandle(); 
     878 
     879isa_ok($handle, 'IO::File', "getFileHandle()") or diag("The getFileHandle() call failed."); 
     880 
     881=end testing 
     882 
     883=cut 
     884 
     885sub getFileHandle { 
     886    # Extract arguments. 
     887    my ($self, %args) = @_; 
     888 
     889    # Log resolved arguments. 
     890    # Make Dumper format more terse. 
     891    $Data::Dumper::Terse = 1; 
     892    $Data::Dumper::Indent = 0; 
     893    $LOG->debug(Dumper(\%args)); 
     894 
     895    return $self->YYData->{'file_handle'};  
     896} 
     897 
    766898####################################################################### 
    767899# Additional Module Documentation                                     # 
  • honeyclient/branches/bug/42/t/honeyclient_agent_integrity_registry.t

    r96 r99  
    8787require_ok('Filesys::CygwinPaths'); 
    8888use Filesys::CygwinPaths qw(:all); 
     89 
     90# Make sure HoneyClient::Agent::Integrity::Registry::Parser loads 
     91BEGIN { use_ok('HoneyClient::Agent::Integrity::Registry::Parser') 
     92        or diag("Can't load HoneyClient::Agent::Integrity::Registry::Parser package. Check to make sure the package library is correctly listed within the path."); } 
     93require_ok('HoneyClient::Agent::Integrity::Registry::Parser'); 
     94use HoneyClient::Agent::Integrity::Registry::Parser; 
    8995} 
    9096 
  • honeyclient/branches/bug/42/t/honeyclient_agent_integrity_registry_parser.t

    r96 r99  
    5555use IO::File; 
    5656 
     57# Make sure Fcntl loads 
     58BEGIN { use_ok('Fcntl') 
     59        or diag("Can't load Fcntl package. Check to make sure the package library is correctly listed within the path."); } 
     60require_ok('Fcntl'); 
     61use Fcntl qw(:seek); 
     62 
    5763# Make sure HoneyClient::Agen