#!/usr/bin/perl
#
# Sample login-Skript for use with radlogin
#
# Copyright  (c)  1998  S.u.S.E. GmbH  Fuerth, Germany.
#
# please send bugfixes or comments to feedback@suse.de.
#
# derived partly from login.radius/migs/login.radius
# currently does not do anything useful - for testing purposes only
# It only sets up Accounting for a simple Rlogin-User
#
# You can install this is /usr/sbin/login.radius for testing with
# radlogin

use strict;

# Programs and files.
my $prog_radacct  = "/usr/bin/radacct";
my $prog_rlogin   = "/usr/bin/rlogin";
my $prog_telnet   = "/usr/bin/telnet";
my $prog_tcpclear = "/usr/bin/telnet -e ''";
my $prog_tty      = "/usr/bin/tty";
my $prog_who      = "/usr/bin/who";

my $debug = 1;

my $path_radiusclient_map = "/etc/radclient/port-id-map";

my $login_host = "0.0.0.0";

#############################################################################

# Main program.

print "Starting.\n" if ($debug);

# Run 'who am i' to determine the current port.
my $port = `$prog_tty`;
chomp ($port);

# Translate port numbers to numbers for RADIUS.
# This translation is done again by radacct, but it may be useful here.
# Remove if CPU time is a problem.

my ($portid, $line);
open (H, $path_radiusclient_map);
while (($line = <H>) && (!$portid))
{
    my @info = split (/\s+/, $line);
    $portid = $info[1] if ($info[0] eq $port);
}
close (H);

if ($debug)
{
    # Print out all the RADIUS variables.
    my @el = grep (/^RADIUS/, keys (%ENV));
    my $e;
    foreach $e (@el)
    {
       print "$e = " . $ENV{$e} . "\n";
    }
}

# If the service type is Framed, then give them PPP.
# SLIP is not implemented (and will probably never be).
my $username = $ENV{"RADIUS_USER_NAME"};

# Generate a "unique" string for the session ID.
my $sessionid = "$$" . time ();

