From a525b562b0e34faf4fbde6bfe2604b2d4219a96f Mon Sep 17 00:00:00 2001 From: ramonn Date: Tue, 12 Aug 2014 13:31:25 +0000 Subject: [PATCH] 2014-08-12 Ramon Novoa * pandora_agent: Fixed to make the 'Command Snapshot' feature work. git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@10409 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f --- pandora_agents/unix/ChangeLog | 4 + pandora_agents/unix/pandora_agent | 7 +- pandora_agents/unix/tentacle_server | 302 +++++++++++++++++----------- 3 files changed, 192 insertions(+), 121 deletions(-) diff --git a/pandora_agents/unix/ChangeLog b/pandora_agents/unix/ChangeLog index e42ecd7c36..041d038f26 100644 --- a/pandora_agents/unix/ChangeLog +++ b/pandora_agents/unix/ChangeLog @@ -1,3 +1,7 @@ +2014-08-12 Ramon Novoa + + * pandora_agent: Fixed to make the 'Command Snapshot' feature work. + 2014-08-12 Ramon Novoa * pandora_agent: Trim leading and trailing whitespaces from module names diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index 9d9501634f..10690ea74e 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -1729,12 +1729,7 @@ sub write_module_xml ($@) { # Data list if ($#data > 0) { - $Xml .= " \n"; - foreach my $data_item (@data) { - chomp ($data_item); - $Xml .= " \n"; - } - $Xml .= " \n"; + $Xml .= " \n"; # Single data } else { chomp ($data[0]); diff --git a/pandora_agents/unix/tentacle_server b/pandora_agents/unix/tentacle_server index 1fcf0286db..a8146c563e 100755 --- a/pandora_agents/unix/tentacle_server +++ b/pandora_agents/unix/tentacle_server @@ -60,8 +60,14 @@ use strict; use warnings; use Getopt::Std; use IO::Select; +use threads; use Thread::Semaphore; use POSIX ":sys_wait_h"; +use Time::HiRes qw(usleep); + +# Constants for Win32 services. +use constant WIN32_SERVICE_STOPPED => 0x01; +use constant WIN32_SERVICE_RUNNING => 0x04; my $t_libwrap_installed = eval { require Authen::Libwrap } ? 1 : 0; @@ -77,9 +83,8 @@ my $SOCKET_MODULE = : eval { require IO::Socket::INET } ? 'IO::Socket::INET' : die $@; -if ($SOCKET_MODULE eq 'IO::Socket::INET') { - print_log ("IO::Socket::INET6 is not found. IPv6 is disabled."); -} +# Service name for Win32. +my $SERVICE_NAME="Tentacle Server"; # Program version our $VERSION = '0.4.0'; @@ -130,7 +135,7 @@ my $t_retries = 3; my $t_select; # Semaphore -my $t_sem; +my $t_sem :shared; # Server socket my @t_server_sockets; @@ -197,6 +202,7 @@ sub print_help { print ("\t-p port\t\tPort to listen on (default $t_port).\n"); print ("\t-q\t\tQuiet. Do now print error messages.\n"); print ("\t-r number\tNumber of retries for network opertions (default $t_retries).\n"); + print ("\t-S (install|uninstall|run) Manage the win32 service.\n"); print ("\t-t time\t\tTime-out for network operations in seconds (default ${t_timeout}s).\n"); print ("\t-v\t\tBe verbose.\n"); print ("\t-w\t\tPrompt for OpenSSL private key password.\n"); @@ -240,27 +246,6 @@ sub daemonize { POSIX::setsid () || error ("Cannot start a new session: $!."); } -################################################################################ -## SUB start_win_service -## Turn the current process into a Windows service. -################################################################################ -#sub start_win_service { -# require Win32::Daemon; -# -# # Tell the OS to start the service -# Win32::Daemon::StartService (); -# -# # Wait until the service manager is ready -# while (SERVICE_START_PENDING != Win32::Daemon::State()) { -# sleep (1); -# } -# -# # Tell the service manager we are running -# Win32::Daemon::State (SERVICE_RUNNING); -# -# # Call Win32::Daemon::StopService() when done -#} - ################################################################################ ## SUB parse_options ## Parse command line options and initialize global variables. @@ -271,7 +256,7 @@ sub parse_options { my @t_addresses_tmp; # Get options - if (getopts ('a:c:de:f:hi:k:m:op:qr:s:t:vwx:b:g:T', \%opts) == 0 || defined ($opts{'h'})) { + if (getopts ('a:b:c:de:f:g:hi:k:m:op:qr:s:S:t:Tvwx:', \%opts) == 0 || defined ($opts{'h'})) { print_help (); exit 1; } @@ -467,19 +452,33 @@ sub parse_options { error ("Authen::Libwrap is not installed."); } } -} -################################################################################ -## SUB sigchld_handler -## Handle child process termination. -################################################################################ -sub sigchld_handler { + # Win32 service management + if (defined ($opts{'S'})) { + my $service_action = $opts{'S'}; + if ($^O ne 'MSWin32') { + error ("Windows services are only available on Win32."); + } else { + eval "use Win32::Daemon"; + die($@) if ($@); - while (waitpid(-1, &WNOHANG) > 0) { - $t_sem->up (); + if ($service_action eq 'install') { + install_service(); + } elsif ($service_action eq 'uninstall') { + uninstall_service(); + } elsif ($service_action eq 'run') { + Win32::Daemon::RegisterCallbacks({ + start => \&callback_start, + running => \&callback_running, + stop => \&callback_stop, + }); + Win32::Daemon::StartService(); + exit 0; + } else { + error("Unknown action: $service_action"); + } + } } - - $SIG{CHLD} = \&sigchld_handler; } ################################################################################ @@ -660,87 +659,86 @@ sub start_ssl { } ################################################################################ -## SUB accept_connection -## Accept an incoming connection and fork. +## SUB accept_connections +## Manage incoming connections. ################################################################################ -sub accept_connection { +sub accept_connections { my $pid; my $t_server_socket; - my @ready = $select->can_read; + # Start server + start_server (); - foreach $t_server_socket (@ready) { + # Initialize semaphore + $t_sem = Thread::Semaphore->new ($t_max_conn); - # Accept connection - $t_client_socket = $t_server_socket->accept (); + while (1) { + my @ready = $select->can_read; + foreach $t_server_socket (@ready) { - if (! defined ($t_client_socket)) { + # Accept connection + $t_client_socket = $t_server_socket->accept (); - # EINTR - if ($! ne '') { - next; + if (! defined ($t_client_socket)) { + next if ($! ne ''); # EINTR + error ("accept: $!."); } - error ("accept: $!."); + print_log ("Client connected from " . $t_client_socket->sockhost ()); + + # Create a new thread and serve the client + $t_sem->down(); + my $thr = threads->create(\&serve_client); + if (! defined ($thr)) { + error ("Error creating thread: $!."); + } + $thr->detach(); } - print_log ("Client connected from " . $t_client_socket->sockhost ()); + usleep (1000); + } +} - # Fork and serve the client - $pid = fork (); - if (! defined ($pid)) { - error ("Cannot fork: $!."); +################################################################################ +## SUB serve_client +## Serve a connected client. +################################################################################ +sub serve_client() { + + if ($t_use_libwrap) { + if (! hosts_ctl($t_program_name, $t_client_socket)) { + print_log ("Connection from " . $t_client_socket->sockhost() . " is closed by tcpwrappers."); + $t_client_socket->close (); + $t_sem->up(); + return; + } + } + + eval { + # Add client socket to select queue + $t_select = IO::Select->new (); + $t_select->add ($t_client_socket); + + # Start SSL + if ($t_ssl == 1) { + start_ssl (); } - # Child - if ($pid == 0) { - - # We do not need the server socket - $t_server_socket->close (); - - if ($t_use_libwrap) { - if (! hosts_ctl($t_program_name, $t_client_socket)) { - print_log ("Connection from " . $t_client_socket->sockhost() . " is closed by tcpwrappers."); - $t_client_socket->close (); - - exit; - } - } - - # Add client socket to select queue - $t_select = IO::Select->new (); - $t_select->add ($t_client_socket); - - # Start SSL - if ($t_ssl == 1) { - start_ssl (); - } - - # Authenticate client - if ($t_pwd ne '') { - auth_pwd (); - } - - # Check if proxy mode is enable - if (defined ($t_proxy_ip)) { - - serve_proxy_connection (); - - } else { - - serve_connection (); - } - - $t_client_socket->close (); - - # Must exit now - exit; + # Authenticate client + if ($t_pwd ne '') { + auth_pwd (); } + + # Check if proxy mode is enable + if (defined ($t_proxy_ip)) { + serve_proxy_connection (); + } else { + serve_connection (); + } + }; - # Parent - $t_client_socket->close (); - - } + $t_client_socket->close (); + $t_sem->up(); } ################################################################################ @@ -1045,10 +1043,8 @@ sub print_log { sub error { if ($t_quiet == 0) { - print (STDERR "[err] $_[0]\n"); + die("[err] $_[0]\n\n"); } - - exit 1; } ################################################################################ @@ -1413,6 +1409,91 @@ sub apply_filters ($) { return ''; } +################################################################################ +## SUB install_service +## Install the Windows service. +################################################################################ +sub install_service() { + + my $service_path = $0; + my $service_params = "-s \"$t_directory\" -S run"; + + my %service_hash = ( + machine => '', + name => 'TENTACLESRV', + display => $SERVICE_NAME, + path => $service_path, + user => '', + pwd => '', + description => 'Tentacle Server http://sourceforge.net/projects/tentacled/', + parameters => $service_params + ); + + if (Win32::Daemon::CreateService(\%service_hash)) { + print "Successfully added.\n"; + exit 0; + } else { + print "Failed to add service: " . Win32::FormatMessage(Win32::Daemon::GetLastError()) . "\n"; + exit 1; + } +} + +################################################################################ +## SUB uninstall_service +## Install the Windows service. +################################################################################ +sub uninstall_service() { + if (Win32::Daemon::DeleteService('', 'TENTACLESRV')) { + print "Successfully deleted.\n"; + exit 0; + } else { + print "Failed to delete service: " . Win32::FormatMessage(Win32::Daemon::GetLastError()) . "\n"; + exit 1; + } +} + +################################################################################ +## SUB callback_running +## Windows service callback function for the running event. +################################################################################ +sub callback_running { + + if (Win32::Daemon::State() == WIN32_SERVICE_RUNNING) { + } +} + +################################################################################ +## SUB callback_start +## Windows service callback function for the start event. +################################################################################ +sub callback_start { + + # Accept_connections (); + my $thr = threads->create(\&accept_connections); + if (!defined($thr)) { + Win32::Daemon::State(WIN32_SERVICE_STOPPED); + Win32::Daemon::StopService(); + return; + } + $thr->detach(); + + Win32::Daemon::State(WIN32_SERVICE_RUNNING); +} + +################################################################################ +## SUB callback_stop +## Windows service callback function for the stop event. +################################################################################ +sub callback_stop { + + foreach my $t_server_socket (@t_server_sockets) { + $t_server_socket->close (); + } + + Win32::Daemon::State(WIN32_SERVICE_STOPPED); + Win32::Daemon::StopService(); +} + ################################################################################ # Main ################################################################################ @@ -1444,25 +1525,16 @@ if ($t_daemon == 1 && $^O ne 'MSWin32') { # Handle ctr-c if ($^O eq 'MSWin32') { + no warnings; $SIG{INT2} = \&stop_server; + use warnings; } else { $SIG{INT} = \&stop_server; } -# Handle SIGCHLD -$SIG{CHLD} = \&sigchld_handler; - -start_server (); - -# Initialize semaphore -$t_sem = Thread::Semaphore->new ($t_max_conn); - # Accept connections -while (1) { - $t_sem->down (); - accept_connection (); -} +accept_connections(); __END__