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

6. Authentication

An Authentication Type specifies which credentials the user is required to supply in order to be authenticated and where the user's authentication data are stored. It is defined by the value of Auth-Type attribute in LHS of a ‘users’ entry.


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

6.1 Accept Authentication Type

Accept is the simplest authentication type. Users with this authentication type will be authenticated successfully without checking any credentials. Actually this means that only username is required for authentication.

This authentication type is used for each ‘users’ entry, whose LHS contains

 
Auth-Type = Accept

This authentication type can be used for guest accounts, e.g. the following profile in ‘users’:

 
guest   Auth-Type = Accept,
                Simultaneous-Use = 10
        Service-Type = Framed-User,
                Framed-Protocol = PPP

allows up to 10 simultaneous guest PPP accounts. To log in using such guest account it is sufficient to use username ‘guest’ and any password.


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

6.2 Reject Authentication Type

The Reject authentication type causes the request to be rejected unconditionally. It can be used to disable a user account (For another method of disabling user accounts, see section List of Blocked Users — ‘raddb/access.deny).

This authentication type is used for each ‘users’ entry, whose LHS contains

 
Auth-Type = Reject

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

6.3 Local Password Authentication Type

The Local Password authentication type allows to keep plaintext user passwords. Although the use of this authentication type is strongly discouraged for security reasons, this is the only authentication type that can be used with CHAP authentication.

There are two ways of using this authentication type

Specifying Passwords in users File.

To keep the plaintext passwords in ‘users’ file, the profile entry must follow this pattern:

 
user-name  Auth-Type = Local,
                     User-Password = plaintext

The plaintext is the user's plaintext password. Obviously, user-name may not be DEFAULT nor BEGIN.

Specifying Passwords in SQL Database.

 
user-name   Auth-Type = Local,
                      Password-Location = SQL

When the user is authenticated using such profile, its password is retrieved from the authentication database using auth_query. The configuration of SQL authentication is described in detail in Authentication Server Parameters.


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

6.4 Encrypted Password Authentication Type

The Encrypted Password type allows to keep user's passwords encrypted via DES or MD5 algorithm. There are two ways of using this authentication type.

Specifying Passwords in users File.

 
user-name  Auth-Type = Crypt-Local,
                     User-Password = crypt-pass

The Crypt-Password is a shortcut for the above notation:

 
user-name  Crypt-Password = crypt-pass

Specifying Passwords in SQL Database.

 
user-name   Auth-Type = Crypt-Local,
                      Password-Location = SQL

Using this profile, the user's password is retrieved from the authentication database using auth_query. The configuration of SQL authentication is described in detail on Authentication Server Parameters.

The shortcut for this notation is Auth-Type = SQL.

In any case, the passwords used with this authentication type must be either DES or MD5 hashed.


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

6.5 System Authentication Type

The System authentication type requires that the user have a valid system account on the machine where the radius server is running. The use of this type is triggered by setting

 
Auth-Type = System

in the LHS of a ‘users’ entry.


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

6.6 SQL Authentication Type

Setting Auth-Type = SQL or Auth-Type = Mysql in the LHS of a ‘users’ entry is a synonym for

 
Auth-Type = Crypt-Local, Password-Location = SQL

and is provided as a shortcut and for backward compatibility with previous versions of GNU Radius.

For description of SQL authentication, see Encrypted Password Authentication Type. The configuration of SQL subsystem is described in SQL Configuration — ‘raddb/sqlserver.


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

6.7 PAM Authentication Type

PAM authentication type indicates that a user should be authenticated using PAM (Pluggable Authentication Module) framework. The simplest way of usage is:

 
Auth-Type = PAM

Any user whose ‘users’ profile contains the above, will be authenticated via PAM, using service name ‘radius’. If you wish to use another service name, set it using Auth-Data attribute, e.g.:

 
Auth-Type = PAM,
    Auth-Data = pam-service

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

6.8 Defining Custom Authentication Types

The are three ways to define custom authentication types:

  1. Write a PAM module.
  2. Use a Guile procedure.
  3. Use an external program

You can write a PAM module implementing the new authentication type. Then, specifying Auth-Type = PAM allows to apply it (see section PAM Authentication Type).