if ($ENV{"RADIUS_SERVICE_TYPE"} =~ /Login/)
{
    # Warning:  This code has not been tested as well as the PPP version,
    # as of now (19961107).

    # Determine what host to connect to.
    if (($ENV{"RADIUS_LOGIN_IP_HOST"} eq "0.0.0.0") ||
       !defined ($ENV{"RADIUS_LOGIN_IP_HOST"}))
    {
       die ("login_host not defined");
    }
    elsif ($ENV{"RADIUS_LOGIN_IP_HOST"} eq "255.255.255.255")
    {
       # The user should be able to choose.  Prompt the user.
       print "Host to connect to?  ";
       $login_host = <STDIN>;
       chomp ($login_host);
    }
    else
    {
       # Use what's specified by the RADIUS server.
       $login_host = $ENV{"RADIUS_LOGIN_IP_HOST"};
    }

    # Log into a host.  Default to telnet.  Do the accounting
    # now, since the target of the login wouldn't know how to
    # account for it.

    # Time.
    my $timestart = time ();
    my $login_service = $ENV{"RADIUS_LOGIN_SERVICE"};

    # What protocol are we running?
    my ($prog_run, $login_port);

    if ($login_service eq "Rlogin")
    {
       $prog_run = $prog_rlogin;
    }
    elsif ($login_service eq "Telnet")
    {
       $prog_run = $prog_telnet;
       $login_port = $ENV{"RADIUS_LOGIN_PORT"};
    }
    elsif ($login_service eq "TCP-Clear")
    {
       $prog_run = $prog_tcpclear;
       $login_port = $ENV{"RADIUS_LOGIN_PORT"};
    } else {
        die "unkown login_service $login_service\n";
    }

    # Start accounting.  Send the record.
    open  (H, "| $prog_radacct") || die ("Cannot run $prog_radacct");

    my $cmd =
       "Acct-Session-ID = \"$sessionid\"\n" .
       "User-Name = \"$username\"\n" .
       "Acct-Status-Type = Start\n" .
        "Acct-Authentic = RADIUS\n" .
        "Service-Type = Login-User\n" .
        "Login-Service = " . $login_service . "\n" .
        "Login-IP-Host = $login_host\n";
    print H $cmd;
    close (H);

    # Store the user information into portinfo.  We need to
    # manually fork, since we have to know the PID of the program.

    my $pid = fork ();
    if ($pid == 0)
    {
       # Child.  Run the program.
       # print "Connecting to $login_host:\n";
       my $cmd = "$prog_run $login_host $login_port";
       print "Running $cmd\n" if ($debug);
       exec ("$cmd");
    }
    else
    {
       # Parent.
       $login_host = $ENV{"RADIUS_LOGIN_IP_HOST"};
    }

    # Log into a host.  Default to telnet.  Do the accounting
    # now, since the target of the login wouldn't know how to
    # account for it.

    # Time.
    my $timestart = time ();
    my $login_service = $ENV{"RADIUS_LOGIN_SERVICE"};

    # What protocol are we running?
    my ($prog_run, $login_port);

    if ($login_service eq "Rlogin")
    {
       $prog_run = $prog_rlogin;
    }
    elsif ($login_service eq "Telnet")
    {
       $prog_run = $prog_telnet;
       $login_port = $ENV{"RADIUS_LOGIN_PORT"};
    }
    elsif ($login_service eq "TCP-Clear")
    {
       $prog_run = $prog_tcpclear;
       $login_port = $ENV{"RADIUS_LOGIN_PORT"};
    } else {
        die "unkown login_service $login_service\n";
    }

    # Start accounting.  Send the record.
    open  (H, "| $prog_radacct") || die ("Cannot run $prog_radacct");

    my $cmd =
       "Acct-Session-ID = \"$sessionid\"\n" .
       "User-Name = \"$username\"\n" .
       "Acct-Status-Type = Start\n" .
        "Acct-Authentic = RADIUS\n" .
        "Service-Type = Login-User\n" .
        "Login-Service = " . $login_service . "\n" .
        "Login-IP-Host = $login_host\n";
    print H $cmd;
    close (H);

    # Store the user information into portinfo.  We need to
    # manually fork, since we have to know the PID of the program.

    my $pid = fork ();
    if ($pid == 0)
    {
       # Child.  Run the program.
       # print "Connecting to $login_host:\n";
       my $cmd = "$prog_run $login_host $login_port";
       print "Running $cmd\n" if ($debug);
       exec ("$cmd");
    }
    else
    {
       # Parent.
       # Create the portinfo record, which needs the pid of the program
       # to kill.
       # The IP address is all zero, as it is not applicable here.
       # Store the time now, and the Session-Timeout.

       # Wait for the session to finish.
       waitpid ($pid, 0);
    }
    # Stop.  Send the record.
    open  (H, "| $prog_radacct") || die ("Cannot run $prog_radacct");

    my $timespent = time () - $timestart;

    my $cmd =
       "Acct-Session-ID = \"$sessionid\"\n" .
       "User-Name = \"$username\"\n" .
       "Acct-Status-Type = Stop\n" .
        "Acct-Authentic = RADIUS\n" .
        "Service-Type = Login-User\n" .
        "Login-Service = " . $login_service . "\n" .
        "Login-IP-Host = $login_host\n" .
        "Acct-Session-Time = $timespent\n";

    print H $cmd;
    close (H);
} else {
    my $r = $ENV{"RADIUS_SERVICE_TYP"};
    print "Unhandled Service-Type $r\n";
}

### END ####




       # Create the portinfo record, which needs the pid of the program
       # to kill.
       # The IP address is all zero, as it is not applicable here.
       # Store the time now, and the Session-Timeout.

       # Wait for the session to finish.
       waitpid ($pid, 0);
    }
    # Stop.  Send the record.
    open  (H, "| $prog_radacct") || die ("Cannot run $prog_radacct");

    my $timespent = time () - $timestart;

    my $cmd =
       "Acct-Session-ID = \"$sessionid\"\n" .
       "User-Name = \"$username\"\n" .
       "Acct-Status-Type = Stop\n" .
        "Acct-Authentic = RADIUS\n" .
        "Service-Type = Login-User\n" .
        "Login-Service = " . $login_service . "\n" .
        "Login-IP-Host = $login_host\n" .
        "Acct-Session-Time = $timespent\n";

    print H $cmd;
    close (H);
} else {
    my $r = $ENV{"RADIUS_SERVICE_TYP"};
    print "Unhandled Service-Type $r\n";
}

### END ####
