identify
password
None
DN and password to use when performing a nonanonymous bind to the directory server for searches.
ldap_cache_timeout
0
Number of seconds until the LDAP client library cache expires. A setting of 0 disables the cache.
ldap_cache_size
0
The cache size to pass to the LDAP client libraries. A size of 0 specifies an unlimited size.
ldap_connections_number
5
The total number of LDAP connections to maintain for the RADIUS server.
ldap_debug
0
OpenLDAP debug flags (see slapd.conf's loglevel parameter).
net_timeout
10
The number of seconds to wait for a response from the LDAP server in the event of a network failure.
password_header
None
Header (such as {CRYPT}) to strip from the beginning of a password before performing a compare operation against checkItems in the request.
password_attribute
None
The name of the attribute containing the password for a user.
port
389
TCP port to use when contacting the directory server.
profile_attribute
None
The attribute containing the DN of the user's radiusprofile object.
server
localhost
Hostname of the LDAP server.
start_tls
no
If enabled, the module will send a StartTLS command prior to any other LDAPoperations.
timelimit
20
Number of seconds the LDAP server has to perform the search (server-side time limit).
timeout
20
Number of seconds to wait for a response to the LDAP query.
tls_mode
no
If enabled, the module will contact the directory using LDAPS.
The next step required to put this new module instance into play is adding a definition to the authenticate section that can be used as a value for the Auth-Type attribute in the users file:
authenticate {
authtype LDAP {
ldap
}
}
Now you can change the authentication default in raddb/users to LDAP:
## raddb/users file defined by the files authorize component
##
## Authenticate all users by binding to the LDAP directory.
DEFAULT Auth-Type := LDAP
After restarting radiusd (again in debug mode), test the new configuration using a preexisting LDAP user entry (uid=kristi and userPassword=testpass):
$ ./radtest kristi testpass localhost 0 testing123
Sending Access-Request of id 147 to 127.0.0.1:1812
User-Name = "kristi"
User-Password = "1q3252620315p214X31022737614]F332"
NAS-IP-Address = garion
NAS-Port = 0
rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=147, length=20
From the client's point of view, nothing appears to be different. The server, however, yields much more information. You should be able to locate a line where the module binds to the directory on behalf of the user.
auth: type "LDAP"
modcall: entering group authtype
< . . . remainingg output omitted . . . >
rlm_ldap: bind as uid=kristi,ou=people,dc=plainjoe,dc=org/test to
ldap.plainjoe.org:389
rlm_ldap: waiting for bind result ...
rlm_ldap: user kristi authenticated successfully
modcall[authenticate]: module "ldap" returns ok
This is definitely the least intrusive way to integrate FreeRadius with an existing directory and will work with any LDAPv3 server. The next step is to use your directory as a data store for the information currently stored in FreeRadius's users file. This, however, will require that you learn about some new schema items.
The FreeRadius project provides an LDAP schema file for use with OpenLDAP 2.x servers. The RADIUS-LDAPv3.schema file can be found in the doc/ directory of the FreeRadius source code distribution. The schema defines many new attributes used to store RADIUS attribute values and a single structural object class named radiusprofile, shown in Figure 8-5, which is used to represent RADIUS users. To keep our focus on LDAP and not RADIUS, we will only concern ourselves with how radiusAuthType maps the Auth-Type RADIUS attribute. Descriptions of the other attributes can be found in the RADIUS RFC.
Figure 8-5. The radiusprofile object class used by the FreeRadius server
First, copy the new schema file to /usr/local/etc/openldap/schema/:
root# cp RADIUS-LDAPv3.schema /usr/local/etc/openldap/schema/
Next, you must include a reference to this file in slapd.conf. Because a radiusprofile object includes the lmPassword and ntPassword attributes from the samba.schema file, it must be placed after the latter file has been parsed:
## /usr/local/etc/openldap/slapd.conf
## core.schema is required for all servers.
include /usr/local/etc/openldap/schema/core.schema
## Included from Chapter 6
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/nis.schema
## Included from Chapter 7
include /usr/local/etc/openldap/schema/inetorgperson.schema
## Dependencies for samba.schema: cosine.schema and inetorgperson.schema needed to
## support --with-ldapsam in Samba
include /usr/local/etc/openldap/schema/samba.schema
## Support for FreeRadius depends on samba.schema for LM/NT password attributes.
include /usr/local/etc/openldap/schema/RADIUS-LDAPv3.schema
The mapping between LDAP attributes and RADIUS attributes is stored in a text file named ldap.attrmap by default. Conventionally, this file is stored in the raddb/ directory, but both the name and location are configurable via the rlm_ldap module's dictionary_mapping parameter. Because we will be using the default schema file, the corresponding attribute dictionary is sufficient. If you decide to use a custom schema, you may have to modify the dictionary as well.
Your next hurdle is decide where to store the radiusprofile entries in the directory. Your first choice might be to store them with the other user account information below the people ou. The problem is that you cannot add the radiusprofile object to your existing users' accounts. You can either change the radiusprofile definition to an auxiliary object or choose to store objects of this type somewhere else. Following the trend of using provided schemas whenever possible, we will create a new organizational unit to hold FreeRadius users and establish a link between the posixAccount and the radiusprofile objects.
First, create a new ou=radius entry below the services ou (created in Chapter 7 for Sendmail):
dn: ou=radius,ou=services,dc=plainjoe,dc=org
objectclass: organizationalUnit
ou: radius
Next, create a profile for the user kristi. The difficulty with this is choosing the RDN for the entry. You have already chosen the uid attribute as the unique naming convention for entries below ou=people. However, the radiusprofile object includes only the cn attribute. The informational RFC 2377 defines an auxiliary uidObject class for situations such as this one. This allows you to include the uid attribute as the RDN for new entries regardless of the structural object class and still maintain your internal naming conventions. You could just use an extensibleObject, but the uidObject is a cleaner approach. Here is the resulting RADIUS user entry:
dn: uid=kristi,ou=radius,ou=services,dc=plainjoe,dc=org
objectclass: radiusprofile
objectclass: uidObject
uid: kristi
cn: Kristi Carter
radiusAuthType: LDAP
Fi
nally, link the posixAccount entry for kristi to her RADIUS information by storing the DN of the radiusprofile object in uid=kristi,ou=people,dc=plainjoe,dc=org. This time we will use the extensibleObject to add the extra attribute. To make the new attributes easier to see, most of the existing optional attributes have been omitted from this LDIF excerpt. Added attributes are shown in bold.
## Existing optional attributes have been omitted from the display.
dn: uid=kristi,ou=people,dc=plainjoe,dc=org
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: sambaAccount
objectclass: extensibleObject
cn: Kristi Carter
cn: Kristi W. Carter
sn: Carter
loginShell: /bin/bash
uidNumber: 781
gidNumber: 100
homeDirectory: /home/kristi
uid: kristi
rid: 2570
radiusprofileDN: uid=kristi,ou=radius,ou=services,dc=plainjoe,dc=org
The two module configuration changes to be made are changing the locations of the dictionary file for LDAP/RADIUS attributes (dictionary_mapping) and specifying the LDAP attribute containing the DN of the user's RADIUS information (profile_attribute):
ldap {
server = "ldap.plainjoe.org"
port = "389"
basedn = "ou=people,dc=plainjoe,dc=org"
filter = "(&(objectclass=posixAccount)(uid=%{Stripped-User-Name:-%{User-Name}}))"
start_tls = yes
profile_attribute = "radiusProfileDn"
dictionary_mapping = ${raddbdir}/ldap.attrmap
}
You can now remove the local copy of the users file from the RADIUS server and add the ldap module to the authorize block in radiusd.conf. The files module is still listed because it also contains directives affecting local accounting policies.
##
## Authorization: obtain information about the user
##
authorize {
files
ldap
}
This example brings up two important points:
Relationships between entries in a directory can be represented by storing the DNs as reference links.
Using auxiliary objects such as the uidObject to maintain a standard naming convention can help reduce the management costs associated with locating related entries.
I'll leave it up to you to use the radtest tool to verify that the server is working correctly.
* * *
[4] A list of RADIUS attributes linked with the corresponding RFCs can be found at http://www.freeradius.org/rfc/attributes.html.
Resolving Hosts
Now let's turn our attention to data describing hosts on a network. One of the most fundamental services provided in any TCP/IP network is the resolution of machine names to network addresses. The most widespread mechanism for looking up IP addresses is the Domain Name System (DNS). Again, coverage of DNS is beyond the scope of this book; for more information, see DNS and BIND, Fourth Edition, by Cricket Liu and Paul Albitz (O'Reilly).
Chapter 1 already made it clear that LDAP is not a replacement for a specialized directory service such as DNS. However, you can use LDAP effectively as a backend storage system for DNS zone files. Stig Venaas has written such a patch for Bind 9 using its new simplified database interface (SDB). The latest release of the patch for BIND 9.1 (or later) and the necessary schema file for OpenLDAP 2 can be obtained from http://www.venaas.no/ldap/bind-sdb/. For performance reasons, I recommend that you obtain the latest patch, rather than using the one included in the contrib/ subdirectory of the latest BIND 9 release.
Venaas has included a brief list of the steps necessary for integrating LDAP-sdb support in Bind 9. Here are the instructions contained in the INSTALL file of the ldap-sdb archive:
Copy the ldap.c source file to the bin/named/ subdirectory of the BIND 9 source tree.
Copy the ldap.h header file to the bin/named/include/ subdirectory of the BIND 9 source tree.
Edit bin/named/Makefile.in and add the following lines:DDRIVER_OBJS = ldapdb.@O@
DDRVIVER_SRCS = ldapdb.c
DDRIVER_LIBS = -lldap -llber
The Makefile variables may already exist; if this is the case, simply append the references to the LDAP files to the existing definitions. You may also need to add the path to the LDAP include files and libraries to the DDRIVER_INCLUDES and DDRIVER_LIBS respectively.
Edit bin/named/main.c and add the line #include
After making these changes, you're ready to build the LDAP-enabled named binary by executing ./configure && make && /bin/su -c "make install". It is a good idea to ensure that the new server is working with an existing set of zone files before continuing. Here is a zone file for the plainjoe.org domain; it contains four hosts, localhost, dns1, ldap, and ahab:
plainjoe.org. IN SOA dns1.plainjoe.org. root.dns.plainjoe.org. (
3 ; Serial
10800 ; Refresh after 3 hours
3600 ; Retry after 1 hour
604800 ; expire after 1 week
86400 ) ; minimum TTL of 1 day
; Name Servers
plainjoe.org. IN NS dns1.plainjoe.org.
; Addresses for local printers
localhost.plainjoe.org. IN A 127.0.0.1
dns1.plainjoe.org. IN A 192.168.1.10
ldap.plainjoe.org. IN A 192.168.1.70
ahab.plainjoe.org. IN A 192.168.1.80
Figure 8-6 shows the schema for the structural dNSZone object class. This schema allows you to store DNS records in the directory. All of the attributes used to represent the various DNS records (MX, A, PTR, etc.) are optional, which means that a dNSZone entry can represent any type of DNS record.
Figure 8-6. The dNSZone object class required for the Bind 9 LDAP-sdb backend
I have chosen to place all plainjoe.org hosts in the hosts organizational unit. The following LDIF entry represents the A record for the host ahab.plainjoe.org:
dn: relativeDomainName=ahab,ou=hosts,dc=plainjoe,dc=org
aRecord: 192.168.1.80
objectClass: dNSZone
relativeDomainName: ahab
dNSTTL: 86400
zoneName: plainjoe.org
After placing your DNS zone data into the LDAP directory, you need to tell the named server how to locate the zone information. The database keyword specifies the SDB type holding the zone information; in this case, you're using an LDAP database. Any remaining arguments after the database type are passed directly to the SDB backend module. Here, you use an LDAP URI to define the directory server's hostname and the base search suffix. The final number (172800) specifies the default time-to-live (TTL) for entries that do not possess a dNSTTL attribute value.
zone "plainjoe.org" in {
type master;
database "ldap ldap://192.168.1.70/ou=hosts,dc=plainjoe,dc=org 172800";
};
You can now use the dig utility to test the new LDAP-served DNS zone. Figure 8-7 describes what will happen when the dig or nslookup tools are executed.
$ dig ahab.plainjoe.org +short
; <<>> DiG 9.1.0 <<>> ahab.plainjoe.org +short
;; global options: printcmd
192.168.1.80
Figure 8-7. Retrieving zone information using LDAP lookups in Bind 9
The zone2ldap tool included with the Bind distribution provides a quick way to transfer existing zone files into an LDAP directory. Newer versions of this utility can also be downloaded from Venaas's web site. I decided against using it because it creates an entry for each component of the FQDN for each host. For example, the host ahab.plainjoe.org results in three entries: one for dc=org, one for dc=plainjoe,dc=org, and one for relativeDomainName=ahab,dc=plainjoe,dc=org. For more information, refer to the zone2ldap manpage.
Central Printer Management
Now that you've moved your DNS zone data into an LDAP directory, you have the leisure to ask, "What's the big deal?" DNS already has highly effective mechanisms for distributing and replicating zone data; it's not like user account data, which needs to be kept consistent on every machine. So have you accomplished anything, aside from being able to point to a directory server that's serving the zone data to your DNS servers? Clearly, you need to be able to justify the effort you've spent, and to do so, you need to find another application that can make use of the same data.
Network printers are devices that are associated with entries in DNS and possess additional attributes used to support a non-DNS application (i.e., printing). Our next step is to design a directory-based solution for managing printer configuration information that simplifies the process of adding, deploying, and retiring printers. A printer should be accessible to its clients as soon as it has been added to the directory. The namespace shown in Figure 8-8 was designed with this philosophy in mind. All printer configuration information is stored below the ou=printers organizational unit. The immediate three children, config, global, and location, are used to group printers and maintain configuration parameters.
Figure 8-8. LDAP namespace for directory-based storage of printer configuration data
The config organizational unit sits at the root of the actual configuration tree. Each printer has an entry containing information such as the printer's name and maximum print job size. For network printers, the entry also contains DNS information, such as IP address and hostname. The ou=config,ou=printers,dc=plainjoe,dc=org entry acts as the base suffix for the lp.plainjoe.org DNS zone used by your BIND 9 server. This means that if an administrator removes a printer's entry from the config organizational unit, it is immediately removed by DNS as well. Devices that are physically connected to a host acting as the spooler are not considered network printers for the purposes of this discussion.
LDAP System Administration Page 23