Alternatively, you may write a Scheme procedure implementing the new authentication type. To apply it, use Scheme-Procedure attribute in RHS. The Auth-Type = Accept can be used in LHS if the whole authentication burden is to be passed to the Scheme procedure. For example, if one wrote a procedure my-auth, to apply it to all users, one will place the following profile in his ‘users’ file:

 
DEFAULT  Auth-Type = Accept
         Scheme-Procedure = "my-auth"

For a discussion of how to write Scheme authentication procedures, See section Authentication with Scheme.

The third way to implement your own authentication method is using an external program. This is less effective than the methods described above, but may be necessary sometimes. To invoke the program, use the following statement in the RHS of ‘users’ entry:

 
Exec-Program-Wait = "progname args"

The progname must be the full path to the program, args — any arguments it needs. The usual substitutions may be used in args to pass any request attributes to the program (see section Macro Substitution).

For a detailed description of Exec-Program-Wait attribute and an example of its use, see Exec-Program-Wait.


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

6.9 Multiple Login Checking

The number of sessions a user can have open simultaneously can be restricted by setting Simultaneous-Use attribute in the user's profile LHS (see section Simultaneous-Use). By default the number of simultaneous sessions is unlimited.

When a user with limited number of simultaneous logins authenticates himself, Radius counts the number of the sessions that are already opened by this user. If this number is equal to the value of Simultaneous-Use attribute the authentication request is rejected.

This process is run in several stages. First, Radius retrieves the information about currently opened sessions from one of its accounting databases. Then, it verifies whether all these sessions are still active. This pass is necessary since an open entry might be a result of missing Stop request. Finally, the server counts the sessions and compares their count with the value of Simultaneous-Use attribute.

The following subsections address each stage in detail.


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

6.9.1 Retrieving Session Data

Radius retrieves the list of sessions currently opened by the user either from the system database (see section System Accounting), or from the SQL database (see section sql Accounting). The system administrator determines which method to use.

By default, system accounting database is used. Its advantages are simplicity and ease of handling. It has, however, a serious deficiency: the information is kept in the local files. If you run several radius servers, each of them has no easy way of knowing about the sessions initiated by other servers.

This problem is easy to solve if you run SQL accounting (see section sql Accounting). In this case, each radius server stores the data in your SQL database and can easily retrieve them from there.

To enable use of SQL database for multiple login checking, do the following:

In your ‘raddb/config’ file set:

 
mlc {
    method sql;
};

In your ‘raddb/sqlserver’ file, specify the queries for retrieving the information about open sessions and, optionally, a query to close an existing open record.

There are two queries for retrieving the information: mlc_user_query returns the list of sessions opened by the user, mlc_realm_query returns the list of sessions opened for the given realm. Each of them should return a list of 4-element tuples(4):

 
user-name, nas-ip-address, nas-port-id, acct-session-id

Here is an example of mlc_user_query and mlc_realm_query:

 
mlc_user_query SELECT user_name,nas_ip_address,\
                      nas_port_id,acct_session_id \
               FROM calls \
               WHERE user_name='%C{User-Name}' \
               AND status = 1

mlc_realm_query SELECT user_name,nas_ip_address,\
                       nas_port_id,acct_session_id \
                FROM calls \
                WHERE realm_name='%C{Realm-Name}'     

Apart from these two queries you may also wish to provide a query for closing a hung record. By default, radiusd will use acct_stop_query. If you wish to override it, supply a query named mlc_stop_query, for example:

 
mlc_stop_query UPDATE calls \
               SET status=4,\
                acct_session_time=unix_timestamp(now())-\
                                  unix_timestamp(event_date_time) \
               WHERE user_name='%C{User-Name}' \
                 AND status = 1 \
                 AND acct_session_id='%C{Acct-Session-Id}' 

See section Writing SQL Accounting Query Templates, for detailed information on how to write these queries.


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

6.9.2 Verifying Active Sessions

Whatever database radiusd uses, an open entry in it does not necessary mean that the corresponding session is still being active. So, after retrieving the information about user sessions, Radius verifies on corresponding NASes whether these are actually active.

