Subject: | error code persistent across queries because not reset by set_error |
# $Id: Radius.pm,v 1.17 2007/02/20 06:15:04 andrew Exp $
This is perl, v5.8.8 built for x86_64-linux-gnu-thread-multi
Linux skunk 2.6.18-5-amd64 #1 SMP Sat Dec 22 20:43:59 UTC 2007 x86_64
GNU/Linux
problem: after one Authen::Radius objects encounters an error, it
maintains its error state forever even if new queries are performed.
I think that the error state should be cleared when a new radius query
is started (e.g. using check_pwd), but the set_error function sets error
to ENONE **only if not defined**.
context: I'm using Authen::Radius in a perl script (attached) as an
authentication helper for squid. Squid authentication helpers run
forever, reading unsername and password on each line and printing ERR or
OK, thus I'm re-using a single radius object for multiple queries.
As I want to be able to query 2 radius servers, I check the error status
after running check_pwd on the first server, and query the second server
unless its ENONE.
But I found out that, after one error was encountered, the same error
code was still there for subsequent queries.
I worked this around by re-creating the radius object if get_error
returns something different not ENONE.
after looking at the source, I see that there is an undocumented
set_error function, which I could have used to explicitly set ENONE
after reading the error status, but if this was the way it should at
least have been documented in
http://search.cpan.org/~manowar/RadiusPerl-0.09/Radius.pm.
Subject: | radius_auth.pl |
#!/usr/bin/perl
#-----------------------------------------------------------------------------------
# Author: Edmar Lourenco Borges;
# Authenticator Squid/Radius;
# Use perl modules perl RadiusPerl-0.05/MD5-1.7/IO-1.20
# Theses modules can be found in http://core.ring.gr.jp/archives/lang/perl/CPAN/modules
#-----------------------------------------------------------------------------------
# modified by MAtteo HCE Valsasna (matteo.valsasna@uninsubria.it)
# * support for 2 radius server with basic failover
# * timestamped logging
# * radius object re-creation on error
# * logging of error condition of errored object before query
# last modification 20080917
use Radius;
$|=1;
BEGIN {;}
END {print "ERR" unless $GLOBAL{loaded};}
#------------------------------------------------------------------------------
#Definition of globals variables:
#Radius Server: $Global{server1} = "" or "ip address[:port]"
#Simetric Key: $Global{key} = "string"
#------------------------------------------------------------------------------
$GLOBAL{loaded} = 0;
$GLOBAL{server1} = "rad-02:1812";
$GLOBAL{server2} = "rad-01:1812";
$GLOBAL{key} = "***";
$GLOBAL{timeout} = 100;
$GLOBAL{error};
$GLOBAL{radius1};
$GLOBAL{radius2};
$GLOBAL{errcount1}=0;
$GLOBAL{errcount2}=0;
$GLOBAL{err_thereshold}=0;
sub debug {
# strip newlines from comment string
s/\\n//;
# timestamp logs
my $now = localtime time;
# Uncomment this to enable debugging
print STDERR "radius_auth[$$]: $now @_\n";
}
main();
sub main {
# init radius objects
$GLOBAL{radius1} = new Authen::Radius(Host => $GLOBAL{server1}, Secret => $GLOBAL{key}, $GLOBAL{timeout}, Debug => 4);
if (! $GLOBAL{radius1} ){
&debug ("1st radius creation failed");
}
$GLOBAL{radius2} = new Authen::Radius(Host => $GLOBAL{server2}, Secret => $GLOBAL{key}, $GLOBAL{timeout}, Debug => 4);
if (! $GLOBAL{radius2} ){
&debug ("2nd radius creation failed");
}
&debug ("initialization completed. servers are $GLOBAL{server1} and $GLOBAL{server2}");
authentication();
} # end of main
sub authentication {
local(@info,$radius);
# use Authen::Radius;
#use Radius;
$GLOBAL{loaded} = 1;
while (<STDIN>) {
# check for error status before query
$error = $GLOBAL{radius1}->get_error;
if ($error ne 'ENONE') {
&debug ("WTF! error $error already set before query on $GLOBAL{server1}\n");
$GLOBAL{errcount1} ++;
if ($GLOBAL{errcount1}=0 > $GLOBAL{err_thereshold}){
&debug ("giving UP\n");
exit (1);
}
}
chop($_);
@info = split(/ / , $_);
# @info[0] =~ s/ateneo\\//;
$res = $GLOBAL{radius1}->check_pwd(@info[0], @info[1]) ? "OK\n" : "ERR\n";
$error = $GLOBAL{radius1}->get_error;
&debug ("checking @info[0] on $GLOBAL{server1}: ERRNO $error, RESULT $res");
if ($error ne 'ENONE') {
# reset radius1
$GLOBAL{radius1} = new Authen::Radius(Host => $GLOBAL{server1}, Secret => $GLOBAL{key}, $GLOBAL{timeout}, Debug => 4);
if (! $GLOBAL{radius1} ){
&debug ("1st radius RE-creation failed");
} else {
&debug ("1st radius RE-creation success");
}
# check for error status before query
$error = $GLOBAL{radius2}->get_error;
if ($error ne 'ENONE') {
&debug ("WTF! error $error already set before query on $GLOBAL{server2}\n");
$GLOBAL{errcount2} ++;
if ($GLOBAL{errcount2}=0 > $GLOBAL{err_thereshold}){
&debug ("giving UP\n");
exit (1);
}
}
$res = $GLOBAL{radius2}->check_pwd(@info[0], @info[1]) ? "OK\n" : "ERR\n";
$error = $GLOBAL{radius2}->get_error;
&debug ("checking again @info[0] on $GLOBAL{server2}: ERRNO $error, RESULT $res");
# reset radius2
if ($error ne 'ENONE') {
$GLOBAL{radius2} = new Authen::Radius(Host => $GLOBAL{server2}, Secret => $GLOBAL{key}, $GLOBAL{timeout}, Debug => 4);
if (! $GLOBAL{radius2} ){
&debug ("1st radius RE-creation failed");
} else {
&debug ("1st radius RE-creation success");
}
}
}
print $res;
}
} # end authentication