diff options
author | Tobi Oetiker <tobi@oetiker.ch> | 2006-07-14 11:00:28 +0200 |
---|---|---|
committer | Tobi Oetiker <tobi@oetiker.ch> | 2006-07-14 11:00:28 +0200 |
commit | 1156e3f7256585535d875e6056651cb93f0abf94 (patch) | |
tree | 12e5fefaf37055b1efe9716299ae6e8226285d66 | |
parent | f23f0db53df28f650056bd4ae5f644aa998bee2c (diff) | |
download | smokeping-1156e3f7256585535d875e6056651cb93f0abf94.tar.gz smokeping-1156e3f7256585535d875e6056651cb93f0abf94.tar.xz |
added tacacsplus probe -- Gary.Mikula nasd.com
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | lib/Smokeping/probes/TacacsPlus.pm | 256 |
2 files changed, 258 insertions, 0 deletions
@@ -1,3 +1,5 @@ +* added TacacsPlus probe -- tobi, Gary.Mikula nasd.com + 2006/7/14 -- released version 20060714_trunk 2006/7/13 -- released version 20060713_trunk diff --git a/lib/Smokeping/probes/TacacsPlus.pm b/lib/Smokeping/probes/TacacsPlus.pm new file mode 100644 index 0000000..7cc9173 --- /dev/null +++ b/lib/Smokeping/probes/TacacsPlus.pm @@ -0,0 +1,256 @@ +package Smokeping::probes::TacacsPlus; + +=head1 301 Moved Permanently + +This is a Smokeping probe module. Please use the command + +C<smokeping -man Smokeping::probes::TacacsPlus> + +to view the documentation or the command + +C<smokeping -makepod Smokeping::probes::TacacsPlus> + +to generate the POD document. + +=cut +use strict; +use base qw(Smokeping::probes::passwordchecker); +use Authen::TacacsPlus; +use Time::HiRes qw(gettimeofday sleep); +use Carp; + +my $DEFAULTINTERVAL = 1; + +sub pod_hash { + return { + name => <<DOC, +Smokeping::probes::TacacsPlus - a TacacsPlus authentication probe for SmokePing +DOC + overview => <<DOC, +Measures TacacsPlus authentication latency for SmokePing +DOC + description => <<DOC, +This probe measures TacacsPlus authentication latency for SmokePing. + +The username to be tested is specified in either the probe-specific or the +target-specific variable `username', with the target-specific one overriding +the probe-specific one. + +The password can be specified either (in order of precedence, with +the latter overriding the former) in the probe-specific variable +`password', in an external file or in the target-specific variable +`password'. The location of this file is given in the probe-specific +variable `passwordfile'. See Smokeping::probes::passwordchecker(3pm) for the +format of this file (summary: colon-separated triplets of the form +`<host>:<username>:<password>') + +The TacacsPlus protocol requires a shared secret between the server and the client. +This secret can be specified either (in order of precedence, with the latter +overriding the former) in the probe-specific variable `secret', in an external file +or in the target-specific variable `secret'. +This external file is located by the probe-specific variable `secretfile', and it should +contain whitespace-separated pairs of the form `<host> <secret>'. Comments and blank lines +are OK. + +The default TacacsPlus authentication type is ASCII. PAP and CHAP are also available. +See the Authen::TacacsPlus documentation for more information; + +The probe tries to be nice to the server and does not send authentication +requests more frequently than once every X seconds, where X is the value +of the target-specific "min_interval" variable ($DEFAULTINTERVAL by default). +DOC + authors => <<'DOC', +Gary Mikula <g2ugzm@hotmail.com> +DOC + bugs => <<DOC, +Not as yet.... +DOC + } +} + +sub ProbeDesc { + return "TacacsPlus Authentication Attempts"; +} + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = $class->SUPER::new(@_); + + # no need for this if we run as a cgi + unless ($ENV{SERVER_SOFTWARE}) { + if (defined $self->{properties}{secretfile}) { + my @stat = stat($self->{properties}{secretfile}); + my $mode = $stat[2]; + carp("Warning: secret file $self->{properties}{secretfile} is world-readable\n") + if defined $mode and $mode & 04; + open(S, "<$self->{properties}{secretfile}") + or croak("Error opening specified secret file $self->{properties}{secretfile}: $!"); + while (<S>) { + chomp; + next unless /\S/; + next if /^\s*#/; + my ($host, $secret) = split; + carp("Line $. in $self->{properties}{secretfile} is invalid"), next + unless defined $host and defined $secret; + $self->secret($host, $secret); + } + close S; + } + + } + + return $self; +} + +sub secret { + my $self = shift; + my $host = shift; + my $newval = shift; + + $self->{secret}{$host} = $newval if defined $newval; + return $self->{secret}{$host}; +} + +sub pingone { + my $self = shift; + my $target = shift; + my $host = $target->{addr}; + my $vars = $target->{vars}; + my $mininterval = $vars->{mininterval}; + my $username = $vars->{username}; + my $authen_type = $vars->{authtype}; + my $secret = $self->secret($host); + my @times; + my $elapsed; + my $result; + my $start; + my $authen; + my $end; + + if (defined $vars->{secret} and + $vars->{secret} ne ($self->{properties}{secret}||"")) { + $secret = $vars->{secret}; + } + $secret ||= $self->{properties}{secret}; + + my $timeout = $vars->{timeout}; + + $self->do_log("Missing TacacsPlus secret for $host"), return + unless defined $secret; + + $self->do_log("Missing TacacsPlus username for $host"), return + unless defined $username; + + my $password = $self->password($host, $username); + if (defined $vars->{password} and + $vars->{password} ne ($self->{properties}{password}||"")) { + $password = $vars->{password}; + } + $password ||= $self->{properties}{password}; + + $self->do_log("Missing TacacsPlus password for $host/$username"), return + unless defined $password; + + my $port = $vars->{port}; + $host .= ":$port" if defined $port; + + for (1..$self->pings($target)) { + if (defined $elapsed) { + my $timeleft = $mininterval - $elapsed; + sleep $timeleft if $timeleft > 0; + } + $host =~ s/:[0-9]+//g; + my $r = new Authen::TacacsPlus(Host => $host, Key => $secret, Port =>$port); + if( $r ) { + $start = gettimeofday(); + if( $authen_type eq 'PAP' ){ + $authen = &Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_PAP; + }elsif( $authen_type eq 'CHAP'){ + $authen = &Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_CHAP; + }else{ + $authen = &Authen::TacacsPlus::TAC_PLUS_AUTHEN_TYPE_ASCII; + } + if( $r->authen($username, $password, $authen ) ) { + $end = gettimeofday(); + $elapsed = $end - $start; + $self->do_debug("$host: TacacsPlus Authen Granted: $elapsed time"); + push @times, $elapsed; + $r->close(); + }else{ + $self->do_log("Unable to Autenticate to:$host with ID:$username Key:$secret"); + $result = "Unable to Authenticate Msg: " . Authen::TacacsPlus::errmsg(); + $self->do_debug("$result"); + } + }else{ + $self->do_log("Unable to Create Constructor Authen::TacacsPlus for host:$host"); + $result = "Unable to Build Constructor Msg: " . Authen::TacacsPlus::errmsg(); + $self->do_debug("$result"); + } + } + return sort { $a <=> $b } @times; +} + +sub probevars { + my $class = shift; + my $h = $class->SUPER::probevars; + delete $h->{timeout}; + return $class->_makevars($h, { + secretfile => { + _doc => <<DOC, +A file containing the TacacsPlus shared secrets for the targets. It should contain +whitespace-separated pairs of the form `<host> <secret>'. Comments and blank lines +are OK. +DOC + _example => '/another/place/secret', + _sub => sub { + my $val = shift; + -r $val or return "ERROR: secret file $val is not readable."; + return undef; + }, + }, + }); +} + +sub targetvars { + my $class = shift; + return $class->_makevars($class->SUPER::targetvars, { + _mandatory => [ 'username' ], + username => { + _doc => 'The username to be tested.', + _example => 'test-user', + }, + password => { + _doc => 'The password for the user, if not present in the password file.', + _example => 'test-password', + }, + secret => { + _doc => 'The TacacsPlus shared secret for the target, if not present in the secrets file.', + _example => 'test-secret', + }, + mininterval => { + _default => $DEFAULTINTERVAL, + _doc => "The minimum interval between each authentication request sent, in (possibly fractional) seconds.", + _re => '(\d*\.)?\d+', + }, + timeout => { + _default => 5, + _doc => "Timeout in seconds for the TacacsPlus queries.", + _re => '\d+', + }, + port => { + _default => 49, + _doc => 'The TacacsPlus port to be used', + _re => '\d+', + _example => 49, + }, + authtype => { + _default => 'ASCII', + _doc => 'The TacacsPlus Authentication type:ASCII(default), CHAP, PAP', + _re => '(ASCII|CHAP|PAP)', + _example => 'CHAP', + }, + }); +} + +1; |