[tac_plus] Working Command Authorization Script

Barry Stephen (YDD08) Derwent Shared Services steve at dss.nhs.uk
Fri Apr 3 16:58:32 UTC 2009


I posted the other day about providing some users different levels of
access depending on the specific device they logged onto, in my case
Access versus Distribution & Core switches.

Having read previous responses from various people I have managed to
create a working authorization script which checks what NAS a user
logged onto and if the NAS/Switch is in a specific list the commands are
checked against a list and only those commands are permitted. For all
other NASes (those not in the list) all commands are allowed.

It took me a while to realise that the script is effectively taking on
the role of the tacacs+ deamon to some extent, that is to say that it is
not returning config/options to the tac_plus deamon in config file
format but direct to the NAS/switch. In any case, in this example we
simply say allow or deny rather than passing any AV pairs back to the
NAS.

It is important to parse STDIN to see what command the NAS is requesting
auth for.

I am using the after authorization method as the before authorization
method seemed a little harder to get working.

This is my tac_plus.conf definition for these group of people:

# Read/Write Access to non distribution devices - All commands
authorised
group = rw-except-distribution {
        default service = permit
        service = exec {
                priv-lvl=15
                idletime=15
                timeout=0
        }
        after authorization "/usr/bin/perl /etc/tac_plus_auth.pl $user
$name $address"
}

I pass username, nas ip address and client ip address to my script but
only use nas address ($name) in my script. In my case $name is the NAS
IP address but possibly may not be in all cases.

It is necessary to have 'default service = permit' with 'after auth'
scripts because it needs to pass the internal deamon checks otherwise it
doesn't get passed to the script. However the script can override the
deamon's permit so not all commands are allowed as it might look like.

I wrote this in perl as I don't do bash. I am a complete amateur so I am
sure there are lots of mistakes and bad practice. I hope this helps
someone and goes some way to repay the help I have received in the past.
Feel free to reply with any questions.

Cheers
Steve

Stephen Barry
Senior IT Service Designer  |  IT Operations  |  Derbyshire Health
Informatics Service  |  Derwent Shared Services
t: 01332 622444  |  m: 07919 173353  |  f: 01332 222256  |  e:
steve at dss.nhs.uk <mailto:steve at dss.nhs.uk> 

############### START SAMPLE AUTH SCRIPT #####################

#! /usr/bin/perl

$log_file = "/var/log/tac_plus_ext_auth.log";
$log_enabled = 1;

#Create array of devices that require special treatment
@device_group_1 =      ("10.95.130.1",
                        "10.95.130.251",
                        "10.95.130.252",
                        "10.95.191.37",
                        "10.95.191.38",
                        "10.95.253.21",
                        "10.95.253.22",
                        "10.95.253.84",
                        "172.16.5.66");

#Create array of all the commands allowed on above devices, regex OK
@command_group_1 =     ("show running-config",
                        "show .*",
                        "ping .*",
                        "traceroute .*");

#Read in the command line arguements
$username  = $ARGV[0];
$nas_ip    = $ARGV[1];
$client_ip = $ARGV[2];

#Read in the stdin and extract commands only
while (defined($line = <STDIN>)){
        if ($line =~ /^cmd=(.*)\n/) {
                $command_string = $1;
        }
        elsif ($line =~ /^cmd-arg=(?!<cr>)(.*)\n/) {
                $command_string = $command_string." ".$1;
        }
}

#Im only interested in commands, ignore if it wasnt a cmd or cmd-arg
if(!defined($command_string)){
        exit 0;
}

#Check for device and command match
if(nas_match($nas_ip,\@device_group_1)) {
        if(command_match($command_string,\@command_group_1)) {
                print_log("Yes","Yes");
                exit 0;
        }
        else {
                print_log("Yes","No");
                exit 1;
        }
}
else {
        #I want to allow any command on devices that dont match any in
my list
        print_log("No","Yes");
        exit 0;
}


#Compares passed nas to array of nases to see if the nas is of interest
sub nas_match
{
        $nas_match_nas_ip = shift(@_);
        $nas_match_nas_list = shift(@_);
        foreach $nas (@$nas_match_nas_list){
                if ($nas_match_nas_ip eq $nas){
                        return TRUE;
                }
        }
}

#Compares passed command to array of commands to see if the nas is of
interest
sub command_match
{
        $command_match_command = shift(@_);
        $command_match_command_list = shift(@_);
        foreach $command (@$command_match_command_list){
                if ($command_match_command =~ /$command/) {
                        return TRUE;
                }
        }
}

#Compares passed command to array of commands to see if the nas is of
interest
sub print_log
{
        if ($log_enabled == 1) {
                $print_log_device_match = shift(@_);
                $print_log_command_allowed = shift(@_);

                open MY_LOG_FILE, ">>", $log_file or die $!;
                        print MY_LOG_FILE "External Auth Script running
at ".localtime()."\n";
                        print MY_LOG_FILE "  Username:  $username\n";
                        print MY_LOG_FILE "  NAS IP:    $nas_ip\n";
                        print MY_LOG_FILE "  Client IP: $client_ip\n";
                        print MY_LOG_FILE "  Command:
$command_string\n";
                        print MY_LOG_FILE "  NAS Match:
$print_log_device_match\n";
                        print MY_LOG_FILE "  Allowed:
$print_log_command_allowed\n";
                        print MY_LOG_FILE "\n";
                close (MY_LOG_FILE);
        }
}

############### END SAMPLE AUTH SCRIPT #####################

DISCLAIMER - This email and any file transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed.  Any views or opinions expressed are those of the author and do not represent the views of Derwent Shared Services, unless otherwise explicitly stated. The information contained in this email may be subject to public disclosure under the Freedom of Information Act 2000. Unless the information is legally exempt from disclosure, the confidentiality of this email cannot be guaranteed.

Derwent Shared Services is an NHS Shared Services Organisation.


More information about the tac_plus mailing list