For each entry in the session list, if its NAS acknowledges the session, the session count is incremented. Otherwise, such entry is marked as closed in the database and is not counted.

There may also be cases when the NAS is unreachable due to some reasons. In such cases the Radius behavior is determined by the value of checkrad-assume-logged in ‘config’ file auth statement (raddb/config). If the value is yes, Radius assumes the session is still active and increases the session count, otherwise it proceeds as if the NAS returned negative reply.

To query a NAS, Radius first looks up its type and additional parameters in ‘naslist’ file (see section NAS List — ‘raddb/naslist). There are two predefined NAS types that cause Radius to act immediately without querying tne NAS: the special type ‘true’ forces Radius to act as if the NAS returned 1, the type ‘false’ forces it to act as if the NAS returned 0. If the type is neither of this predefined types, Radius uses it as a look up key into the ‘nastypes’ file (see section NAS Types — ‘raddb/nastypes) and tries to retrieve an entry which has matching type. If such entry does not exist, Radius issues the error message and acts accordingly to the value of configuration variable checkrad-assume-logged. Otherwise, Radius determines the query method to use from the second field of this entry, and constructs method arguments by appending arguments from the ‘naslist’ entry to those of nastypes entry. Note, that the former take precedence over the latter, and can thus be used to override default values specified in ‘nastypes’.

Having determined the query method and its argument, Radius queries NAS and analyzes its output by invoking a user-supplied Rewrite function. The function to use is specified by the function= argument to the method. It is called each time a line of output is received from the NAS (for finger queries) or a variable is received (for SNMP queries). The process continues until the function returns 1 or the last line of output is read or a timeout occurs whichever comes first.

If the user-function returns 1 it is taken to mean the user's session is now active at the NAS, otherwise, if it replies 0 or if the end of output is reached, it is taken to mean the user's session is not active.

The syntax conventions for user-supplied functions are described in detail in Login Verification Functions.


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

6.10 Controlling Authentication Probes

Authentication probe is an attempt of a user to use other user's account, by guessing his password. The obvious indication of an authentication probe is appearence of several consecutive authentication failures for the same user. Of course, if the intruder is given sufficient number of such probes he will sooner or later succeed in finding the actual password. The conventional method to prevent this from occurring is to keep failure counters for each user and to lock the account when its failure counter reaches a predefined limit. Notice that a legitimate user may fail (sometimes even several times in sequence) in entering his password, so two important points should always be observed. First, failure counters record the number of consecutive authentication failures and they are reset after each successive authentication. Secondly, the maximum number of allowed consecutive failures should be set sufficiently high.

The version 1.6 offers two ways for controlling authentication probes: using external programs and using special SQL queries.

To control authentication probes using external programs, use the combination of Exec-Program-Wait and Auth-Failure-Trigger. The program specified by Auth-Failure-Trigger is executed each time an authentication attempt failed. When both attributes are used together, the program invoked by Auth-Failure-Trigger can update the failure counter, and the one invoked by Exec-Program-Wait can compare the counter value with the predefined limit and reject authentication when both values become equal. Such approach is most useful in conjunction with BEGIN profile.

Let's suppose the program ‘/sbin/check_failure’ accepts a user name and returns 1 if the failure counter for this user has reached maximum allowed value. Otherwise it returns 0 and clears the counter. Another program, ‘/sbin/count_failure’ increases failure counter value for the given user name. Assuming our basic authentication type is ‘PAM’, the ‘raddb/users’ file will look as follows:

 
BEGIN   NULL
        Exec-Program-Wait = "/sbin/check_failure  %C{User-Name}",
        Auth-Failure-Trigger = "/sbin/count_failure %C{User-Name}",
                Fall-Through = Yes

DEFAULT Auth-Type = PAM
        Service-Type = Framed-User,
                Framed-Protocol = PPP

[… Other profiles …]                

The BEGIN profile will be executed before any other profile. It will add to the RHS Exec-Program-Wait and Auth-Failure-Trigger attributes and then radiusd will proceed to finding a matching profile (due to Fall-Through attribute). When such profile is found, the user will be authenticated according to the method set up by the profile's Auth-Type attribute. If authentication fails, ‘/sbin/count_failure’ will be called and the user name passed to it as the argument. Otherwise, ‘/sbin/check_failure’ will be invoked.

