root/honeyclient/branches/rel/1.0/lib/HoneyClient/Manager.pm

Revision 994, 29.3 kB (checked in by kindlund, 1 year ago)

Bumped version to v1.00.

  • Property svn:keywords set to Id "$file"
Line 
1 #######################################################################
2 # Created on:  May 11, 2006
3 # Package:     HoneyClient::Manager
4 # File:        Manager.pm
5 # Description: Central library used for manager-based operations.
6 #
7 # CVS: $Id$
8 #
9 # @author knwang, ttruong, jdurick, kindlund
10 #
11 # Copyright (C) 2007 The MITRE Corporation.  All rights reserved.
12 #
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation, using version 2
16 # of the License.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 # GNU General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301, USA.
27 #
28 #######################################################################
29
30 =pod
31
32 =head1 NAME
33
34 # XXX: Fill this in.
35
36 =head1 VERSION
37
38 This documentation refers to HoneyClient::Manager version 1.00.
39
40 =head1 SYNOPSIS
41
42 =head2 CREATING THE SOAP SERVER
43
44 # XXX: Fill this in.
45
46 =head2 INTERACTING WITH THE SOAP SERVER
47
48 # XXX: Fill this in.
49
50 =head1 DESCRIPTION
51
52 # XXX: Fill this in.
53
54 =cut
55
56 package HoneyClient::Manager;
57
58 # XXX: Disabled version check, Honeywall does not have Perl v5.8 installed.
59 #use 5.008006;
60 use strict;
61 use warnings FATAL => 'all';
62 use Config;
63 use Carp ();
64
65 #######################################################################
66 # Module Initialization                                               #
67 #######################################################################
68
69 BEGIN {
70     # Defines which functions can be called externally.
71     require Exporter;
72     our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION, @DRIVERS);
73
74     # Set our package version.
75     $VERSION = 1.00;
76
77     @ISA = qw(Exporter);
78
79     # Symbols to export automatically
80     @EXPORT = qw(init destroy);
81
82     # Items to export into callers namespace by default. Note: do not export
83     # names by default without a very good reason. Use EXPORT_OK instead.
84     # Do not simply export all your public functions/methods/constants.
85
86     # This allows declaration use HoneyClient::Manager ':all';
87     # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
88     # will save memory.
89
90     %EXPORT_TAGS = (
91         'all' => [ qw(init destroy) ],
92     );
93
94     # Symbols to autoexport (when qw(:all) tag is used)
95     @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
96
97     # Check to see if ithreads are compiled into this version of Perl.
98     $Config{useithreads} or Carp::croak "Error: Recompile Perl with ithread support, in order to use this module.\n";
99
100     $SIG{PIPE} = 'IGNORE'; # Do not exit on broken pipes.
101 }
102 our (@EXPORT_OK, $VERSION);
103
104 =pod
105
106 =begin testing
107
108 # Make sure the module loads properly, with the exportable
109 # functions shared.
110 BEGIN { use_ok('HoneyClient::Manager', qw(init destroy)) or diag("Can't load HoneyClient::Manager package.  Check to make sure the package library is correctly listed within the path."); }
111 require_ok('HoneyClient::Manager');
112 can_ok('HoneyClient::Manager', 'init');
113 can_ok('HoneyClient::Manager', 'destroy');
114 use HoneyClient::Manager qw(init destroy);
115
116 # Make sure HoneyClient::Util::SOAP loads.
117 BEGIN { use_ok('HoneyClient::Util::SOAP', qw(getServerHandle getClientHandle)) or diag("Can't load HoneyClient::Util::SOAP package.  Check to make sure the package library is correctly listed within the path."); }
118 require_ok('HoneyClient::Util::SOAP');
119 can_ok('HoneyClient::Util::SOAP', 'getServerHandle');
120 can_ok('HoneyClient::Util::SOAP', 'getClientHandle');
121 use HoneyClient::Util::SOAP qw(getServerHandle getClientHandle);
122
123 # Make sure HoneyClient::Util::Config loads.
124 BEGIN { use_ok('HoneyClient::Util::Config', qw(getVar)) or diag("Can't load HoneyClient::Util::Config package.  Check to make sure the package library is correctly listed within the path."); }
125 require_ok('HoneyClient::Util::Config');
126 can_ok('HoneyClient::Util::Config', 'getVar');
127 use HoneyClient::Util::Config qw(getVar);
128
129 # Make sure Storable loads.
130 BEGIN { use_ok('Storable', qw(nfreeze thaw)) or diag("Can't load Storable package.  Check to make sure the package library is correctly listed within the path."); }
131 require_ok('Storable');
132 can_ok('Storable', 'nfreeze');
133 can_ok('Storable', 'thaw');
134 use Storable qw(nfreeze thaw);
135
136 # Make sure MIME::Base64 loads.
137 BEGIN { use_ok('MIME::Base64', qw(encode_base64 decode_base64)) or diag("Can't load MIME::Base64 package.  Check to make sure the package library is correctly listed within the path."); }
138 require_ok('MIME::Base64');
139 can_ok('MIME::Base64', 'encode_base64');
140 can_ok('MIME::Base64', 'decode_base64');
141 use MIME::Base64 qw(encode_base64 decode_base64);
142
143 =end testing
144
145 =cut
146
147 #######################################################################
148
149 # Include the SOAP Utility Library
150 use HoneyClient::Util::SOAP qw(getClientHandle getServerHandle);
151
152 # Include Thread Libraries
153 use threads;
154 use threads::shared;
155 use Thread::Semaphore;
156 use Thread::Queue;
157
158 # Include utility access to global configuration.
159 use HoneyClient::Util::Config qw(getVar);
160
161 # Include the VM Utility Library
162 # TODO: Include unit tests.
163 use HoneyClient::Manager::VM qw();
164
165 # Check if DB support is enabled.
166 our $DB_ENABLE = getVar(name      => "enable",
167                         namespace => "HoneyClient::DB");
168
169 if ($DB_ENABLE) {
170     # Include DB Utility Library
171     # TODO: Include unit tests.
172     require HoneyClient::DB::Fingerprint;
173     require HoneyClient::DB::Client;
174     require HoneyClient::DB::Url::History;
175     require HoneyClient::DB::Time;
176 }
177
178 # XXX: Remove this, eventually.
179 use Data::Dumper;
180
181 # Make Dumper format more verbose.
182 $Data::Dumper::Terse = 0;
183 $Data::Dumper::Indent = 2;
184
185 # Include Hash Serialization Utility Libraries
186 use Storable qw(nfreeze thaw);
187
188 # Include Base64 Libraries
189 use MIME::Base64 qw(encode_base64 decode_base64);
190
191 # Include FW Utility Library
192 # TODO: Include unit tests.
193 #use HoneyClient::Manager::FW;
194
195 # Include Hash Serialization Utility Libraries
196 # TODO: Include unit tests.
197 use Storable qw(nfreeze thaw);
198
199 # Include VmPerl Constants.
200 # TODO: Include unit tests.
201 use VMware::VmPerl qw(VM_EXECUTION_STATE_ON
202                       VM_EXECUTION_STATE_OFF
203                       VM_EXECUTION_STATE_STUCK
204                       VM_EXECUTION_STATE_SUSPENDED);
205
206 # TODO: Include unit tests.
207 use IO::File;
208
209 # TODO: Include unit tests.
210 use DateTime::HiRes;
211
212 # TODO: Include unit tests.
213 use Sys::Hostname::Long;
214
215 # TODO: Include unit tests.
216 use Sys::HostIP;
217
218 # TODO: Include unit tests.
219 # Include Logging Library
220 use Log::Log4perl qw(:easy);
221
222 # The global logging object.
223 our $LOG = get_logger();
224
225 # Complete URL of SOAP server, when initialized.
226 our $URL_BASE       : shared = undef;
227 our $URL            : shared = undef;
228
229 # The process ID of the SOAP server daemon, once created.
230 our $DAEMON_PID     : shared = undef;
231
232 # XXX: These will be migrated somewhere else, eventually.
233 our $vmStateTable = { };
234 our $vmCloneConfig      = undef;
235 our $stubVM             = undef;
236 our $stubAgent          = undef;
237 our $stubFW             = undef;
238
239 # This is a temporary, shared variable, used to print out the
240 # state of the agent, when _cleanup() occurs.
241 # XXX: This variable and all reference to it will be deleted,
242 # eventually.
243 our $globalAgentState   = undef;
244
245 # This static variable may contain a filename that the Manager
246 # would use to dump its entire state information, upon termination.
247 # XXX: May want to change this format/usage, eventually.
248 our $STATE_FILE = getVar(name => "manager_state");
249
250 # Temporary variable, used to indicate to the fault handler whether
251 # or not errors/warnings should be suppressed.
252 our $SUPPRESS_ERRORS = 0;
253
254 #######################################################################
255 # Daemon Initialization / Destruction                                 #
256 #######################################################################
257
258 =pod
259
260 =head1 EXPORTED FUNCTIONS
261
262 The following init() and destroy() functions are the only direct
263 calls required to startup and shutdown the SOAP server.
264
265 All other interactions with this daemon should be performed as
266 C<SOAP::Lite> function calls, in order to ensure consistency across
267 client sessions.  See the L<"EXTERNAL SOAP FUNCTIONS"> section, for
268 more details.
269
270 =head2 HoneyClient::Manager->init()
271
272 =over 4
273
274 Starts a new SOAP server, within a child process.
275
276 I<Inputs>:
277
278 # XXX: Finish this.
279
280 I<Output>:
281
282 # XXX: Finish this.
283
284 =back
285
286 =begin testing
287
288 # XXX: Test init() method.
289
290 =end testing
291
292 =cut
293
294 sub init {
295     # Extract arguments.
296     # Hash-based arguments are used, since HoneyClient::Util::SOAP is unable to handle
297     # hash references directly.  Thus, flat hashtables are used throughout the code
298     # for consistency.
299     my ($class, %args) = @_;
300    
301     # XXX: Finish this.
302 }
303
304 =pod
305
306 =head2 HoneyClient::Manager->destroy()
307
308 =over 4
309
310 Terminates the SOAP server within the child process.
311
312 I<Output>: True if successful, false otherwise.
313
314 =back
315
316 =begin testing
317
318 # XXX: Test destroy() method.
319
320 # TODO: delete this.
321 #exit;
322
323 =end testing
324
325 =cut
326
327 sub destroy {
328     my $ret = undef;
329    
330     # XXX: Finish this.
331     
332     return $ret;
333 }
334
335 #######################################################################
336 # Private Methods Implemented                                         #
337 #######################################################################
338
339 sub _handleFault {
340
341     # Extract arguments.
342     my ($class, $res) = @_;
343
344     # Construct error message.
345     # Figure out if the error occurred in transport or over
346     # on the other side.
347     my $errMsg = $class->transport->status; # Assume transport error.
348
349     if (ref $res) {
350         $errMsg = $res->faultcode . ": ".  $res->faultstring . "\n";
351     }
352
353     if (!$SUPPRESS_ERRORS) {
354         $LOG->warn("Error occurred during processing. " . $errMsg);
355         Carp::carp __PACKAGE__ . "->_handleFault(): Error occurred during processing.\n" . $errMsg;
356     }
357 }
358
359 sub _handleFaultAndCleanup {
360
361     # Extract arguments.
362     my ($class, $res) = @_;
363
364     # Print fault.
365     _handleFault($class, $res);
366    
367     # Cleanup before dying.
368     _cleanup();
369 }
370
371 sub _cleanup {
372
373     $LOG->info("Cleaning up.");
374
375     # Mask all possible signals, so that we don't call this function multiple times.
376     $SIG{HUP}     = sub { };
377     $SIG{INT}     = sub { };
378     $SIG{QUIT}    = sub { };
379     $SIG{ABRT}    = sub { };
380     $SIG{PIPE}    = sub { };
381     $SIG{TERM}    = sub { };
382
383     HoneyClient::Manager::VM->destroy();
384
385     # XXX: Need to clean this up.
386     my $stubFW = getClientHandle(namespace     => "HoneyClient::Manager::FW");
387
388     # XXX: Change this to fwInit(), eventually.
389     # Reset the firewall, to allow everything open.
390     $stubFW->testConnect();
391
392     # Check to see if a clone was created...
393     if (defined($vmCloneConfig)) {
394         # We sleep for a bit, to make sure that the previous VM daemon was
395         # properly destroyed and released the previous port that was in use.
396         sleep (10);
397
398         # We reinstantiate a new VM daemon, because if the user had hit CTRL-C
399         # or called any other signal, then that signal would propagate to all
400         # processes, causing the VM daemon's signal handler to self terminate.
401         #
402         # Hence, rather than fight the VM daemon's natural self termination,
403         # we let the daemon die, but the create a new one, for the sole purpose
404         # of cleanup up the clones.
405         HoneyClient::Manager::VM->init();
406         $LOG->info("Calling suspendVM(config => " . $vmCloneConfig . ").");
407         my $stubVM = getClientHandle(namespace => "HoneyClient::Manager::VM");
408         $stubVM->suspendVM(config => $vmCloneConfig);
409         print "Done!\n";
410         HoneyClient::Manager::VM->destroy();
411     }
412
413     # XXX: May want to change this format/usage, eventually.
414     if (length($STATE_FILE) > 0 &&
415         defined($globalAgentState)) {
416         $LOG->info("Saving state to '" . $STATE_FILE . "'.");
417         my $dump_file = new IO::File($STATE_FILE, "a");
418
419         # XXX: Delete this block, eventually.
420         $Data::Dumper::Terse = 0;
421         $Data::Dumper::Indent = 2;
422         print $dump_file Dumper(thaw(decode_base64($globalAgentState)));
423     }
424
425     exit;
426 }
427
428 # XXX: Install the cleanup handler, in case the parent process dies
429 # unexpectedly.
430 $SIG{HUP} = sub { _cleanup(); };
431 $SIG{INT}  = sub { _cleanup(); };
432 $SIG{QUIT} = sub { _cleanup(); };
433 $SIG{ABRT} = sub { _cleanup(); };
434 $SIG{PIPE} = sub { _cleanup(); };
435 $SIG{TERM} = sub { _cleanup(); };
436
437 #######################################################################
438 # Public Methods Implemented                                          #
439 #######################################################################
440
441 =pod
442
443 =head1 EXPORTS
444
445 =head2 run()
446
447 =over 4
448
449 # XXX: Fill this in.
450
451 I<Inputs>:
452  B<$arg> is an optional argument.
453
454 driver
455 master_vm_config
456 start_state
457  
458 I<Output>: XXX: Fill this in.
459
460 =back
461
462 =begin testing
463
464 # XXX: Fill this in.
465
466 =end testing
467
468 =cut
469
470 sub run {
471     # Extract arguments.
472     # Hash-based arguments are used, since HoneyClient::Util::SOAP is unable to handle
473     # hash references directly.  Thus, flat hashtables are used throughout the code
474     # for consistency.
475     my ($class, %args) = @_;
476     my $agentState = undef;
477
478     # Sanity check, make sure the master_vm_config has
479     # been specified.
480     my $argsExist = scalar(%args);
481     if (!$argsExist ||
482         !exists($args{'master_vm_config'}) ||
483         !defined($args{'master_vm_config'})) {
484         # Get the master_vm_config from the configuration file.
485         $args{'master_vm_config'} = getVar(name      => "master_vm_config",
486                                            namespace => "HoneyClient::Manager::VM");
487     }
488
489     for (;;) {
490         print "Starting new session...\n";
491         $agentState = $class->runSession(%args);
492         $args{'agent_state'} = $agentState;
493
494         # XXX: Delete this, eventually.
495         $globalAgentState = $agentState;
496
497         #$Data::Dumper::Terse = 0;
498         #$Data::Dumper::Indent = 2;
499         #print Dumper(thaw(decode_base64($agentState)));
500     }
501 }
502
503 sub runSession {
504
505     # Extract arguments.
506     # Hash-based arguments are used, since HoneyClient::Util::SOAP is unable to handle
507     # hash references directly.  Thus, flat hashtables are used throughout the code
508     # for consistency.
509     my ($class, %args) = @_;
510
511     my $som       = undef;
512     my $ret       = undef;
513     my $vmIP      = undef;
514     my $vmMAC     = undef;
515     my $vmName    = undef;
516     my $URL       = undef;
517     my $vmState   = undef;
518     my $vmCompromised = 0;
519     my $clientDbId = 0;
520
521     # Get a stub connection to the firewall.
522     $stubFW = getClientHandle(namespace     => "HoneyClient::Manager::FW",
523                               fault_handler => \&_handleFaultAndCleanup);
524
525     # Open up the firewall initially, to allow the Agent to do an SVN update.
526     $stubFW->testConnect();
527
528     $URL = HoneyClient::Manager::VM->init();
529     print "VM Daemon Listening On: " . $URL . "\n";
530    
531     $stubVM = getClientHandle(namespace     => "HoneyClient::Manager::VM",
532                               fault_handler => \&_handleFaultAndCleanup);
533    
534     print "Calling setMasterVM()...\n";
535     $som = $stubVM->setMasterVM(config => $args{'master_vm_config'});
536     print "Result: " . $som->result() . "\n";
537
538     print "Calling quickCloneVM()...\n";
539     $som = $stubVM->quickCloneVM();
540     print "Result: " . $som->result() . "\n";
541     $vmCloneConfig = $som->result();
542
543     # Make sure the VM is fully cloned, before trying to make any subsequent calls.
544     print "Calling isRegisteredVM()...\n";
545     $som = $stubVM->isRegisteredVM(config => $vmCloneConfig);
546     $ret = $som->result();
547
548     if (defined($ret)) {
549         print "Result: " . $ret . "\n";
550     }
551
552     while (!defined($ret)) {
553         sleep (3);
554         print "Calling isRegisteredVM()...\n";
555         $som = $stubVM->isRegisteredVM(config => $vmCloneConfig);
556         $ret = $som->result();
557         if (defined($ret)) {
558             print "Result: " . $ret . "\n";
559         }
560     }
561
562     print "Calling getStateVM()...\n";
563     $som = $stubVM->getStateVM(config => $vmCloneConfig);
564     $vmState = $som->result();
565
566     if ($vmState == VM_EXECUTION_STATE_ON) {
567         print "ON\n";
568     } elsif ($vmState == VM_EXECUTION_STATE_OFF) {
569         print "OFF\n";
570     } elsif ($vmState == VM_EXECUTION_STATE_SUSPENDED) {
571         print "SUSPENDED\n";
572     } elsif ($vmState == VM_EXECUTION_STATE_STUCK) {
573         print "STUCK\n";
574     } else {
575         print "UNKNOWN\n";
576     }
577
578     while ($vmState != VM_EXECUTION_STATE_ON) {
579         sleep (3);
580
581         print "Calling getStateVM()...\n";
582         $som = $stubVM->getStateVM(config => $vmCloneConfig);
583         $vmState = $som->result();
584
585         if ($vmState == VM_EXECUTION_STATE_ON) {
586             print "ON\n";
587         } elsif ($vmState == VM_EXECUTION_STATE_OFF) {
588             print "OFF\n";
589         } elsif ($vmState == VM_EXECUTION_STATE_SUSPENDED) {
590             print "SUSPENDED\n";
591         } elsif ($vmState == VM_EXECUTION_STATE_STUCK) {
592             print "STUCK\n";
593         } else {
594             print "UNKNOWN\n";
595         }
596     }
597
598     print "Calling getMACaddrVM()...\n";
599     $som = $stubVM->getMACaddrVM(config => $vmCloneConfig);
600     print "Result: " . $som->result() . "\n";
601     $vmMAC = $som->result();
602
603     # Figure out when the Agent on the VM is alive and well.
604     $ret = undef;
605     my $logMsgPrinted = 0;
606     while (!$ret) {
607         sleep (3);
608         print "Calling getIPaddrVM()...\n";
609         $som = $stubVM->getIPaddrVM(config => $vmCloneConfig);
610         if (defined($som->result())) {
611             print "Result: " . $som->result() . "\n";
612         }
613         $vmIP = $som->result();
614
615         print "Calling getNameVM()...\n";
616         $som = $stubVM->getNameVM(config => $vmCloneConfig);
617         print "Result: " . $som->result() . "\n";
618         $vmName = $som->result();
619
620         if (defined($vmIP) && defined($vmName)) {
621             if (!$logMsgPrinted) {
622                 $LOG->info("Created clone VM (" . $vmName . ") using IP (" . $vmIP . ") and MAC (" . $vmMAC . ").");
623                 $logMsgPrinted = 1;
624             }
625
626             # Try contacting the Agent; ignore any faults.
627             $SUPPRESS_ERRORS = 1;
628             $stubAgent = getClientHandle(namespace     => "HoneyClient::Agent",
629                                          address       => $vmIP,
630                                          fault_handler => \&_handleFault);
631
632             eval {
633                 print "Calling getStatus()...\n";
634                 $som = $stubAgent->getStatus();
635                 $ret = thaw(decode_base64($som->result()));
636                 print "Result:\n";
637                 # Make Dumper format more verbose.
638                 $Data::Dumper::Terse = 0;
639                 $Data::Dumper::Indent = 2;
640                 print Dumper($ret);
641
642             };
643             # Clear returned state, if any fault occurs.
644             if ($@) {
645                 $ret = undef;
646             }
647             $SUPPRESS_ERRORS = 0;
648         }
649     }
650
651     #Register Client with the Honeyclient Database
652     if ($DB_ENABLE) {
653         eval {
654             $clientDbId = dbRegisterClient($vmName);
655         };
656         if ($@) {
657             $clientDbId = 0; #$DB_FAILURE
658             $LOG->warn("Failure Inserting Client Object:\n$@");
659         }
660     }
661
662     # Build our VM's connection table.
663     # Note: We assume our VM has a single MAC address
664     # and a single IP address.
665     $vmStateTable->{$vmName}->{sources}->{$vmMAC}->{$vmIP} = {
666         # XXX: We assume we can't pinpoint what source TCP ports the
667         # corresponding driver will need.  (We may want to get this
668         # information eventually from the Agent, as part of Driver::next().)
669         'tcp' => undef,
670     };
671
672     print "VM State Table:\n";
673     # Make Dumper format more verbose.
674     $Data::Dumper::Terse = 0;
675     $Data::Dumper::Indent = 2;
676     print Dumper($vmStateTable) . "\n";
677  
678     # Initialize the firewall.
679     $stubFW->fwInit();
680
681     # Add new chain, per cloned VM.
682     $stubFW->addChain($vmStateTable);
683    
684     sleep (2);
685
686     # Recreate the client stub; handle faults.
687     $stubAgent = getClientHandle(namespace     => "HoneyClient::Agent",
688                                  address       => $vmIP,
689                                  fault_handler => \&_handleFaultAndCleanup);
690
691     # Call updateState() first, to seed initial data.
692     # TODO: Need to support asynchronous updates (url adding)
693     # from user input.
694     print "Calling updateState()...\n";
695     $som = $stubAgent->updateState($args{'agent_state'});
696
697     # Recreate the client stub; ignore faults.
698     $stubAgent = getClientHandle(namespace     => "HoneyClient::Agent",
699                                  address       => $vmIP,
700                                  fault_handler => \&_handleFault);
701
702     # Recreate the firewall stub; ignore faults.
703     $stubFW = getClientHandle(namespace     => "HoneyClient::Manager::FW",
704                               fault_handler => \&_handleFault);
705
706     for (my $counter = 1;; $counter++) {
707
708         # From this point on, catch all errors generated and
709         # assume that the Agent's watchdog process will recover.
710         eval {
711             print "Calling getState()...\n";
712             $som = $stubAgent->getState();
713             $args{'agent_state'} = $som->result();
714
715             # XXX: Delete this, eventually.
716             $globalAgentState = $args{'agent_state'};
717
718             print "Calling getStatus()...\n";
719             $som = $stubAgent->getStatus();
720             print "Result:\n";
721             $ret = thaw(decode_base64($som->result()));
722             # Make Dumper format more verbose.
723             $Data::Dumper::Terse = 0;
724             $Data::Dumper::Indent = 2;
725             print Dumper($ret->{$args{'driver'}}->{status});
726             #print Dumper($ret);
727
728             # Check to see if Agent::run() thread has stopped
729             # and that a compromise was detected.
730             if (!$ret->{$args{'driver'}}->{status}->{is_running}) {
731                 if ($ret->{$args{'driver'}}->{status}->{is_compromised}) {
732                     # Check to see if the VM has been compromised.
733                     print "WARNING: VM HAS BEEN COMPROMISED!\n";
734                     $LOG->info("Calling suspendVM(config => " . $vmCloneConfig . ").");
735                     $som = $stubVM->suspendVM(config => $vmCloneConfig);
736                     HoneyClient::Manager::VM->destroy();
737                     $vmCompromised = 1;
738
739                     # Insert Compromised Fingerprint into DB.
740                     my $fingerprint = $ret->{$args{'driver'}}->{status}->{fingerprint};
741                     $LOG->warn("VM Compromised.  Last Resource (" . $fingerprint->{'last_resource'} . ")");
742                     if ($DB_ENABLE && ($clientDbId > 0)) {
743                         # Remove the last_url from the fingerprint and insert it as Url History
744                         # XXX: Will be removed when all of clients Url History is stored.
745                         my $dt = DateTime::HiRes->now();
746                         my $last_url = HoneyClient::DB::Url::History->new({
747                             url=>delete($fingerprint->{'last_resource'}),
748                             visited => $dt->ymd('-').'T'.$dt->hms(':').".".$dt->nanosecond(),
749                             status => $HoneyClient::DB::Url::History::STATUS_VISITED,
750                         });
751                         my $urlId = $last_url->insert();
752                         $LOG->info("Database Insert last url successful");
753                         # Update the History item to reflect the Client it belongs to.
754                         HoneyClient::DB::Url::History->update(
755                             -set => {
756                                 Client_url_history_fk => $clientDbId,
757                             },
758                             -where => {
759                                 id => $urlId,
760                             },
761                         );
762                         $LOG->info("Database Update Client fk in last url");
763                         # Remove the compromise time from the fingerprint. This is to be added to the Client Object
764                         my $compromise_time = HoneyClient::DB::Time->new(delete($fingerprint->{'compromise_time'}));
765                         $LOG->info("Inserting Fingerprint Into Database.");
766                         my $fp = HoneyClient::DB::Fingerprint->new($fingerprint);
767                         my $fpId = $fp->insert();
768                         my $ctId = $compromise_time->insert();
769                         HoneyClient::DB::Client->update(
770                             '-set' => {
771                                 status => $HoneyClient::DB::Client::STATUS_COMPROMISED,
772                                 fingerprint => $fpId,
773                                 compromise_time => $ctId,
774                             },
775                             '-where' => {
776                                 id => $clientDbId,
777                             }
778                         );
779                         $LOG->info("Database Insert Successful.");
780                     }
781                     return; # Return out of eval block.
782                 } else {
783                     print "VM Integrity Check: OK!\n";
784
785                     # Check to see if any links remain to be processed by the
786                     # Agent.
787                     if (!$ret->{$args{'driver'}}->{status}->{links_remaining}) {
788
789                         $LOG->info("All URLs exhausted.  Shutting down Manager.");
790                         # Get a local copy of the configuration and kill the global copy.
791                         my $vmCfg = $vmCloneConfig;
792                         $vmCloneConfig = undef;
793                         $LOG->info("Calling suspendVM(config => " . $vmCfg . ").");
794                         $stubVM->suspendVM(config => $vmCfg);
795                         print "Done!\n";
796                         _cleanup();
797
798                     } else {
799                         # The Agent::run() thread has stopped; we assume
800                         # it's because the Agent is waiting for the firewall
801                         # to allow access to the new targets.
802                 
803                         # Delete the old firewall rules, based upon existing
804                         # targets.
805                         $stubFW->deleteRules($vmStateTable);
806
807                         # Get the new targets from the Agent.
808                         $vmStateTable->{$vmName}->{targets} = $ret->{$args{'driver'}}->{next}->{targets};
809
810                         print "VM State Table:\n";
811                         # Make Dumper format more verbose.
812                         $Data::Dumper::Terse = 0;
813                         $Data::Dumper::Indent = 2;
814                         print Dumper($vmStateTable) . "\n";
815
816                         # Add the new targets from the Agent.
817                         $stubFW->addRules($vmStateTable);
818
819                         print "Calling run()...\n";
820                         $som = $stubAgent->run(driver_name => $args{'driver'});
821                     }
822                 }
823             }
824         };
825         if ($@) {
826             print "Error: $@\n";
827             my $resetSuccessful = 0;
828             while (!$resetSuccessful) {
829                 print "Resetting firewall...\n";
830                 eval {
831                     # We assume the error was caused by some sort of communications
832