[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2 radtest

Radtest is a radius client shell, providing a simple and convenient language for sending requests to RADIUS servers and analyzing their reply packets.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.1 Invoking radtest

(This message will disappear, once this node revised.)

-a variable=value
--assign=variable=value

Assign a value to variable. See section Assignment Options, for a detailed discussion.

-f file
--file=file

Read input from file. Stops further processing of the command line.

-i
--no-interactive

Disable interactive mode.

-n
--dry-run

Check the input file syntax and exit.

-q
--quick

Do not read the configuration file.

-r number
--retry=number

Set number of retries.

-s server
--server=server

Set radius server parameters.

-t number
--timeout=number

Set timeout

-v
--verbose

Verbose mode

-x debugspec
--debug=debugspec

Set debugging level

-d dir
--directory dir

Specify alternate configuration directory. Default is ‘/usr/local/etc/raddb’.

-L
--license

Print license and exit.

-?
--help

Print short usage summary

--usage

Print even shorter usage summary.

-V
--version

Print program version.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.2 Literal Values

There are four basic data types in radtest language: integer, ipaddr, string and avlist.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.2.1 Numeric Values

Integer means a signed integer value in the range -2147483648..2147483647.

Ipaddr is an unsigned integer value suitable for representing IPv4 addresses. These can be input either as decimal numbers or as IP addresss in usual “dotted-quad” notation.

As a convenience measure, RADIUS request code names can be used in integer context. The following table lists currently defined request names with their integer codes:

Access-Request

1

Access-Accept

2

Access-Reject

3

Accounting-Request

4

Accounting-Response

5

Accounting-Status

6

Password-Request

7

Password-Ack

8

Password-Reject

9

Accounting-Message

10

Access-Challenge

11

Status-Server

12

Status-Client

13

Ascend-Terminate-Session

31

Ascend-Event-Request

33

Ascend-Event-Response

34

Ascend-Allocate-IP

51

Ascend-Release-IP

52


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.2.2 Character Strings

String is an arbitrary string of characters. Any input token consisting of letters of Latin alphabet, decimal digits, underscores dashes and dots and starting with a Latin alphabet letter or underscores is considered a string. To input strings containing other letters, surround them by double quotes. The following are valid strings:

 
A-string
"String, containing white space"

The double quote character ‘"’ must be preceeded by a backslash ‘\’ if it is part of a string:

 
"Always quote \" character"

Generally speaking, ‘\’ is an escape character, that alters the meaning of the immediately following character. If it is located at the end of the line, it allows to input newline character to strings:

 
"This string contains a \
newline character."

Other special escape sequences are:

\a

Audible bell character (ASCII 7)

\b

Backspace (ASCII 8)

\e

Escape character (ASCII 27)

\f

Form feed (ASCII 12)

\n

Newline (ASCII 10)

\r

Carriage return (ASCII 13)

\t

Horizontal tab (ASCII 9)

\\

Backslash

\ooo

(‘o’ represents an octal digit) A character whose ASCII value is represented by the octal number ‘ooo’.

\xHH
\XHH

(‘H’ represents a hex digit) A character whose ASCII value is represented by the hex number ‘HH’.

If the character following the backslash is not one of those specified, the backslash is ignored.

An important variant of string is a numeric string, or STRNUM for short. A numeric string is a string that can be converted to a number, for example "+2". This concept is used for type conversion between integer and string values.

Another way to represent strings is using here document syntax. Its format is as follows:

 
<<[-]delimiter
  text
delimiter

Delimiter is any word you choose to delimit the text, text represent the text of the string. If delimiter is prepended by a dash, any leading tabulation characters will be removed from text. This allows for natural indentation of ‘here document’ constructs.

The ‘here document’ construct is especially useful to represent strings containing embedded newlines, as shown in the example below:

 
print <<EOT
usage: foo [OPTIONS] [NAME...]
OPTIONS are:
  -h            Print this help list.
EOT

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.2.3 Lists of A/V pairs

Avlist are whitespace or comma-separated lists of RADIUS attribute-value pairs. A syntax for A/V pair is

 
name op value

where name is attribute name, op is a comparison operator (‘=’, ‘!=’, ‘<’, ‘<=’, ‘>’, ‘>=’), and value is any valid radtest data or expression. An A/V pair list must be enclosed in parentheses. This is an example of an A/V pair list consisting of two pairs:

 
( User-Name = "test" NAS-IP-Address = 10.10.10.1 )

An empty pair list is represented by a pair of parentheses: ().


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.3 Reserved Keywords

The following keywords are reserved in radtest:

 
acct, and, auth, begin, break, case, continue, 
do, else, end, exit, expect, getopt, if,       
in, input, not, or, print, return, send,     
set, shift, while    

The reserved keywords may be used as variable names, provided that the following requrements are met:


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.4 Variables

Variables are means of storing data values at one point of your program for using them in another parts of it. Variables can be assigned either in the program itself, or from the radtest command line.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.4.1 Using Variables

The name of a variable must be a sequence of letters, digits, underscores and dashes, but it may not begin with a digit or dash. Notice, that in contrast to the majority of programming languages, use of dashes (minus signs) is allowed in user names. This is because traditionally RADIUS attribute names contain dashes, so extending this practice to variable names makes radtest programs more consistent. On the other hand, this means that you should be careful when using minus sign as a subtraction operator (see minus-ambiguity). Case is significant in variable names: a and A are different variables.

A name of a variable may coincide with one of radtest reserved keywords. See section Reserved Keywords, for description on how to use such variables.

A few variables have special built-in meanings (see section Built-in Variables). Such variables can be assigned and accessed just as any other ones. All built-in variables names are entirely upper-case.

Variables are never declared, they spring into existence when an assignment is made to them. The type of a variable is determined by the type of the value assigned to it.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.4.2 Variable Assignments

An assignment stores a new value into a variable. It's syntax is quite straightforward:

 
variable = expression

As a result of the assignment, the expression is evaluated and its value is assigned to variable. If variable did not exist before the assignment, it is created. Otherwise, whatever old value it had before the assignment is forgotten.

It is important to notice that variables do not have permanent types. The type of a variable is the type of whatever value it currently holds. For example:

 
foo = 1
print $foo ⇒ 1
foo = "bar"
print $foo ⇒ bar
foo = ( User-Name = "antonius" NAS-IP-Address = 127.0.0.1 )
print $foo ⇒ ( User-Name = "antonius" NAS-IP-Address = 127.0.0.1 )

Another important point is that in radtest, assignment is not an expression, as it is in many other programming languages. So C programmers should resist temptation to use assignments in expressions. The following is not correct:

 
x = y = 1

Finally, if the variable name coincides with one of radtest keywords, it must be enclosed in single quotes:

 
'case' = 1

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.4.3 Dereferencing Variables

Dereferencing a variable means accessing its value. The simplest form of dereferencing is by prepending a dollar sign to the variable name:

 
foo = 1
print foo ⇒ foo
print $foo ⇒ 1

Notice, that in the example above, the first print statement understands foo as a literal string, whereas the second one prints the value of the variable.

Dereferencing an undefined variable produces error message:

 
print $x error--> variable `x' used before definition

Optionally, the variable name may be surrounded by curly braces. Both $foo and ${foo} are equivalent. The use of the latter form is obligatory only when the variable name coincides with one of the reserved keywords (see section Reserved Keywords). It also can be used to resolve ambiguity between using dash as a part of user name and as a subtraction operator:

 
long-name = 2
$long-name ⇒ 2
$long-name-1 error--> variable `long-name-1' used before definition
${long-name}-1 ⇒ 1
$long-name - 1 ⇒ 1

We recommend to always surround ‘-’ with whitespace when it is used as arithmetic operator.

The ${} notation also permits some operations similar to shell variable substitution.

${variable:-text}

Use default values. If variable is unset, return text, otherwise return the value of the variable.

 
$x error--> variable `x' used before definition
${x:-1} ⇒ 1
x = 2
${x:-1} ⇒ 2
${variable:=text}

Assign default values. If variable is unset, text is assigned to it. The expression always returns the value of the variable.

 
$x error--> variable `x' used before definition
${x:=1} ⇒ 1
$x ⇒ 1
${variable:?text}

Display error if unset. If variable is unset, text is written to the standard error (if text is empty, the default diagnostic message is used) and further execution of the program is aborted. Otherwise, the value of variable is returned.

 
$x error--> variable `x' used before definition
${x:?} error--> x: variable unset
${x:?foobar} error--> foobar
${variable::text}

Prompt for the value if unset. If variable is unset, radtest prints text (or a default message, if it is empty), reads the standard input up to the newline character and returns the value read. Otherwise, the value of the variable is returned. This notation provides a convenient way for asking user to supply default values.

 
${x::} -| (<teletype>:1)x?
${x::Enter value of x: } -| Enter value of x: 
${variable:&text}

Prompt for the value with echo turned off if unset. This is similar to the ${variable::text}, with the exception that the input value will not be echoed on the screen. This notation provides a convenient way for asking user to supply default values for variables (such as passwords, shared secrets, etc.) while preventing them from being compromised.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.4.4 Accessing Elements of A/V Pair Lists

Elements of an avlist are accessed as if it were an array, i.e.:

 
$variable [ attribute-name ]

If the attribute attribute-name is of string data type and variable may contain more than one pair with this attribute, adding an asterisk after attribute-name returns concatenated values of all such pairs:

 
$variable [ attribute-name * ]

Examples:

 
x = (NAS-Port-Id = 127.0.0.1 \
     Reply-Message = "a long"
     Reply-Message = " string"

$x[NAS-Port-Id] ⇒ 127.0.0.1
$x[Reply-Message] ⇒ "a long"
$x[Reply-Message*] ⇒ "a long string"

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.4.5 Assignment Options

You can set any radtest variable from the command line. There are two ways of doing so.

First, you can use variable assignment option--assign’ (or ‘-a’). Its syntax is:

 
--assign variable=text
-a variable=text

For example:

 
radtest -a foobar=5

Another way is useful when you load a radtest program by ‘--file’ or ‘-f’. This second way consists in including a variable assignment in the form

 
variable=text

in the command line after the script name. For example:

 
radtest -f myprog.rad foo=5 addr=127.0.0.1

This method is especially useful for executable scripts that are run using #! shell magic. Consider a simple script:

 
#! /usr/local/bin/radtest -f
print $addr

The value of addr can be given to the script from the command line as in the example below:

 
myprog.rad addr=127.0.0.1

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.4.6 Built-in Variables

The following variables are predefined:

_

(an underscore character)

Contains the result of last evaluated expression.

REPLY_CODE

Contains the last reply code received from the RADIUS server (integer).

REPLY

Contains the A/V pairs lastly received from the RADIUS server (avlist).

SOURCEIP

Contains the source IP address of the RADIUS client (ipaddr). By default, it equals the IP address set via source_ip statement in your ‘client.conf’ file (see section Client Configuration).

INPUT

The value of the input read by input statement (see section input).

OPTVAR

The option obtained by the recent call to getopt (see section getopt).

OPTARG

Argument to the option obtained by the recent call to getopt.

OPTIND

Index of the next command line argument to be processed by getopt. If the last call to getopt returned false, OPTIND contains index of the first non-optional argument in the command line.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.5 Positional Parameters

Normally radtest stops parsing its command line when it encounters either first non-optional argument (i.e. the one not starting with dash), or an argument consisting of two dashes. The rest of the command line starting from the first non-optional argument forms positional parameters. These parameters are said to form the top-level environment.

Similarly, when invoking a user-defined function (see section Function Definitions), arguments passed to it are said to form the current environment of the function. These arguments are positional parameters for this function.

Positional parameters are assigned numbers starting from 1. To access (dereference) a positional parameter, the syntax $n is used, where n is the number of the parameter. Alternative forms, such as ${n} or ${n:-text}, can also be used. These work exactly as described in Dereferencing Variables).

The number of positional parameters can be accessed using a special notation $#.

Several things need to be mentioned:

For example, suppose you run:

 
radtest -f script.rad name foo=bar 5

Then, the top-level environment of program ‘script.rad’ consists of the following variables:

 
$0 ⇒ script.rad
$1 ⇒ name
$2 ⇒ 5

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.6 Expressions

An expression evaluates to a value, which can be printed, assigned to a variable, used in a conditional statement or passed to a function. As in other languages, expressions in radtest include literals, variable and positional parameter dereferences, function calls and combinations of these with various operators.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.6.1 Arithmetic Operations

Radtest provides the common arithmetic operators, which follow normal precedence rules (see section Operator Precedence (How Operators Nest)), and work as you would expect them to. The only notable exception is subtraction operator (minus) which can be used as part of a variable or attribute name, and therefore expressions like $x-3 are ambiguous. This expression can be thought of either as a dereference of the variable x-3 (see section Dereferencing Variables), or as subtraction of the value 3 from the value of the variable x. Radtest always resolves this ambiguityin the favor of variable dereference. Therefore we advise you to always surround minus sign by whitespace, if it is used as a subtraction operator. So, instead of $x-3, write $x - 3. For other methods of solving this ambiguity, See minus-ambiguity.

This table lists the arithmetic operators in order from highest precedence to lowest:

- x

Negation.

+ x

Unary plus. This is equivalent to x.

x * y

Multiplication.

x / y

Division.

x % y

Remainder.

x + y

Addition.

x - y

Subtraction.

Unary plus and minus have the same precedence, the multiplication, division and remainder all have the same precedence, and addition and subtraction have the same precedence.

If x and y are of different data types, their values are first coerced to a common data type, selected using a set of rules (see section Conversion Between Data Types).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.6.2 String Operations

There is only one string operation: concatenation. It is represented by plus sign, e.g.:

 
"string" + "ent" ⇒ "stringent"

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.6.3 Operations on A/V Lists

(This message will disappear, once this node revised.)

The following operations are defined on A/V lists:

x + y

Addition. The A/V pairs from y are added to x, honoring the respective pairs additivity (see section additivity). For example:

 
( User-Name = "foo" ) + ( Password = "bar" )
⇒ ( User-Name = "foo" Password = "bar" )

( User-Name = "foo" Service-Type = Login-User ) + \
 ( Service-Type = Framed-User Password = "bar" )
⇒ ( User-Name = "foo" \
          Service-Type = Framed-User \
          Password = "bar" )
x - y

Subtraction. The result of this operation is an A/V list consisting of pairs from x, which are not found in y.

 
( User-Name = "foo" Service-Type = Login-User ) - \
( Service-Type = Framed-User )
⇒ ( User-Name = "foo" )

Notice, that only attribute name matters, its value is ignored.

x % y

Intersection. The result of this operation is an A/V pair list consisting of pairs from x which are also present in y.

 
( User-Name = "foo" Service-Type = Login-User ) - \
( Service-Type = Framed-User )
⇒ ( Service-Type = Login-User )

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.6.4 Comparison Operations

Comparison expressions compare operands for relationships such as equality. They return boolean values, i.e. true or false. The comparison operations are nonassociative, i.e. they cannot be used together as in:

 
# Wrong!
1 < $x < 2

Use boolean operations (see section Boolean Operations) to group comparisons together.

Comparison operations can only be used in conditional expressions.

This table lists all comparison operators in order from highest precedence to lowest (notice, however, the comment after it):

x = y

True if x is equal to y. C and AWK programmers, please note single equal sign!

x != y

True if x is not equal to y.

x < y

True if x is less than y.

x <= y

True if x is less than or equal to y.

x > y

True if x is greater than y.

x >= y

True if x is greater than or equal to y.

Operators = and != have equal precedence. Operators <, <=, >, >= have equal precedence.

Most operators are defined for all radtest data types. However, only = and != are defined for avlists. Using any other comparison operator with avlists produces error.

If x and y are of different data types, their values are first coerced to a common data type, selected using a set of rules (see section Conversion Between Data Types).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.6.5 Boolean Operations

A boolean operation is a combination of comparison expressions. Boolean operations can only be used in conditional expressions.

This table lists all comparison operators in order from highest precedence to lowest.

not x
! x

True if x is false.

x and y

True if both x and y are true. The subexpression y is evaluated only if x is true.

x or y

True if at least one of x or y is true. The subexpression y is evaluated only if x is false.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.6.6 Conversion Between Data Types

(This message will disappear, once this node revised.)

The unary negation operand is always converted to integer type:

 
-(1 + 1)  ⇒ -2
-(127.0.0.1 + 2) ⇒ -2130706435
- ("1" + "1") ⇒ -11
- "text" error--> cannot convert string to integer

The unary not operand is converted using the following rules:

  1. If the operand is integer, no conversion is performed.
  2. If the operand is STRNUM (see STRNUM) or ipaddr, it is converted to integer.
  3. If the operand is string (but is not STRNUM), the result of not is true only if the operand is an empty string.
  4. If the operand is avl, the result of not is true if the list is empty.

Examples:

 
not 0 ⇒ 1
not 10 ⇒ 0
not "23" ⇒ 0
not "0" ⇒ 1
not "text" ⇒ 0
not "" ⇒ 1
not 127.0.0.1 ⇒ 0
not 0.0.0.0 ⇒ 1

When operands of two different data types are used in a binary operation, one of the operands is converted (cast) to another operand's type according to the following rules:

  1. If one of the operands is literal, radtest attemtps to convert another operand to the literal data type. If this attempt fails, it goes on to rule 2.
  2. If one of operands is STRNUM (see STRNUM) and another is of numeric data type (i.e. either integer or ipaddr), the latter is converted to string representation.
  3. If one of the operands is ipaddr and another is integer, the latter is converted to ipaddr.
  4. Otherwise, if one of the operands is string, the second operand is also converted to string.
  5. Otherwise, the two operands are incompatible. Radtest prints appropriate diagnostics and aborts execution of the current statement.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.6.7 Function Calls

A function is a name for a particular sequence of statements. It is defined using special definition syntax (see section Function Definitions). Normally a function return some value. The way to use this value in an expression is with a function call expression, which consists of the function name followed by a comma-separated list of arguments in parentheses. The arguments are expressions which provide values for the function call environment (see section Positional Parameters. When there is more than one argument, they are separated by commas. If there are no arguments, write just ‘()’ after the function name. Here are some examples:

 
foo()             no arguments
bar(1)            one argument
bar(1, "string")  two arguments

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.6.8 Operator Precedence (How Operators Nest)

Operator precedence determines the order of executing operators, when different operators appear close by in one expression. For example, * has higher precedence than +; thus, a + b * c means to multiply b and c, and then add a to the product.

You can overrule the precedence of the operators by using parentheses. You can think of the precedence rules as saying where the parentheses are assumed to be if you do not write parentheses yourself. Thus the above example is equivalent to a + (b * c).

When operators of equal precedence are used together, the leftmost operator groups first. Thus, a - b + c groups as (a - b) + c.

This table lists radtest operators in order from highest precedence to the lowest:

$

Dereference.

(…)

Grouping.

+ - not !

Unary plus, minus. Unary boolean negation.

* / %

Multiplication, division, modulus.

+ -

Addition, subtraction.

< <= = != > >=

Relational operators.

and

Logical ‘and’.

or

Logical ‘or’.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.7 Function Definitions

A function is a name for a particular sequence of statements. The syntax for the function definition is:

 
name
begin
  …
end

where name is function name and ‘’ represent a non-empty list of valid radtest statements.

Notice that newline characters are obligatory after name, begin and before the final end keyword.

If the function accepts arguments, these can be referenced in the function body using $n notation (see section Positional Parameters). To return the value from the function return statement is used.

For example, here is a function that computes sum of the squares of its two arguments:

 
hypo
begin
        return $1*$1 + $2*$2
end

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.8 Interacting with Radius Servers

Radtest provides two commands for interaction with remote RADIUS servers.

Command send sends request to the server specified in ‘raddb/client.conf’. Its syntax is:

 
send [flags] port-type code [expr-or-pair-list]

Optional flags can be used for fine-tuning the internals of send. You will seldom need to use these, unless you are developing GNU Radius. See section send, for the detailed description of these.

The first obligatory argument, port-type, specifies which RADIUS port to send the request to. Specifying ‘auth’ will send the request to the authentication port (see section auth-port); specifying ‘acct’ will send it to the accounting port (see section acct-port).

Argument code gives the request code. It is either a number or a symbolic request code name (see section Numeric Values).

The last argument, expr-or-pair-list is either a radtest expression evaluating to avlist or a list of A/V pairs. These pairs will be included in the request.

Here are several examples:

 
# Send a Status-Server request without attributes.
send auth Status-Server

# Send an Access-Request with two attributes
send auth Access-Request User-Name = "foo" User-Password = "bar"

# Send an Accounting-Request, taking attributes from the variable
# attr
send acct Accounting-Request $attr

Command send stores the reply code into the variable REPLY_CODE and reply pairs into the variable REPLY (see section Built-in Variables).

Another primitive is expect. Expect takes at most two arguments: a request code (either numeric or symbolic, (see section Numeric Values)) and optional list of A/V pairs (similar to send expr-or-pair-list argument). Expect check if these match current REPLY_CODE and REPLY values and if so, prints the string ‘PASS’. Otherwise, it prints ‘FAIL’. This command is designed primarily for use in GNU Radius testsuite.

Expect is usually used right after send, as shown in the example below:

 
send auth Access-Request User-Name = "foo" User-Password = "bar"
expect Access-Accept Reply-Message = "Access allowed"

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.9 Conditional Statements

(This message will disappear, once this node revised.)

Radtest provides two kinds of conditional statements: if and case.

If statement

An if statement in its simplest form is:

 
if cond stmt

where cond is a conditional expression and stmt is a valid radtest statement. Optional newline may be inserted between cond stmt.

In this form, if evaluates the condition and if it yields true, executes the statement. For example:

 
if $REPLY[NAS-IP-Address] = 127.0.0.1
   print "Request from localhost"

More complex form of this statement allows to select between the two statements:

 
if cond stmt-1 else stmt-2 

Here, stmt-1 will be executed if cond evaluates to true, and stmt-2 will be executed if cond evaluates to false.

Notice, that an optional newline is allowed between cond and stmt-1 and right after else keyword. However, a newline before else constitutes an error.

If several statements should be executed in a branch of the if statement, use compound statement as in the example below:

 
if $REPLY_CODE != Accounting-Response
begin
  print "Accounting failed.\n"
  exit 1        
end else
  print "Accounting succeeded.\n"

If statements can be nested to any depth.

Case statement

Case statement allows select a statement based on whether a string expression matches given regular expression. The syntax of case statement is:

 
case expr in
expr-1 ) stmt-1
expr-2 ) stmt-2expr-n ) stmt-n
end

where expr is a control expression, expr-1, expr-2 etc. are expressions evaluating to extended POSIX regular expressions (for the detailed description of these see (regex)Top section `Regular Expression Library' in Regular Expression Library).

Case statement first evaluates expr and converts it to string data type. Then it evaluates each expr-n in turn and tests if the resulting regular expression matches expr. If so, the statement stmt-n is executed and the execution of case statement finishes.

The following example illustrates the concept:

 
case $COMMAND in
"auth.*")       authenticate($LIST, no)
"acct")         authenticate($LIST, yes)
".*")           begin
                  print "Unknown command."
                  exit 1
                end
