#!/usr/bin/perl -w # # Warden.pm # # Copyright (C) 2011-2012 Cesnet z.s.p.o # # Use of this source is governed by a BSD-style license, see LICENSE file. package Warden; use strict; use DBI; use DBD::mysql; use Format::Human::Bytes; use Sys::Syslog qw(:DEFAULT setlogsock); Sys::Syslog::setlogsock('unix'); use File::Basename; use Net::CIDR::Lite; use DateTime; use MIME::Base64; use Crypt::X509; use SOAP::Lite; use Carp; our $VERSION = "2.1"; ################################################################################ # READING OF CONFIGURATION VARIABLES ################################################################################ my $conf_file = "/opt/warden-server/etc/warden-server.conf"; # path is updated by install.sh our $SYSLOG = undef; our $SYSLOG_VERBOSE = undef; our $SYSLOG_FACILITY = undef; our $DB_NAME = undef; our $DB_USER = undef; our $DB_PASS = undef; our $DB_HOST = undef; our $MAX_EVENTS_LIMIT = 1000000; # default value our %VALID_STRINGS = undef; # load set variables by user unless (do $conf_file) { die("Errors in config file '$conf_file': $@") if $@; die("Can't read config file '$conf_file': $!") unless defined $_; # if $_ defined, it's retvalue of last statement of conf, for which we don't care } ################################################################################ # VARIABLES ################################################################################ our $DBH = DBI->connect("DBI:mysql:database=$DB_NAME;host=$DB_HOST", $DB_USER, $DB_PASS, {RaiseError => 1, mysql_auto_reconnect => 1}) || die "Could not connect to database: $DBH->errstr"; ################################################################################ # LOCAL FUNCTIONS ################################################################################ #------------------------------------------------------------------------------- # sendMsg - sent message to syslog (SYS::Syslog) and to client (SOAP::Fault) # # Args: (SYSLOG severity, SYSLOG msg, SOAP msg) #------------------------------------------------------------------------------- sub sendMsg { my $severity = shift; my $syslog_msg = shift; my $soap_msg = shift; my $filename = File::Basename::basename($0); if ($SYSLOG_VERBOSE == 1 && ($severity eq "err" || $severity eq "debug")) { $syslog_msg .= "\nStack info: " . Carp::longmess(); } if ($SYSLOG == 1 && defined $severity && defined $syslog_msg) { Sys::Syslog::openlog($filename, "cons,pid", $SYSLOG_FACILITY); Sys::Syslog::syslog("$severity", "$syslog_msg"); Sys::Syslog::closelog(); } if (defined $soap_msg) { die SOAP::Fault->faultstring($soap_msg); } } # End of sendMsg #------------------------------------------------------------------------------- # getAltNames - parse Alternate names from SSL certifiate #------------------------------------------------------------------------------- sub getAltNames { my @an_array; my $cn = $ENV{'SSL_CLIENT_S_DN_CN'}; push(@an_array, $DBH->quote($cn)); my @a = split("\n", $ENV{'SSL_CLIENT_CERT'}); pop @a; shift @a; my $der = decode_base64(join("", @a)); my $decoded= Crypt::X509->new(cert => $der); foreach my $tmp (@{$decoded->SubjectAltName}) { if($tmp =~ s/dNSName=//){ push(@an_array, $DBH->quote($tmp)); } } my $alt_names = join(',', @an_array); return $alt_names; } #------------------------------------------------------------------------------- # authorizeClient - authorize client by CN,AN and source IP range #------------------------------------------------------------------------------- sub authorizeClient { my ($alt_names, $ip, $service_type, $client_type, $function_name) = @_; my $sth; # obtain cidr based on rigth common name and alternate names, service and client_type if($function_name eq 'saveNewEvent') { $sth = $DBH->prepare("SELECT hostname, ip_net_client, receive_own_events FROM clients WHERE hostname IN ($alt_names) AND service = ? AND client_type = ? ORDER BY SUBSTRING_INDEX(ip_net_client,'/', -1) DESC;"); } elsif($function_name eq 'getNewEvents') { $sth = $DBH->prepare("SELECT hostname, ip_net_client, receive_own_events FROM clients WHERE hostname IN ($alt_names) AND (type = ? OR type = '_any_') AND client_type = ? ORDER BY SUBSTRING_INDEX(ip_net_client,'/', -1) DESC;"); } if (!defined $sth) { sendMsg("err", "Cannot prepare authorization statement in $function_name: $DBH->errstr", "Internal 'prepare' server error") } $sth->execute($service_type, $client_type); my ($an, $cidr, $receive_own, $cidr_list); my $correct_ip_source = 0; my %ret; while(($an, $cidr, $receive_own) = $sth->fetchrow()) { my $cidr_list = Net::CIDR::Lite-> new -> add($cidr); $ret{'dns'} = $an; $ret{'cidr'} = $cidr; $ret{'receive_own'} = $receive_own; if ($cidr_list->bin_find($ip)) { $correct_ip_source = 1; last; } } # check if client is registered if ($sth->rows == 0) { sendMsg("err", "Unauthorized access to function '$function_name' from: '$ip'; CN(AN): $alt_names; used service: '$service_type' - client is not registered", "Access denied - client is not registered at warden server $ENV{'SERVER_NAME'}"); return undef; } # check if client has IP from registered CIDR if (!$correct_ip_source) { sendMsg ("err", "Unauthorized access to function '$function_name' from: '$ip'; CN(AN): $alt_names; used service: '$service_type' - access from bad subnet: Registered subnet '$ret{'cidr'}'", "Access denied - access to $ENV{'SERVER_NAME'} from unauthorized subnet"); return undef; } return %ret; } # END of authorizeClient ################################################################################ # SOAP Functions ################################################################################ #----------------------------------------------------------------------------- # saveNewEvent - save new received event into database #----------------------------------------------------------------------------- sub saveNewEvent { my ($class, $data) = @_; my ($sth, $cidr_list); # client network information my $cn = $ENV{'SSL_CLIENT_S_DN_CN'}; my $alt_names = getAltNames(undef); my $ip = $ENV{'REMOTE_ADDR'}; # variables defined by server my $function_name = 'saveNewEvent'; my $client_type = 's'; # incoming client MUST be sender my $valid = 't'; # registered sender has valid events my $received = DateTime->now; # time of event delivery (UTC) # parse object (event) parameters my $service = $data->{'SERVICE'}; my $detected = $data->{'DETECTED'}; my $type = $data->{'TYPE'}; my $source_type = $data->{'SOURCE_TYPE'}; my $source = $data->{'SOURCE'}; my $target_proto = $data->{'TARGET_PROTO'}; my $target_port = $data->{'TARGET_PORT'}; my $attack_scale = $data->{'ATTACK_SCALE'}; my $note = $data->{'NOTE'}; my $priority = $data->{'PRIORITY'}; my $timeout = $data->{'TIMEOUT'}; my %client = authorizeClient($alt_names, $ip, $service, $client_type, $function_name); if(defined %client) { if (!(exists $VALID_STRINGS{'type'} && grep $type eq $_, @{$VALID_STRINGS{'type'}})) { sendMsg("err", "Unknown event type - client from: '$ip'; CN(AN): $alt_names; used type: '$type'", "Unknown event type '$type'"); } elsif (!(exists $VALID_STRINGS{'source_type'} && grep $source_type eq $_, @{$VALID_STRINGS{'source_type'}})) { sendMsg("err", "Unknown source type - client from: '$ip'; CN(AN): $alt_names; used source_type: '$source_type'", "Unknown source type '$source_type'"); # http://my.safaribooksonline.com/book/programming/regular-expressions/9780596802837/4dot-validation-and-formatting/id2983571 } elsif ($detected !~ /^((?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[0-1]|0[1-9]|[1-2][0-9])T(2[0-3]|[0-1][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[0-1][0-9]):[0-5][0-9])?/) { sendMsg("err", "Unknown detected time format - client from: '$ip'; CN(AN): $alt_names; used detected: '$detected'", "Unknown detected time format '$detected'"); } elsif ($target_port !~ /^\d+\z/ && defined $target_port) { sendMsg("err", "Unknown target port - client from: '$ip'; CN(AN): $alt_names; used target_port: '$target_port'", "Unknown target port '$target_port'"); } elsif ($attack_scale !~ /^\d+\z/ && defined $attack_scale) { sendMsg("err", "Unknown attack scale - client from: '$ip'; CN(AN): $alt_names; used attack_scale: '$attack_scale'", "Unknown attack scale '$attack_scale'"); } elsif ($priority !~ /^\d+\z/ && defined $priority) { sendMsg("err", "Unknown priority - client from: '$ip'; CN(AN): $alt_names; used priority: '$priority'", "Unknown priority '$priority'"); } elsif ($timeout !~ /^\d+\z/ && defined $timeout) { sendMsg("err", "Unknown timeout - client from: '$ip'; CN(AN): $alt_names; used timeout: '$timeout'", "Unknown timeout '$timeout'"); } else { $sth=$DBH->prepare("INSERT INTO events VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute(undef, $client{'dns'}, $service, $detected, $received, $type, $source_type, $source, $target_proto, $target_port, $attack_scale, $note, $priority, $timeout, $valid); return 1; } } } # END of saveNewEvent #----------------------------------------------------------------------------- # getNewEvents - get new events from the DB greater than received ID #----------------------------------------------------------------------------- sub getNewEvents { my ($class, $data) = @_; my ($sth, @events, $event, @ids, $cidr_list); my ($id, $hostname, $service, $detected, $type, $source_type, $source, $target_proto, $target_port, $attack_scale, $note, $priority, $timeout); # client network information my $cn = $ENV{'SSL_CLIENT_S_DN_CN'}; my $alt_names = getAltNames(undef); my $ip = $ENV{'REMOTE_ADDR'}; my $client_type = 'r'; # incoming client MUST be sender my $function_name = 'getNewEvents'; # parse SOAP data object my $requested_type = $data->{'REQUESTED_TYPE'} || '_any_'; my $last_id = $data->{'LAST_ID'}; my $max_rcv_events_limit = $data->{'MAX_RCV_EVENTS_LIMIT'}; # client events limit # comparison of client and server limit - which can be used my $used_limit; if (defined $max_rcv_events_limit && $max_rcv_events_limit < $MAX_EVENTS_LIMIT) { $used_limit = $max_rcv_events_limit; } else { $used_limit = $MAX_EVENTS_LIMIT; } my %client = authorizeClient($alt_names, $ip, $requested_type, $client_type, $function_name); if(defined %client) { if ($client{'receive_own'} eq 't') { if ($requested_type eq '_any_') { $sth = $DBH->prepare("SELECT * FROM events WHERE type != 'test' AND id > ? AND valid = 't' ORDER BY id ASC LIMIT ?;"); if (!defined $sth) { sendMsg("err", "Cannot prepare ROE-ANY statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute($last_id, $used_limit); } else { $sth = $DBH->prepare("SELECT * FROM events WHERE type != 'test' AND id > ? AND type = ? AND valid = 't' ORDER BY id ASC LIMIT ?;"); if (!defined $sth) { sendMsg("err", "Cannot prepare ROE statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute($last_id, $requested_type, $used_limit); } } else { if ($requested_type eq '_any_') { $sth = $DBH->prepare("SELECT * FROM events WHERE type != 'test' AND id > ? AND valid = 't' AND hostname NOT LIKE ? ORDER BY id ASC LIMIT ?;"); if (!defined $sth) { sendMsg("err", "Cannot prepare ANY statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } my ($domain) = $cn =~ /([^\.]+\.[^\.]+)$/; $domain = '\%' . $domain; $sth->execute($last_id, $domain, $used_limit); } else { $sth = $DBH->prepare("SELECT * FROM events WHERE type != 'test' AND id > ? AND type = ? AND valid = 't' AND hostname NOT LIKE ? ORDER BY id ASC LIMIT ?;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr\n", "Internal 'prepare' server error"); } my ($domain) = $cn =~ /([^\.]+\.[^\.]+)$/; $domain = '\%' . $domain; $sth->execute($last_id, $requested_type, $domain, $used_limit); } } # parse items of events stored in DB while (my @result = $sth->fetchrow()) { $id = $result[0]; $hostname = $result[1]; $service = $result[2]; $detected = $result[3]; $type = $result[5]; $source_type = $result[6]; $source = $result[7]; $target_proto = $result[8]; $target_port = $result[9]; $attack_scale = $result[10]; $note = $result[11]; $priority = $result[12]; $timeout = $result[13]; # create SOAP data object $event = SOAP::Data->name(event => \SOAP::Data->value( SOAP::Data->name(ID => $id), SOAP::Data->name(HOSTNAME => $hostname), SOAP::Data->name(SERVICE => $service), SOAP::Data->name(DETECTED => $detected), SOAP::Data->name(TYPE => $type), SOAP::Data->name(SOURCE_TYPE => $source_type), SOAP::Data->name(SOURCE => $source), SOAP::Data->name(TARGET_PROTO => $target_proto), SOAP::Data->name(TARGET_PORT => $target_port), SOAP::Data->name(ATTACK_SCALE => $attack_scale), SOAP::Data->name(NOTE => $note), SOAP::Data->name(PRIORITY => $priority), SOAP::Data->name(TIMEOUT => $timeout) )); push(@events, $event); push(@ids, $id); } # log sent ID of events if (scalar @events != 0) { if (scalar @ids == 1) { sendMsg("info", "Sent 1 event [#$ids[0]] to '$ip' [CN(AN): $alt_names], client_limit: '$max_rcv_events_limit', requested_type: '$requested_type'", undef); } else { sendMsg("info", "Sent " . scalar @ids . " events [#$ids[0] - #$ids[-1]] to '$ip' [CN(AN): $alt_names], client_limit: '$max_rcv_events_limit', requested_type: '$requested_type'", undef); } } return @events; } } # END of getNewEvents #----------------------------------------------------------------------------- # getLastId - get lastest saved event ID #----------------------------------------------------------------------------- sub getLastId { my ($class, $arg) = @_; my $function_name = 'getLastId'; my $sth = $DBH->prepare("SELECT max(id) FROM events;"); if ( !defined $sth ) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute; my $result = $sth->fetchrow(); return $result; } # END of getLastID #----------------------------------------------------------------------------- # registerSender - register new sender #----------------------------------------------------------------------------- sub registerSender { my ($class, $data) = @_; my $sth; # client network information my $cn = $ENV{'SSL_CLIENT_S_DN_CN'}; my $ip = $ENV{'REMOTE_ADDR'}; my $local_ip = $ENV{'SERVER_ADDR'}; my $function_name = 'registerSender'; if ($local_ip ne $ip) { sendMsg("err", "Unauthorized access to function '$function_name' from: '$ip' ('$cn') - access allowed only from localhost", "Access denied - access allowed only from localhost"); } else { # defined variables by method my $client_type = "s"; my $registered = DateTime->now; my $type = undef; my $receive_own_events = undef; # parse SOAP data oject my $hostname = $data->{'HOSTNAME'}; my $requestor = $data->{'REQUESTOR'}; my $service = $data->{'SERVICE'}; my $description_tags = $data->{'DESCRIPTION_TAGS'}; my $ip_net_client = $data->{'IP_NET_CLIENT'}; # check if sender has been already registered $sth = $DBH->prepare("SELECT registered FROM clients WHERE hostname = ? AND service = ? AND client_type = ? AND ip_net_client = ? LIMIT 1;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute($hostname, $service, $client_type, $ip_net_client); my $result = $sth->fetchrow(); # register new sender if (defined $result) { sendMsg("err", "Attempt to re-register the sender: {hostname: '$hostname', service: '$service', cidr: '$ip_net_client'}", "Sender has been already registered at $ENV{'SERVER_NAME'} in '$result'"); } else { $sth = $DBH->prepare("INSERT INTO clients VALUES (?,?,?,?,?,?,?,?,?,?);"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute(undef, $hostname, $registered, $requestor, $service, $client_type, $type, $receive_own_events, $description_tags, $ip_net_client); sendMsg("info", "New sender '$hostname' {service: '$service', cidr: '$ip_net_client'} was registered at $ENV{'SERVER_NAME'}", undef); return 1; } } } # END of registerSender #----------------------------------------------------------------------------- # registerReceiver - register new receiver #----------------------------------------------------------------------------- sub registerReceiver { my ($class, $data) = @_; my $sth; # client network information my $cn = $ENV{'SSL_CLIENT_S_DN_CN'}; my $ip = $ENV{'REMOTE_ADDR'}; my $local_ip = $ENV{'SERVER_ADDR'}; my $function_name = 'registerReceiver'; if ($local_ip ne $ip) { sendMsg("err", "Unauthorized access to function '$function_name' from: '$ip' ('$cn') - access allowed only from localhost", "Access denied - access allowed only from localhost"); } else { # variables defined by method my $client_type = "r"; my $registered = DateTime->now; my $service = undef; my $description_tags = undef; # parse SOAP data oject my $hostname = $data->{'HOSTNAME'}; my $requestor = $data->{'REQUESTOR'}; my $type = $data->{'TYPE'}; my $receive_own_events = $data->{'RECEIVE_OWN_EVENTS'}; my $ip_net_client = $data->{'IP_NET_CLIENT'}; # check if receiver has been already registered $sth = $DBH->prepare("SELECT registered FROM clients WHERE hostname = ? AND client_type = ? AND type = ? AND ip_net_client = ? LIMIT 1;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute($hostname, $client_type, $type, $ip_net_client); my $result = $sth->fetchrow(); # register new receiver if (defined $result) { sendMsg("err", "Attempt to re-register the receiver: {hostname: '$hostname', type: '$type', cidr: '$ip_net_client'}", "Receiver has already been registered at $ENV{'SERVER_NAME'} in '$result'"); } else { $sth = $DBH->prepare("INSERT INTO clients VALUES (?,?,?,?,?,?,?,?,?,?);"); if (!defined($sth)) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute(undef, $hostname, $registered, $requestor, $service, $client_type, $type, $receive_own_events, $description_tags, $ip_net_client); sendMsg("info", "New receiver '$hostname' {type: '$type', cidr: '$ip_net_client'} was registered at $ENV{'SERVER_NAME'}", undef); return 1; } } } # END of registerReceiver #----------------------------------------------------------------------------- # unregisterClient - unregister client #----------------------------------------------------------------------------- sub unregisterClient { my ($class, $data) = @_; my $sth; # client network information my $cn = $ENV{'SSL_CLIENT_S_DN_CN'}; my $ip = $ENV{'REMOTE_ADDR'}; my $local_ip = $ENV{'SERVER_ADDR'}; my $function_name = 'unregisterClient'; if ($local_ip ne $ip) { sendMsg("err", "Unauthorized access to function '$function_name' from: '$ip' ('$cn') - access allowed only from localhost", "Access denied - access allowed only from localhost"); } else { # parse SOAP data oject my $client_id = $data->{'CLIENT_ID'}; # check if receiver has been already registered $sth = $DBH->prepare("SELECT client_id, hostname, service, client_type FROM clients WHERE client_id = ? LIMIT 1;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute($client_id); my ($id, $hostname, $service, $client_type) = $sth->fetchrow(); # delete registered client if (!defined $id) { sendMsg("err", "Attempt to delete unregister client '$id', '$hostname', '$service', '$client_type'", "Client (#$client_id) is not registered at $ENV{'SERVER_NAME'}"); } else { if ($client_type eq 's') { $sth = $DBH->prepare("DELETE FROM clients WHERE client_id = ?;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute($client_id); $sth = $DBH->prepare("UPDATE events SET valid = 'f' where hostname = ? AND service = ?;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute($hostname, $service); sendMsg("info", "Sender '$hostname' (client_id: '$client_id', service: '$service') was deleted and its data were invalidated", undef); return 1; } else { $sth = $DBH->prepare("DELETE FROM clients WHERE client_id = ?;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute($client_id); sendMsg("info", "Receiver '$hostname' (client_id: '$client_id') was deleted from $ENV{'SERVER_NAME'}", undef); return 1; } } } } # END of unregisterClient #----------------------------------------------------------------------------- # getClients - get list of clients which were registered at warden server #----------------------------------------------------------------------------- sub getClients { my ($class, $arg) = @_; # client network information my $cn = $ENV{'SSL_CLIENT_S_DN_CN'}; my $ip = $ENV{'REMOTE_ADDR'}; my $local_ip = $ENV{'SERVER_ADDR'}; my $function_name = 'getClients'; if ($local_ip ne $ip) { sendMsg("err", "Unauthorized access to function '$function_name' from: '$ip' ('$cn') - access allowed only from localhost", "Access denied - access allowed only from localhost"); } else { my (@clients, $client); my ($client_id, $hostname, $registered, $requestor, $service, $client_type, $type, $receive_own_events, $description_tags, $ip_net_client); my $sth = $DBH->prepare("SELECT * FROM clients ORDER BY client_id ASC;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute; while ( my @result = $sth->fetchrow() ) { $client_id = $result[0]; $hostname = $result[1]; $registered = $result[2]; $requestor = $result[3]; $service = $result[4]; $client_type = $result[5]; $type = $result[6]; $receive_own_events = $result[7]; $description_tags = $result[8]; $ip_net_client = $result[9]; $client = SOAP::Data->name(client => \SOAP::Data->value( SOAP::Data->name(CLIENT_ID => $client_id), SOAP::Data->name(HOSTNAME => $hostname), SOAP::Data->name(REGISTERED => $registered), SOAP::Data->name(REQUESTOR => $requestor), SOAP::Data->name(SERVICE => $service), SOAP::Data->name(CLIENT_TYPE => $client_type), SOAP::Data->name(TYPE => $type), SOAP::Data->name(RECEIVE_OWN_EVENTS => $receive_own_events), SOAP::Data->name(DESCRIPTION_TAGS => $description_tags), SOAP::Data->name(IP_NET_CLIENT => $ip_net_client), )); push(@clients, $client); } my $sum = scalar @clients; sendMsg("info", "Sending information about '$sum' registered clients from $ENV{'SERVER_NAME'}", undef); return @clients; } } # END of getClients #----------------------------------------------------------------------------- # getStatus - get list of status items of warden server #----------------------------------------------------------------------------- sub getStatus { my ($class, $arg) = @_; # client network information my $cn = $ENV{'SSL_CLIENT_S_DN_CN'}; my $ip = $ENV{'REMOTE_ADDR'}; my $local_ip = $ENV{'SERVER_ADDR'}; my $function_name = 'getStatus'; #----------------------------------------------------------------------------- # Warden server stats if ($local_ip ne $ip) { sendMsg("err", "Unauthorized access to function '$function_name' from: '$ip' ('$cn') - access allowed only from localhost", "Access denied - access allowed only from localhost"); } else { my ($sth, @status); # Warden server hostname my $hostname = $ENV{'SERVER_NAME'}; # IP address of Warden server my $ip_address = $ENV{'REMOTE_ADDR'}; # used port my $port = $ENV{'SERVER_PORT'}; # size of database events $sth = $DBH->prepare("SELECT data_length + index_length FROM information_schema.TABLES WHERE table_schema = ? AND TABLE_NAME = ?"); $sth->execute('warden', 'events'); my $size = $sth->fetchrow(); my $db_size = (defined $size ? Format::Human::Bytes::base10($size) : "none"); # sum of records in table events $sth = $DBH->prepare("SELECT count(*) FROM events WHERE valid = 't';"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute; my $events_sum = $sth->fetchrow(); if (!defined $events_sum) { $events_sum = "none" } # id of last record in table events $sth = $DBH->prepare("SELECT max(id) FROM events;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute; my $events_last_id = $sth->fetchrow(); if (!defined $events_last_id) { $events_last_id = "none" } # timestamp of first record in table events $sth = $DBH->prepare("SELECT received FROM events WHERE id = (SELECT min(id) FROM events);"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute; my $events_first_timestamp = $sth->fetchrow(); if (!defined $events_first_timestamp) { $events_first_timestamp = "none" } # timestamp of last record in table events $sth = $DBH->prepare("SELECT received FROM events WHERE id = (SELECT max(id) FROM events);"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute; my $events_last_timestamp = $sth->fetchrow(); if (!defined $events_last_timestamp) { $events_last_timestamp = "none" } # sum of records in table clients $sth = $DBH->prepare("SELECT count(*) FROM clients;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute; my $clients_sum = $sth->fetchrow(); if (!defined $clients_sum) { $clients_sum = "none" } my $server_status = SOAP::Data->name(server_status => \SOAP::Data->value( SOAP::Data->name(VERSION => $VERSION), SOAP::Data->name(HOSTNAME => $hostname), SOAP::Data->name(IP_ADDRESS => $ip_address), SOAP::Data->name(PORT => $port), SOAP::Data->name(SYSLOG => $SYSLOG), SOAP::Data->name(SYSLOG_VERBOSE => $SYSLOG_VERBOSE), SOAP::Data->name(SYSLOG_FACILITY => $SYSLOG_FACILITY), SOAP::Data->name(DB_NAME => $DB_NAME), SOAP::Data->name(DB_USER => $DB_USER), SOAP::Data->name(DB_HOST => $DB_HOST), SOAP::Data->name(DB_SIZE => $db_size), SOAP::Data->name(EVENTS_SUM => $events_sum), SOAP::Data->name(EVENTS_LAST_ID => $events_last_id), SOAP::Data->name(EVENTS_FIRST_TIMESTAMP => $events_first_timestamp), SOAP::Data->name(EVENTS_LAST_TIMESTAMP => $events_last_timestamp), SOAP::Data->name(CLIENTS_SUM => $clients_sum) )); push(@status, $server_status); #--------------------------------------------------------------------------- # Statistics table of senders if ($clients_sum != 0) { $sth = $DBH->prepare("SELECT clients.client_id, clients.hostname, clients.service, count(*), max(received) FROM events LEFT JOIN clients ON (events.hostname=clients.hostname AND events.service=clients.service) GROUP BY hostname, service;"); if (!defined $sth) { sendMsg("err", "Cannot prepare statement in function '$function_name': $DBH->errstr", "Internal 'prepare' server error"); } $sth->execute; my ($hash_ref, $client_id, $hostname, $service, $count, $timestamp, $client_status); $hash_ref = $sth->fetchall_hashref("client_id"); foreach my $key (sort {$a<=>$b} keys %$hash_ref) { $client_status = SOAP::Data->name(client_status => \SOAP::Data->value( SOAP::Data->name(CLIENT_ID => $hash_ref->{$key}->{client_id}), SOAP::Data->name(HOSTNAME => $hash_ref->{$key}->{hostname}), SOAP::Data->name(SERVICE => $hash_ref->{$key}->{service}), SOAP::Data->name(COUNT => $hash_ref->{$key}->{"count(*)"}), SOAP::Data->name(TIMESTAMP => $hash_ref->{$key}->{"max(received)"}), )); push(@status, $client_status); } } sendMsg("info", "Sent warden server status info from $ENV{'SERVER_NAME'}", undef); return @status; } } # END of getStatus 1;