LDAP - An Overview

by Rick Moen

Revised: 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?

Any PAM-enabled application will get authentication, this way, automatically.


Application support:


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.


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.