Changeset 99
- Timestamp:
- 12/11/06 06:23:07 (2 years ago)
- Files:
-
- honeyclient/branches/bug/42/etc/honeyclient_log.conf (modified) (1 diff)
- honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry.pm (modified) (15 diffs)
- honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.pm (modified) (22 diffs)
- honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.yp (modified) (16 diffs)
- honeyclient/branches/bug/42/t/honeyclient_agent_integrity_registry.t (modified) (1 diff)
- honeyclient/branches/bug/42/t/honeyclient_agent_integrity_registry_parser.t (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
honeyclient/branches/bug/42/etc/honeyclient_log.conf
r85 r99 60 60 61 61 log4perl.rootLogger=DEBUG, Screen 62 # Suppress Parser Debugging Messages 63 log4perl.logger.HoneyClient.Agent.Integrity.Registry.Parser=INFO, Screen 62 64 log4perl.appender.Screen=Log::Log4perl::Appender::Screen 63 65 # If you want colorized logging to the screen, enable this line, instead. honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry.pm
r97 r99 109 109 use HoneyClient::Util::Config qw(getVar); 110 110 111 # Include Registry Parsing Library 112 use HoneyClient::Agent::Integrity::Registry::Parser; 113 111 114 # Use Dumper Library 112 115 use Data::Dumper; … … 248 251 use Filesys::CygwinPaths qw(:all); 249 252 253 # Make sure HoneyClient::Agent::Integrity::Registry::Parser loads 254 BEGIN { 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."); } 256 require_ok('HoneyClient::Agent::Integrity::Registry::Parser'); 257 use HoneyClient::Agent::Integrity::Registry::Parser; 258 250 259 =end testing 251 260 … … 315 324 316 325 # Baseline File Collection 317 # A hashtable of file handles, one fileper hive name.326 # A hashtable of file parsers, one parser per hive name. 318 327 # (For internal use only.) 319 _baseline_ files => { },328 _baseline_parsers => { }, 320 329 321 330 # Checkpoint File Collection 322 # A hashtable of file handles, one fileper hive name.331 # A hashtable of file parsers, one parser per hive name. 323 332 # (For internal use only.) 324 _checkpoint_ files => { },325 326 # A hashtable of file names, where the hash key is the file handle333 _checkpoint_parsers => { }, 334 335 # A hashtable of file names, where the hash key is the file parser 327 336 # and the hash value is the file name. 328 337 # (For internal use only.) … … 330 339 331 340 # A hashtable of current key info objects, where the hash key is the 332 # file handleand the hash value is the info object.341 # file parser and the hash value is the info object. 333 342 # (For internal use only.) 334 343 _currentKeys => { }, … … 336 345 # A hashtable of counters, where each counter keeps track of 337 346 # 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. 339 348 _currentEntryIndex => { }, 340 349 ); … … 354 363 # Delete any temporary files created. 355 364 # foreach my $hive (@{$self->{hives_to_check}}) { 356 # my $fh = $self->{_baseline_ files}->{$hive};365 # my $fh = $self->{_baseline_parsers}->{$hive}; 357 366 # $LOG->debug("Deleting baseline of hive '" . $hive . "' in '" . 358 367 # $self->{_filenames}->{$fh} . "'."); … … 375 384 sub _snapshot { 376 385 # Extract arguments. 377 my ($self, $ file_collection) = @_;378 my $ fh= undef;386 my ($self, $parser_collection) = @_; 387 my $parser = undef; 379 388 my $fname = undef; 389 my $fname_tmp = undef; 380 390 foreach my $hive (@{$self->{hives_to_check}}) { 381 391 $fname = tmpnam(); 392 $fname_tmp = tmpnam(); 382 393 $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) { 385 399 $LOG->fatal("Error: Unable to write '" . $hive . "' hive data to '" . $fname ."'."); 386 400 Carp::croak("Error: Unable to write '" . $hive . "' hive data to '" . $fname ."'."); 387 401 } 388 402 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 ."'."); 393 407 } 394 408 409 $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $fname); 410 395 411 # 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)) { 397 414 # $LOG->fatal("Error: Unable to unlink '" . $hive . "' hive data in '" . $fname ."'."); 398 415 # Carp::croak("Error: Unable to unlink '" . $hive . "' hive data in '" . $fname ."'."); 399 416 # } 400 417 401 $ file_collection->{$hive} = $fh;402 $self->{_filenames}->{$ fh} = $fname;418 $parser_collection->{$hive} = $parser; 419 $self->{_filenames}->{$parser} = $fname; 403 420 } 404 }405 406 # Helper function, designed to read a single key from the specified407 # file descriptor.408 #409 # Inputs: HoneyClient::Agent::Integrity::Registry object,410 # file descriptor to read the key from411 #412 # Outputs: Returns undef on error, an empty hash reference if end413 # of file is encountered, our outputs the following414 # 'info' hashtable:415 #416 # {417 # 'key' => "theName", # name of key (with HKEY_...)418 # 'status' => 'd' | 'n' | 'e', # d: deleted, n:new, e:existing419 # 'entries' => [ { # entries added/changed/deleted420 # '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 key450 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 about461 # 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 the473 # adjacent string, which would signify if the registry key is new, deleted, or474 # 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 and496 # 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 lines504 # as long as we have a continuation marker (\) at the end of505 # 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 by562 # 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: None569 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";586 421 } 587 422 … … 640 475 # name, out of the specified file. 641 476 # 642 # Inputs: HoneyClient::Agent::Integrity::Registry object, file descriptor to read477 # Inputs: HoneyClient::Agent::Integrity::Registry object, file parser to read 643 478 # 644 479 # Outputs: next registry key directory name; undef if no key directory names 645 480 # are left to read 646 481 sub _nextKey { 647 my ($self, $ file) = @_;482 my ($self, $parser) = @_; 648 483 649 484 # Read the next key from the specified file. 650 $self->{_currentKeys}->{$ file} = $self->_readKey($file);485 $self->{_currentKeys}->{$parser} = $parser->nextGroup(); 651 486 652 487 # Check to make sure read was successful. 653 if (!defined($self->{_currentKeys}->{$ file})) {488 if (!defined($self->{_currentKeys}->{$parser})) { 654 489 $LOG->fatal("Error: Unable to read registry keys from '" . 655 $self->{_filenames}->{$ file} . "'.");490 $self->{_filenames}->{$parser} . "'."); 656 491 Carp::croak("Error: Unable to read registry keys from '" . 657 $self->{_filenames}->{$ file} . "'.");492 $self->{_filenames}->{$parser} . "'."); 658 493 } 659 494 660 495 # Encountered empty hash ref, thus we are at 661 496 # the end of the file. 662 if (!%{$self->{_currentKeys}->{$ file}}) {497 if (!%{$self->{_currentKeys}->{$parser}}) { 663 498 return undef; 664 499 } … … 666 501 # Key read was successful, reset the entry index 667 502 # for this file. 668 $self->{_currentEntryIndex}->{$ file} = 0;503 $self->{_currentEntryIndex}->{$parser} = 0; 669 504 670 505 # Return the corresponding key directory name. 671 return $self->{_currentKeys}->{$ file}->{'key'};506 return $self->{_currentKeys}->{$parser}->{'key'}; 672 507 } 673 508 … … 675 510 # the last key directory that was fetched by _nextKey(). 676 511 # 677 # Inputs: HoneyClient::Agent::Integrity::Registry object, file descriptor to read512 # Inputs: HoneyClient::Agent::Integrity::Registry object, file parser to read 678 513 # 679 514 # Outputs: next entry (name, value) pair; undef if no entries were found that 680 515 # correspond to the last key directory fetched by _nextKey() 681 516 sub _nextVal { 682 my ($self, $ file) = @_;517 my ($self, $parser) = @_; 683 518 684 519 # Read the last key object read from the specified file. 685 my ($k) = $self->{_currentKeys}->{$file};520 my ($k) = $self->{_currentKeys}->{$parser}; 686 521 687 522 # Get the latest entry index associated with the latest key. 688 my ($i) = $self->{_currentEntryIndex}->{$ file};523 my ($i) = $self->{_currentEntryIndex}->{$parser}; 689 524 690 525 # If the index is past our array of known entries, then return undef. … … 694 529 695 530 # There is an entry to be read, so increment the entry index. 696 $self->{_currentEntryIndex}->{$ file} = $i + 1;531 $self->{_currentEntryIndex}->{$parser} = $i + 1; 697 532 698 533 # Return the corresponding entry (name, value) pair. … … 782 617 783 618 # Perform registry baselining. 784 $self->_snapshot($self->{_baseline_ files});619 $self->_snapshot($self->{_baseline_parsers}); 785 620 786 621 # Finally, return the blessed object. … … 848 683 849 684 # Checkpoint the registry. 850 $self->_snapshot($self->{_checkpoint_ files});685 $self->_snapshot($self->{_checkpoint_parsers}); 851 686 852 687 my ($from, $to); … … 871 706 872 707 $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}; 875 710 876 711 my $dellen = 99999; … … 888 723 #$LOG->debug("FROM: ". Dumper($fromkey)); 889 724 #$LOG->debug("TO: " . Dumper($tokey)); 890 $self->_printKey($self->{_currentKeys}->{$from}); 725 print "FROM: ". Dumper($fromkey) . "\n"; 726 print "TO: ". Dumper($tokey) . "\n\n"; 727 #print Dumper($self->{_currentKeys}->{$from}) . "\n"; 891 728 892 729 # Figure out the length of the to key. honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.pm
r97 r99 69 69 70 70 # 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}))) { 73 73 print Dumper($registryGroup); 74 $registryGroup = $parser->nextGroup(); 74 75 } 75 76 … … 113 114 use IO::File; 114 115 116 # Use Seek Library. 117 use Fcntl qw(:seek); 118 115 119 ####################################################################### 116 120 # Module Initialization # … … 198 202 require_ok('IO::File'); 199 203 use IO::File; 204 205 # Make sure Fcntl loads 206 BEGIN { use_ok('Fcntl') 207 or diag("Can't load Fcntl package. Check to make sure the package library is correctly listed within the path."); } 208 require_ok('Fcntl'); 209 use Fcntl qw(:seek); 200 210 201 211 # Make sure HoneyClient::Agent::Integrity::Registry::Parser loads … … 344 354 'registry', 0, 345 355 sub 346 #line 2 18 "Parser.yp"356 #line 228 "Parser.yp" 347 357 { 348 358 $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 { }; 351 361 } 352 362 ], … … 354 364 'registry', 1, 355 365 sub 356 #line 2 23 "Parser.yp"366 #line 233 "Parser.yp" 357 367 { 358 368 $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 { }; 361 371 } 362 372 ], … … 364 374 'registry', 2, 365 375 sub 366 #line 2 28 "Parser.yp"376 #line 238 "Parser.yp" 367 377 { 368 378 $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 { }; 371 381 } 372 382 ], … … 386 396 'group', 2, 387 397 sub 388 #line 2 45 "Parser.yp"398 #line 255 "Parser.yp" 389 399 { 390 400 my $ret = { }; … … 405 415 'group', 1, 406 416 sub 407 #line 2 59 "Parser.yp"417 #line 269 "Parser.yp" 408 418 { 409 419 my $ret = { }; … … 430 440 'entry', 2, 431 441 sub 432 #line 2 83 "Parser.yp"442 #line 293 "Parser.yp" 433 443 { 434 444 my $entry = { … … 445 455 } 446 456 447 #line 293 "Parser.yp"457 #line 303 "Parser.yp" 448 458 449 459 … … 541 551 } 542 552 553 # Helper function, designed to index all groups, based upon beginning file 554 # offsets. 555 # 556 # Inputs: parser 557 # Outputs: None 558 sub _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 543 610 ####################################################################### 544 611 # Public Methods Implemented # … … 551 618 The following functions have been implemented by any Parser object. 552 619 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) 554 621 555 622 =over 4 … … 560 627 I<Inputs>: 561 628 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 630 ahead and scan the entire file, indexing the file offsets of where groups start and 631 end. Otherwise, this indexing process is not performed. 562 632 563 633 I<Output>: The instantiated Parser B<$object>, fully initialized. … … 605 675 Carp::croak("Error: Unable to read file '" . $args{'input_file'} . "'!\n"); 606 676 } 677 678 # Save the file handle. 679 $parser->YYData->{'file_handle'} = $fh; 680 607 681 undef $/; 608 682 $parser->YYData->{DATA} = <$fh>; … … 625 699 $parser->YYData->{'input_pos'} = 0; 626 700 701 # Array to record where group boundaries occur. 702 $parser->YYData->{'group_index'} = [0, ]; 703 627 704 # Initialize statistics. 628 705 # Total number of directories parsed. … … 631 708 # Total number of key/value pairs parsed. 632 709 $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 } 633 718 634 719 # Return parser object. … … 659 744 660 745 I<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. 746 returns an empty hash ref, if the Parser B<$object> has reached the end of 747 the input stream. 662 748 663 749 =back … … 670 756 671 757 # Create a generic Parser object, with test state data. 672 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file );758 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file, index_groups => 1); 673 759 674 760 # Verify Test Group #1 … … 804 890 # Verify Test Group #9 805 891 $nextGroup = $parser->nextGroup(); 806 is_deeply($nextGroup, undef, "nextGroup() - 9") or diag("The nextGroup() call failed.");892 is_deeply($nextGroup, { }, "nextGroup() - 9") or diag("The nextGroup() call failed."); 807 893 808 894 =end testing … … 852 938 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 853 939 854 while(defined($nextGroup = $parser->nextGroup)) { 940 $nextGroup = $parser->nextGroup(); 941 while(scalar(keys(%{$nextGroup}))) { 942 $nextGroup = $parser->nextGroup(); 855 943 } 856 944 … … 897 985 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 898 986 899 while(defined($nextGroup = $parser->nextGroup)) { 987 $nextGroup = $parser->nextGroup(); 988 while(scalar(keys(%{$nextGroup}))) { 989 $nextGroup = $parser->nextGroup(); 900 990 } 901 991 … … 919 1009 } 920 1010 1011 =pod 1012 1013 =head2 $object->getFileHandle() 1014 1015 =over 4 1016 1017 Returns the file handle associated with the current Parser B<$object>. 1018 1019 I<Output>: Returns the file handle in use. 1020 1021 =back 1022 1023 =begin testing 1024 1025 my ($handle); 1026 my $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. 1030 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 1031 1032 $handle = $parser->getFileHandle(); 1033 1034 isa_ok($handle, 'IO::File', "getFileHandle()") or diag("The getFileHandle() call failed."); 1035 1036 =end testing 1037 1038 =cut 1039 1040 sub 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 921 1053 ####################################################################### 922 1054 # Additional Module Documentation # honeyclient/branches/bug/42/lib/HoneyClient/Agent/Integrity/Registry/Parser.yp
r97 r99 52 52 53 53 # 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}))) { 56 56 print Dumper($registryGroup); 57 $registryGroup = $parser->nextGroup(); 57 58 } 58 59 … … 96 97 use IO::File; 97 98 99 # Use Seek Library. 100 use Fcntl qw(:seek); 101 98 102 ####################################################################### 99 103 # Module Initialization # … … 182 186 use IO::File; 183 187 188 # Make sure Fcntl loads 189 BEGIN { use_ok('Fcntl') 190 or diag("Can't load Fcntl package. Check to make sure the package library is correctly listed within the path."); } 191 require_ok('Fcntl'); 192 use Fcntl qw(:seek); 193 184 194 # Make sure HoneyClient::Agent::Integrity::Registry::Parser loads 185 195 BEGIN { use_ok('HoneyClient::Agent::Integrity::Registry::Parser') … … 218 228 { 219 229 $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 { }; 222 232 } 223 233 | groups { 224 234 $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 { }; 227 237 } 228 238 | HEADER groups { 229 239 $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 { }; 232 242 } 233 243 ; … … 386 396 } 387 397 398 # Helper function, designed to index all groups, based upon beginning file 399 # offsets. 400 # 401 # Inputs: parser 402 # Outputs: None 403 sub _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 388 455 ####################################################################### 389 456 # Public Methods Implemented # … … 396 463 The following functions have been implemented by any Parser object. 397 464 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) 399 466 400 467 =over 4 … … 405 472 I<Inputs>: 406 473 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 475 ahead and scan the entire file, indexing the file offsets of where groups start and 476 end. Otherwise, this indexing process is not performed. 407 477 408 478 I<Output>: The instantiated Parser B<$object>, fully initialized. … … 450 520 Carp::croak("Error: Unable to read file '" . $args{'input_file'} . "'!\n"); 451 521 } 522 523 # Save the file handle. 524 $parser->YYData->{'file_handle'} = $fh; 525 452 526 undef $/; 453 527 $parser->YYData->{DATA} = <$fh>; … … 470 544 $parser->YYData->{'input_pos'} = 0; 471 545 546 # Array to record where group boundaries occur. 547 $parser->YYData->{'group_index'} = [0, ]; 548 472 549 # Initialize statistics. 473 550 # Total number of directories parsed. … … 476 553 # Total number of key/value pairs parsed. 477 554 $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 } 478 563 479 564 # Return parser object. … … 504 589 505 590 I<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. 591 returns an empty hash ref, if the Parser B<$object> has reached the end of 592 the input stream. 507 593 508 594 =back … … 515 601 516 602 # Create a generic Parser object, with test state data. 517 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file );603 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file, index_groups => 1); 518 604 519 605 # Verify Test Group #1 … … 649 735 # Verify Test Group #9 650 736 $nextGroup = $parser->nextGroup(); 651 is_deeply($nextGroup, undef, "nextGroup() - 9") or diag("The nextGroup() call failed.");737 is_deeply($nextGroup, { }, "nextGroup() - 9") or diag("The nextGroup() call failed."); 652 738 653 739 =end testing … … 697 783 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 698 784 699 while(defined($nextGroup = $parser->nextGroup)) { 785 $nextGroup = $parser->nextGroup(); 786 while(scalar(keys(%{$nextGroup}))) { 787 $nextGroup = $parser->nextGroup(); 700 788 } 701 789 … … 742 830 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 743 831 744 while(defined($nextGroup = $parser->nextGroup)) { 832 $nextGroup = $parser->nextGroup(); 833 while(scalar(keys(%{$nextGroup}))) { 834 $nextGroup = $parser->nextGroup(); 745 835 } 746 836 … … 764 854 } 765 855 856 =pod 857 858 =head2 $object->getFileHandle() 859 860 =over 4 861 862 Returns the file handle associated with the current Parser B<$object>. 863 864 I<Output>: Returns the file handle in use. 865 866 =back 867 868 =begin testing 869 870 my ($handle); 871 my $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. 875 my $parser = HoneyClient::Agent::Integrity::Registry::Parser->init(input_file => $test_registry_file); 876 877 $handle = $parser->getFileHandle(); 878 879 isa_ok($handle, 'IO::File', "getFileHandle()") or diag("The getFileHandle() call failed."); 880 881 =end testing 882 883 =cut 884 885 sub 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 766 898 ####################################################################### 767 899 # Additional Module Documentation # honeyclient/branches/bug/42/t/honeyclient_agent_integrity_registry.t
r96 r99 87 87 require_ok('Filesys::CygwinPaths'); 88 88 use Filesys::CygwinPaths qw(:all); 89 90 # Make sure HoneyClient::Agent::Integrity::Registry::Parser loads 91 BEGIN { 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."); } 93 require_ok('HoneyClient::Agent::Integrity::Registry::Parser'); 94 use HoneyClient::Agent::Integrity::Registry::Parser; 89 95 } 90 96 honeyclient/branches/bug/42/t/honeyclient_agent_integrity_registry_parser.t
r96 r99 55 55 use IO::File; 56 56 57 # Make sure Fcntl loads 58 BEGIN { use_ok('Fcntl') 59 or diag("Can't load Fcntl package. Check to make sure the package library is correctly listed within the path."); } 60 require_ok('Fcntl'); 61 use Fcntl qw(:seek); 62 57 63 # Make sure HoneyClient::Agen