end

Bourne shell programmers should notice that:


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.10 Loops

(This message will disappear, once this node revised.)

Two looping constructs are provided: while and do...while.

While loop

The syntax of a while loop is:

 
while cond
  stmt

Newline after cond is obligatory.

Do...while loop

 
do
  stmt
while cond

As usual do...while loop differs from its while counterpart in that its stmt is executed at least once.

The looping constructs can be nested to any depth.

Two special statements are provided for branching within loop constructs. These are break and continue.

Break statement stops the execution of the current loop statement and passes control to the statement immediately following it

 
while $x < 10
begin
  if $x < $y
     break
  …
  x = $x + 1
end
print "OK\n"

In the example above, execution of break statement passes control to print statement.

Break may also take an argument: a literal number representing the number of nested loop statements to break from. For example, the break statement in the sample code below will exit from the outermost while:

 
while $y < 10
begin
  while $x < 10
  begin
    if $x < $y
       break 2
    …
    x = $x + 1 
  end
  …
  y = $y + 1 
end  
print "OK\n"

Continue statement passes control to the condition of the current looping construct. When used with a numeric argument, the latter specifies the number of the nesting looping construct to pass control to (as with break, the innermost loop is considered to have number 1, so continue is equivalent to continue 1).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.11 Built-in Primitives

