root/honeyclient/tags/exp/UP1-stephenson-link_scoring/lib/HoneyClient/Agent.pm

Revision 136, 38.2 kB (checked in by kindlund, 2 years ago)

Perl doesn't like MAJOR.MINOR.MACRO versioning, but rather MAJOR.MINORMACRO versioning. Updated all code to reflect this change.

  • Property svn:keywords set to Id "$file"
Line 
1 #######################################################################
2 # Created on:  May 11, 2006
3 # Package:     HoneyClient::Agent
4 # File:        Agent.pm
5 # Description: Central library used for agent-based operations.
6 #
7 # CVS: $Id$
8 #
9 # @author knwang, ttruong, kindlund
10 #
11 # Copyright (C) 2006 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 HoneyClient::Agent - Perl extension to instantiate a SOAP server
35 that provides a central interface for all agent-based HoneyClient
36 operations.
37
38 =head1 VERSION
39
40 0.92
41
42 =head1 SYNOPSIS
43
44 =head2 CREATING THE SOAP SERVER
45
46 # XXX: Fill this in.
47
48 =head2 INTERACTING WITH THE SOAP SERVER
49
50 # XXX: Fill this in.
51
52 =head1 DESCRIPTION
53
54 This library creates a SOAP server within the HoneyClient VM, allowing
55 the HoneyClient::Manager to perform agent-based operations within the
56 VM.
57
58 =cut
59
60 package HoneyClient::Agent;
61
62 # XXX: Disabled version check, Honeywall does not have Perl v5.8 installed.
63 #use 5.008006;
64 use strict;
65 use warnings FATAL => 'all';
66 use Config;
67 use Carp ();
68 # TODO: This can go away.
69 use POSIX qw(SIGALRM);
70
71 #######################################################################
72 # Module Initialization                                               #
73 #######################################################################
74
75 BEGIN {
76     # Defines which functions can be called externally.
77     require Exporter;
78     our (@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION, @DRIVERS);
79
80     # Set our package version.
81     $VERSION = 0.92;
82
83     @ISA = qw(Exporter);
84
85     # Symbols to export on request
86     @EXPORT = qw();
87
88     # Items to export into callers namespace by default. Note: do not export
89     # names by default without a very good reason. Use EXPORT_OK instead.
90     # Do not simply export all your public functions/methods/constants.
91
92     # This allows declaration use HoneyClient::Agent ':all';
93     # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
94     # will save memory.
95
96     %EXPORT_TAGS = (
97         'all' => [ qw() ],
98     );
99
100     # Symbols to autoexport (:DEFAULT tag)
101     @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
102
103     # Check to make sure our OS is Windows-based.
104     # XXX: Fix this!
105     #if ($Config{osname} !~ /^MSWin32$/) {
106     #    Carp::croak "Error: " . __PACKAGE__ . " will only run on Win32 platforms!\n";
107     #}
108
109     # Check to see if ithreads are compiled into this version of Perl.
110     $Config{useithreads} or Carp::croak "Error: Recompile Perl with ithread support, in order to use this module.\n";
111
112     # Registered driver list.
113     # TODO: Eventually, make this more dynamic, based upon the presence of HoneyClient::Agent::Driver::* elements
114     # within the global configuration file.  Or, feed the initialization logic through init() as part of the arguments.
115     @DRIVERS = ( 'IE' );
116     foreach (@DRIVERS) {
117         eval "use HoneyClient::Agent::Driver::Browser::$_";
118         if ($@) {
119             Carp::croak "$@";
120         }
121     }
122
123     $SIG{PIPE} = 'IGNORE'; # Do not exit on broken pipes.
124 }
125 our (@EXPORT_OK, $VERSION, @DRIVERS);
126
127 =pod
128
129 =begin testing
130
131 # Make sure the module loads properly, with the exportable
132 # functions shared.
133 BEGIN { use_ok('HoneyClient::Agent') or diag("Can't load HoneyClient::Agent package.  Check to make sure the package library is correctly listed within the path."); }
134 require_ok('HoneyClient::Agent');
135 can_ok('HoneyClient::Agent', 'init');
136 can_ok('HoneyClient::Agent', 'destroy');
137 use HoneyClient::Agent;
138
139 # Make sure HoneyClient::Util::SOAP loads.
140 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."); }
141 require_ok('HoneyClient::Util::SOAP');
142 can_ok('HoneyClient::Util::SOAP', 'getServerHandle');
143 can_ok('HoneyClient::Util::SOAP', 'getClientHandle');
144 use HoneyClient::Util::SOAP qw(getServerHandle getClientHandle);
145
146 # Make sure HoneyClient::Util::Config loads.
147 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."); }
148 require_ok('HoneyClient::Util::Config');
149 can_ok('HoneyClient::Util::Config', 'getVar');
150 use HoneyClient::Util::Config qw(getVar);
151
152 # TODO: Change Driver::IE to Driver::Browser::IE
153 # Make sure HoneyClient::Agent::Driver::IE loads.
154 BEGIN { use_ok('HoneyClient::Agent::Driver::IE') or diag("Can't load HoneyClient::Agent::Driver::IE package.  Check to make sure the package library is correctly listed within the path."); }
155 require_ok('HoneyClient::Agent::Driver::IE');
156 can_ok('HoneyClient::Agent::Driver::IE', 'new');
157 can_ok('HoneyClient::Agent::Driver::IE', 'drive');
158 can_ok('HoneyClient::Agent::Driver::IE', 'getNextLink');
159 can_ok('HoneyClient::Agent::Driver::IE', 'next');
160 can_ok('HoneyClient::Agent::Driver::IE', 'isFinished');
161 can_ok('HoneyClient::Agent::Driver::IE', 'status');
162 use HoneyClient::Agent::Driver::IE;
163
164 # Make sure Storable loads.
165 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."); }
166 require_ok('Storable');
167 can_ok('Storable', 'nfreeze');
168 can_ok('Storable', 'thaw');
169 use Storable qw(nfreeze thaw);
170
171 # Make sure MIME::Base64 loads.
172 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."); }
173 require_ok('MIME::Base64');
174 can_ok('MIME::Base64', 'encode_base64');
175 can_ok('MIME::Base64', 'decode_base64');
176 use MIME::Base64 qw(encode_base64 decode_base64);
177
178 #XXX: Check to see if the port number should be externalized.
179 # Global test variables.
180 our $PORT = getVar(name      => "port",
181                    namespace => "HoneyClient::Agent");
182 our ($stub, $som);
183
184 =end testing
185
186 =cut
187
188 #######################################################################
189
190 # Include the SOAP Utility Library
191 use HoneyClient::Util::SOAP qw(getClientHandle getServerHandle);
192
193 # Include Integrity Library
194 # TODO: Include corresponding unit tests.
195 use HoneyClient::Agent::Integrity;
196
197 # Include Thread Libraries
198 use threads;
199 use threads::shared;
200 use Thread::Semaphore;
201 use Thread::Queue;
202
203 # Include utility access to global configuration.
204 use HoneyClient::Util::Config qw(getVar);
205
206 # XXX: Remove this, eventually.
207 use Data::Dumper;
208
209 # Include Hash Serialization Utility Libraries
210 # TODO: Update unit tests to include 'dclone'
211 use Storable qw(nfreeze thaw dclone);
212 $Storable::Deparse = 1;
213 $Storable::Eval = 1;
214
215 # Include Base64 Libraries
216 use MIME::Base64 qw(encode_base64 decode_base64);
217
218 # Include Data Differential Analysis Libraries
219 # TODO: Include corresponding unit tests.
220 # XXX: Do we need this?
221 use Data::Diff;
222 # TODO: Include corresponding unit tests.
223 # XXX: Do we need this?
224 use Data::Structure::Util qw(unbless);
225 # TODO: Include corresponding unit tests.
226 # XXX: Do we need this?
227 use Data::Compare;
228
229 # Complete URL of SOAP server, when initialized.
230 our $URL_BASE       : shared = undef;
231 our $URL            : shared = undef;
232
233 # The process ID of the SOAP server daemon, once created.
234 our $DAEMON_PID     : shared = undef;
235
236 # Global static value, to indicate if the Agent should perform
237 # any integrity checks.
238 our $PERFORM_INTEGRITY_CHECKS : shared =
239     getVar(name => "perform_integrity_checks");
240
241 # A globally shared, serialized hashtable, containing the
242 # initialized integrity state of the VM -- ready to be checked
243 # against, at any time.
244 our $integrityState : shared = undef;
245
246 # A globally shared, serialized hashtable, containing data per
247 # registered driver.  Specifically, for each @DRIVER <entry>,
248 # the following data is created:
249 #   '<entry_name>' => {
250 #       'state'     => undef; # Driver-specific state information.
251 #       'thread_id' => undef; # The thread registered to handle
252 #                             # the driver.
253 #       'status'    => undef; # Driver-specific status information.
254 #       'next'      => undef; # Driver-specific connection information.
255 #   }
256 our $driverData     : shared = undef;
257
258 # A global shared semaphore, designed to limit read/write
259 # access to $driverData, by only allowing one thread
260 # at a time to freeze/thaw the data.  While $driverData is
261 # a scalar, the freeze/thaw operation is not atomic; thus,
262 # this semaphore ensures all operations remain atomic.
263 our $driverDataSemaphore     = Thread::Semaphore->new(1);
264
265 # A globally shared hashtable, containing one "update queue"
266 # per driver.  This allows different "driver threads" to
267 # receive asynchronous updates to their state information
268 # in a thread-safe manor.
269 our %driverUpdateQueues : shared = ( );
270
271 #######################################################################
272 # Daemon Initialization / Destruction                                 #
273 #######################################################################
274
275 =pod
276
277 =head1 LOCAL FUNCTIONS
278
279 The following init() and destroy() functions are the only direct
280 calls required to startup and shutdown the SOAP server.
281
282 All other interactions with this daemon should be performed as
283 C<SOAP::Lite> function calls, in order to ensure consistency across
284 client sessions.  See the L<"EXTERNAL SOAP FUNCTIONS"> section, for
285 more details.
286
287 =head2 HoneyClient::Agent->init(address => $localAddr, port => $localPort, ...)
288
289 =over 4
290
291 Starts a new SOAP server, within a child process.
292
293 I<Inputs>:
294  B<$localAddr> is an optional argument, specifying the IP address for the SOAP server to listen on.
295  B<$localPort> is an optional argument, specifying the TCP port for the SOAP server to listen on.
296
297 Additionally optional, driver-specific arguments can be specified
298 as sub-hashtables, where the top-level key corresponds to the name of
299 the implemented driver and the value contains all the expected hash data
300 that can be fed to HoneyClient::Agent::Driver->new() instances.
301
302  Here is an example set of arguments:
303
304    HoneyClient::Agent->init(
305        address => '127.0.0.1',
306        port    => 9000,
307        IE      => {
308            timeout => 30,
309            links_to_visit => {
310                'http://www.mitre.org/' => 1,
311            },
312        },
313    );
314
315  
316 I<Output>: The full URL of the web service provided by the SOAP server.
317
318 =back
319
320 =begin testing
321
322 # XXX: Test init() method.
323 our $URL = HoneyClient::Agent->init();
324 our $PORT = getVar(name      => "port",
325                    namespace => "HoneyClient::Agent");
326 our $HOST = getVar(name      => "address",
327                    namespace => "HoneyClient::Agent");
328 is($URL, "http://$HOST:$PORT/HoneyClient/Agent", "init()") or diag("Failed to start up the VM SOAP server.  Check to see if any other daemon is listening on TCP port $PORT.");
329
330 =end testing
331
332 =cut
333
334 # TODO: Update documentation to reflect hash-based args.
335 sub init {
336     # Extract arguments.
337     # Hash-based arguments are used, since HoneyClient::Util::SOAP is unable to handle
338     # hash references directly.  Thus, flat hashtables are used throughout the code
339     # for consistency.
340     my ($class, %args) = @_;
341
342     # Sanity check.  Make sure the daemon isn't already running.
343     if (defined($DAEMON_PID)) {
344         Carp::croak "Error: " . __PACKAGE__ . " daemon is already running (PID = $DAEMON_PID)!\n";
345     }
346
347     # Acquire data lock.
348     _lock();
349
350     # Initialize the $driverData shared hashtable.
351     my $data = { };
352     for my $driverName (@DRIVERS) {
353
354         # TODO: Figure out which drivers' data to initialize, based upon
355         # which driver argument hashtables were provided.  Then keep
356         # that list in a globally, defined array.
357         
358         $data->{$driverName} = {
359             'state'     => undef,
360             'thread_id' => undef,
361             'status'    => undef,
362             'next'      => undef,
363         };
364
365         # Initialize the corresponding %driverUpdateQueues
366         $driverUpdateQueues{$driverName} = new Thread::Queue;
367     }
368
369     # Perform initial integrity baseline check.
370     #my $integrity = undef;
371     #if ($PERFORM_INTEGRITY_CHECKS) {
372     #    print "Initializing Integrity Check...\n";
373     #    # TODO: Initialize Integrity Checks
374     #    $integrity = HoneyClient::Agent::Integrity->new();
375     #    $integrity->initAll();
376     #}
377     #$integrityState = $integrity->serialize();
378
379     # Release data lock.
380     _unlock($data);
381
382     my $argsExist = scalar(%args);
383
384     if (!($argsExist &&
385           exists($args{'address'}) &&
386           defined($args{'address'}))) {
387         $args{'address'} = getVar(name => "address");
388     }
389
390     if (!($argsExist &&
391           exists($args{'port'}) &&
392           defined($args{'port'}))) {
393         $args{'port'} = getVar(name => "port");
394     }
395
396     $URL_BASE = "http://" . $args{'address'} . ":" . $args{'port'};
397     $URL = $URL_BASE . "/" . join('/', split(/::/, __PACKAGE__));
398
399     my $pid = undef;
400     if ($pid = fork) {
401         # We use a local variable to get the pid, and then we set the global
402         # DAEMON_PID variable after the fork().  This is intentional, because
403         # it seems the Win32 version of fork() doesn't seem to be an atomic
404         # operation.
405         $DAEMON_PID = $pid;
406         return $URL;
407    
408     } else {
409         # Make sure the fork was successful.
410         if (!defined($pid)) {
411             Carp::croak "Error: Unable to fork child process.\n$!";
412         }
413
414         # Do not attempt to rejoin parent process tree,
415         # if any type of termination signal is received.
416         local $SIG{HUP} = sub { exit; };
417         local $SIG{INT} = sub { exit; };
418         local $SIG{QUIT} = sub { exit; };
419         local $SIG{ABRT} = sub { exit; };
420         local $SIG{PIPE} = sub { exit; };
421         local $SIG{TERM} = sub { exit; };
422
423         my $daemon = getServerHandle(address => $args{'address'},
424                                      port    => $args{'port'});
425
426         # Populate our driver's object state with the remaining
427         # arguments.
428         delete($args{'address'});
429         delete($args{'port'});
430
431         # If this call fails, an exception is thrown or the process
432         # remains locked.  If the process locks, then external
433         # detection is used to catch for these types of failures.
434         updateState($class, encode_base64(nfreeze(\%args)));
435    
436         for (;;) {
437             $daemon->handle;
438         }
439     }
440 }
441
442 =pod
443
444 =head2 HoneyClient::Agent->destroy()
445
446 =over 4
447
448 Terminates the SOAP server within the child process.
449
450 I<Output>: True if successful, false otherwise.
451
452 =back
453
454 =begin testing
455
456 # XXX: Test destroy() method.
457 is(HoneyClient::Agent->destroy(), 1, "destroy()") or diag("Unable to terminate Agent SOAP server.  Be sure to check for any stale or lingering processes.");
458
459 # TODO: delete this.
460 #exit;
461
462 =end testing
463
464 =cut
465
466 sub destroy {
467     my $ret = undef;
468     # Make sure the PID is defined and not
469     # the parent process...
470     if (defined($DAEMON_PID) && ($DAEMON_PID != 0)) {
471         # The Win32 version of kill() seems to only respond to SIGKILL(9).
472         $ret = kill(9, $DAEMON_PID);
473     }
474     if ($ret) {
475         # Acquire data lock.
476         _lock();
477
478         # Destroy all globally shared state data.
479         $URL                  = undef;
480         $URL_BASE             = undef;
481         $DAEMON_PID           = undef;
482         $driverData           = undef;
483         $driverDataSemaphore  = Thread::Semaphore->new(1);
484         %driverUpdateQueues   = ( );
485
486         # Release data lock.
487         _unlock();
488     }
489     return $ret;
490 }
491
492 #######################################################################
493 # Private Methods Implemented                                         #
494 #######################################################################
495
496 # Helper function designed to acquire exclusive access to the
497 # shared $driverData, for use within any thread.
498 #
499 # In perl, it is difficult to share hashtables between threads.
500 # However, it is easy to share scalars between threads.
501 # As such, we share a hashtable between threads by *serializing*
502 # the data using nfreeze().  The result can be stored in a scalar.
503 #
504 # When we are in a thread where we subsequently want to read/use
505 # this hashtable, we thaw() the serialized data (it performs the
506 # deserialization process) and use the hashtable accordingly.
507 #
508 # This function guarantees that no other thread will access
509 # $driverData and returns the thaw()'d contents of $driverData.
510 #
511 # Input: None
512 # Output: driverData (deserialized)
513 sub _lock {
514     # Acquire lock on stored driver state.
515     $driverDataSemaphore->down();
516        
517     # Thaw the data.
518     return thaw($driverData);
519 }
520
521 # Helper function designed to release exclusive access to the
522 # shared $driverData, for use within any thread.
523 #
524 # By calling this function, we assume that the thread has already
525 # called _lock() and would like to (optionally) update $driverData
526 # with a new, modified hashtable, prior to releasing the lock
527 # on $driverData.
528 #
529 # This function can optionally take in a normal hashtable reference,
530 # overwriting the $driverData with the contents of the supplied
531 # hashtable.  Once the $driverData's updated contents has been
532 # set and serialized, this function releases the corresponding
533 # lock.
534 #
535 # Input: driverData (deserialized, optional)
536 # Output: None
537 sub _unlock {
538     my $data = shift;
539
540     if (defined($data)) {
541         # Refreze changed data.
542         $driverData = nfreeze($data);
543     }
544    
545     # Release lock on stored driver state.
546     $driverDataSemaphore->up();
547 }
548
549 # Helper function designed to retrieve queued, external
550 # updates to driver state information from %driverUpdateQueues.
551 #
552 # When called from run(), this function takes in the corresponding
553 # Driver object; checks to see if there's a new entry within the
554 # driver's corresponding update queue; and dequeues the *first*
555 # entry in the queue, overwriting the Driver's state data
556 # accordingly.
557 #
558 # The external updateState() call adds new driver state into the queue,
559 # one entry per call.  The internal _update() function merges this
560 # driver state with the currently running driver, one merge
561 # operation per call.  In order words, a single call to _update()
562 # may *NOT* empty the corresponding Driver update queue completely
563 # -- only one entry within the queue will be dequeued per _update()
564 # call made.
565 #
566 # Input: driver
567 # Output: driver (updated)
568 sub _update {
569     # Extract arguments.
570     my $driver = shift;
571
572     # Figure out the corresponding driver name.
573     my @package = split(/::/, ref($driver));
574     my $driverName = pop(@package);
575
576     # Extract the corresponding queue.
577     my $queue = $driverUpdateQueues{$driverName};
578
579     # If we have data in our driver specific queue...
580     if ($queue->pending) {
581
582         # Update our driver state with the first entry
583         # found...
584         my $queuedData = thaw($queue->dequeue_nb);
585
586         # Sanity check: Only copy defined data.
587         if (defined($queuedData)) {
588
589             # Copy (and overwrite) overloaded object data
590             # into shared memory.  This looks creepy, I know, but
591             # it actually works.  We're essentially identifying
592             # driver-specific parameters that the user supplied
593             # via $queuedData and overwriting our current driver state
594             # with any matching, user supplied values.
595             @{$driver}{keys %{$queuedData}} = values %{$queuedData};
596         }
597     }
598
599     # Return the modified driver state.
600     return $driver;
601 }
602
603 #######################################################################
604 # Public Methods Implemented                                          #
605 #######################################################################
606
607 =pod
608
609 =head1 EXPORTS
610
611 =head2 run()
612
613 =over 4
614
615 # XXX: Fill this in.
616
617 I<Inputs>:
618  B<$arg> is an optional argument.
619 SOAP server to listen on.
620  
621 I<Output>: XXX: Fill this in.
622
623 =back
624
625 =begin testing
626
627 # XXX: Fill this in.
628 1;
629
630 =end testing
631
632 =cut
633
634 sub run {
635     # Extract arguments.
636
637     # Temporary variable, used to hold thawed driver data.
638     my $data = undef;
639
640     # Temporary variable, used to hold thread IDs.
641     my $tid = undef;
642
643     # Temporary variable, used to hold thread objects.
644     my $thread = undef;
645
646     # TODO: Eventually, use the globally defined array
647     # of actual drivers used (set by init()).
648     for my $driverName (@DRIVERS) {
649
650         # Acquire data lock.
651         $data = _lock();
652
653         # Read the TID.
654         $tid = $data->{$driverName}->{'thread_id'};
655        
656         # Sanity check: Return false, if we already have a
657         # driver thread running.
658         if (defined($tid) &&
659             defined($thread = threads->object($tid)) &&
660             $thread->is_running()) {
661
662             # Release data lock.
663             _unlock();
664
665             return 0;
666         }
667
668         # Quickly define a temporary thread ID.
669         # This value is simply a placeholder that will
670         # get redefined later on in this function to
671         # the thread's valid ID, once the thread has been
672         # initialized.
673         #
674         # By defining a placeholder valid here, we avoid
675         # a potential race condition, where multiple calls
676         # to run() are made consecutively.
677         #
678         # Temporarily set the driver thread to be the
679         # main thread.
680         $data->{$driverName}->{'thread_id'} = 0;
681        
682         # Release data lock.
683         _unlock($data);
684
685         # TODO: Clean up this comment block.
686         # This function should do the following:
687         # - Initialize all drivers with starting state.
688         # - "Drive" each driver, one-by-one.
689         # - Collect any integrity violations found, with offending
690         #   state information.
691         #
692         # Notes:
693         # This function will eventually sit in a sub-thread, allowing the parent
694         # thread to return without any delay.  It is expected that the Manager
695         # would then subsequently call a getStatus() operation, in order to
696         # then poll for any new violations found.
697         #
698         # TODO: We need to create a fault reporting mechanism, in order
699         # to properly deal with exceptions/faults that occur within this
700         # thread.
701         $thread = async {
702             threads->yield();
703    
704             # Trap all faults that may occur from these asynchronous operations.
705             eval {
706
707                 ###################################
708                 ### Driver Initialization Phase ###
709                 ###################################
710
711                 # Initially set local integrity object to undef.
712                 my $integrity = undef;
713                
714                 # Initially set all driver objects to undef.
715                 my $driver = undef;
716    
717                 # Acquire lock on stored driver state.
718                 $data = _lock();
719
720                 if ($PERFORM_INTEGRITY_CHECKS) {
721                     # XXX: WARNING - The $integrityState object data is NOT thread-safe
722                     # (since it relies on external data stored on the file system).
723                     # As such, do NOT try to call integrity checks on multiple, simultaneous
724                     # asynchronous threaded drivers.
725                     #$integrity = thaw($integrityState);
726                     # Perform initial integrity baseline check.
727                     print "Initializing Integrity Check...\n";
728                     # TODO: Initialize Integrity Checks
729                     $integrity = HoneyClient::Agent::Integrity->new();
730                     $integrity->initAll();
731
732                     # TODO: Delete this.
733                     #$Data::Dumper::Indent = 1;
734                     #$Data::Dumper::Terse = 1;
735                     #print "Integrity: " . Dumper($integrity) . "\n";
736                 }
737
738                 # Now, initialize each driver object.
739                 # Figure out which $driver object to use...
740                 my $driverClass = 'HoneyClient::Agent::Driver::Browser::' . $driverName;
741                
742                 if (!defined($data->{$driverName}->{'state'})) {
743    
744                     # If the driver state is undefined, then
745                     # create a new state object.
746                     $driver = $driverClass->new();
747
748                 } else {
749                     # Then the driver state object is already defined,
750                     # so go ahead and reuse it.
751                     $driver = $driverClass->new(
752                         %{$data->{$driverName}->{'state'}},
753                     );
754                 }
755
756                 # Next, we make sure we have no updates, before we update
757                 # the corresponding shared memory version.
758                 $driver = _update($driver);
759
760                 # Once we've initialized the object, be sure to update
761                 # the corresponding shared memory version.  We do this
762                 # one time before the loop starts, in case we end up
763                 # finishing before we drove anywhere.
764                 
765                 # Copy object data to shared memory.
766                 $data->{$driverName}->{'next'} = $driver->next();
767                 $data->{$driverName}->{'status'} = $driver->status();
768                 $data->{$driverName}->{'status'}->{'is_compromised'} = 0;
769                 $data->{$driverName}->{'state'} = $driver;
770
771                 if ($driver->isFinished()) {
772                     # Thread is about to finish, set the ID back to undef.
773                     # This looks ugly, but setting it this early avoids the
774                     # potential race condition of when the run() thread is finished
775                     # and when updateState() checks for $driverData->{$driverName}->{'thread_id'}
776                     # to be set to undef.
777                     $data->{$driverName}->{'thread_id'} = undef;
778                 }
779
780                 # Release lock on stored driver state.
781                 _unlock($data);
782                
783                 ###################################
784                 ### Driver Running Phase        ###
785                 ###################################
786
787                 # Boolean to indicate that the driver is about to transition
788                 # to a new set of targets upon the next drive() operation.
789                 my $driverTargetsChanged = 0;
790
791                 while (!$driver->isFinished() && !$driverTargetsChanged) {
792                     # XXX: Debug.  Remove this.
793                     # We assume $driver->next() returns defined data.
794                     foreach my $resource (keys %{$driver->next()->{resources}}) {
795                         print "Using Resource: " . $resource . "\n";
796                     }
797
798                     # Drive the driver for one step.
799                     # If the operation fails, then an exception will be generated.
800                     $driver->drive();
801    
802                     # Acquire lock on stored driver state.
803                     $data = _lock();
804                    
805                     # Check for any additional external driver updates.
806                     $driver = _update($driver);
807
808                     # Check to see if our driver's targets have changed.
809                     $driverTargetsChanged = not(Compare($data->{$driverName}->{'next'}->{'targets'}, $driver->next()->{'targets'}));
810
811                     # Copy object data to shared memory.
812                     $data->{$driverName}->{'next'} = $driver->next();
813                     $data->{$driverName}->{'status'} = $driver->status();
814                     $data->{$driverName}->{'status'}->{'is_compromised'} = 0;
815                     $data->{$driverName}->{'state'} = $driver;
816
817                     if ($driver->isFinished() or