mod_radius
ProFTPD module.
Common Configurations
First, let's start with the most basic mod_radius
configuration,
where we want to use the RADIUS server only for validating the user's
password:
<IfModule mod_radius.c> AuthOrder mod_radius.c mod_auth_unix.c mod_auth_file.c RadiusEngine on RadiusAuthServer localhost:1812 testing123 5 RadiusLog /etc/proftpd/radius.log </IfModule>Here, we have told
mod_radius
the IP address of the RADIUS
server via the RadiusAuthServer
directive, which includes the port, shared secret,
and default timeout value (in seconds).
Since this configuration only uses the RADIUS server for validating the
password, we still need to get the user's UID, GID, home directory, group
membership, etc from somewhere. Thus we need the AuthOrder
directive to tell proftpd
to use the
mod_auth_unix
and
mod_auth_file
modules
as well.
Using the above configuration, when a client connects and sends the
USER
and PASS
FTP commands, the
mod_radius
module will send an Access-Request
RADIUS
packet to the RADIUS server, which will include the following attributes:
Service-Type 8 (i.e. Authenticate-Only) User-Name username User-Password password NAS-Identifier "ftp" NAS-IP-Address (or NAS-IPv6-Address) server-ip-address NAS-Port server-port NAS-Port-Type 5 (i.e. Virtual) Calling-Station-Id client-ip-address Acct-Session-Id session-pid Message-Authenticator macIf the RADIUS server responds with an
Access-Accept
packet, then
the login succeeds, and the FTP session is establish. If, on the other hand,
the RADIUS server responds with Access-Reject
, the login fails.
(The mod_radius
module does not currently support the
Access-Challenge
packet type.)
Now, let's examine a slightly more complex configuration, which enables the use of RADIUS accounting:
<IfModule mod_radius.c> AuthOrder mod_radius.c mod_auth_unix.c mod_auth_file.c RadiusEngine on RadiusAuthServer localhost:1812 testing123 5 RadiusAcctServer localhost:1813 testing123 5 RadiusLog /etc/proftpd/radius.log </IfModule>The additional directive here is the
RadiusAcctSerer
directive, which is quite similar
to the RadiusAuthServer
directive. The use of the
RadiusAcctServer
directive instructs mod_radius
to
use RADIUS accounting.
With this configuration, mod_radius
will do the same as before.
In addition, once the login has succeeded, mod_radius
will send
an Accounting-Request
packet to the RADIUS accounting server
which includes:
User-Name username Acct-Status-Type 1 (i.e. Start) Acct-Session-Id session-pid Acct-Authentic 1 (i.e. Local) Event-Timestamp timestampThen, when the client disconnects,
mod_radius
sends another
Accounting-Request
packet, this time with a lot of information
about the just-ended session:
User-Name username
Acct-Status-Type 2 (i.e. Stop)
Acct-Session-Id session-pid
Acct-Authentic 1 (i.e. Local)
Acct-Session-Time session-duration
Acct-Input-Octets bytes-in
Acct-Output-Octets bytes-out
Acct-Terminate-Cause cause
Event-Timestamp timestamp
Class class (if provided in Access-Accept
)
The above configurations are the most common, as RADIUS is normally used only as way of checking whether a client should be allowed to connect, based on username/password.
Sophisticated Configurations
It is possible to use RADIUS as the sole means of user authentication, rather
than just validating passwords. The mod_radius
configuration
to do so would look like:
<IfModule mod_radius.c> AuthOrder mod_radius.c RadiusEngine on RadiusAuthServer localhost:1812 testing123 5 RadiusAcctServer localhost:1813 testing123 5 RadiusLog /etc/proftpd/radius.log # Use RADIUS Vendor-Specific Attributes (VSAs) for user details RadiusVendor Unix 4 RadiusUserInfo $(10:1000) $(11:1000) $(12:/tmp) $(13:/bin/bash) RadiusGroupInfo $(14:users,ftpd) $(15:500,501) </IfModule>The key difference here is the use of the
RadiusUserInfo
directive. Its appearance within
the configuration is what instructs mod_radius
to do more than
just password validation. The RadiusUserInfo
and RadiusGroupInfo
directives
together tell mod_radius
where to find the necessary information
about a user, such as the UID, GID, home directory, group membership,
etc in the response packets from the RADIUS server.
To let the RADIUS server know that we are expecting it do more than just
validate the password, the Access-Request
packet will use a
different Service-Type
attribute. Now the packet will look like:
Service-Type 1 (i.e. Login) User-Name username User-Password password NAS-Identifier "ftp" NAS-IP-Address (or NAS-IPv6-Address) server-ip-address NAS-Port server-port NAS-Port-Type 5 (i.e. Virtual) Calling-Station-Id client-ip-address Acct-Session-Id session-pid Message-Authenticator mac
Upon receiving the Access-Accept
packet, mod_radius
will now look for specific attributes, bearing user details, within the packet.
What attributes does it look for? Answer: Vendor-Specific Attributes (commonly
called "VSAs").
Every VSA is prefixed with a vendor ID, followed by an attribute ID/value which are defined by that vendor. For example, Cisco has a vendor ID of 9, Microsoft has a vendor ID of 311, and "Unix" has a vendor ID of 4. (For the curious, these vendor IDs, per RFC 2865, Section 5.26, come from the IANA Enterprise Numbers registry.)
With this background, we can explain the RadiusUserInfo
and
RadiusGroupInfo
directives in detail. Notice that we tell
mod_radius
the vendor ID to look for, using the
RadiusVendor
directive:
RadiusVendor Unix 4The above is actually not necessary;
mod_radius
will look for
VSAs for vendor ID 4 (Unix) by default. It is useful, though, to make it
explicitly visible in the configuration.
Let's now see just what the RadiusUserInfo
parameters are doing:
RadiusUserInfo $(10:1000) $(11:1000) $(12:/tmp) $(13:/bin/bash)In order for
proftpd
to log a user in, it needs to know that
user's UID, GID, home directory, and shell. And the RadiusUserInfo
parameters say where to find those values, in that order.
For UIDs, "$(10:1000)" says to look for a vendor-specific attribute ID of 10. If we find such an attribute, use the attribute value as the UID. Otherwise, use 1000 as the UID for the user logging in.
For GIDs, "$(11:1000)" says to look for a vendor-specific attribute ID of 11. If we find such an attribute, use the attribute value as the GID. Otherwise, use 1000 as the GID for the user logging in.
For home directories, "$(12:/tmp)" says to look for a vendor-specific attribute ID of 12. If we find such an attribute, use the attribute value as the home directory. Otherwise, use /tmp as the home directory for the user logging in.
And for the shell, "$(13:/bin/bash)" says to look for a vendor-specific attribute ID of 13. If we find such an attribute, use the attribute value as the shell. Otherwise, use /bin/bash as the shell for the user logging in.
The RadiusGroupInfo
directive is very similar: it tells
mod_radius
which VSAs will contain the group membership, both
in terms of group IDs and group names, for the logging in user:
RadiusGroupInfo $(14:users,ftpd) $(15:500,501)
For group names, "$(14:users,ftpd)" says to look for a vendor-specific attribute ID of 14. If we find such an attribute, use the attribute value as the comma-separated list of supplemental group names. Otherwise, use users,ftpd as the group names for the user logging in.
For group IDs, "$(15:500,501)" says to look for a vendor-specific attribute ID of 15. If we find such an attribute, use the attribute value as the comma-separated list of supplemental group IDs. Otherwise, use 500,501 as the group IDs for the user logging in.
FreeRADIUS Configuration
To help demonstrate how you would configure and use VSAs, I will show the
FreeRADIUS configuration that I used for
development and testing.
Here is the FreeRADIUS dictionary.unix
file I used (slightly
modified from the stock dictionary.unix
file distributed with
FreeRADIUS); this file defines the attributes supported for the "Unix"
vendor:
VENDOR Unix 4 BEGIN-VENDOR Unix ATTRIBUTE Unix-User-UID 10 integer ATTRIBUTE Unix-User-GID 11 integer ATTRIBUTE Unix-User-Home 12 string ATTRIBUTE Unix-User-Shell 13 string ATTRIBUTE Unix-User-Group-Names 14 string ATTRIBUTE Unix-User-Group-Ids 15 string END-VENDOR UnixYou can see how:
VENDOR Unix 4here corresponds to the
mod_radius
configuration line:
RadiusVendor Unix 4
The following attribute IDs are what we use in our mod_radius
directives:
ATTRIBUTE Unix-User-UID 10 integer ATTRIBUTE Unix-User-GID 11 integer ATTRIBUTE Unix-User-Home 12 string ATTRIBUTE Unix-User-Shell 13 stringwhich match up with our
RadiusUserInfo
parameters:
RadiusUserInfo $(10:1000) $(11:1000) $(12:/tmp) $(13:/bin/bash)
Similarly for the group membership attributes, dictionary.unix
has:
ATTRIBUTE Unix-User-Group-Names 14 string ATTRIBUTE Unix-User-Group-Ids 15 stringand our
RadiusGroupInfo
parameters are:
RadiusGroupInfo $(14:users,ftpd) $(15:500,501)
Note that only the IDs (numbers) for attributes are used in the RADIUS packets sent between clients/servers. The attribute names are to make the configuration and logging more human-readable.
Now, in order to tell FreeRADIUS that we want it to include those
VSAs in its Access-Accept
packet back to mod_radius
,
we have to modify the FreeRADIUS users
file, like so:
DEFAULT Auth-Type := System Unix-User-UID := 500, Unix-User-GID := 500, Unix-User-Home := "/home/tj", Unix-User-Shell := "/bin/bash", Unix-User-Group-Names := "radius,ftpd", Unix-User-Group-Ids := "200,501", Fall-Through = 1See the FreeRADIUS documentation for the
users
file format in
order to learn how to configure different UID/GID/home/group values for each
user in that file.
Obtaining Quota Information via RADIUS
If you use the mod_quotatab
module for quota support in proftpd
, and you use the
mod_radius
module for authentication, then you might also be
interesting in getting your quota information from your RADIUS server, much
like you can get user details from the RADIUS server.
The mechanism is identical that used for user details, i.e.
vendor-specific attributes (VSAs). Assuming that you are using FreeRADIUS,
you would add the following to your FreeRADIUS dictionary.unix
file:
ATTRIBUTE Unix-FTP-Quota-Per-Session 106 string ATTRIBUTE Unix-FTP-Quota-Limit-Type 107 string ATTRIBUTE Unix-FTP-Quota-Bytes-Upload 108 string ATTRIBUTE Unix-FTP-Quota-Bytes-Download 109 string ATTRIBUTE Unix-FTP-Quota-Bytes-Transfer 110 string ATTRIBUTE Unix-FTP-Quota-Files-Upload 111 string ATTRIBUTE Unix-FTP-Quota-Files-Download 112 string ATTRIBUTE Unix-FTP-Quota-Files-Transfer 113 stringand in the FreeRADIUS
users
file (assuming the above user-related
attributes as well):
DEFAULT Auth-Type := System Unix-User-UID := 500, Unix-User-GID := 500, Unix-User-Home := "/home/tj", Unix-User-Shell := "/bin/bash", Unix-User-Group-Names := "radius,ftpd", Unix-User-Group-Ids := "200,501", Unix-FTP-Quota-Per-Session := "false", Unix-FTP-Quota-Limit-Type := "soft", Unix-FTP-Quota-Bytes-Upload := "1.1", Unix-FTP-Quota-Bytes-Download := "2.2", Unix-FTP-Quota-Bytes-Transfer := "3.3", Unix-FTP-Quota-Files-Upload := "4", Unix-FTP-Quota-Files-Download := "5", Unix-FTP-Quota-Files-Transfer := "6", Fall-Through = 1and then, to tell
mod_radius
that it should look for quota-related
VSAs in the Access-Accept
RADIUS packet, there is the aptly-named
RadiusQuotaInfo
directive:
RadiusQuotaInfo $(106:false) $(107:hard) $(108:40.0) $(109:0.0) $(110:0.0) $(111:0) $(112:0) $(113:0)