Radtest built-in: getopt optstring [opt [arg [ind]]]

Getopt is used to break up command line options for subsequent parsing.

The only mandatory argument, optstring is a list of short (one-character) options to be recognized. Each short option character in optstring may be followed by one colon to indicate it has a required argument, and by two colons to indicate it has an optional argument.

Each subsequent invocation of getopt processes next command line argument. Getopt returns true if the argument is an option and returns false otherwise. It stores the retrieved option (always with a leading dash) in the variable opt (OPTVAR by default). If the option has an argument, the latter is stored in the variable arg (OPTARG by default). Index of the next command line argument to be processed is preserved in the variable ind (OPTIND by default).

The usual way of processing command line options is by invoking getopt in a condition expression of while loop and analyzing its return values within the loop. For example:

 
while getopt "hf:"
case $OPTVAR in
"-h")  print "Got -h option\n"
"-f")  print "Got -f option. Argument is " $OPTARG "\n"
".*")  begin
          print "Unknown option: " $OPTVAR "\n"
          exit 1
       end
  end
end
Radtest statement: input [expr name]

Evaluates expr and prints its result on standard output. Then reads a line from standard input and assigns it to the variable name.

If expr is given, name must also be present.

If name is not given, variable INPUT is used by default.

Radtest statement: set options

