Commit 6d3151e4 authored by Robert Dubner's avatar Robert Dubner
Browse files

Finalizing for deployment

parent 56b0429c
Pipeline #3624 passed with stage
in 43 minutes and 32 seconds
......@@ -45,12 +45,10 @@ schemadir = $(sysconfdir)/schema
mandir = $(exec_prefix)/share/man
man5dir = $(mandir)/man5
all: simple.pem
OBJS = radiusov.lo radius.lo md5.lo hmacmd5.lo rpacket.lo reap.lo tls.lo md4.lo mschap.lo sha1.lo des.lo
MANPAGES = slapo-radiusov.5
.SUFFIXES: .c .o .lo
......@@ -62,19 +60,21 @@ $(OBJS) $(XOBJS)
$(LIBTOOL) --mode=link $(CC) $(OPT) -version-info 0:0:0 \
-rpath $(moduledir) -module -o $@ $(OBJS) $(XOBJS) $(LIBS)
install: install-lib install-man FORCE
install: all install-lib FORCE
mkdir -p $(DESTDIR)$(moduledir)
$(LIBTOOL) --mode=install cp $(DESTDIR)$(moduledir)
# cp ldapns.schema $(DESTDIR)$(schemadir)
install-man: $(MANPAGES)
mkdir -p $(DESTDIR)$(man5dir)
$(INSTALL) -m 644 $(MANPAGES) $(DESTDIR)$(man5dir)
mkdir -p $(sysconfdir)
cp simple.pem $(sysconfdir)
openssl req -nodes -x509 -newkey rsa:2048 -out simple.pem -keyout simple.pem -days 1 -subj '/CN=localhost'
rm -f *.*o *.la .libs/*
rm -rf .libs
rm *.pem
This directory creates a slapd overlay, radiusov, that handles
RADIUS requests on UDP port 1812. It was cloned from the N.S.S-ov
overlay. Look there for attributions on the original source code.
To use the overlay, add:
include <path to>nis.schema
moduleload <path to>
database mdb
overlay radiusov
This work is part of OpenLDAP Software <>.
Copyright 1998-2021 The OpenLDAP Foundation.
Portions Copyright 2008-2009 Howard Chu, Symas Corp. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted only as authorized by the OpenLDAP
Public License.
A copy of this license is available in the file LICENSE in the
top-level directory of the distribution or, alternatively, at
# The RADIUSOV overlay for OpenLDAP
The RADIUSOV overlay allows the OpenLDAP `slapd` daemon to provide 802.1x authentication services via the RADIUS protocol.
## The RADIUS protocol?
It's never easy, figuring out what information to include in a README. Assuming the reader knows more than they do leads to frustration. But including too much information obfuscates what the user probably really needs to know.
So, first, a very quick summary:
The RADIUS protocol has been under active development since about 1989, first at the University of Michigan. That software base was taken over by the FreeRADIUS project in the late 1990s, and has been under active development ever since.
A very common use case, to the tune of hundreds of millions of installations, are Enterprise WiFi Access Points (also known as base stations).
In contrast to a typical home or small business, which has a single password for the WiFi network, each user in a large organization has their own unique WiFi password. When such a user connects to an Access Point, the user is asked for their username and password.
The AP then sends an authentication request to the well-known RADIUS UDP port 1812 on a designated RADIUS server. The server's IP address has to be configured into the AP, along with a RADIUS protocol "shared secret" known to both the AP and the server.
The RADIUS server looks up the username's password in a backend database, and the AP and the server go through the protocol and the AP is told that the password is good or bad.
That's enough information to understand the following instructions for deploying and configuring the RADIUSOV overlay. It is highly recommended that users who want a deeper understanding of RADIUS install FreeRADIUS and go through their documentation, which we are not going to attempt to duplicate here.
## Before deployment, compilation
Navigate to `<repositories>/openldap/contrib/slapd-modules/radiusov` and execute
make && make install
Pretty much the only thing that might need changing is the `OPT=` line of the Makefile; right now it's set to the `-O0` optimization level, and you might want something else. In testing, the optimization level made no obvious difference; overall processing time is, I speculate, swamped by communications latencies.
## Loading and configuring the overlay.
Loading and configuring the overlay is primarily controlled by entries in the OpenLDAP `slapd.conf` file. By default, it is found (at least sometimes!) in `/usr/local/etc/openldap` See the [OpenLDAP Administrator's Guide]( for more information.
### Causing the overlay to load
These entries in `slapd.conf` will load and configure the overlay:
# Load the mdb backend
moduleload # Add this to the list of "moduleload" entries
The RADIUSOV overlay understands these `slapd.conf` parameters, which get associated with the backend that contains the passwords for the usernames:
I don't know about you, but I find examples to be the richest source of answers to the question, "What in tarnation is going on here!" Please look at the Makefile and related configuration files in `./demonstration/ldap`. In particular, the relevant section of `slapd.conf` in the demonstration looks like this:
database mdb
suffix "dc=renbud,dc=com"
rootdn "cn=Manager,dc=renbud,dc=com"
rootpw secret
directory ./testdir/openldap-data
maxsize 33554432
overlay radiusov
radiusPort 18129
radiusTlsConfigFile ./radiustls.conf
radiusClientURI ldap:///device=RadiusClient,dc=renbud,dc=com?sharedSecret?sub?(&(ipa=$1)(port=$2))
radiusUserURI ldap:///ou=People,dc=renbud,dc=com?userPassword?sub?(uid=$1)
radiusPort is set to `18129` so that RADIUSOV and FreeRADIUS can exist concurrently; FreeRADIUS listens for RADIUS packets on the well-known UDP port `1812`, while OpenLDAP will look for RADIUS packets on UDP port `18129`. This is a demonstration configuration; in ordinary operation, FreeRADIUS and OpenLDAP will not run concurrently, and OpenLDAP will listen on `1812`.
radiusHost is set to ``, so that OpenLDAP will accept packets from anywhere.
radiusClientURI describes how the RADIUS `sharedSecret` for a particular IP address (the `ipa`) is found in the `dc=renbud,dc=com` database.
radiusUserURI describes how the `password` for a particular username (the `uid`) is found in that same database.
With that description as the starting point, I think the most understanding will come the most quickly from examining the working example in `./demonstration/ldap`
## Certificate difficulties
The most likely cause of problems will come when efforts are made to use certificates for authenticating both ends of the TLS link set up by the RADIUS protocol.
The included demonstration shows how to set up radiusclient, OpenLDAP, and FreeRADIUS to do the most rigorous authentication: The servers *demand* that the client send a client certificate, and the servers and the client all check the certificates, and the specified Certificate Authority, for validity and unexpired status.
But setting up a TLS tunnel doesn't have to be that persnickety.
It is necessary for the server to send the client a certificate -- it's needed for the initial handshake that results in a session key for encrypting data through the tunnel -- it is not necessary that that the certificate be current, or that it be signed by a Certificate Authority.
This is controlled, in both the `radiusclient` and RADIUSOV, by the `verify_mode` parameter, which has these four possible values for the server.
never - The server doesn't ask the client for a certificate.
allow - The server asks the client for a certificate, but ignores whether or not a certificate is sent, and ignores the certificate if it is sent.
try - The server asks the client for a certificate. If no certificate is sent, processing continues with no error indication. If a certificate is sent, it is checked for validity and an error issued if the certificate is invalid.
demand - The server requires that the client send a valid certificate.
On the client side, `never` and `demand` are effectively the valid possibilities.
In the interests of not throwing an error by default, the OpenLDAP RADIUSOV out-of-the-box configuration points to a TLS configuration `radiustls.conf` file that itself points to `/usr/local/etc/openldap/simple.pem`.
That `simple.pem` is a self-signed expired certificate with an unprotected private key. It is completely insecure and utterly unsuitable for *any* purpose except getting RADIUSOV working.
By default, and for the same reasonse, RADIUSOV sets `verify_mode` to `none`.
......@@ -567,6 +567,7 @@ build_tls_response( RADIUS_PACKET *response,
STATE_VOLATILES *volatiles = state->volatiles;
SSL_CONFIGURATION *conf = volatiles->radius_info->conf;
// We are here because somebody wants to authenticate a user. That somebody,
// who might be a WiFi base station, or the like, is variously called an
......@@ -653,7 +654,8 @@ build_tls_response( RADIUS_PACKET *response,
uint8_t flag_byte = EAP_TLS_FLAG_VERSION;
if( state->dirty_bytes_sent_so_far == 0
&& dirty_bytes_left > remaining_packet_tls_bytes)
&& ( (dirty_bytes_left > remaining_packet_tls_bytes)
|| (conf->include_length) ))
// This is the very first fragment in the very first packet,
// and there are going to be more packets. So, include the
......@@ -2346,7 +2348,7 @@ process_eap_message_peap_or_ttls( RADIUS_INFO *radius_info,
uint8_t flags = *peap++;
int length_bytes;
int length_bytes = flags & EAP_TLS_FLAG_LENGTH_INCLUDED ? 4 : 0;
// At this point in the transfer process, we are receiving one or
// more RADIUS packets with encrypted data being carried in their
......@@ -2365,7 +2367,6 @@ process_eap_message_peap_or_ttls( RADIUS_INFO *radius_info,
// byte, or else we imply it from the length of the EAP-Message
length_bytes = 4;
state->tls_record_expected_length = 0;
if( (char *)peap - (char *) eap_message + 4 >= eap_message_length )
......@@ -2393,7 +2394,6 @@ process_eap_message_peap_or_ttls( RADIUS_INFO *radius_info,
// We are inferring the length from the eap_message length
state->tls_record_expected_length = eap_message_length-6;
length_bytes = 0;
DPREFIX "%s(): We are using the implicit expected length of %ld bytes\n",
......@@ -2420,7 +2420,6 @@ process_eap_message_peap_or_ttls( RADIUS_INFO *radius_info,
if( state->tls_record_in_recvd_len > state->tls_record_expected_length )
......@@ -2540,6 +2539,42 @@ process_eap_message_peap_or_ttls( RADIUS_INFO *radius_info,
DPREFIX "%s(): We need to ask for more data\n",
// We have to send the stubby little six-byte EAP message
// that means, "More data, please"
rc = build_tls_response(&response,
build_packet_preamble(&response, PC_Access_Challenge, get_identifier(request));
// This brings us to the attributes portion of the RADIUS packet we are building.
// The first attribute we are going to build is an EAP-PEAP challenge.
static const int stubby_length = 6;
uint8_t eap_message_data[stubby_length];
eap_message_data[0] = EAP_MESSAGE_CODE_REQUEST;
eap_message_data[1] = eap_message->Identifier + 1;
eap_message_data[2] = 0; // High byte of big-endian length
eap_message_data[3] = stubby_length;
eap_message_data[4] = eap_message_type;
eap_message_data[5] = EAP_TLS_FLAG_VERSION;
add_attribute_to_radius_packet( &response,
server_postamble(&response, request, shared_secret);
rc = SendThePacket( &response,
return rc;
# This is a configuration file for the OpenLDAP RADIUSOV overlay
# TLS Transport Layer Security parameters, which are separate from the
# ones for the OpenLDAP server proper.
# The triply-hashed commented values show the defaults that are programmed
# into the tls.c software module. We respectfully suggest that the default
# values be left here as a reference, and that changes be made as additional
# lines.
###session_id_context RADIUSOV_SERVER
###fragment_size 1000
###tls_min_version TLS1_2_VERSION
###tls_max_version TLS_MAX_VERSION
###include_length false
###check_crl no
###check_all_crl no
###allow_expired_crl false
###check_cert_issuer no
###check_cert_cn no
###file_type PEM
###certificate_file /usr/local/etc/openldap/simple.pem
###private_key_file /usr/local/etc/openldap/simple.pem
###auto_chain yes
###verify_mode never # never|allow|try|demand
###verify_depth 100
.\" Copyright 1998-2021 The OpenLDAP Foundation, All Rights Reserved.
.\" Copying restrictions apply. See the COPYRIGHT file.
.\" $OpenLDAP$
slapo-radiusov \- RADIUS and PAM requests through a local Unix Domain socket
.B radiusov
overlay to
.BR slapd (8)
services RADIUS and PAM requests through a local Unix Domain socket.
It uses the same IPC protocol as Arthur de Jong's radius-pam-ldapd.
An extract of the radius-ldapd source is included along with the
radiusov source code to allow the overlay to communicate with the
radius-pam-ldapd client stubs.
Using a separate IPC protocol for RADIUS and PAM requests eliminates the
libldap dependencies/clashes that the current pam_ldap/radius_ldap solutions
all suffer from. Both the original radius-ldapd and this radiusov solution
are free from these library issues.
Unlike radius-pam-ldapd, since this overlay executes inside slapd it allows for
the possibility of sophisticated caching, without any of the weaknesses of
nscd and other related caching solutions. E.g., a remote LDAP database can
be accessed using back-ldap with proxy caching (see
.BR slapd-ldap (5)
.BR slapo-pcache (5)
) to leverage back-ldap's
connection pooling as well as pcache's persistent caching, to provide
high performance and a measure of support for disconnected operation.
Alternatively, cache considerations can be completely eliminated by running
a regular database with syncrepl to maintain synchronization with a remote
LDAP database.
Another major benefit of radiusov is that it allows all security policy to be
administered centrally via LDAP, instead of having fragile rules scattered
across multiple flat files. As such, there is no client-side configuration at
all for the RADIUS/PAM stub libraries. (The stubs talk to the server via a Unix
domain socket whose path is hardcoded to NSLCDPATH). As a side benefit,
this can finally eliminate the perpetual confusion between OpenLDAP's
ldap.conf file in ETCDIR/ldap.conf and the similarly named files typically
used by pam_ldap and radius_ldap.
User authentication is performed by internal simple Binds. User authorization
leverages the slapd ACL engine, which offers much more power and flexibility
than the simple group/hostname checks in the old pam_ldap code.
To use this code, you will need the client-side stub library from
radius-pam-ldapd. You can get it from:
You will not need the nslcd daemon; this overlay replaces that part.
To disable building of the nslcd daemon in radius-pam-ldapd, add the
--disable-nslcd option to the radius-pam-ldapd configure script. You
should already be familiar with the RFC2307 and RFC2307bis schema
to use this overlay. See the radius-pam-ldapd README for more information
on the schema and which features are supported.
You will also need to include the nis.schema in your slapd configuration
for RFC2307 support. If you wish to use RFC2307bis you will need a slightly
different schema. You will also need the ldapns.schema for PAM authorization
You must select
.B ldap
in the appropriate services in
.I /etc/radiuswitch.conf
in order for these RADIUS features to take effect. Likewise, you must
.B pam_ldap
for the authenticate, account, session, and password services in
.I /etc/pam.conf
.I /etc/pam.d
for these PAM features to take effect.
.B overlay radiusov
This directive adds the radiusov overlay to the current backend.
.B radiusov-ssd <service> <url>
This directive configures a Service Search Descriptor (SSD) for each RADIUS
service that will be used. The <service> may be one of
and the <url> must be of the form
.B ldap:///[<basedn>][??[<scope>][?<filter>]]
.B <basedn>
will default to the first suffix of the current database.
.B <scope>
defaults to "subtree". The default
.B <filter>
depends on which service is being used.
.B radiusov-map <service> <orig> <new>
If the local database is actually a proxy to a foreign LDAP server, some
mapping of schema may be needed. This directive allows some simple attribute
substitutions to be performed. See the
.B radius-ldapd/README
for the original attribute names used in this code.
.B radiusov-pam <option> [...]
This directive determines a number of PAM behaviors. Multiple options may
be used at once, and available levels are:
.PD 0
.B userhost
check host attribute in user entry for authorization
.B userservice
check authorizedService attribute in user entry for authorization
.B usergroup
check that user is a member of specific group for authorization
.B hostservice
check authorizedService attribute in host entry for authorization
.B authz2dn
use authz-regexp mapping to map uid to LDAP DN
.B uid2dn
use RADIUS passwd SSD to map uid to LDAP DN
Setting the
.BR userhost ,
.BR userservice ,
.B usergroup
options duplicates the original pam_ldap authorization behavior.
The recommended approach is to use
.B hostservice
instead. In this case, ipHost entries must be created for all hosts
being managed, and they must also have the authorizedServiceObject
class to allow authorizedService attributes to be used. Also the
RADIUS host SSD must be configured so that ipHost entries can be found.
Authorization is checked by performing an LDAP Compare operation
looking for the PAM service name in the authorizedService attribute.
.B slapd
ACLs should be set to grant or deny
.B Compare
privilege to the appropriate users or groups as desired.
If the
.B authz2dn
option is set then authz-regexp mappings will be used to map the
PAM username to an LDAP DN. The authentication DN will be of the
.B cn=<service>+uid=<user>,cn=<hostname>,cn=pam,cn=auth
If no mapping is found for this authentication DN, then this
mapping will be ignored.
If the
.B uid2dn
option is set then the RADIUS passwd SSD will be used to map the
PAM username to an LDAP DN. The passwd SSD must have already been
configured for this mapping to succeed.
If neither the authz2dn nor the uid2dn mapping succeeds, the module
will return a PAM_USER_UNKNOWN failure code. If both options are set,
the authz mapping is attempted first; if it succeeds the uid2dn mapping
will be skipped.
By default only the
.B uid2dn
option is set.
.B radiusov-pam-defhost <hostname>
Specify a default hostname to check if an ipHost entry for the current
hostname cannot be found. This setting is only relevant if the
.B hostservice
option has been set.
.B radiusov-pam-group-dn <DN>
Specify the DN of an LDAP group to check for authorization. The LDAP user
must be a member of this group for the login to be allowed. There is no
default value. This setting is only relevant if the
.B usergroup
option has been set.
.B radiusov-pam-group-ad <attribute>
Specify the attribute to use for group membership checks.
There is no default value. This setting is only relevant if the
.B usergroup
option has been set.
.B radiusov-pam-min-uid <integer>
Specify a minimum uid that is allowed to login. Users with a uidNumber
lower than this value will be denied access. The default is zero, which
disables this setting.
.B radiusov-pam-max-uid <integer>
Specify a maximum uid that is allowed to login. Users with a uidNumber
higher than this value will be denied access. The default is zero, which
disables this setting.
.B radiusov-pam-template-ad <attribute>
Specify an attribute to check in a user's entry for a template login name.
The template login feature is used by FreeBSD's PAM framework. It can be
viewed as a form of proxying, where a user can authenticate with one
username/password pair, but is assigned the identity and credentials of
the template user. This setting is disabled by default.
.B radiusov-pam-template <name>
Specify a default username to be used if no template attribute is found
in the user's entry. The
.B radiusov-pam-template-ad
directive must be configured for this setting to have any effect.
.B radiusov-pam-session <service>
Specify a PAM service name whose sessions will be recorded. For the
configured services, logins will be recorded in the
.B radiusov-pam-password-prohibit-message <message>
Disable password change service and return the specified message to
.B radiusov-pam-pwdmgr-dn <dn>
Specify the dn of the password manager.
.B radiusov-pam-pwdmgr-pwd <pwd>
Specify the pwd of the password manager.
.B loginStatus
operational attribute of the user's entry. The attribute's values are
of the form
.B <generalizedTime> <host> <service> <tty> (<ruser@rhost>)
Upon logout the corresponding value will be deleted. This feature allows
a single LDAP Search to be used to check which users are logged in across
all the hosts of a network. The rootdn of the database is used to perform
the updates of the loginStatus attribute, so a rootdn must already be
configured for this feature to work. By default no services are configured.
The PAM functions support LDAP Password Policy as well. If the password
policy overlay is in use (see
.BR slapo-ppolicy (5)),
information (e.g. password expiration, password quality, etc.)
may be returned to the PAM client as a result of authentication,
account management, and password modification requests.
The overlay also supports dynamic configuration in cn=config. An example
of the config entry is
dn: olcOverlay={0}radiusov,ocDatabase={1}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcRadiusOvConfig
olcOverlay: {0}radiusov
olcRadiusSsd: passwd ldap:///ou=users,dc=example,dc=com??one
olcRadiusMap: passwd uid accountName
olcRadiusPam: hostservice uid2dn
olcRadiusPamDefHost: defaulthost
olcRadiusPamMinUid: 500
olcRadiusPamMaxUid: 32000
olcRadiusPamSession: login
olcRadiusPamSession: sshd
which enables the passwd service, and uses the accountName attribute to
fetch what is usually retrieved from the uid attribute. It also enables
some PAM authorization controls, and specifies that the PAM
.B login
.B sshd
services should have their logins recorded.
default slapd configuration file
.BR slapd.conf (5),
.BR slapd\-config (5),
.BR slapd\-ldap (5),
.BR slapo\-pcache (5),