| Server IP : 173.209.174.21 / Your IP : 216.73.216.89 Web Server : Apache/2.4.58 (Ubuntu) System : Linux wcfs-server 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64 User : nodor ( 1000) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /proc/thread-self/root/sbin/ |
Upload File : |
#!/usr/bin/perl
#
# checkrad See if a user is (still) logged in on a certain port.
#
# This is used by the FreeRADIUS server to check
# if its idea of a user logged in on a certain port/nas
# is correct if a double login is detected.
#
# Called as: nas_type nas_ip nas_port login session_id
#
# Returns: 0 = no duplicate, 1 = duplicate, >1 = error.
#
# Version: $Id: c0cf440106232184228ec3d4dc79dacb21037ff8 $
#
# livingston_snmp 1.2 Author: miquels@cistron.nl
# cvx_snmp 1.0 Author: miquels@cistron.nl
# portslave_finger 1.0 Author: miquels@cistron.nl
# max40xx_finger 1.0 Author: costa@mdi.ca
# ascend_snmp 1.1 Author: blaz@amis.net
# computone_finger 1.2 Author: pacman@world.std.com
# sub tc_tccheck 1.1 Author: alexisv@compass.com.ph
# cyclades_telnet 1.2 Author: accdias@sst.com.br
# patton_snmp 1.0 Author: accdias@sst.com.br
# digitro_rusers 1.1 Author: accdias@sst.com.br
# cyclades_snmp 1.0 Author: accdias@sst.com.br
# usrhiper_snmp 1.0 Author: igor@ipass.net
# juniper_e_snmp 1.1 Author: guilhermefranco@gmail.com
# multitech_snmp 1.0 Author: ehonzay@willmar.com
# netserver_telnet 1.0 Author: mts@interplanet.es
# versanet_snmp 1.0 Author: support@versanetcomm.com
# bay_finger 1.0 Author: chris@shenton.org
# cisco_l2tp 1.14 Author: paul@distributel.net
# mikrotik_telnet 1.1 Author: Evren Yurtesen <yurtesen@ispro.net.tr>
# mikrotik_snmp 1.0 Author: Evren Yurtesen <yurtesen@ispro.net.tr>
# redback_telnet Author: Eduardo Roldan
#
# Config: $debug is the file you want to put debug messages in
# $snmpget is the location of your ``snmpget'' program
# $snmpwalk is the location of your ``snmpwalk'' program
# $snmp_timeout is the timeout for snmp queries
# $snmp_retries is the number of retries for timed out snmp queries
# $snmp_version is the version of to use for snmp queries [1,2c,3]
# $rusers is the location of your ``rusers'' program
# $naspass is the location of your NAS admin password file
#
$prefix = "/usr";
$localstatedir = "/var";
$logdir = "/var/log/freeradius";
$sysconfdir = "/etc";
$raddbdir = "/etc/freeradius/3.0";
$debug = "";
#$debug = "$logdir/checkrad.log";
$snmpget = "/usr/bin/snmpget";
$snmpwalk = "/usr/bin/snmpwalk";
$snmp_timeout = 5;
$snmp_retries = 1;
$snmp_version = "2c";
$rusers = "/usr/bin/rusers";
$naspass = "$raddbdir/naspasswd";
# Community string. Change this if yours isn't "public".
$cmmty_string = "public";
# path to finger command
$finger = "/usr/bin/finger";
# Extremely slow way of converting port descriptions to actual indexes
$portisdescr = 0;
# Realm used by Cisco sub
$realm = '';
#
# USR-Hiper: $hiper_density is the reported port density (default 256
# but 24 makes more sense)
#
$hiper_density = 256;
#
# Try to load Net::Telnet, SNMP_Session etc.
# Do not complain if we cannot find it.
# Prefer a locally installed copy.
#
BEGIN {
unshift @INC, "/usr/local/lib/site_perl";
eval "use Net::Telnet 3.00;";
$::HAVE_NET_TELNET = ($@ eq "");
eval "use SNMP_Session;";
if ($@ eq "") {
eval "use BER;";
$::HAVE_SNMP_SESSION = ($@ eq "");
eval "use Socket;";
}
};
#
# Get password from /etc/raddb/naspasswd file.
# Returns (login, password).
#
sub naspasswd {
my ($terminalserver, $emptyok) = @_;
my ($login, $password);
my ($ts, $log, $pass);
unless (open(NFD, $naspass)) {
if (!$emptyok) {
print LOG "checkrad: naspasswd file not found; " .
"possible match for $ARGV[3]\n" if ($debug);
print STDERR "checkrad: naspasswd file not found; " .
"possible match for $ARGV[3]\n";
}
return ();
}
while (<NFD>) {
chop;
next if (m/^(#|$|[\t ]+$)/);
($ts, $log, $pass) = split(/\s+/, $_, 3);
if ($ts eq $terminalserver) {
$login = $log;
$password = $pass;
last;
}
}
close NFD;
if ($password eq "" && !$emptyok) {
print LOG "checkrad: password for $ARGV[1] is null; " .
"possible match for $ARGV[3] on " .
"port $ARGV[2]\n" if ($debug);
print STDERR "checkrad: password for $ARGV[1] is null; " .
"possible match for $ARGV[3] on port $ARGV[2]\n";
}
($login, $password);
}
#
# See if Net::Telnet is there.
#
sub check_net_telnet {
if (!$::HAVE_NET_TELNET) {
print LOG
" checkrad: Net::Telnet 3.00+ CPAN module not installed\n"
if ($debug);
print STDERR
"checkrad: Net::Telnet 3.00+ CPAN module not installed\n";
return 0;
}
1;
}
#
# Do snmpwalk by calling snmpwalk.
#
sub snmpwalk_prog {
my ($host, $community, $oid) = @_;
local $_;
print LOG "snpwalk: $snmpwalk -r $snmp_retries -t $snmp_timeout -v$snmp_version -c '$community' $host $oid\n";
$_ = `$snmpwalk -r $snmp_retries -t $snmp_timeout -v$snmp_version -c '$community' $host $oid`;
return $_;
}
#
# Do snmpwalk.
#
sub snmpwalk {
my $ret;
if (-x $snmpwalk) {
$ret = snmpwalk_prog(@_);
} else {
$e = "$snmpwalk not found!";
print LOG "$e\n" if ($debug);
print STDERR "checkrad: $e\n";
$ret = "";
}
$ret;
}
#
# Do snmpget by calling snmpget.
#
sub snmpget_prog {
my ($host, $community, $oid) = @_;
my ($ret);
local $_;
print LOG "snmpget: $snmpget -r $snmp_retries -t $snmp_timeout -v$snmp_version -c '$community' $host $oid\n";
$_ = `$snmpget -r $snmp_retries -t $snmp_timeout -v$snmp_version -c '$community' $host $oid`;
if (/^.*(\s|\")([0-9A-Za-z]{8})(\s|\"|$).*$/) {
# Session ID format.
$ret = $2;
} elsif (/^.*=.*"(.*)"/) {
# oid = "...." junk format.
$ret = $1;
} elsif (/^.*=\s*(?:.*:\s*)?(\S+)/) {
# oid = string format
$ret = $1;
}
# Strip trailing junk if any.
$ret =~ s/\s*Hex:.*$//;
$ret;
}
#
# Do snmpget by using SNMP_Session.
# Coded by Jerry Workman <jerry@newwave.net>
#
sub snmpget_session {
my ($host, $community, $OID) = @_;
my ($ret);
local $_;
my (@enoid, $var,$response, $bindings, $binding, $value);
my ($inoid, $outoid, $upoid, $oid, @retvals);
$OID =~ s/^.iso.org.dod.internet.private.enterprises/.1.3.6.1.4.1/;
push @enoid, encode_oid((split /\./, $OID));
srand();
my $session = SNMP_Session->open($host, $community, 161);
if (!$session->get_request_response(@enoid)) {
$e = "No SNMP answer from $ARGV[0].";
print LOG "$e\n" if ($debug);
print STDERR "checkrad: $e\n";
return "";
}
$response = $session->pdu_buffer;
($bindings) = $session->decode_get_response ($response);
$session->close ();
while ($bindings) {
($binding,$bindings) = decode_sequence ($bindings);
($oid,$value) = decode_by_template ($binding, "%O%@");
my $tempo = pretty_print($value);
$tempo=~s/\t/ /g;
$tempo=~s/\n/ /g;
$tempo=~s/^\s+//;
$tempo=~s/\s+$//;
push @retvals, $tempo;
}
$retvals[0];
}
#
# Do snmpget
#
sub snmpget {
my $ret;
if ($::HAVE_SNMP_SESSION) {
$ret = snmpget_session(@_);
} elsif (-x $snmpget) {
$ret = snmpget_prog(@_);
} else {
$e = "Neither SNMP_Session module or $snmpget found!";
print LOG "$e\n" if ($debug);
print STDERR "checkrad: $e\n";
$ret = "";
}
$ret;
}
#
# Get ifindex from description
#
sub ifindex {
my $port = shift;
# If its not an integer, portisdescr lies!
return $port unless $portisdescr || $port !~ /^[0-9]*$/;
$_ = snmpwalk($ARGV[1], "$cmmty_string", ".1.3.6.1.2.1.2.2.1.2");
foreach (split /\n/){
if(/\.([0-9]+)\s*=.*$port"?$/){
print LOG " port descr $port is at SNMP ifIndex $1\n" if ($debug);
return $1;
}
}
return $port;
}
#
# Strip domains, prefixes and suffixes from username
#
# Known prefixes: (P)PP, (S)LIP e (C)SLIP
# Known suffixes: .ppp, .slip e .cslip
#
# Author: Antonio Dias of SST Internet <accdias@sst.com.br>
#
sub strip_username {
my ($user) = @_;
#
# Trim white spaces.
#
$user =~ s/^\s*(.*?)\s*$/$1/;
#
# Strip out domains, prefix and suffixes
#
$user =~ s/\@(.)*$//;
$user =~ s/^[PSC]//;
$user =~ s/\.(ppp|slip|cslip)$//;
$user;
}
#
# Check whether a session is current on any device which implements the standard IEEE 802.1X MIB
#
# Note: Vendors use different formats for the session ID, and it often doesn't map
# between Acct-Session-ID so can't be used to identify and 802.1X session (we ignore it).
#
# If a session matching the username is found on the port specified, and the
# session is still active then thats good enough...
#
# Author: Arran Cudbard-Bell <arran.cudbard-bell@freeradius.org>
#
$ieeedot1m = '.iso.0.8802.1.1';
sub dot1x_snmp {
$ifIndex = ifindex($ARGV[2]);
# User matches and not terminated yet?
if(
snmpget($ARGV[1], "$cmmty_string", "$ieeedot1m.1.1.2.4.1.9.$ifIndex") eq $ARGV[3] &&
snmpget($ARGV[1], "$cmmty_string", "$ieeedot1m.1.1.2.4.1.8.$ifIndex") eq '999'
){
print LOG " found user $ARGV[3] at port $ARGV[2] ($ifIndex)" if $debug;
return 1;
}
0;
}
#
# See if the user is logged in using the Livingston MIB.
# We don't check the username but the session ID.
#
$lvm = '.iso.org.dod.internet.private.enterprises.307';
sub livingston_snmp {
#
# We don't know at which ifIndex S0 is, and
# there might be a hole at S23, or at S30+S31.
# So we figure out dynamically which offset to use.
#
# If the port < S23, probe ifIndex 5.
# If the port < S30, probe IfIndex 23.
# Otherwise probe ifIndex 32.
#
my $ifIndex;
my $test_index;
if ($ARGV[2] < 23) {
$test_index = 5;
} elsif ($ARGV[2] < 30) {
$test_index = 23;
} else {
$test_index = 32;
}
$_ = snmpget($ARGV[1], "$cmmty_string", "$lvm.3.2.1.1.1.2.$test_index");
/S([0-9]+)/;
$xport = $1 + 0;
$ifIndex = $ARGV[2] + ($test_index - $xport);
print LOG " port S$ARGV[2] at SNMP ifIndex $ifIndex\n"
if ($debug);
#
# Now get the session id from the terminal server.
#
$sessid = snmpget($ARGV[1], "$cmmty_string", "$lvm.3.2.1.1.1.5.$ifIndex");
print LOG " session id at port S$ARGV[2]: $sessid\n" if ($debug);
($sessid eq $ARGV[4]) ? 1 : 0;
}
#
# See if the user is logged in using the Aptis MIB.
# We don't check the username but the session ID.
#
# sessionStatusActiveName
$apm1 = '.iso.org.dod.internet.private.enterprises.2637.2.2.102.1.12';
# sessionStatusActiveStopTime
$apm2 = '.iso.org.dod.internet.private.enterprises.2637.2.2.102.1.20';
sub cvx_snmp {
# Remove unique identifier, then take remainder of the
# session-id as a hex number, convert that to decimal.
my $sessid = $ARGV[4];
$sessid =~ s/^.*://;
$sessid =~ s/^0*//;
$sessid = "0" if ($sessid eq '');
#
# Now get the login from the terminal server.
# Blech - the SNMP table is called 'sessionStatusActiveTable,
# but it sometimes lists inactive sessions too.
# However an active session doesn't have a Stop time,
# so we can differentiate that way.
#
my $login = snmpget($ARGV[1], "$cmmty_string", "$apm1." . hex($sessid));
my $stopt = snmpget($ARGV[1], "$cmmty_string", "$apm2." . hex($sessid));
$login = "--" if ($stopt > 0);
print LOG " login with session-id $ARGV[4]: $login\n" if ($debug);
(strip_username($login) eq strip_username($ARGV[3])) ? 1 : 0;
}
#
# See if the user is logged in using the Cisco MIB
#
$csm = '.iso.org.dod.internet.private.enterprises.9';
sub cisco_snmp {
# Look up community string in naspasswd file.
my ($login, $pass) = naspasswd($ARGV[1], 1);
if ($login eq '') {
$pass = $cmmty_string;
} elsif ($login ne 'SNMP') {
if ($debug) {
print LOG
" Error: Need SNMP community string for $ARGV[1]\n";
}
return 2;
}
my $port = $ARGV[2];
my $sess_id = hex($ARGV[4]);
if ($port < 20000) {
#
# The AS5350 doesn't support polling the session ID,
# so we do it based on nas-port-id. This only works
# for analog sessions where port < 20000.
# Yes, this means that simultaneous-use on the as5350
# doesn't work for ISDN users.
#
$login = snmpget($ARGV[1], $pass, "$csm.2.9.2.1.18.$port");
print LOG " user at port S$port: $login\n" if ($debug);
} else {
$login = snmpget($ARGV[1], $pass,
"$csm.9.150.1.1.3.1.2.$sess_id");
print LOG " user with session id $ARGV[4] ($sess_id): " .
"$login\n" if ($debug);
}
# ($login eq $ARGV[3]) ? 1 : 0;
if($login eq $ARGV[3]) {
return 1;
}else{
$out=snmpwalk($ARGV[1],$pass,".iso.org.dod.internet.private.enterprises.9.10.19.1.3.1.1.3");
if($out=~/\"$ARGV[3]\"/){
return 1;
}else{
return 0;
}
}
}
#
# Check the subscriber name on a Juniper JunosE E-Series BRAS (ERX, E120, E320). Requires "radius acct-session-id-format decimal" configuration in the BRAS.
#
# Author: Guilherme Franco <guilhermefranco@gmail.com>
#
sub juniper_e_snmp {
#receives acct_session
my $temp = $ARGV[4];
#removes the leading 0s
my $clean_temp = int $temp;
$out=snmpget($ARGV[1], $cmmty_string, ".1.3.6.1.4.1.4874.2.2.20.1.8.4.1.2.$clean_temp");
if($out=~/\"$ARGV[3]\"/){
return 1;
}else{
return 0;
}
}
#
# Check a MultiTech CommPlete Server ( CC9600 & CC2400 )
#
# Author: Eric Honzay of Bennett Office Products <ehonzay@willmar.com>
#
$msm = '.iso.org.dod.internet.private.enterprises.995';
sub multitech_snmp {
my $temp = $ARGV[2] + 1;
$login = snmpget($ARGV[1], "$cmmty_string", "$msm.2.31.1.1.1.$temp");
print LOG " user at port S$ARGV[2]: $login\n" if ($debug);
($login eq $ARGV[3]) ? 1 : 0;
}
#
# Check a Computone Powerrack via finger
#
# Old Author: Shiloh Costa of MDI Internet Inc. <costa@mdi.ca>
# New Author: Alan Curry <pacman@world.std.com>
#
# The finger response format is version-dependent. To do this *right*, you
# need to know exactly where the port number and username are. I know that
# for 1.7.2, and 3.0.4 but for others I just guess.
# Oh yeah and on top of it all, the thing truncates usernames. --Pac.
#
# 1.7.2 and 3.0.4 both look like this:
#
# 0 0 000 00:56 luser pppfsm Incoming PPP, ppp00, 10.0.0.1
#
# and the truncated ones look like this:
#
# 25 0 000 00:15 longnameluse..pppfsm Incoming PPP, ppp25, 10.0.0.26
#
# Yes, the fields run together. Long Usernames Considered Harmful.
#
sub computone_finger {
my $trunc, $ver;
open(FD, "$finger \@$ARGV[1]|") or return 2;
<FD>; # the [hostname] line is definitely uninteresting
$trunc = substr($ARGV[3], 0, 12);
$ver = "";
while(<FD>) {
if(/cnx kernel release ([^ ,]+)[, ]/) {
$ver = $1;
next;
}
# Check for known versions
if ($ver eq '1.7.2' || $ver eq '3.0.4') {
if (/^\Q$ARGV[2]\E\s+\S+\s+\S+\s+\S+\s+\Q$trunc\E(\s+|\.\.)/) {
close FD;
return 1;
}
next;
}
# All others.
if (/^\s*\Q$ARGV[2]\E\s+.*\s+\Q$trunc\E\s+/) {
close FD;
return 1;
}
}
close FD;
return 0;
}
#
# Check an Ascend Max4000 or similar model via finger
#
# Note: Not all software revisions support finger
# You may also need to enable the finger option.
#
# Author: Shiloh Costa of MDI Internet Inc. <costa@mdi.ca>
#
sub max40xx_finger {
open(FD, "$finger $ARGV[3]\@$ARGV[1]|");
while(<FD>) {
$line = $_;
if( $line =~ /Session/ ){
next;
}
if( $line =~ /$ARGV[4]/ ){
return 1; # user is online
}
}
close FD;
return 0; # user is offline
}
#
# Check an Ascend Max4000 or similar model via SNMP
#
# Author: Blaz Zupan of Medinet <blaz@amis.net>
#
$asm = '.iso.org.dod.internet.private.enterprises.529';
sub ascend_snmp {
my $sess_id;
my $l1, $l2;
$l1 = '';
$l2 = '';
#
# If it looks like hex, only try it as hex,
# otherwise try it as both decimal and hex.
#
$sess_id = $ARGV[4];
if ($sess_id !~ /^0/ && $sess_id !~ /[a-f]/i) {
$l1 = snmpget($ARGV[1], "$cmmty_string", "$asm.12.3.1.4.$sess_id");
}
if (!$l1){
$sess_id = hex $ARGV[4];
$l2 = snmpget($ARGV[1], "$cmmty_string", "$asm.12.3.1.4.$sess_id");
}
print LOG " user at port S$ARGV[2]: $l1 (dec)\n" if ($debug && $l1);
print LOG " user at port S$ARGV[2]: $l2 (hex)\n" if ($debug && $l2);
(($l1 && $l1 eq $ARGV[3]) || ($l2 && $l2 eq $ARGV[3])) ? 1 : 0;
}
#
# See if the user is logged in using the portslave finger.
#
sub portslave_finger {
my ($Port_seen);
$Port_seen = 0;
open(FD, "$finger \@$ARGV[1]|");
while(<FD>) {
#
# Check for ^Port. If we don't see it we
# wont get confused by non-portslave-finger
# output too.
#
if (/^Port/) {
$Port_seen++;
next;
}
next if (!$Port_seen);
next if (/^---/);
($port, $user) = /^.(...) (...............)/;
$port =~ s/ .*//;
$user =~ s/ .*//;
$ulen = length($user);
#
# HACK: strip [PSC] from the front of the username,
# and things like .ppp from the end.
#
$user =~ s/^[PSC]//;
$user =~ s/\.(ppp|slip|cslip)$//;
#
# HACK: because ut_user usually has max. 8 characters
# we only compare up the the length of $user if the
# unstripped name had 8 chars.
#
$argv_user = $ARGV[3];
if ($ulen == 8) {
$ulen = length($user);
$argv_user = substr($ARGV[3], 0, $ulen);
}
if ($port == $ARGV[2]) {
if ($user eq $argv_user) {
print LOG " $user matches $argv_user " .
"on port $port" if ($debug);
close FD;
return 1;
} else {
print LOG " $user doesn't match $argv_user " .
"on port $port" if ($debug);
close FD;
return 0;
}
}
}
close FD;
0;
}
#
# See if the user is already logged-in at the 3Com/USR Total Control.
# (this routine by Alexis C. Villalon <alexisv@compass.com.ph>).
# You must have the Net::Telnet module from CPAN for this to work.
# You must also have your /etc/raddb/naspasswd made up.
#
sub tc_tccheck {
#
# Localize all variables first.
#
my ($Port_seen, $ts, $terminalserver, $log, $login, $pass, $password);
my ($telnet, $curprompt, $curline, $ok, $totlines, $ccntr);
my (@curlines, @cltok, $user, $port, $ulen);
return 2 unless (check_net_telnet());
$terminalserver = $ARGV[1];
$Port_seen = 0;
#
# Get login name and password for a certain NAS from $naspass.
#
($login, $password) = naspasswd($terminalserver, 1);
return 2 if ($password eq "");
#
# Communicate with NAS using Net::Telnet, then issue
# the command "show sessions" to see who are logged in.
# Thanks to Chris Jackson <chrisj@tidewater.net> for the
# for the "-- Press Return for More --" workaround.
#
$telnet = new Net::Telnet (Timeout => 5,
Prompt => '/\>/');
$telnet->open($terminalserver);
$telnet->login($login, $password);
$telnet->print("show sessions");
while ($curprompt ne "\>") {
($curline, $curprompt) = $telnet->waitfor
(String => "-- Press Return for More --",
String => "\>",
Timeout => 5);
$ok = $telnet->print("");
push @curlines, split(/^/m, $curline);
}
$telnet->close;
#
# Telnet closed. We got the info. Let's examine it.
#
$totlines = @curlines;
$ccntr = 0;
while($ccntr < $totlines) {
#
# Check for ^Port.
#
if ($curlines[$ccntr] =~ /^Port/) {
$Port_seen++;
$ccntr++;
next;
}
#
# Ignore all unnecessary lines.
#
if (!$Port_seen || $curlines[$ccntr] =~ /^---/ ||
$curlines[$ccntr] =~ /^ .*$/) {
$ccntr++;
next;
}
#
# Parse the current line for the port# and username.
#
@cltok = split(/\s+/, $curlines[$ccntr]);
$ccntr++;
$port = $cltok[0];
$user = $cltok[1];
$ulen = length($user);
#
# HACK: strip [PSC] from the front of the username,
# and things like .ppp from the end. Strip S from
# the front of the port number.
#
$user =~ s/^[PSC]//;
$user =~ s/\.(ppp|slip|cslip)$//;
$port =~ s/^S//;
#
# HACK: because "show sessions" shows max. 15 characters
# we only compare up to the length of $user if the
# unstripped name had 15 chars.
#
$argv_user = $ARGV[3];
if ($ulen == 15) {
$ulen = length($user);
$argv_user = substr($ARGV[3], 0, $ulen);
}
if ($port == $ARGV[2]) {
if ($user eq $argv_user) {
print LOG " $user matches $argv_user " .
"on port $port" if ($debug);
return 1;
} else {
print LOG " $user doesn't match $argv_user " .
"on port $port" if ($debug);
return 0;
}
}
}
0;
}
#
# Check a Cyclades PathRAS via telnet
#
# Version: 1.2
#
# Author: Antonio Dias of SST Internet <accdias@sst.com.br>
#
sub cyclades_telnet {
#
# Localize all variables first.
#
my ($pr, $pr_login, $pr_passwd, $pr_prompt, $endlist, @list, $port, $user);
#
# This variable must match PathRAS' command prompt
# string as entered in menu option 6.2.
# The value below matches the default command prompt.
#
$pr_prompt = '/Select option ==\>$/i';
#
# This variable match the end of userslist.
#
$endlist = '/Type \<enter\>/i';
#
# Do we have Net::Telnet installed?
#
return 2 unless (check_net_telnet());
#
# Get login name and password for NAS
# from $naspass file.
#
($pr_login, $pr_passwd) = naspasswd($ARGV[1], 1);
#
# Communicate with PathRAS using Net::Telnet, then access
# menu option 6.8 to see who are logged in.
# Based on PathRAS firmware version 1.2.3
#
$pr = new Net::Telnet (
Timeout => 5,
Host => $ARGV[1],
ErrMode => 'return'
) || return 2;
#
# Force PathRAS shows its banner.
#
$pr->break();
#
# Log on PathRAS
#
if ($pr->waitfor(Match => '/login : $/i') == 1) {
$pr->print($pr_login);
} else {
print LOG " Error: sending login name to PathRAS\n" if ($debug);
$pr->close;
return 2;
}
if ($pr->waitfor(Match => '/password : $/i') == 1) {
$pr->print($pr_passwd);
} else {
print LOG " Error: sending password to PathRAS.\n" if ($debug);
$pr->close;
return 2;
}
$pr->print();
#
# Access menu option 6 "PathRAS Management"
#
if ($pr->waitfor(Match => $pr_prompt) == 1) {
$pr->print('6');
} else {
print LOG " Error: accessing menu option '6'.\n" if ($debug);
$pr->close;
return 2;
}
#
# Access menu option 8 "Show Active Ports"
#
if ($pr->waitfor(Match => $pr_prompt) == 1) {
@list = $pr->cmd(String => '8', Prompt => $endlist);
} else {
print LOG " Error: accessing menu option '8'.\n" if ($debug);
$pr->close;
return 2;
}
#
# Since we got the info we want, let's close
# the telnet session
#
$pr->close;
#
# Lets examine the userlist stored in @list
#
foreach(@list) {
#
# We are interested in active sessions only
#
if (/Active/i) {
($port, $user) = split;
#
# Strip out any prefix, suffix and
# realm from $user check to see if
# $ARGV[3] matches.
#
if(strip_username($ARGV[3]) eq strip_username($user)) {
print LOG " User '$ARGV[3]' found on '$ARGV[1]:$port'.\n" if ($debug);
return 1;
}
}
}
print LOG " User '$ARGV[3]' not found on '$ARGV[1]'.\n" if ($debug);
0;
}
#
# Check a Patton 2800 via SNMP
#
# Version: 1.0
#
# Author: Antonio Dias of SST Internet <accdias@sst.com.br>
#
sub patton_snmp {
my($oid);
#$oid = '.1.3.6.1.4.1.1768.5.100.1.40.' . hex $ARGV[4];
# Reported by "Andria Legon" <andria@patton.com>
# The OID below should be the correct one instead of the one above.
$oid = '.1.3.6.1.4.1.1768.5.100.1.56.' . hex $ARGV[4];
#
# Check if the session still active
#
if (snmpget($ARGV[1], "monitor", "$oid") == 0) {
print LOG " Session $ARGV[4] still active on NAS " .
"$ARGV[1], port $ARGV[2], for user $ARGV[3].\n" if ($debug);
return 1;
}
0;
}
#
# Check a Digitro BXS via rusers
#
# Version: 1.1
#
# Author: Antonio Dias of SST Internet <accdias@sst.com.br>
#
sub digitro_rusers {
my ($ret);
local $_;
if (-e $rusers && -x $rusers) {
#
# Get a list of users logged in via rusers
#
$_ = `$rusers $ARGV[1]`;
$ret = ((/$ARGV[3]/) ? 1 : 0);
} else {
print LOG " Error: can't execute $rusers\n" if $debug;
$ret = 2;
}
$ret;
}
#
# Check Cyclades PR3000 and PR4000 via SNMP
#
# Version: 1.0
#
# Author: Antonio Dias of SST Internet <accdias@sst.com.br>
#
sub cyclades_snmp {
my ($oid, $ret);
local $_;
$oid = ".1.3.6.1.4.1.2925.3.3.6.1.1.2";
$_ = snmpwalk($ARGV[1],"$cmmty_string",$oid);
$ret = ((/$ARGV[3]/) ? 1 : 0);
$ret;
}
#
# 3Com/USR HiPer Arc Total Control.
# This works with HiPer Arc 4.0.30
# (this routine by Igor Brezac <igor@ipass.net>)
#
# This routine modified by Dan Halverson <danh@tbc.net>
# to support additional versions of Hiper Arc
#
$usrm = '.iso.org.dod.internet.private.enterprises.429';
sub usrhiper_snmp {
my ($login,$password,$oidext);
# Look up community string in naspasswd file.
($login, $password) = naspasswd($ARGV[1], 1);
if ($login && $login ne 'SNMP') {
if($debug) {
print LOG
" Error: Need SNMP community string for $ARGV[1]\n";
}
return 2;
} else {
# If password is defined in naspasswd file, use it as community, otherwise use $cmmty_string
if ($password eq '') {
$password = "$cmmty_string";
}
}
my ($ver) = get_hiper_ver(usrm=>$usrm, target=>$ARGV[1], community=>$password);
$oidext = get_oidext(ver=>$ver, tty=>$ARGV[2]);
my ($login);
$login = snmpget($ARGV[1], $password, "$usrm.4.10.1.1.18.$oidext");
if ($login =~ /\"/) {
$login =~ /^.*\"([^"]+)\"/;
$login = $1;
}
print LOG " user at port S$ARGV[2]: $login\n" if ($debug);
($login eq $ARGV[3]) ? 1 : 0;
}
#
# get_hiper_ver and get_oidext by Dan Halverson <danh@tbc.net>
#
sub get_hiper_ver {
my (%args) = @_;
my ($ver
);
$ver = snmpget ($args{'target'}, $args{'community'}, $args{'usrm'}.".4.1.14.0");
return($ver);
}
#
# Add additional OID checks below before the else.
# Else is for 4.0.30
#
sub get_oidext {
my (%args) = @_;
my ($oid
);
if ($args{'ver'} =~ /V5.1.99/) {
$oid = $args{'tty'}+1257-1;
}
else {
$oid = 1257 + 256*int(($args{'tty'}-1) / $hiper_density) +
(($args{'tty'}-1) % $hiper_density);
}
return($oid);
}
#
# Check USR Netserver with Telnet - based on tc_tccheck.
# By "Marti" <mts@interplanet.es>
#
sub usrnet_telnet {
#
# Localize all variables first.
#
my ($ts, $terminalserver, $login, $password);
my ($telnet, $curprompt, $curline, $ok);
my (@curlines, $user, $port);
return 2 unless (check_net_telnet());
$terminalserver = $ARGV[1];
$Port_seen = 0;
#
# Get login name and password for a certain NAS from $naspass.
#
($login, $password) = naspasswd($terminalserver, 1);
return 2 if ($password eq "");
#
# Communicate with Netserver using Net::Telnet, then access
# list connectionsto see who are logged in.
#
$telnet = new Net::Telnet (Timeout => 5,
Prompt => '/\>/');
$telnet->open($terminalserver);
#
# Log on Netserver
#
$telnet->login($login, $password);
#
# Launch list connections command
$telnet->print("list connections");
while ($curprompt ne "\>") {
($curline, $curprompt) = $telnet->waitfor
( String => "\>",
Timeout => 5);
$ok = $telnet->print("");
push @curlines, split(/^/m, $curline);
}
$telnet->close;
#
# Telnet closed. We got the info. Let's examine it.
#
foreach(@curlines) {
if ( /mod\:/ ) {
($port, $user, $dummy) = split;
#
# Strip out any prefixes and suffixes
# from the username
#
# uncomment this if you use the standard
# prefixes
#$user =~ s/^[PSC]//;
#$user =~ s/\.(ppp|slip|cslip)$//;
#
# Check to see if $user is already connected
#
if ($user eq $ARGV[3]) {
print LOG " $user matches $ARGV[3] " .
"on port $port" if ($debug);
return 1;
};
};
};
print LOG
" $ARGV[3] not found on Netserver logged users list " if ($debug);
0;
}
#
# Versanet's Perl Script Support:
#
# ___ versanet_snmp 1.0 by support@versanetcomm.com ___ July 1999
# Versanet Enterprise MIB Base: 1.3.6.1.4.1.2180
#
# VN2001/2002 use slot/port number to locate modems. To use snmp get we
# have to translate the original port number into a slot/port pair.
#
$vsm = '.iso.org.dod.internet.private.enterprises.2180';
sub versanet_snmp {
print LOG "argv[2] = $ARGV[2] " if ($debug);
$port = $ARGV[2]%8;
$port = 8 if ($port eq 0);
print LOG "port = $port " if ($debug);
$slot = (($ARGV[2]-$port)/8)+1;
print LOG "slot = $slot" if ($debug);
$loginname = snmpget($ARGV[1], "$cmmty_string", "$vsm.27.1.1.3.$slot.$port");
#
# Note: the "$cmmty_string" string above could be replaced by the public
# community string defined in Versanet VN2001/VN2002.
#
print LOG " user at slot $slot port $port: $loginname\n" if ($debug); ($loginname eq $ARGV[3]) ? 1 : 0;
}
# 1999/08/24 Chris Shenton <chris@shenton.org>
# Check Bay8000 NAS (aka: Annex) using finger.
# Returns from "finger @bay" like:
# Port What User Location When Idle Address
# asy2 PPP bill --- 9:33am :08 192.0.2.194
# asy4 PPP hillary --- 9:36am :04 192.0.2.195
# [...]
# But also returns partial-match users if you say like "finger g@bay":
# Port What User Location When Idle Address
# asy2 PPP gore --- 9:33am :09 192.0.2.194
# asy22 PPP gwbush --- Mon 9:19am :07 192.0.2.80
# So check exact match of username!
sub bay_finger { # ARGV: 1=nas_ip, 2=nas_port, 3=login, 4=sessid
open(FINGER, "$finger $ARGV[3]\@$ARGV[1]|") || return 2; # error
while(<FINGER>) {
my ($Asy, $PPP, $User) = split;
if( $User =~ /^$ARGV[3]$/ ){
close FINGER;
print LOG "checkrad:bay_finger: ONLINE $ARGV[3]\@$ARGV[1]"
if ($debug);
return 1; # online
}
}
close FINGER;
print LOG "checkrad:bay_finger: offline $ARGV[3]\@$ARGV[1]" if ($debug);
return 0; # offline
}
#
# Cisco L2TP support
# This is for PPP sessions coming from an L2TP tunnel from a Dial
# or DSL wholesale provider
# Paul Khavkine <paul@distributel.net>
# July 19 2001
#
# find_l2tp_login() walks a part of cisco vpdn tree to find out what session
# and tunnel ID's are for a given Virtual-Access interface to construct
# the following OID: .1.3.6.1.4.1.9.10.24.1.3.2.1.2.2.$tunID.$sessID
# Then gets the username from that OID.
# Make sure you set the $realm variable at the begining of the file if
# needed. The new type for naslist is cisco_l2tp
sub find_l2tp_login
{
my($host, $community, $port_num) = @_;
my $l2tp_oid = '.1.3.6.1.4.1.9.10.24.1.3.2.1.2.2';
my $port_oid = '.iso.org.dod.internet.private.enterprises.9.10.51.1.2.1.1.2.2';
my $port = 'Vi' . $port_num;
my $sess = new SNMP::Session(DestHost => $host, Community => $community);
my $snmp_var = new SNMP::Varbind(["$port_oid"]);
my $val = $sess->getnext($snmp_var);
do
{
$sess->getnext($snmp_var);
} until ($snmp_var->[$SNMP::Varbind::val_f] =~ /$port/) ||
(!($snmp_var->[$SNMP::Varbind::ref_f] =~ /^$port_oid\.(\d+)\.(\d+)$/)) ||
($sess->{ErrorNum});
my $val1 = $snmp_var->[$SNMP::Varbind::ref_f];
if ($val1 =~ /^$port_oid/) {
$result = substr($val1, length($port_oid));
$result =~ /^\.(\d+)\.(\d+)$/;
$tunID = $1;
$sessID = $2;
}
my $snmp_var1 = new SNMP::Varbind(["$l2tp_oid\.$tunID\.$sessID"]);
$val = $sess->get($snmp_var1);
my $login = $snmp_var1->[$SNMP::Varbind::val_f];
return $login;
}
sub cisco_l2tp_snmp
{
my $login = find_l2tp_login("$ARGV[1]", $cmmty_string, "$ARGV[2]");
print LOG " user at port S$ARGV[2]: $login\n" if ($debug);
($login eq "$ARGV[3]\@$realm") ? 1 : 0;
}
sub mikrotik_snmp {
# Set SNMP version
# MikroTik only supports version 1
$snmp_version = "1";
# Look up community string in naspasswd file.
($login, $password) = naspasswd($ARGV[1], 1);
if ($login && $login ne 'SNMP') {
if($debug) {
print LOG "Error: Need SNMP community string for $ARGV[1]\n";
}
return 2;
} else {
# If password is defined in naspasswd file, use it as community,
# otherwise use $cmmty_string
if ($password eq '') {
$password = "$cmmty_string";
}
}
# We want mtxrInterfaceStatsName from MIKROTIK-MIB
$oid = "1.3.6.1.4.1.14988.1.1.14.1.1.2";
# Mikrotik doesnt give port IDs correctly to RADIUS :(
# practically this would limit us to a simple only-one user limit for
# this script to work properly.
@output = snmpwalk_prog($ARGV[1], $password, "$oid");
foreach $line ( @output ) {
#remove newline
chomp $line;
#remove trailing whitespace
($line = $line) =~ s/\s+$//;
if( $line =~ /<.*-$ARGV[3]>/ ) {
$username_seen++;
}
}
#lets return something
if ($username_seen > 0) {
return 1;
} else {
return 0;
}
}
sub mikrotik_telnet {
# Localize all variables first.
my ($t, $login, $password);
my (@fields, @output, $output, $username_seen, $user);
return 2 unless (check_net_telnet());
$terminalserver = $ARGV[1];
$user = $ARGV[3];
# Get login name and password for a certain NAS from $naspass.
($login, $password) = naspasswd($terminalserver, 1);
return 2 if ($password eq "");
# MikroTik routeros doesnt tell us to which port the user is connected
# practically this would limit us to a simple only-one user limit for
# this script to work properly.
$t = new Net::Telnet (Timeout => 5,
Prompt => '//\[.*@.*\] > /');
# Dont just exit when there is error
$t->errmode('return');
# Telnet to terminal server
$t->open($terminalserver) or return 2;
#Send login and password etc.
$t->login(Name => $login,
Password => $password,
# We must detect if we are logged in from the login banner.
# Because if routeros is with a free license the command
# prompt dont come. Instead it waits us to press "Enter".
Prompt => '/MikroTik/');
# Just be sure that routeros isn't waiting for us to press "Enter"
$t->print("");
# Wait for the real prompt
$t->waitfor('/\[.*@.*\] > /');
# It is not possible to get the line numbers etc.
# Thus we cant support if simultaneous-use is over 1
# At least I was using pppoe so it wasnt possible.
$t->print('ppp active print column name detail');
# Somehow routeros echo'es our commands 2 times. We dont want to mix
# this with the real command prompt.
$t->waitfor('/\[.*@.*\] > ppp active print column name detail/');
# Now lets get the list of online ppp users.
( $output ) = $t->waitfor('/\[.*@.*\] > /');
# For debugging we can print the list to stdout
# print $output;
#Lets logout to make everybody happy.
#If we close the connection without logging out then routeros
#starts to complain after a while. Saying;
#telnetd: All network ports in use.
$t->print("quit");
$t->close;
#check for # of $user in output
#the output includes only one = between name and username so we can
#safely use it as a seperator.
#disabled until mikrotik starts to send newline after each line...
# @output = $output;
# foreach $line ( @output ) {
# #remove newline
# chomp $line;
# #remove trailing whitespace
# ($line = $line) =~ s/\s+$//;
# if( $line =~ /name=/ ) {
# print($line);
# @fields = split( /=/, $line );
# if( $fields[1] == "\"$user\"") {
# $username_seen++;
# }
# }
# }
if( $output =~ /name="$user"/ ) {
$username_seen++;
}
#lets return something
if ($username_seen > 0) {
return 1;
} else {
return 0;
}
}
sub redback_telnet {
#Localize all variables first.
my ($terminalserver, $login, $password);
my ($user, $context, $operprompt, $adminprompt, $t);
return 2 unless (check_net_telnet());
$terminalserver = $ARGV[1];
($user, $context) = split /@/, $ARGV[3];
if (not $user) {
print LOG " Error: No user defined\n" if ($debug);
return 2;
}
if (not $context) {
print LOG " Error: No context defined\n" if ($debug);
return 2;
}
# Get loggin information
($root, $password) = naspasswd($terminalserver, 1);
return 2 if ($password eq "");
$operprompt = '/\[.*\].*>$/';
$adminprompt = '/\[.*\].*#$/';
# Logging to the RedBack NAS
$t = new Net::Telnet (Timeout => 5, Prompt => $operprompt);
$t->input_log("./debug");
$t->open($terminalserver);
$t->login($root, $password);
#Enable us
$t->print('ena');
$t->waitfor('/Password/');
$t->print($password);
$t->waitfor($adminprompt);
$t->prompt($adminprompt);
#Switch context
$t->cmd(String => "context $context");
#Ask the question
@lines = $t->cmd(String => "show subscribers active $user\@$context");
if ($lines[0] =~ /subscriber $user\@$context/ ) {
return 1;
}
return 0;
}
###############################################################################
# Poor man's getopt (for -d)
if ($ARGV[0] eq '-d') {
shift @ARGV;
$debug = "stdout";
}
if ($debug) {
if ($debug eq 'stdout') {
open(LOG, ">&STDOUT");
} elsif ($debug eq 'stderr') {
open(LOG, ">&STDERR");
} else {
open(LOG, ">>$debug");
$now = localtime;
print LOG "$now checkrad @ARGV\n";
}
}
if ($#ARGV != 4) {
print LOG "Usage: checkrad nas_type nas_ip " .
"nas_port login session_id\n" if ($debug);
print STDERR "Usage: checkrad nas_type nas_ip " .
"nas_port login session_id\n"
unless ($debug =~ m/^(stdout|stderr)$/);
close LOG if ($debug);
exit(2);
}
if ($ARGV[0] eq 'livingston') {
$ret = &livingston_snmp;
} elsif ($ARGV[0] eq 'cisco') {
$ret = &cisco_snmp;
} elsif ($ARGV[0] eq 'cvx') {
$ret = &cvx_snmp;
} elsif ($ARGV[0] eq 'juniper') {
$ret = &juniper_e_snmp;
} elsif ($ARGV[0] eq 'multitech') {
$ret = &multitech_snmp;
} elsif ($ARGV[0] eq 'computone') {
$ret = &computone_finger;
} elsif ($ARGV[0] eq 'max40xx') {
$ret = &max40xx_finger;
} elsif ($ARGV[0] eq 'ascend' || $ARGV[0] eq 'max40xx_snmp') {
$ret = &ascend_snmp;
} elsif ($ARGV[0] eq 'portslave') {
$ret = &portslave_finger;
} elsif ($ARGV[0] eq 'tc') {
$ret = &tc_tccheck;
} elsif ($ARGV[0] eq 'pathras') {
$ret = &cyclades_telnet;
} elsif ($ARGV[0] eq 'pr3000') {
$ret = &cyclades_snmp;
} elsif ($ARGV[0] eq 'pr4000') {
$ret = &cyclades_snmp;
} elsif ($ARGV[0] eq 'patton') {
$ret = &patton_snmp;
} elsif ($ARGV[0] eq 'digitro') {
$ret = &digitro_rusers;
} elsif ($ARGV[0] eq 'usrhiper') {
$ret = &usrhiper_snmp;
} elsif ($ARGV[0] eq 'netserver') {
$ret = &usrnet_telnet;
} elsif ($ARGV[0] eq 'versanet') {
$ret = &versanet_snmp;
} elsif ($ARGV[0] eq 'bay') {
$ret = &bay_finger;
} elsif ($ARGV[0] eq 'cisco_l2tp'){
$ret = &cisco_l2tp_snmp;
} elsif ($ARGV[0] eq 'mikrotik'){
$ret = &mikrotik_telnet;
} elsif ($ARGV[0] eq 'mikrotik_snmp'){
$ret = &mikrotik_snmp;
} elsif ($ARGV[0] eq 'redback'){
$ret = &redback_telnet;
} elsif ($ARGV[0] eq 'dot1x'){
$ret = &dot1x_snmp;
} elsif ($ARGV[0] eq 'other') {
$ret = 1;
} else {
print LOG " checkrad: unknown NAS type $ARGV[0]\n" if ($debug);
print STDERR "checkrad: unknown NAS type $ARGV[0]\n";
$ret = 2;
}
if ($debug) {
$mn = "login ok";
$mn = "double detected" if ($ret == 1);
$mn = "error detected" if ($ret == 2);
print LOG " Returning $ret ($mn)\n";
close LOG;
}
exit($ret);