Sets radtest command line options. Options should be a valid radtest command line (see section Invoking radtest).

Radtest statement: shift [expr]

Shift positional parameters left by one, so that $2 becomes $1, $3 becomes $2 etc. $# is decremented. $0 is not affected.

If expr is given, it is evaluated, converted to integer and used as shift value. Thus shift 2 shifts all positional parameters left by 2.

Radtest statement: return [expr]

Returns from the current function (see section Function Definitions). If expr is present, it is evaluated and the value thus obtained becomes the function return value.

It is an error to use return outside of a function definition.

Radtest statement: break [n]

Exit from within a loop.If n is specified, break from number levels. n must be >= 1. If n is greater than the number of enclosing loops, an error message is issued.

See section Loops, for the detailed discussion of the subject.

Radtest statement: continue [n]

Resume the next iteration of the enclosing loop. If n is specified, resume at the nth enclosing loop. n must be >= 1. If n is greater than the number of enclosing loops, an error message is issued.

See section Loops, for the detailed discussion of the subject.

Radtest statement: exit [expr]

Exit to the shell. If expr is specified, it is evaluated and used as exit code. Otherwise, 0 is returned to the shell.

Radtest statement: print expr-list

Evaluate and print expressions. Expr-list is whitespace or comma-separated list of expressions. Each expression is evaluated in turn and printed to the standard output.

