[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As an example, let's consider radauth
program
(see section radauth
). Its main purpose is to send authentication
request to the remote server, analyze its reply and if it is
positive, send an appropriate accounting record, thereby initiating
user's session. Optionally, the script should also be able to
send a lone accounting record.
In the discussion below, we will show and explain subsequent parts of the script text. For the ease of explanation, each line of program text will be prepended by its ordinal line number.
The script begins as follows:
1 #! /usr/bin/radtest -f 2 3 while getopt "n:s:P:hv" 4 begin 5 case $OPTVAR in 6 "-n") NASIP = $OPTARG 7 "-s") SID = $OPTARG 8 "-P") PID = $OPTARG 9 "-v") set -v |
It is a pragmatic comment informing shell that it
should run radtest
in order to interpret the program.
This line starts option processing loop. Getopt
(see section getopt) in line 3 analyzes each
subsequent command line argument and if it is an option checks
whether it matches one of the option letters defined in its
first argument. The option letter will be returned in OPTVAR
variable, its argument (if any) – in OPTARG
variable.
OPTARG
value is analyzed using case
statement. Lines
6 – 8 preserve OPTARG
values in appropriate variables for
later use. NASIP
will be used as the value of
NAS-IP-Address
attribute, SID
is the session id
(Acct-Session-Id
attribute), and PID
is the port
number (for NAS-Port-Id
attribute.
This line sets ‘-v’ option to the radtest
interpreter (see section Invoking radtest).
The next piece of code handles ‘-h’ and erroneous options:
10 "-h") begin 11 print <<-EOT 12 usage: radauth [OPTIONS] [COMMAND] login [password] 13 Options are: 14 -v Print verbose descriptions of what is being done 15 -n IP Set NAS IP address 16 -s SID Set session ID 17 -P PORT Set NAS port number 18 COMMAND is one of: 19 auth Send only Access-Request (default) 20 acct Send Access-Request. If successfull, send 21 accounting start request 22 start Send accounting start request 23 stop Send accounting stop request 24 EOT 25 exit 0 26 end 27 ".*") begin 28 print "Unknown option: " $OPTVAR "\n" 29 exit 1 30 end 31 end 32 end |
Print short description and exit, if the program is given ‘-h’. Notice that ‘here document’ syntax is used to print the text (See section Character Strings, for its description). The leading whitespace in lines 12 to 24 is composed of tabulation characters (ASCII 9), not usual space characters (ASCII 32), as required by ‘<<-’ construct.
These lines handle unrecognized options.
Closes case statement started on line 5
Closes compound statement started on line 4
33 34 shift ${OPTIND}-1 35 36 if $# > 3 37 begin 38 print "Wrong number of arguments." 39 print "Try radauth -h for more info" 40 exit 1 41 end |
OPTIND
keeps the ordinal number of the first non-optional
argument. This line shifts off all the options processed by
getopt
, so that the first non-optional argument may be
addressed by $1
notation. Notice use of curly braces to
solve minus ambiguity (see minus-ambiguity).
At this point we may have at most three arguments: command, user name, and password. If there are more, display the diagnostic message and exit the program.
Next piece of code:
42 43 case $1 in 44 "auth|acct|start|stop") begin 45 COMMAND=$1 46 shift 1 47 end 48 ".*") COMMAND="auth" 49 end 50 51 LOGIN=${1:?User name is not specified. Try radauth -h for more info.} 52 53 if ${NASIP:-} = "" 54 NASIP=$SOURCEIP 55 56 LIST = ( User-Name = $LOGIN NAS-IP-Address = $NASIP ) |
Check if a command is given. If so, store command name in the variable
COMMAND
and shift arguments by one, so login becomes argument
$1
. Otherwise, assume ‘auth’ command.
If the user login name is supplied, store it into LOGIN
variable. Otherwise, print diagnostic message and exit.
Provide a default value for NASIP
variable from the built-in
variable SOURCEIP
(see section Built-in Variables)
The variable LIST
will hold the list of A/V pairs to be sent
to the server. This line initializes it with a list of two A/V pairs:
User-Name
and NAS-IP-Address
.
Accounting function will be used to send accounting requests to
the server. It is supposed to take a single argument: an avlist
of A/V pairs to be sent to the server.
57 58 'acct' 59 begin 60 if ${SID:-} = "" 61 input "Enter session ID: " SID 62 if ${PID:-} = "" 63 input "Enter NAS port ID: " PID 64 send acct Accounting-Request $1 + \ (Acct-Session-Id = $SID NAS-Port-Id = $PID) |
These lines start the function definition. Notice quoting of the function name (‘acct’): it is necessary because it coincides with a reserved keyword (see section Reserved Keywords).
If the value of SID
(session ID) is not supplied, prompt the
user to input it.
If the value of PID
(port ID) is not supplied, prompt the
user to input it.
Send accounting request. The list of A/V pairs to send is formed by
concatenating Acct-Session-Id
and NAS-Port-Id
attributes
to the function's first argument.
The final part of acct
function analyzes the reply from the
server:
65 if $REPLY_CODE != Accounting-Response 66 begin 67 print "Accounting failed.\n" 68 exit 1 69 end 70 print "Accounting OK.\n" 71 exit 0 72 end 73 |
Notice, that acct
never returns. Instead it exits with an
error code indicating success or failure.
The purpose of the authentication function auth
is
to send an Access-Request
to the server and perform
some actions based on its reply.
The function will take three arguments:
$1
The list of A/V pairs to include in the request.
$2
User password.
$3
This argument indicates whether accounting request must be sent after successful authentication. String ‘yes’ means to send the accounting request, ‘no’ means not to send it.
The function is not expected to return. Instead it should exit to the shell with an appropriate error code.
74 'auth' 75 begin 76 send auth Access-Request $1 + (User-Password = $2) |
Begin the function definition. Notice quoting of the function name (‘auth’): it is necessary because it coincides with a reserved keyword (see section Reserved Keywords).
Send the initial authentication request. The list of A/V pairs is
formed by appending User-Password
pair to the list given
by the first argument to the function.
The rest of the function analyzes the reply from the server and takes
appropriate actions. Notice that if the server replies with an
Access-Challenge
packet, we will have to send subsequent
authentication requests, so this piece of code is enclosed within
a while
loop.
First, the function handles Access-Accept
and
Access-Reject
replies:
77 while 1 78 begin 79 if $REPLY_CODE = Access-Accept 80 begin 81 print "Authentication passed. " + $REPLY[Reply-Message*] + "\n" 82 if ${3:-no} = no 83 exit 0 84 'acct'($1 + ( Acct-Status-Type = Start )) 85 end else if $REPLY_CODE = Access-Reject 86 begin 87 print "Authentication failed. " + $REPLY[Reply-Message*] + "\n" 88 break |
Begin an “endless” while
loop. It will eventually be exited
either using break
, or using exit
(see below).
Hanlde Access-Accept
replies:
Print the reply message. Notice the use of ‘*’ to print all
the instances of Reply-Message
attribute from the reply
packet (see section Accessing Elements of A/V Pair Lists).
If the third argument is missing or is a string ‘no’, exit indicating success (see section Dereferencing Variables).
Otherwise, call acct
function to perform accounting. The
A/V pairs included in the accounting request are formed by adding
Acct-Status-Type
attribute to the list given by the first
argument to the function.
Handle Access-Reject
replies. Print the reply message and
break from the loop.
Next piece of code deals with Access-Challenge
replies. For
simplicity we assume that such replies always carry user menus
(See section Login Menus — ‘raddb/menus’, for the description of these). So, upon
receiving an Access-Challenge
we should print out the menu,
read the users selection and send back an Access-Request
to the server. This part is the only one that actually continues
the loop at line 77.
89 end else if $REPLY_CODE = Access-Challenge 90 begin 91 print $REPLY[Reply-Message*] 92 input 93 send auth Access-Request \ 94 (User-Name = $LOGIN User-Password = $INPUT \ State = $REPLY[State]) |
Print the menu contents carrieb by Reply-Message
attributes. There may be several instances of the attribute, hence the
use of ‘*’ to concatenate their values together.
Read the input from the user. The input will be stored in INPUT
variable. See section Built-in Primitives, for the description of
input
statement.
Send an Access-Request
packet with three attributes.
User-Password
contains the user reply, State
contains
the menu state from the server reply packet.
Final part of the function:
95 end else begin 96 print "Authentication failed. Reply code " + $REPLY_CODE + "\n" 97 break 98 end 99 end 100 exit 1 101 end 102 |
Handle unknown reply codes.
Closes the while loop started on line 77.
Exit to the shell indicating failure. This statement will be reached
only if a break
is executed either on line 88 or on line 97.
Closes function definition started on lines 74 – 75
The final part selects an action based on the user command and
executes it. It is equivalent to the main
function in a
C
program:
103 case ${COMMAND} in 104 "auth") 'auth'($LIST, ${2:&Password: }, no) 105 "acct") 'auth'($LIST, ${2:&Password: }, yes) 106 "start") 'acct'($LIST+(Acct-Status-Type = Start)) 107 "stop") 'acct'($LIST+(Acct-Status-Type = Stop)) 108 ".*") begin 109 print "Unknown command. Try radauth -h for more info" 110 exit 1 111 end 112 end 113 114 # End of radauth |
Select an action based on the value of COMMAND
variable.
Call auth
function. If the second argument is given in the
command line, its value is taken as user's password. Otherwise, the
user is prompted for the password with the string ‘Password: ’.
The input is read with echo turned off to prevent the password from
being compromised (the ‘:&’ construct, see section Dereferencing Variables).
Call acct
function for ‘start’ and stop
commands.
Handle an unknown command verb.
Closes case
statement from line 103.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by Sergey Poznyakoff on December, 6 2008 using texi2html 1.78.