To complete the example, here are working versions of both programs. Failure counters for each user name are kept in separate file in ‘/var/log/radius/fails’ directory. Both programs are written in bash.

The /sbin/count_failure program

 
#! /bin/bash

test $# -eq 1 || exit 1

MAXFAIL=8
REGDIR=/var/log/radius/fails

if [ -r "$REGDIR/$1" ]; then
  read COUNT < "$REGDIR/$1"
  COUNT=$((COUNT+1))
else
  COUNT=1
fi
echo $COUNT > "$REGDIR/$1"      
# End of /sbin/count_failure

The /sbin/check_failure program

 
#! /bin/bash

test $# -eq 1 || exit 1

MAXFAIL=8
REGDIR=/var/log/radius/fails

if [ -r "$REGDIR/$1" ]; then
  read COUNT < "$REGDIR/$1"
  if [ $COUNT -ge $MAXFAIL ]; then
    echo "Reply-Message=\"Too many login failures. Your account is locked\""
    exit 1
  else
    rm "$REGDIR/$1"
  fi
fi
exit 0

# End of check_failure

Another way of controlling authentication probes is by using SQL database to store failure counters. Two queries are provided for this purpose in ‘raddb/sqlserver’ file: auth_success_query is executed upon each successful authentication, and auth_failure_query is executed upon each authentication failure. Both queries are not expected to return any values. One obvious purpose of auth_failure_query would be to update failure counters and that of auth_success_query would be to clear them. The auth_query or group_query should then be modified to take into account the number of authentication failures.

The default SQL configuration GNU Radius is shipped with provides a working example of using these queries. Let's consider this example.

First, we create a special table for keeping authentication failure counters for each user:

 
CREATE TABLE authfail (
  # User name this entry refers to
  user_name           varchar(32) binary default '' not null,
  # Number of successive authentication failures for this user
  count               int,
  # Timestamp when this entry was last updated
  time                datetime DEFAULT '1970-01-01 00:00:00' NOT NULL,
  # Create a unique index on user_name
  UNIQUE uname (user_name)
);

The query auth_fail_query will increment the value of count column for the user in question:

 
auth_failure_query UPDATE authfail \
                   SET count=count+1,time=now() \
                   WHERE user_name='%C{User-Name}'

The query auth_success_query will clear count:

 
auth_success_query UPDATE authfail \
                   SET count=0,time=now() \
                   WHERE user_name='%C{User-Name}'

Now, the question is: how to use this counter in authentication? The answer is quite simple. First, let's create a special group for all the users whose authentication failure counter has reached its maximum value. Let this group be called ‘*LOCKED_ACCOUNT*’. We'll add the following entry to ‘raddb/users’:

 
DEFAULT Group = "*LOCKED_ACCOUNT*",
                Auth-Type = Reject
        Reply-Message = "Your account is currently locked.\n\
Please, contact your system administrator\n"

which will reject all such users with an appropriate reply message.

The only thing left now is to rewrite group_query so that it returns ‘*LOCKED_ACCOUNT*’ when authfail.count reaches its maximum value. Let's say this maximum value is 8. Then the following query will do the job:

 
group_query       SELECT user_group FROM groups \
                  WHERE user_name='%u' \
                  UNION \
                  SELECT CASE WHEN (SELECT count > 8 FROM authfail \
                                                 WHERE user_name='%u')
                         THEN '*LOCKED_ACCOUNT*' END

The default configuration comes with these queries commented out. It is up to you to uncomment them if you wish to use SQL-based control over authentication failures.

Notice the following important points when using this approach:

  1. Your SQL server must support UNION. Earlier versions of MySQL lacked this support, so if you run MySQL make sure you run a reasonably new version (at least 4.0.18).
  2. Both auth_failure_query and auth_success_query assume the database already contains an entry for each user. So, when adding a new user to the database, make sure to insert an appropriate record into authfails table, e.g.
     
    INSERT INTO authfail VALUES('new-user',0,now());
    

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

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