Radtest statement: send [flags] port-type code expr-or-pair-list

Send a request to the RADIUS server and wait for the reply. Stores reply code in the variable REPLY_CODE and reply A/V pairs in the variable REPLY (see section Interacting with Radius Servers).

flags are a whitespace-separated list of variable assignments. Following variables are understood:

repeat=n

Unconditionally resend the request n times.

id=n

Specify the request ID.

keepauth=1

Do not alter request authenticator when resending the request.

port-type

Specifies which port to use when sending the request. Use ‘auth’ to send the request to the authentication port (see section auth-port), and ‘acct’ to send it to the accounting port (see section acct-port).

code

RADIUS request code. Either numeric or symbolic (see section Numeric Values).

expr-or-pair-list

Specifies the A/V pairs to include in the request. This argument is either an expression evaluating to avlist, or an immediate avlist (see section Lists of A/V pairs). In the latter case, the parentheses around the list are optional.

Radtest statement: expect code [expr-or-pair-list]

Test if REPLY_CODE matches code and, optionally, if REPLY matches expr-or-pair-list. If so, print the string ‘PASS’, otherwise print ‘FAIL’.

See section Interacting with Radius Servers, for the detailed discussion of this statement.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.12 Sample Radtest Program

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.

Parsing command line options

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
1

It is a pragmatic comment informing shell that it should run radtest in order to interpret the program.

3

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.

4 – 8

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.

9

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
10 – 26

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.

27 – 30

These lines handle unrecognized options.

31

Closes case statement started on line 5

32

Closes compound statement started on line 4

Checking Command Line Consistency

 
 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
34

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).

36 – 41

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 )
43 – 48

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.

51

If the user login name is supplied, store it into LOGIN variable. Otherwise, print diagnostic message and exit.

53 – 54

Provide a default value for NASIP variable from the built-in variable SOURCEIP (see section Built-in Variables)

56

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.

Defining Accounting Function

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)
58 – 59

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).

60 – 61

If the value of SID (session ID) is not supplied, prompt the user to input it.

62 – 63

If the value of PID (port ID) is not supplied, prompt the user to input it.

64

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.

Defining Authentication Function

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)
74 – 75

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).

76

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
77

Begin an “endless” while loop. It will eventually be exited either using break, or using exit (see below).

79 – 84

Hanlde Access-Accept replies:

81

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).

82 – 83

If the third argument is missing or is a string ‘no’, exit indicating success (see section Dereferencing Variables).

84

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.

85 – 88

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])
91

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.

92

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.

93 – 94

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
95 – 98

Handle unknown reply codes.

99

Closes the while loop started on line 77.

100

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.

101

Closes function definition started on lines 74 – 75

Final Part of Radauth Program

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
103

Select an action based on the value of COMMAND variable.

104 – 105

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).

106 – 107

Call acct function for ‘start’ and stop commands.

108 – 111

Handle an unknown command verb.

112

Closes case statement from line 103.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Sergey Poznyakoff on December, 6 2008 using texi2html 1.78.