Skip to content
Snippets Groups Projects
Commit adac7952 authored by Pavel Kácha's avatar Pavel Kácha
Browse files

Brown paper bag commit

parent 4f0d6bf7
No related branches found
No related tags found
No related merge requests found
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# #
# WardenClientCommon.pm # WardenClientCommon.pm
# #
# Copyright (C) 2011-2013 Cesnet z.s.p.o # Copyright (C) 2011-2012 Cesnet z.s.p.o
# #
# Use of this source is governed by a BSD-style license, see LICENSE file. # Use of this source is governed by a BSD-style license, see LICENSE file.
...@@ -10,9 +10,14 @@ package WardenClientCommon; ...@@ -10,9 +10,14 @@ package WardenClientCommon;
use strict; use strict;
use Carp; use Carp;
use SOAP::Lite;
use IO::Socket::SSL qw(debug1); use Net::SSLeay qw(post_https make_headers make_form
use SOAP::Transport::HTTP; load_error_strings
set_cert_and_key set_fd
get_peer_certificate ssl_write_all
print_errs die_if_ssl_error die_now ssl_read_all);
use XML::Parser;
use Data::Dumper;
our $VERSION = "2.2"; our $VERSION = "2.2";
...@@ -50,6 +55,164 @@ sub errMsg ...@@ -50,6 +55,164 @@ sub errMsg
} # End of errMsg } # End of errMsg
#-------------------------------------------------------------------------------
# https_send_receive - send $out_message, return (data, http error, headers)
#-------------------------------------------------------------------------------
sub https_send_receive
{
my ($dest_serv, $port, $out_message, $crt_path, $key_path, $ca_path) = @_;
my ($ctx, $ssl, $res, $errs);
($res, $errs) = Net::SSLeay::open_tcp_connection($dest_serv, $port);
goto final unless $res;
# SSLeay init
load_error_strings();
Net::SSLeay::SSLeay_add_ssl_algorithms();
Net::SSLeay::randomize();
# Setup and configure protocol context
$ctx = Net::SSLeay::new_x_ctx();
goto cleanup2 if $errs = print_errs('CTX_new') or !$ctx;
Net::SSLeay::CTX_set_options($ctx, &Net::SSLeay::OP_ALL);
goto cleanup2 if $errs = print_errs('CTX_set_options');
# Setup certificates
warn "Cert `$crt_path' given without key" if $crt_path && !$key_path;
set_cert_and_key($ctx, $crt_path, $key_path) if $crt_path;
# Set allowed CAs and require Warden server peer verify
Net::SSLeay::CTX_load_verify_locations($ctx, $ca_path, '');
goto cleanup2 if $errs = print_errs('CTX_load_verify_locations');
Net::SSLeay::CTX_set_verify($ctx, &Net::SSLeay::VERIFY_PEER, 0);
goto cleanup2 if $errs = print_errs('CTX_set_verify');
# Create SSL session
$ssl = Net::SSLeay::new($ctx);
goto cleanup if $errs = print_errs('SSL_new') or !$ssl;
# Attach filehandle and connect
set_fd($ssl, fileno(Net::SSLeay::SSLCAT_S));
goto cleanup if $errs = print_errs('set_fd');
$res = Net::SSLeay::connect($ssl);
goto cleanup_shut if $errs = print_errs('SSL_connect');
# Ok, exchange data
($res, $errs) = ssl_write_all($ssl, $out_message);
goto cleanup_shut unless $res;
($res, $errs) = ssl_read_all($ssl);
cleanup_shut:
shutdown Net::SSLeay::SSLCAT_S, 2;
cleanup:
Net::SSLeay::free ($ssl);
$errs .= print_errs('SSL_free');
cleanup2:
Net::SSLeay::CTX_free ($ctx);
$errs .= print_errs('CTX_free');
close Net::SSLeay::SSLCAT_S;
final:
$res = "HTTP/1.0 900 NET OR SSL ERROR\r\n\r\n$errs\r\n\r\n$res" if $errs;
my ($prolog, $data) = split /\s?\n\s?\n/, $res, 2;
my ($ret, $headers) = split /\s?\n/, $prolog, 2;
return wantarray ? ($data, $ret, $headers) : $data;
}
#-------------------------------------------------------------------------------
# expat2hash - convert convoluted expat list of lists to simpler hash
#-------------------------------------------------------------------------------
sub expat2hash {
my $l = shift;
# send XML attributes to the fiery pits of hell
if (ref($l->[0]) eq "HASH") {
shift(@{$l});
}
my $res = {};
while (scalar(@{$l})!=0) {
my $key = shift(@{$l});
my $value = shift(@{$l});
if (ref($value) eq "ARRAY") {
# process sublists recursively
$value = expat2hash($value);
}
push(@{$res->{$key}}, $value);
};
# flatten list singles
# special case warden events to simplify access, we want
# them in list even if only single event arrives
for my $key (keys %{$res}) {
if (scalar(@{$res->{$key}})==1 and not ($key eq 'event')) {
$res->{$key} = $res->{$key}->[0];
}
}
# nil values yield empty hashes now
if (!%{$res}) {
undef $res;
}
# flatten XML text node singles
elsif (scalar(keys(%{$res}))==1 and exists $res->{'0'}) {
$res = $res->{'0'};
};
return $res;
}
#-------------------------------------------------------------------------------
# hash2soapquery - convert parameters from hash into SOAP query payload
#-------------------------------------------------------------------------------
sub hash2soapquery {
my ($server, $port, $service, $method, $data) = @_;
my @datalist;
while (my ($key, $value) = each %{$data} )
{
if (!defined $value) {
push @datalist, "<$key xsi:nil=\"true\" />"
} elsif ($value =~ /^[+-]?\d+\z/) {
push @datalist, "<$key xsi:type=\"xsd:int\">$value</$key>"
} else {
push @datalist, "<$key xsi:type=\"xsd:string\">$value</$key>"
}
}
my $payload =
'<?xml version="1.0" encoding="UTF-8"?>' .
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' .
'<soap:Body>' .
"<$method xmlns=\"Warden\">" .
'<request>' .
join("", @datalist) .
'</request>' .
"</$method>" .
'</soap:Body>' .
'</soap:Envelope>';
my $paylen = length($payload);
my $header =
"POST /$service HTTP/1.1\r\n" .
"Host: $server:$port\r\n" .
"Content-Type: application/soap+xml; charset=utf-8\r\n" .
"Content-Length: $paylen\r\n" .
"SOAPAction: \"http://www.w3.org/2003/05/soap-envelope\"\r\n" .
"\r\n";
return $header . $payload;
}
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# c2s - connect to server, send request and receive response # c2s - connect to server, send request and receive response
...@@ -65,62 +228,40 @@ sub c2s ...@@ -65,62 +228,40 @@ sub c2s
my $client; my $client;
my ($server, $port, $service) = $uri =~ /https:\/\/(.+)\:(\d+)\/(.+)/; my ($server, $port, $service) = $uri =~ /https:\/\/(.+)\:(\d+)\/(.+)/;
eval {
$client = SOAP::Transport::HTTP::Client->new();
} or return errMsg('Unknown error in c2s() when creating socket, SOAP::Transport::HTTP::Client->new(), ' . $@);
eval {$client->timeout($WardenClientConf::CONNECTION_TIMEOUT);}
or return errMsg('Unknown error in c2s() when setting socket timeout, ' . $@);
eval { # format HTTP request
$client->ssl_opts(verify_hostname => 1, my $message = hash2soapquery($server, $port, $service, $method, $data);
SSL_use_cert => 1,
SSL_verify_mode => 0x02, my ($res, $err);
SSL_key_file => $ssl_key_file,
SSL_cert_file => $ssl_cert_file,
SSL_ca_file => $ssl_ca_file);
return 1; # fix of eval triggering 'or' statement
} or return errMsg('Unknown error in c2s() when setting socket SSL options, ' . $@);
# setting of URI and serialize SOAP envelope and data object
my $soap;
eval {
$soap = SOAP::Lite->uri($service)->proxy($uri);
} or return errMsg('Unknown error in c2s() when serializing SOAP object, ' . $@);
my $envelope;
if (!defined $data) {
eval {
$envelope = $soap->serializer->envelope(method => $method);
} or return errMsg('Unknown error in c2s() when setting enevelope, ' . $@);
} else {
eval {
$envelope = $soap->serializer->envelope(method => $method, $data);
} or return errMsg('Unknown error in c2s() when setting envelope, ' . $@);
}
# setting of TCP URI and send serialized SOAP envelope and data
my $server_uri = "https://$server:$port/$service";
my $result;
eval { eval {
$result = $client->send_receive(envelope => $envelope, endpoint => $server_uri); ($res, $err, undef) = https_send_receive($server, $port, $message, $ssl_cert_file, $ssl_key_file, $ssl_ca_file)
} or return errMsg('Unknown error in c2s() sending SOAP data, ' . $@); } or return errMsg('Unknown error in c2s() sending SOAP data, ' . $@);
# check HTTP error
my ($code) = $err =~ /[^ ]* ([^ ]*) /;
if ($code != "200") {
return errMsg("Server returned HTTP error: $err.");
}
# check server response # check server response
if (!defined $result) { if (!defined $res) {
errMsg("Server returned empty response. Problem with used SSL ceritificates or Warden server at $server:$port is down."); return errMsg("Server returned empty response. Problem with used SSL ceritificates or Warden server at $server:$port is down.");
} else {
# deserialized response from server -> create SOAP envelope and data object
my $response;
eval {
$response = $soap->deserializer->deserialize($result);
} or return errMsg('Unknown error in SOAP data deserialization. Received data: ' . $result . ', ' . $@);
# check SOAP fault status
$response->fault ? return errMsg("Server sent error message:: " . $response->faultstring) : return $response;
} }
# deserialize response from server
my $result;
eval {
my $parser = XML::Parser->new(Style => "Tree", ErrorContext => 2);
$result = expat2hash($parser->parse($res));
} or return errMsg('Unknown error in SOAP data deserialization. Received data: ' . $res . ', ' . $@);
# Flatten unneeded branches if structure is sane
unless (exists($result->{'soap:Envelope'}) and exists($result->{'soap:Envelope'}->{'soap:Body'})) {
return errMsg('Server returned unexpected SOAP response. Received data: ' . $res);
}
$result = $result->{'soap:Envelope'}->{'soap:Body'};
return $result;
} }
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
......
...@@ -2,16 +2,13 @@ ...@@ -2,16 +2,13 @@
# #
# WardenClientReceive.pm # WardenClientReceive.pm
# #
# Copyright (C) 2011-2013 Cesnet z.s.p.o # Copyright (C) 2011-2012 Cesnet z.s.p.o
# #
# Use of this source is governed by a BSD-style license, see LICENSE file. # Use of this source is governed by a BSD-style license, see LICENSE file.
package WardenClientReceive; package WardenClientReceive;
use strict; use strict;
use SOAP::Lite;
use IO::Socket::SSL qw(debug1);
use SOAP::Transport::HTTP;
use FindBin; use FindBin;
use Sys::Syslog; use Sys::Syslog;
...@@ -57,7 +54,9 @@ sub getNewEvents ...@@ -57,7 +54,9 @@ sub getNewEvents
my $response = WardenClientCommon::c2s($WardenClientConf::URI, $WardenClientConf::SSL_KEY_FILE, $WardenClientConf::SSL_CERT_FILE, $WardenClientConf::SSL_CA_FILE, "getLastId"); my $response = WardenClientCommon::c2s($WardenClientConf::URI, $WardenClientConf::SSL_KEY_FILE, $WardenClientConf::SSL_CERT_FILE, $WardenClientConf::SSL_CA_FILE, "getLastId");
defined $response or return; # receive data or return undef defined $response or return; # receive data or return undef
$last_id = $response->result; # SOAP generates random names for unnamed return values, we sidestep through array
my @last_id = values(%{$response->{'getLastIdResponse'}});
$last_id = $last_id[0];
open(ID, "> $id_file") or return WardenClientCommon::errMsg("Cannot open ID file $id_file: $!"); open(ID, "> $id_file") or return WardenClientCommon::errMsg("Cannot open ID file $id_file: $!");
print ID $last_id; print ID $last_id;
close ID; close ID;
...@@ -66,29 +65,23 @@ sub getNewEvents ...@@ -66,29 +65,23 @@ sub getNewEvents
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# get new events from warden server DB based on gathered last ID # get new events from warden server DB based on gathered last ID
my $request_data; my %request_data = (
eval { "REQUESTED_TYPE" => $requested_type,
# create SOAP data object "LAST_ID" => $last_id,
$request_data = SOAP::Data->name( "MAX_RCV_EVENTS_LIMIT" => $WardenClientConf::MAX_RCV_EVENTS_LIMIT
request => \SOAP::Data->value( );
SOAP::Data->name(REQUESTED_TYPE => $requested_type),
SOAP::Data->name(LAST_ID => $last_id),
SOAP::Data->name(MAX_RCV_EVENTS_LIMIT => $WardenClientConf::MAX_RCV_EVENTS_LIMIT)
)
)
} or return errMsg('Unknown error when creating SOAP data object, ' . $@);
# call server method getNewEvents # call server method getNewEvents
my $response = WardenClientCommon::c2s($WardenClientConf::URI, $WardenClientConf::SSL_KEY_FILE, $WardenClientConf::SSL_CERT_FILE, $WardenClientConf::SSL_CA_FILE, "getNewEvents", $request_data); my $response = WardenClientCommon::c2s($WardenClientConf::URI, $WardenClientConf::SSL_KEY_FILE, $WardenClientConf::SSL_CERT_FILE, $WardenClientConf::SSL_CA_FILE, "getNewEvents", \%request_data);
defined $response or return; # connect to warden server or return undef defined $response or return; # connect to warden server or return undef
# parse returned SOAP data object # parse returned SOAP data object
my ($id, $hostname, $service, $detected, $type, $source_type, $source, $target_proto, $target_port, $attack_scale, $note, $priority, $timeout); my ($id, $hostname, $service, $detected, $type, $source_type, $source, $target_proto, $target_port, $attack_scale, $note, $priority, $timeout);
my @response_list = $response->valueof('/Envelope/Body/getNewEventsResponse/event/'); my $response_list = ($response->{'getNewEventsResponse'}->{'event'} or []);
while (scalar @response_list) { while (scalar @{$response_list}) {
my $response_data = shift(@response_list); my $response_data = shift(@{$response_list});
my @event; my @event;
# parse items of one event # parse items of one event
......
...@@ -2,16 +2,13 @@ ...@@ -2,16 +2,13 @@
# #
# WardenClientSend.pm # WardenClientSend.pm
# #
# Copyright (C) 2011-2013 Cesnet z.s.p.o # Copyright (C) 2011-2012 Cesnet z.s.p.o
# #
# Use of this source is governed by a BSD-style license, see LICENSE file. # Use of this source is governed by a BSD-style license, see LICENSE file.
package WardenClientSend; package WardenClientSend;
use strict; use strict;
use SOAP::Lite;
use IO::Socket::SSL qw(debug1);
use SOAP::Transport::HTTP;
use Sys::Syslog; use Sys::Syslog;
our $VERSION = "2.2"; our $VERSION = "2.2";
...@@ -23,71 +20,63 @@ sub saveNewEvent ...@@ -23,71 +20,63 @@ sub saveNewEvent
{ {
my $result; my $result;
my $warden_path = shift; my $warden_path = shift;
my $event_ref = shift; my $event_ref = shift;
my $etcdir = $warden_path . "/etc/"; my $etcdir = $warden_path . "/etc/";
my $libdir = $warden_path . "/lib/"; my $libdir = $warden_path . "/lib/";
require $libdir . "WardenClientConf.pm"; require $libdir . "WardenClientConf.pm";
require $libdir . "WardenClientCommon.pm"; require $libdir . "WardenClientCommon.pm";
# read the config file # read the config file
my $conf_file = $etcdir . "warden-client.conf"; my $conf_file = $etcdir . "warden-client.conf";
WardenClientConf::loadConf($conf_file); WardenClientConf::loadConf($conf_file);
# prepare variables of event # prepare variables of event
my @event = @{$event_ref}; my @event = @{$event_ref};
my $service = $event[0]; my $service = $event[0];
my $detected = $event[1]; my $detected = $event[1];
my $type = $event[2]; my $type = $event[2];
my $source_type = $event[3]; my $source_type = $event[3];
my $source = $event[4]; my $source = $event[4];
my $target_proto = $event[5]; my $target_proto = $event[5];
my $target_port = $event[6]; my $target_port = $event[6];
my $attack_scale = $event[7]; my $attack_scale = $event[7];
my $note = $event[8]; my $note = $event[8];
my $priority = $event[9]; my $priority = $event[9];
my $timeout = $event[10]; my $timeout = $event[10];
# Issue #596 - Should be removed in Warden client 3.0. # Issue #596 - Should be removed in Warden client 3.0.
# Checking for obsolete attributes priority or timeout. If not default or 'undef' values are found, print out warning. # Checking for obsolete attributes priority or timeout. If not default or 'undef' values are found, print out warning.
# check if obsolete event attribute Priority is used # check if obsolete event attribute Priority is used
if ((defined $priority) && ($priority >= 1)) { if ((defined $priority) && ($priority >= 1)) {
# print warning # print warning
WardenClientCommon::errMsg('Event attribute "Priority" is now obsolete and will be removed in Warden client 3.0', 'warn'); WardenClientCommon::errMsg('Event attribute "Priority" is now obsolete and will be removed in Warden client 3.0', 'warn');
} }
# check if obsolete event attribute Timeout is used # check if obsolete event attribute Timeout is used
if ((defined $timeout) && ($timeout >= 0)) { if ((defined $timeout) && ($timeout >= 0)) {
# print warning # print warning
WardenClientCommon::errMsg('Event attribute "Timeout" is now obsolete and will be removed in Warden client 3.0', 'warn'); WardenClientCommon::errMsg('Event attribute "Timeout" is now obsolete and will be removed in Warden client 3.0', 'warn');
} }
# end of Issue #596 # end of Issue #596
my $event = {
my $event; SERVICE => $service,
eval { DETECTED => $detected,
# create SOAP data object TYPE => $type,
$event = SOAP::Data->name( SOURCE_TYPE => $source_type,
event => \SOAP::Data->value( SOURCE => $source,
SOAP::Data->name(SERVICE => $service), TARGET_PROTO => $target_proto,
SOAP::Data->name(DETECTED => $detected), TARGET_PORT => $target_port,
SOAP::Data->name(TYPE => $type), ATTACK_SCALE => $attack_scale,
SOAP::Data->name(SOURCE_TYPE => $source_type), NOTE => $note,
SOAP::Data->name(SOURCE => $source), PRIORITY => $priority,
SOAP::Data->name(TARGET_PROTO => $target_proto), TIMEOUT => $timeout
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)
)
);
} # end of eval
or WardenClientCommon::errMsg('Unknown error when creating SOAP data object, ' . $@);
# c2s() returns undef on fail. # c2s() returns undef on fail.
$result = WardenClientCommon::c2s($WardenClientConf::URI, $WardenClientConf::SSL_KEY_FILE, $WardenClientConf::SSL_CERT_FILE, $WardenClientConf::SSL_CA_FILE, "saveNewEvent", $event); $result = WardenClientCommon::c2s($WardenClientConf::URI, $WardenClientConf::SSL_KEY_FILE, $WardenClientConf::SSL_CERT_FILE, $WardenClientConf::SSL_CA_FILE, "saveNewEvent", $event);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment