OpenRADIUS

Introduction

FAQ

Download

Documentation
   Installation/Usage
   Module interface
   Language
   Packet handling
   Modules
      Ascfile
      Delay
      Radlogger
      RadLDAP
      RadSQL
      Unixpasswd

Configurations
   Pre-paid

Contributed
   Using VSAs
   Installing on OSX

Mailing list...

Add-ons/Services

Other software...

Using OpenRADIUS


0. Contents

1. Installation
2. Configuration
   2.1. The configuration file (defines sources and module interfaces)
   2.2. The behaviour file
3. Running the server
 

1. Installation

In order to successfully put OpenRADIUS to use, the best thing is to first install it with the example configuration, to test it, and then to adapt it to suit your needs.

Here is a short summary of the steps you'll need to take.

  • Download the source from here and unpack it in your home directory. It will create a directory called openradius-vX.y (for version X.y).

  • Go to this directory and edit your platform's Makefile to reflect the desired installation paths, module selection and compiler flags. Running 'configure' will list the platforms for which a Makefile is available.

    Note: if you set the location of the configuration directory to something other than '/usr/local/etc/openradius', you'll have to edit the configuration file as well, as the path also appears on some modules' command lines. You can also do that after installation though.

  • Type 'make -f Makefile.platform' to compile it. You should not get any warnings or error messages. If you do, please see the system requirements in the release notes here. If you are using a recent GNU make, a working ANSI C compiler, and any BSD, GNU or SysV-like Unix variant, it should definitely be possible to build it.

  • If everything went allright, type 'make -f Makefile.platform install' to install it. Again, you should not get any error messages. If you do, you'll have to install into a different directory or become root before invoking this command.
     

2. Configuration

After installation comes configuration. Not counting the dictionary, OpenRADIUS itself uses only two configuration files:

  • .../etc/openradius/configuration - this file defines the server's sources and external interfaces. For each source it lists the addresses and ports to listen on; for each interface it lists the modules to run, the attributes to be included in the requests to it and the ones that are allowed to be taken from its responses, its type (ASCII or binary), and some other options.

  • .../etc/openradius/behaviour - this file defines how the server handles each request: when to do what with which attribute. It defines the external interfaces to be queried, the authentication methods to be performed, the response attributes to be included, and so on.
Both files are read only once, at server startup. No HUP handling is done yet - I'd like to do implement that by having the signal create a complete new configuration set while keeping the old one around as well; then jobs could refer to the configuration under which they were created, and we'd use job-based reference counting to discard the old configuration if there are no running jobs anymore that use them, thus guaranteeing consistent behaviour at all times. But that's for later.
 
2.1. The configuration file

The configuration file actually uses the same language as the behaviour file, which is described here.

Both are compiled once, when the server is started; the difference is that the configuration file is also actually executed immediately after compiling, causing the network sockets to be created and the interface modules to be started. (The behaviour file, on the other hand, is executed for each incoming request.)

Defining sources to listen on and callable interfaces for use in the behaviour file, is done using two magic callable 'interfaces' that are defined internally when the configuration file is compiled and executed: 'source', and 'interface'.

Other than their special purpose (to add sources and interfaces), they only differ from the normal callable interfaces that you create here in that they completely empty the request- and reply lists after each call. (This is done purely for convenience; otherwise you'd have to remember to do at least a 'delall sendattr, delall recvattr' between each interface that you create - see below why).

2.1.1. Sources

Each call to the pseudo-interface 'source' defines one or more sockets to listen on, based on the instances of the 'addr' and 'port' attributes that you have put on the request list before calling it. In fact, each instance of 'port' adds a new socket definition; the 'addr' specifications are optional and are put in the socket definitions only after they have been created for this source.

Some examples of using 'source' that illustrates this behaviour:

# The following few examples all define two 
# sockets, one listening on 172.16.1.1:1645 
# and the other on port 1812 for all addresses:

source(addr=172.16.1.1, port=1645,
       addr=0.0.0.0,    port=1812),

# which is the same as:

source(port=1645, addr=172.16.1.1,
       port=1812, addr=0.0.0.0),

# which is the same as:

source(port=1645, addr=172.16.1.1,
       port=1812),

# which is the same as:

source(port=1645,       port=1812,
       addr=172.16.1.1, addr=0.0.0.0),

# which is of course the same as:

source(port=1645, port=1812,
       addr=172.16.1.1),

# but not the same as:

source(port=1812, port=1645,
       addr=172.16.1.1),

# although it *is* the same as:

source(port=1812,    port=1645,
       addr=0.0.0.0, addr=172.16.1.1),

# which is also the same as

source(addr=172.16.1.1, port=1645),
source(addr=0.0.0.0, port=1812),

# which is the same as

source(port=1645, addr=172.16.1.1),
source(port=1812, addr=0.0.0.0),

# which is the same as

source(port=1645, addr=172.16.1.1),
source(port=1812),

# which is the same as

source(port=1812),
source(port=1645, addr=172.16.1.1),

# Enfin, you get the idea ;)

2.1.2. Interfaces

Each call to the pseudo-interface 'interface' defines a new external interface that can be used in the behaviour file. The following attributes are meaningful to 'interface':

  • name: defines the name by which the new interface can be called from the behaviour file. One instance is required.

  • sendattr: if not specified, then all attributes that are present on the request list at the time of an interface call are sent to the module. Otherwise, the instances of 'sendattr' together define an inclusive list of attributes that are allowed to be sent.

  • prog: defines one or more subprocesses to be spawned at startup for this interface and their command line arguments.

    At least one instance is required; if you specify multiple subprocesses, then each time the interface is called, the server looks in round-robin fashion for one that is idle. If all are busy, the job put in a queue for this interface; the first subprocess that becomes idle after that will immediately take the call from the queue.

    This provides simple load sharing, database connection pooling, takes advantage of SMP and allows the modules themselves to be extremely simple as they only have to worry about one request at a time. See the module interface documentation for more details.

  • recvattr: if not specified, all attributes that are present in a module's response are added to the reply list. Otherwise, each instance of 'recvattr' adds an attribute to the inclusive list of attributes that are allowed to be received from this interface.

  • timeout: defines the watchdog timer for this interface's subprocesses. If no data could be sent to or received from a subprocess during a period longer than the number of seconds specified in this attribute, the process is terminated (and subsequently restarted).

  • flags: a numeric value that holds a combination of flags. The following flag constants are defined for this attribute (see also the specification of the module interface):

    • Ascii: Use ASCII messages for interface
    • Add-Tab: Add tabs before pairs (ASCII)
    • Add-Spaces: Add spaces in pairs around the equals sign (ASCII)
    • Add-Type: Add attribute type and a colon before value (ASCII)
    • Hex-Value: Send and receive values in hexadecimal (using a series of two-digit hexadecimal values for strings) (ASCII)
    • Double-Backslash: Send two backslashes instead of one to introduce escape sequences (ASCII)
    • Named-Const: Send a numeric value's constant name instead of its decimal value if the dictionary defines one (ASCII)
    • Short-Attr: Omit space- and vendor names (ASCII)
Here are some examples of defining interfaces (based on the contents of .../etc/openradius/configuration.sample included with OpenRADIUS 0.9.5).

The first three define logging interfaces that all use the radlogger module, but each logs a different set of attributes (the 'sendattr'-lists) to a different output file, as specified on the module's command line ('prog').

The fourth interface is a dummy one for testing the module support (uses the 'cat' command as a module that echoes all requests as responses). This works both for ASCII and binary interface types.

The fifth defines an interface that uses the 'radldap' module to connect to a replicated LDAP tree that is available on two different machines that are to be queried in round-robin mode.

interface (name="Stdlogger", 
           sendattr="RAD-Code",
           sendattr="User-Name",
           sendattr="User-Password",
           sendattr="Calling-Station-Id",
           sendattr="Called-Station-Id",
           sendattr="NAS-Port",
           sendattr="NAS-Port-Type",
           sendattr="NAS-IP-Address", 
           sendattr="NAS-Identifier",
           sendattr="str",
           prog="radlogger /tmp/radaccess.log",
           flags=Ascii + Short-Attr + Named-Const + 
	   	 Double-Backslash),

interface (name="Errorlogger", 
           sendattr="str",
           prog="radlogger /tmp/raderrs.log",
           flags=Ascii + Short-Attr + 
	   	 Double-Backslash),

interface (name="Acctlogger",
           sendattr="str",
           sendattr="User-Name",
           sendattr="Calling-Station-Id",
           sendattr="Called-Station-Id",
           sendattr="NAS-Port",
           sendattr="NAS-Port-Type",
           sendattr="NAS-IP-Address", 
           sendattr="NAS-Identifier",
           sendattr="Acct-Status-Type",
           sendattr="Acct-Session-Id",
           sendattr="Record-Unique-Key",
           sendattr="Session-Key",
           sendattr="Acct-Input-Octets",
           sendattr="Acct-Output-Octets",
           sendattr="Acct-Input-Packets",
           sendattr="Acct-Output-Packets",
           sendattr="Acct-Terminate-Cause",
           sendattr="Timestamp",
           sendattr="Acct-Delay-Time",
           sendattr="Acct-Session-Time",
           sendattr="Acct-Authentic",
           prog="radlogger /tmp/radacct.log",
           recvattr="int",
           flags=Ascii + Short-Attr + Named-Const + 
	   	 Double-Backslash,
           timeout=5),

interface (name="Loopback",
           prog="/bin/cat",
           prog="/bin/cat",
           prog="/bin/cat",
           timeout=1),

interface (name="Ldapdb",
           sendattr="User-Name",
           sendattr="User-Password",
           sendattr="str",
# Lines wrapped and concatenated with '.' only for
# brevity here. Not really needed.
           prog="radldap -b cn=radius,ou=People," .
	   		   "dc=my,dc=dom,dc=tld " .
		       " -s ldappassword 192.168.5.26",
           prog="radldap -b cn=radius,ou=People," .
	   		   "dc=my,dc=dom,dc=tld " .
		       " -s ldappassword 192.168.6.33",
           timeout=25),

2.2. The behaviour file

Tutorial not yet written. See the language reference for now.

Some hints: the server works by putting everything that it knows about an incoming request on a so-called REQUEST list of attribute/value pairs, and prepares an empty list, the REPLY list. Together with an expression execution context, these three things are called a 'job'.

After a new job is created (because a new request came in), the server will execute the compiled behaviour expression. You can use it to perform any operation on any instance of any pair on either list.

The expression is ran until it finishes (because of the 'abort' operator which causes the request to be dropped, the end of the expression or the 'halt' operator, which causes a response to be encoded and sent based on the contents of the REPLY list), or until it makes a call to an interface that's defined in the configuration file.

When that happens, the server builds a request message for the module using the current REQUEST list and sends it to the module. When the answer comes in, all attributes allowed in according to the recvattr ACL are added to the REPLY list, and the job again continues running the expression, again until it finishes or makes another interface call.

In the mean time, the server still tends to new requests, module communications, possibly crashed childs, and so on.

One important aspect of the expression language is the short-circuit boolean evaluation. This allows you to do conditional subexpressions, like int && str="abc", which only adds a 'str' attribute with value 'abc' to the bottom of the request list if the last instance of the int attribute on the reply list has a value that can be interpreted as 'true'.

The || operator only executes the subexpression on its right if the one on its left is 'false'. The operator returns the last evaluated subexpression, so you can write things like str = (str || "hello"), to supply a default value for an attribute, or more powerful things that employ auto-conversion, like str = (NAS-Identifier || NAS-IP-Address).

These two operators together also provide if-then-else constructs, like this:

Reply-Message = "The last 'int' on the reply list was ",

int == 3 && (
	Reply-Message := REP:Reply-Message . 
			 "indeed 3! Yes sir.",
1) || (
	Reply-Message := REP:Reply-Message . 
			 "not 3, but " . int .
			 "!"
),

For the rest, and why the '=' operator added a pair to the REQUEST instead of the REPLY list in the 'str="abc"'-example, and why the '==' operator tested the 'int' attribute on the REPLY list instead of the REQUEST list, which is what you'd expect and what the language normally does, and why I used a REP: prefix on the right hand side of the ':=' operator and not on the left even though both sides refer to the same A/V pair, see the real documentation.
 

3. Running the server

Not yet written - sorry. Please use 'radiusd -h' and see main.c for now. The most important example to get started is 'radiusd -dall -b', which turns on moderate debugging on all facilities and prevents the server from going to background.

Generated on Sat Jul 2 01:18:04 2011 by decorate.pl / menuize.pl