Newer
Older
Tomáš Plesník
committed
# Warden.pm
#
# Copyright (C) 2011-2012 Cesnet z.s.p.o
#
Tomáš Plesník
committed
# 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;
Tomáš Plesník
committed
use SOAP::Lite;
Tomáš Plesník
committed
use Carp;
Tomáš Plesník
committed
################################################################################
Tomáš Plesník
committed
# READING OF CONFIGURATION VARIABLES
################################################################################
my $conf_file = "/opt/warden-server/etc/warden-server.conf"; # path is updated by install.sh
Tomáš Plesník
committed
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;
Tomáš Plesník
committed
our $MAX_EVENTS_LIMIT = 1000000; # default value
our %VALID_STRINGS = undef;
Tomáš Plesník
committed
unless (do $conf_file) {
Tomáš Plesník
committed
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
Tomáš Plesník
committed
################################################################################
# VARIABLES
################################################################################
Tomáš Plesník
committed
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";
Tomáš Plesník
committed
################################################################################
# LOCAL FUNCTIONS
################################################################################
#-------------------------------------------------------------------------------
Tomáš Plesník
committed
# sendMsg - sent message to syslog (SYS::Syslog) and to client (SOAP::Fault)
#
# Args: (SYSLOG severity, SYSLOG msg, SOAP msg)
#-------------------------------------------------------------------------------
Tomáš Plesník
committed
sub sendMsg
Tomáš Plesník
committed
my $severity = shift;
my $syslog_msg = shift;
my $soap_msg = shift;
my $filename = File::Basename::basename($0);
Tomáš Plesník
committed
if ($SYSLOG_VERBOSE == 1 && ($severity eq "err" || $severity eq "debug")) {
Tomáš Plesník
committed
$syslog_msg .= "\nStack info: " . Carp::longmess();
}
if ($SYSLOG == 1 && defined $severity && defined $syslog_msg) {
Sys::Syslog::openlog($filename, "cons,pid", $SYSLOG_FACILITY);
Tomáš Plesník
committed
Sys::Syslog::syslog("$severity", "$syslog_msg");
Sys::Syslog::closelog();
}
Tomáš Plesník
committed
if (defined $soap_msg) {
die SOAP::Fault->faultstring($soap_msg);
}
} # End of sendMsg
#-------------------------------------------------------------------------------
Tomáš Plesník
committed
# getAltNames - parse Alternate names from SSL certifiate
#-------------------------------------------------------------------------------
Tomáš Plesník
committed
sub getAltNames
Tomáš Plesník
committed
my $cn = $ENV{'SSL_CLIENT_S_DN_CN'};
Tomáš Plesník
committed
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}) {
Tomáš Plesník
committed
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
{
Tomáš Plesník
committed
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') {
Tomáš Plesník
committed
$sth = $DBH->prepare("SELECT client_id, 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;");
Tomáš Plesník
committed
} elsif($function_name eq 'getNewEvents') {
Tomáš Plesník
committed
$sth = $DBH->prepare("SELECT client_id, 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;");
} elsif($function_name eq 'getClientInfo') {
$sth = $DBH->prepare("SELECT client_id, hostname, ip_net_client, receive_own_events FROM clients WHERE hostname IN ($alt_names) ORDER BY SUBSTRING_INDEX(ip_net_client,'/', -1) DESC;");
} elsif($function_name eq 'getLastId') {
$sth = $DBH->prepare("SELECT client_id, hostname, ip_net_client, receive_own_events FROM clients WHERE hostname IN ($alt_names) AND client_type = 'r' ORDER BY SUBSTRING_INDEX(ip_net_client,'/', -1) DESC;");
}
# check db handler
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare authorization statement in $function_name: $DBH->errstr",
"Internal 'prepare' server error")
}
Tomáš Plesník
committed
Tomáš Plesník
committed
# execute query for two or none params functions
if ($function_name eq 'saveNewEvent' || $function_name eq 'getNewEvents') {
$sth->execute($service_type, $client_type);
} else {
$sth->execute;
}
# obtain registration info about clients
my ($client_id, $an, $cidr, $receive_own, $cidr_list);
Tomáš Plesník
committed
my $correct_ip_source = 0;
my %ret;
Tomáš Plesník
committed
while(($client_id, $an, $cidr, $receive_own) = $sth->fetchrow()) {
Tomáš Plesník
committed
my $cidr_list = Net::CIDR::Lite-> new -> add($cidr);
Tomáš Plesník
committed
$ret{'client_id'} = $client_id;
$ret{'dns'} = $an;
$ret{'cidr'} = $cidr;
Tomáš Plesník
committed
$ret{'receive_own'} = $receive_own;
if ($cidr_list->bin_find($ip)) {
$correct_ip_source = 1;
last;
Tomáš Plesník
committed
}
Tomáš Plesník
committed
# check if client is registered
if ($sth->rows == 0) {
Tomáš Plesník
committed
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'}");
Tomáš Plesník
committed
return undef;
}
# check if client has IP from registered CIDR
if (!$correct_ip_source) {
Tomáš Plesník
committed
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");
Tomáš Plesník
committed
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);
Tomáš Plesník
committed
# client network information
my $cn = $ENV{'SSL_CLIENT_S_DN_CN'};
my $alt_names = getAltNames(undef);
my $ip = $ENV{'REMOTE_ADDR'};
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)
Tomáš Plesník
committed
# parse object (event) parameters
my $service = $data->{'SERVICE'};
my $detected = $data->{'DETECTED'};
Tomáš Plesník
committed
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'};
Tomáš Plesník
committed
my $note = $data->{'NOTE'};
my $priority = $data->{'PRIORITY'};
my $timeout = $data->{'TIMEOUT'};
my %client = authorizeClient($alt_names, $ip, $service, $client_type, $function_name);
Tomáš Plesník
committed
if(defined %client) {
Tomáš Plesník
committed
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) {
Tomáš Plesník
committed
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) {
Tomáš Plesník
committed
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) {
Tomáš Plesník
committed
sendMsg("err",
"Unknown priority - client from: '$ip'; CN(AN): $alt_names; used priority: '$priority'",
"Unknown priority '$priority'");
} elsif ($timeout !~ /^\d+\z/ && defined $timeout) {
Tomáš Plesník
committed
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 (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);");
Tomáš Plesník
committed
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;
}
Tomáš Plesník
committed
}
} # END of saveNewEvent
#-----------------------------------------------------------------------------
# getNewEvents - get new events from the DB greater than received ID
#-----------------------------------------------------------------------------
sub getNewEvents
{
my ($class, $data) = @_;
Tomáš Plesník
committed
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);
Tomáš Plesník
committed
# client network information
Tomáš Plesník
committed
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';
my $requested_type = $data->{'REQUESTED_TYPE'} || '_any_';
my $last_id = $data->{'LAST_ID'};
Tomáš Plesník
committed
my $max_rcv_events_limit = $data->{'MAX_RCV_EVENTS_LIMIT'}; # client events limit
# comparison of client and server limit - which can be used
Tomáš Plesník
committed
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);
Tomáš Plesník
committed
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 ?;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare ROE-ANY statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
$sth->execute($last_id, $used_limit);
Tomáš Plesník
committed
} else {
$sth = $DBH->prepare("SELECT * FROM events WHERE type != 'test' AND id > ? AND type = ? AND valid = 't' ORDER BY id ASC LIMIT ?;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare ROE statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
$sth->execute($last_id, $requested_type, $used_limit);
Tomáš Plesník
committed
}
Tomáš Plesník
committed
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 ?;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare ANY statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
my ($domain) = $cn =~ /([^\.]+\.[^\.]+)$/;
$domain = '\%' . $domain;
Tomáš Plesník
committed
$sth->execute($last_id, $domain, $used_limit);
Tomáš Plesník
committed
} 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 ?;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare statement in function '$function_name': $DBH->errstr\n",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
my ($domain) = $cn =~ /([^\.]+\.[^\.]+)$/;
$domain = '\%' . $domain;
Tomáš Plesník
committed
$sth->execute($last_id, $requested_type, $domain, $used_limit);
Tomáš Plesník
committed
}
}
# 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];
Tomáš Plesník
committed
$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(
Tomáš Plesník
committed
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),
Tomáš Plesník
committed
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
Tomáš Plesník
committed
if (scalar @events != 0) {
if (scalar @ids == 1) {
Tomáš Plesník
committed
sendMsg("info",
Tomáš Plesník
committed
"Sent 1 event [#$ids[0]] to '$ip' [CN(AN): $alt_names], client_limit: '$max_rcv_events_limit', requested_type: '$requested_type'",
Tomáš Plesník
committed
undef);
Tomáš Plesník
committed
} else {
Tomáš Plesník
committed
sendMsg("info",
Tomáš Plesník
committed
"Sent " . scalar @ids . " events [#$ids[0] - #$ids[-1]] to '$ip' [CN(AN): $alt_names], client_limit: '$max_rcv_events_limit', requested_type: '$requested_type'",
Tomáš Plesník
committed
undef);
Tomáš Plesník
committed
}
}
return @events;
}
} # END of getNewEvents
Tomáš Plesník
committed
#-----------------------------------------------------------------------------
# getLastId - get lastest saved event ID
#-----------------------------------------------------------------------------
sub getLastId
{
my ($class, $arg) = @_;
Tomáš Plesník
committed
# client network information
my $cn = $ENV{'SSL_CLIENT_S_DN_CN'};
my $alt_names = getAltNames(undef);
my $ip = $ENV{'REMOTE_ADDR'};
my $service = undef;
my $client_type = undef;
my $function_name = 'getLastId';
Tomáš Plesník
committed
my %client = authorizeClient($alt_names, $ip, $service, $client_type, $function_name);
if (defined %client) {
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;
Tomáš Plesník
committed
}
Tomáš Plesník
committed
#-----------------------------------------------------------------------------
# registerSender - register new sender
#-----------------------------------------------------------------------------
sub registerSender
{
my ($class, $data) = @_;
my $sth;
Tomáš Plesník
committed
# 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';
Tomáš Plesník
committed
if ($local_ip ne $ip) {
Tomáš Plesník
committed
sendMsg("err",
"Unauthorized access to function '$function_name' from: '$ip' ('$cn') - access allowed only from localhost",
"Access denied - access allowed only from localhost");
Tomáš Plesník
committed
# defined variables by method
my $client_type = "s";
my $registered = DateTime->now;
Tomáš Plesník
committed
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
Tomáš Plesník
committed
$sth = $DBH->prepare("SELECT registered FROM clients WHERE hostname = ? AND service = ? AND client_type = ? AND ip_net_client = ? LIMIT 1;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
$sth->execute($hostname, $service, $client_type, $ip_net_client);
my $result = $sth->fetchrow();
# register new sender
if (defined $result) {
Tomáš Plesník
committed
sendMsg("err",
Tomáš Plesník
committed
"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'");
Tomáš Plesník
committed
$sth = $DBH->prepare("INSERT INTO clients VALUES (?,?,?,?,?,?,?,?,?,?);");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
$sth->execute(undef, $hostname, $registered, $requestor, $service, $client_type, $type, $receive_own_events, $description_tags, $ip_net_client);
Tomáš Plesník
committed
sendMsg("info",
"New sender '$hostname' {service: '$service', cidr: '$ip_net_client'} was registered at $ENV{'SERVER_NAME'}",
Tomáš Plesník
committed
undef);
return 1;
}
}
} # END of registerSender
Tomáš Plesník
committed
#-----------------------------------------------------------------------------
# registerReceiver - register new receiver
#-----------------------------------------------------------------------------
sub registerReceiver
{
my ($class, $data) = @_;
my $sth;
Tomáš Plesník
committed
# 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';
Tomáš Plesník
committed
if ($local_ip ne $ip) {
Tomáš Plesník
committed
sendMsg("err",
"Unauthorized access to function '$function_name' from: '$ip' ('$cn') - access allowed only from localhost",
"Access denied - access allowed only from localhost");
Tomáš Plesník
committed
# variables defined by method
my $client_type = "r";
my $registered = DateTime->now;
Tomáš Plesník
committed
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
Tomáš Plesník
committed
$sth = $DBH->prepare("SELECT registered FROM clients WHERE hostname = ? AND client_type = ? AND type = ? AND ip_net_client = ? LIMIT 1;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
$sth->execute($hostname, $client_type, $type, $ip_net_client);
my $result = $sth->fetchrow();
# register new receiver
if (defined $result) {
Tomáš Plesník
committed
sendMsg("err",
Tomáš Plesník
committed
"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'");
Tomáš Plesník
committed
$sth = $DBH->prepare("INSERT INTO clients VALUES (?,?,?,?,?,?,?,?,?,?);");
Tomáš Plesník
committed
if (!defined($sth)) {
sendMsg("err",
"Cannot prepare statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
$sth->execute(undef, $hostname, $registered, $requestor, $service, $client_type, $type, $receive_own_events, $description_tags, $ip_net_client);
Tomáš Plesník
committed
sendMsg("info",
"New receiver '$hostname' {type: '$type', cidr: '$ip_net_client'} was registered at $ENV{'SERVER_NAME'}",
Tomáš Plesník
committed
undef);
return 1;
}
}
} # END of registerReceiver
#-----------------------------------------------------------------------------
# unregisterClient - unregister client
#-----------------------------------------------------------------------------
sub unregisterClient
{
my ($class, $data) = @_;
my $sth;
Tomáš Plesník
committed
# 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';
Tomáš Plesník
committed
if ($local_ip ne $ip) {
Tomáš Plesník
committed
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
Tomáš Plesník
committed
$sth = $DBH->prepare("SELECT client_id, hostname, service, client_type FROM clients WHERE client_id = ? LIMIT 1;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
$sth->execute($client_id);
my ($id, $hostname, $service, $client_type) = $sth->fetchrow();
# delete registered client
if (!defined $id) {
Tomáš Plesník
committed
sendMsg("err",
"Attempt to delete unregister client '$id', '$hostname', '$service', '$client_type'",
"Client (#$client_id) is not registered at $ENV{'SERVER_NAME'}");
Tomáš Plesník
committed
$sth = $DBH->prepare("DELETE FROM clients WHERE client_id = ?;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
$sth->execute($client_id);
Tomáš Plesník
committed
$sth = $DBH->prepare("UPDATE events SET valid = 'f' where hostname = ? AND service = ?;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
$sth->execute($hostname, $service);
Tomáš Plesník
committed
sendMsg("info",
"Sender '$hostname' (client_id: '$client_id', service: '$service') was deleted and its data were invalidated",
undef);
Tomáš Plesník
committed
$sth = $DBH->prepare("DELETE FROM clients WHERE client_id = ?;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
$sth->execute($client_id);
Tomáš Plesník
committed
sendMsg("info",
"Receiver '$hostname' (client_id: '$client_id') was deleted from $ENV{'SERVER_NAME'}",
Tomáš Plesník
committed
undef);
return 1;
}
}
}
} # END of unregisterClient
#-----------------------------------------------------------------------------
# getStatus - get list of status items of warden server
#-----------------------------------------------------------------------------
sub getStatus
{
my ($class, $arg) = @_;
Tomáš Plesník
committed
# 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';
Tomáš Plesník
committed
#-----------------------------------------------------------------------------
# Warden server stats
Tomáš Plesník
committed
if ($local_ip ne $ip) {
Tomáš Plesník
committed
sendMsg("err",
"Unauthorized access to function '$function_name' from: '$ip' ('$cn') - access allowed only from localhost",
"Access denied - access allowed only from localhost");
Tomáš Plesník
committed
# 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'};
Tomáš Plesník
committed
$sth = $DBH->prepare("SELECT data_length + index_length FROM information_schema.TABLES WHERE table_schema = ? AND TABLE_NAME = ?");
Tomáš Plesník
committed
$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';");
Tomáš Plesník
committed
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;");
Tomáš Plesník
committed
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);");
Tomáš Plesník
committed
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);");
Tomáš Plesník
committed
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;");
Tomáš Plesník
committed
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),
Tomáš Plesník
committed
SOAP::Data->name(HOSTNAME => $hostname),
SOAP::Data->name(IP_ADDRESS => $ip_address),
SOAP::Data->name(PORT => $port),
Tomáš Plesník
committed
SOAP::Data->name(SYSLOG => $SYSLOG),
SOAP::Data->name(SYSLOG_VERBOSE => $SYSLOG_VERBOSE),
SOAP::Data->name(SYSLOG_FACILITY => $SYSLOG_FACILITY),
Tomáš Plesník
committed
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);
Tomáš Plesník
committed
#---------------------------------------------------------------------------
# Statistics table of senders
$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;");
Tomáš Plesník
committed
if (!defined $sth) {
sendMsg("err",
"Cannot prepare statement in function '$function_name': $DBH->errstr",
"Internal 'prepare' server error");
}
Tomáš Plesník
committed
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(
Tomáš Plesník
committed
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)"}),
Tomáš Plesník
committed
push(@status, $client_status);
Tomáš Plesník
committed
sendMsg("info",
"Sent warden server status info from $ENV{'SERVER_NAME'}",
Tomáš Plesník
committed
undef);
return @status;
}
} # END of getStatus
Tomáš Plesník
committed
#-------------------------------------------------------------------------------
# getClientInfo - get list of registered clients on Warden server
# by Warden client
Tomáš Plesník
committed
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
#-------------------------------------------------------------------------------
sub getClientInfo
{
my ($class, $data) = @_;
my (@clients, $client);
my ($client_id, $hostname, $registered, $requestor, $service, $client_type, $type, $receive_own_events, $description_tags, $ip_net_client);
# client network information
my $cn = $ENV{'SSL_CLIENT_S_DN_CN'};
my $alt_names = getAltNames(undef);
my $ip = $ENV{'REMOTE_ADDR'};
my $service = undef;
my $client_type = undef;
my $function_name = 'getClientInfo';
my %client = authorizeClient($alt_names, $ip, $service, $client_type, $function_name);
if (defined %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 getClientInfo