LDAP - An Overview
by Rick MoenRevised: Friday, 2001-10-19
Master version will be at http://linuxmafia.com/faq/Network_Other/ldap.html and I'll try to improve it there.
What is a "directory"?
"Directory" is a generalised term for database-stored information about network objects[1] with access or security attributes. Examples: Microsoft SAM database, Novell NDS database, NIS/NIS+ database. Typically not transactional.
What is "access"?
We mean client-server network access. In this case, the native transport is over TCP or UDP port 389. Alternatively:
LDAP channel can run over SSL, using stunnel (LDAP V2 - OpenLDAP 1.2.x) or natively (LDAP V3 - OpenLDAP 2.0.x). Default fallback, with negligible security, is the TCP/UDP port 389 mechanism.
(We will be discussing OpenLDAP, not the U. of Michigan LDAP Server: OpenLDAP is derived from the other one, but there are differences.)
LDAP-over-SSL is often called "LDAPS" -- not the plural of LDAP!
There is also an option for MIT Kerberos (v. 5) or KTH Kerberos (v. 4) by itself or via a SASL (Simple Authentication and Security Layer) or GSSAPI authentication interface -- not covered here.
What software does it use?
OpenLDAP (slapd), related libs and utilities.
pam_ldap.so and nss_ldap.so modules. The PAM version does
user/group information only; the NSS one can also support many
other databases (listed below).
OpenSSL (optional)
Originally, the OSI consortium (the people who gave us the seven-layer OSI network model) invented the "DAP" protocol, which would have operated over the OSI network stack. After the collapse of OSI, U. of Michigan and the ISODE Consortium invented LDAP (IETF's RFC 1487, 1993) as a more lightweight variant, running over TCP/IP.
What's LDAP for?
- Unified authentication (user accounts) across multiple
machines on a LAN, similar to NIS/NIS+.
- Re-uses / is compatible with other "directory"-like information such as employee database records / address books.
Any PAM-enabled application will get authentication, this way, automatically.
Application support:
- No LDAP support in Samba-stable, only betas. (Not fully
PAM-ified.)
- Sendmail supports it.
- Postfix supports it.
- BIND supports it (with a patch).
- Netscape Navigator/Communicator's Roaming Access for Address Book and Bookmark information are an LDAP client.
PAM vs. NSS:
PAM = Pluggable Authentication Modules : Intermediate software layer for general access authentication, e.g., for login, passwd, rlogin, su, ftp, ssh, etc. Access to diverse back-end databases is implemented via plug-ins. pam-ldap is one such.
PAM was invented by Sun for Solaris, and is now standard on most Linux distributions.
NSS = Name Service Switch, also invented by Sun, is a library-invocation interface by which the system libraries get any combination of these database types from a hierarchical list of sources:
aliases: Mail aliases. ethers: Ethernet numbers. group: Groups of users. hosts: Host names and numbers. netgroup: Network wide list of host and users. network: Network names and numbers. protocols: Network protocols. passwd: User passwords. rpc: Remote procedure call names and numbers. services: Network services. shadow: Shadow user passwords.
It's a bad idea to try to get anything but shadow, passwd and group data from LDAP (performance, they change too seldom, and it's more convenient to have them as local files), so in practice that isn't implemented.
Populating OpenLDAP's default "ldbm"[2] disk database (priming the pump):
First, create an LDIF (LDAP Data Interchange Format) flat-file your_file.ldif, then run "ldif2ldbm -i your_file.ldif" to import it. You have to do this before slapd will start.
LDIF is a way of writing X.500 directory data. Example LDIF file (always in ASCII) from the LDAP Implementation HOWTO follows:
# dn = "distinguished name" is an X.500 descriptor fully identifying an object dn:dc=yourorg, dc=com # Below a "dn", one has object attributes in "name: value" format. objectclass: top objectclass: organizationalUnit #multiple records within an LDIF are delimited by blank lines dn:ou=groups, dc=yourorg, dc=com objectclass: top objectclass: organizationalUnit ou: groups dn:ou=people, dc=yourorg, dc=com objectclass: top objectclass: organizationalUnit ou: people dn: cn=Giuseppe LoBiondo, ou=people, dc=yourorg, dc=com cn: Giuseppe Lo Biondo sn: Lo Biondo objectclass: top objectclass: person objectclass: posixAccount objectclass: shadowAccount uid:giuseppe userpassword:{crypt}$1$ss2ii(0$gbs*do&@=)eksd uidnumber:104 gidnumber:100 gecos:Giuseppe Lo Biondo loginShell:/bin/zsh homeDirectory: /home/giuseppe shadowLastChange:10877 shadowMin: 0 shadowMax: 999999 shadowWarning: 7 shadowInactive: -1 shadowExpire: -1 shadowFlag: 0 dn: cn=mygroup, ou=groups, dc=yourorg, dc=com objectclass: top objectclass: posixGroup cn: mygroup gidnumber: 100 memberuid: giuseppe memberuid: anotheruser
Afterwards, ordinarily one maintains LDAP database contents using normal account tools. One general-purpose browser directly to the LDAP database: Jarek Gawor's LDAP Browser/Editor, http://www-unix.mcs.anl.gov/~gawor/ldap/ Or, one can use OpenLDAP's "slapadd" command-line utility to import from more LDIF files, ldapsearch to search records, ldapdelete to delete records, ldapmodify to edit/add records,
Enabling LDAP support via PAM:
For each service you'll want to LDAP-enable (such as login, sshd), edit its /etc/pam.d/* file to be roughly like this:
auth required /lib/security/pam_securetty.so auth required /lib/security/pam_nologin.so auth sufficient /lib/security/pam_ldap.so auth required /lib/security/pam_unix_auth.so use_first_pass account sufficient /lib/security/pam_ldap.so account required /lib/security/pam_unix_acct.so password required /lib/security/pam_cracklib.so password sufficient /lib/security/pam_ldap.so password required /lib/security/pam_unix_passwd.so use_first_pass md5 shadow session required /lib/security/pam_unix_session.so
Warning: Do not fool with PAM files without having a backup copy of the entire /etc/pam.d/ directory stored away, in case you lock yourself out and have to boot a maintenance floppy to recover your system.
Enabling LDAP support via NSS:
This approach is easier. Edit /etc/nsswitch.conf to change the authentication order, like this:
passwd: files ldap group: files ldap shadow: files ldap
Note the other service names: hosts, networks, protocols, services,ethers, rpc, netgroup. You can use LDAP for hosts, but with speed problems that are best not dealt with by nscd, but rather pdnsd or similar.
Do NOT put "dns" before "ldap" on the hosts line: Infinite recursion whenever DNS doesn't return results, since LDAP calls getbyhostname. Or at the minimum, populate the /etc/hosts file thoroughly, so that "files" takes precedence.
LDAP client configuration:
Either the NSS or PAM approach will be constrained by /etc/ldap.conf, as will any other LDAP-using process. This is the client config, which specifies where the LDAP server is, and how to talk to it.
# Your LDAP server. Must be resolvable without using LDAP. host 192.111.111.111 # The distinguished name of the search base. base dc=yourorg, dc=com # ldap_version 3 # binddn cn=manager,dc=padl,dc=com #bindpw secret port 636 # stunnel #scope sub #scope one #scope base # # Specific to nss_ldap. #crypt md5 #crypt sha #crypt des #default # # Specific to pam_ldap. pam_filter objectclass=posixAccount # # The user ID attribute (defaults to uid) pam_login_attribute uid # Group member attribute pam_member_attribute memberuid #pam_login_attribute userPrincipalName #pam_template_login_attribute uid #pam_template_login nobody # # Hash password locally pam_crypt local # # SSL Configuration ssl yes sslpath /usr/local/ssl/certs #
Configuring nscd (nameservice caching daemon):
Runs as a SysVInit service to compensate for speed problems with directory services (LDAP, NIS, NIS+), configured in /etc/nscd.conf:
enable-cache passwd yes positive-time-to-live passwd 600 negative-time-to-live passwd 20 suggested-size passwd 211 keep-hot-count passwd 20 check-files passwd yes enable-cache group yes positive-time-to-live group 3600 negative-time-to-live group 60 suggested-size group 211 keep-hot-count group 20 check-files group yes # enable-cache hosts yes # positive-time-to-live hosts 600 # negative-time-to-live hosts 20 # suggested-size hosts 211 # keep-hot-count hosts 20 # check-files hosts yes
Note: nscd is bad about retaining obsolete DNS data (cache inconsistencies); consider pdnsd or other alternatives, for the DNS part. Omit nscd entirely until system size and activity demands it.
First step in any debugging process should be to halt nscd, pdnsd, or any other caching process.
Also, NSS and nscd chew up file descriptors the way Java chews up threads, so you might want to double /proc/sys/fs/file-max to 8192.
Enabling slapd:
Runs as a SysVInit process.
To use the default port 389, just start "slapd" with no options/parameters.
To tunnel LDAP over stunnel, do
stunnel -r ldap -d 636 -p stunnel.pem
To start LDAP v. 3 (if using OpenLDAP 2.0) over OpenSSL/TLS, do
slapd -h "ldap:/// ldaps:///"
Security concerns:
There are two separate and equally worrying types of security exposure inherent in running an LDAP server: resource discovery and direct attack. For this reason, publicly accessible LDAP servers are almost unheard of, and they should be used internally within an enterprise only with caution. The "resource discovery" problem is that people can mine the contents of the LDAP database to glean extensive details about the organisation. This is the same risk as with DNS servers, except magnified by the greater extent of information on file. (You can mitigate this exposure, somewhat, by imposing ACLs = Access Control Lists on who can view which contents.)
Aside from that, the OpenLDAP server process has a shaky security history, and must run with root-equivalent authority. Even if accessible only over SSL/TLS or Kerberos, it is thus an obvious point of attack on one's key server machines.
Replication:
This is a bit beyond the scope of this talk, but OpenLDAP comes with "slurpd", which replicates the LDAP database to secondary copies, for redundancy and localisation of traffic.
Exercises:
(1) Set up OpenLDAP, and populate it with a schema to check
your Netscape Bookmarks into Roaming Access. You'll find
details in the LDAP HOWTO's section 6.1 - 6.2, and at the
"Implementing Roaming Access" link below.
(2) Configure PAM (/etc/pam.d/*, pam_ldap.so) and the LDAP client (/etc/ldap.conf) to authenticate root and your regular username to LDAP instead of your standard authentication mechanism. Use any authentication mechanism you want. (The default port 389 one is fine.)
Further Reading:
You Can Get There from Here, Part 4 (detailed LDAP setup) by
Marcel Gagné
http://www.linuxjournal.com/article.php?sid=5566
An Introduction to LDAP
http://www.onlamp.com/pub/a/onlamp/2001/08/16/ldap.html
LDAP Implementation HOWTO
http://en.tldp.org/HOWTO/LDAP-Implementation-HOWTO/
LDAP Linux HOWTO
http://en.tldp.org/HOWTO/LDAP-HOWTO/
OpenLDAP site
http://www.umich.edu/~dirsvcs/ldap/doc/
Implementing Roaming Access in Netscape
http://web.archive.org/web/20040323100715/http://igloo.its.unimelb.edu.au/Webmail/tips/msg00295.html
(formerly at http://help.netscape.com/products/client/communicator/manual_roaming2.html)
How to Use the Roaming Feature of Netscape Communicator
http://www.geocities.com/petru2/netscape_roaming.html
A project for Linux Directory Services over LDAP
http://www.rage.net/ldap/
LDAP Roadmap and FAQ
http://www.kingsmountain.com/ldapRoadmap.shtml
GNU libc (source of nscd)
http://www.gnu.org/software/libc/libc.html
pdnsd by Paul Rombouts and Thomas Moestl
http://www.phys.uu.nl/~rombouts/pdnsd.html
LDAP setup information, various
http://www.padl.com/Contents/Documentation.html
NIS/LDAP RFC info
http://www.padl.com/~lukeh/rfc2307bis.txt
Notes:
[1] Technically, it can contain arbitrary sorts of information, but usually is limited to the foregoing.
[2] Alternative storage mechanisms include Sleepcat's Berkeley db and FSF's gdbm, or various SQL databases. However, ldbm is so much faster and better-optimised for this role that people are usually advised to, if anything, keep master copies of the LDAP database in a SQL database, and roll it out to ldbm.