Contents

  1. SCREWIT

  2. OVERVIEW

  3. SERVER SETUP

    • CentOS 7

    • Installing OpenLDAP From Source

    • Starting Server

    • Adding Records

    • Ubuntu 9.10 Using /etc/ldap/slapd.conf

    • slapd Init Script

    • Gentoo OpenLDAP Server

    • Managing Accounts With ACL

  4. CLIENT SETUP

    • Centos 7 Client Setup

    • Centos 6 Client Setup

    • CentOS 5 Client Setup

    • Ubuntu Client Setup

    • Gentoo Client Setup

  5. ENCRYPTION SETUP

    • OpenSSL Key Generation

    • TLS

    • Generating SSL Keys For OpenLDAP

  6. CLIENT FUNCTIONALITY

    • Gentoo LDAP Clients

    • LDIF Format

    • ldapmodify

    • ldapadd

    • ldapsearch

    • /usr/bin/ldapdelete

    • Other Utilities

  7. REPLICATION

  8. TROUBLESHOOTING

    • Logging

    • Mystery Death

    • InK’s Excellent Pro Tips

    • Fix passwd functionality

    • Connectivity

    • Directory Backup And Restore

    • Helpful Utilities

  9. REFERENCE

    • Useful Documents

    • Glossary

    • List Of Ubuntu LDAP Package Highlights

Screw LDAP/FreeIPA

It’s just too painful and recovering from problems is a full time job I do not want to have. You can replace gigabytes of cruft with this small script that just manually synchronizes users from a master machine.

#!/usr/bin/bash
# Chris X Edwards - 2018-07-19

# == Concept
# This script is designed to maintain /etc/passwd files on many
# hosts such that the system (UID<1000) accounts are left as is
# but the user accounts (1000<UID<65534) are populated from a
# different password file (the master file). The idea is to avoid
# LDAP or FreeIPA and just manipulate the passwd file entries
# directly from a master source.

# == Usage
# ***This script is run on the host to change.***
#     ${PATH}/pwclone <saved-passwd-master-file
#            or (pull)
#     ssh masterpw.example.edu cat /etc/passwd | ${PATH}/pwclone
#            or (push)
#     ssh clientpw.example.edu ${PATH}/pwclone </etc/passwd
#
# This script takes standard input so that it can be more easily
# used remotely. You must pipe the master file to this script which
# will modify the local /etc/passwd file based on the master's user
# (but not system) entries.
#
# This is where the password file lives. It should be in the standard
# place. Change to do testing.
PWFILE=/etc/passwd
#PWFILE=/root/pwclone/passwd-test

# == Possible Problems
# ***Make sure your master passwd file is not shadowed!!!***
#
# Note that if someone on a client machine makes a change to this
# file by changing their entry with the `passwd` command, running
# this script will confusingly overwrite that change. One solution
# is to do something like this to disable the local passwd command.
#    mv /usr/bin/passwd /usr/bin/passwd.local
#    NOTE='Log in to master.example.edu to make password changes.'
#    echo '#!/usr/bin/bash'$'\n'echo \"${NOTE}\" > /usr/bin/passwd

# == Must be run as root/sudo
# Fail nicely if this was run by a regular user without sudo.
(( $EUID != 0 )) && echo "UID 0 (root) required. Try running with sudo." && exit

# == Check and disable shadow if necessary
# Check to see if this system is using the shadow system.
# If so, there will be a shadow file (if not, none).
# If there is a shadow system, it must be turned off _temporarily_.
# If there is not a shadow system, it should remain that way.
SHADOWPATH=/etc/shadow
if [ -f ${SHADOWPATH} ]; then
    echo "Shadow password file detected at ${SHADOWPATH}"
    echo "Temporarily disabling shadow..."
    SHADOWCMD="pwunconv"
else # Do nothing special. Ready to go.
    SHADOWCMD=""
fi
${SHADOWCMD}

# == MERGE
# Merge user entries from master with system entries from current local.
TEMPFILE=$(mktemp --tmpdir=/tmp pwclone.tmp.XXXXX)
cat <(awk -F: '$3<1000 || $1=="nfsnobody"' ${PWFILE}) \
    <(awk -F: '$3>=1000 && $1!="nfsnobody"' - ) \
    | sort -n -t: -k3 > ${TEMPFILE}
echo "Updating live ${PWFILE}..."
mv ${TEMPFILE} ${PWFILE}

# == Password file must be readable
# If these permissions aren't right, then you can't look up names to UIDs.
chmod 644 ${PWFILE}

# == Restore shadow if necessary
# If it was shadow before, restore it now.
[ -n "${SHADOWCMD}" ] && echo "Restoring shadow..." && pwconv

To disable LDAP so that you can start using straightforward local password hashes use this command.

authconfig --disableldapauth --disableldap --enableshadow --updateall

OVERVIEW

LDAP stands for Lightweight Directory Access Protocol (see Glossary). A "directory" in this technical sense is like a database with the distinction that it is optimized to extract data rather than receive it. Normal databases tend to be more symmetrical in this respect. Directories are useful when the required task involves far more look ups than edits or record insertions.

Originally the prototypical "directory" was a large company’s phone directory but the more typical use now is a centralized collection of an organization’s user and infrastructure data, importantly including a centralized repository for user authentication information. In practical terms, if an organization has 100 machines and 10 users who are allowed to use all of them, only 10 centralized records are needed. Traditionally, each machine would need a separate lists of all 10 users. If a user changed his password or other information on one of the machines, in the simple approach, 99 other machines would have to be manually updated. Clearly synchronization is a strong feature of LDAP.

With LDAP authentication, when attempts to log into an LDAP enabled host, the host does not (necessarily) need to check the /etc/passwd file but instead contacts the LDAP server specified in its configuration. The host invokes LDAP client libraries which contact the LDAP server. The host tells the server which username was selected and provides a hash of the password the user gave. The LDAP server then consults its directory and decides if that user and hash are correct and if so, it tells the client to accept the user as authenticated.

Clearly sending hashes of valid passwords over the network to a central location is sensitive business so an LDAP setup that does not use end to end encryption is not really a functional setup. Establishing the correct encryption techniques and testing their functionality is a big part of LDAP configuration management.

SERVER SETUP

CentOS 7 free-ipa

Well LDAP is such a PITA and apparently I wasn’t the only one to notice. It looks like Red Hat or somebody has spearheaded a big fancy dummy proof version called freeipa. I discuss it below, but I have confirmed that it does work on two CentOS 7 machines in March 2018.

So this is all getting to be ridiculous. So much so that getting all the parts to talk to each other correctly is extremely challenging thanks to the combinatoric explosion of possibilities (OpenSSL or GNUTLS? Port 636 or 398? sssd or nslcd?) Red Hat seems to have noticed this and, trying hard to compete with Active Directory, they’ve come up with a thing called "Red Hat Identity Management (IdM)" which "provides a centralized and unified way to manage identity stores, authentication, policies, and authorization policies in a Linux-based domain." IdM Documentation

There seems to be a free project called free-ipa. Here is its website.

This guide to installing Free-IPA seems ok. After following these instructions on a pristine install of CentOS 7 it pulled in 300 or so dependencies (no kidding) and then asked me a lot of questions eventually coming out with something like this.

The IPA Master Server will be configured with:
Hostname:       auth-alab.ucex.edu
IP address(es): 172.99.99.07
Domain name:    auth-alab.ucex.edu
Realm name:     AUTH-ALAB.UCEX.EDU

Then the installer did some major BTC mining (or something) as it went through a 1000 step setup script. It finally spit out some more instructions that it might be wise to note.

Next steps:
        1. You must make sure these network ports are open:
                TCP Ports:
                  * 80, 443: HTTP/HTTPS
                  * 389, 636: LDAP/LDAPS
                  * 88, 464: kerberos
                UDP Ports:
                  * 88, 464: kerberos
                  * 123: ntp

        2. You can now obtain a kerberos ticket using the command: 'kinit admin'
           This ticket will allow you to use the IPA tools (e.g., ipa user-add)
           and the web user interface.

Be sure to back up the CA certificates stored in /root/cacert.p12
These files are required to create replicas. The password for these
files is the Directory Manager password

How about this for those firewall changes?

firewall-cmd --permanent --add-service=ntp

firewall-cmd --permanent --add-service=http

firewall-cmd --permanent --add-service=https

firewall-cmd --permanent --add-service=ldap

firewall-cmd --permanent --add-service=ldaps

firewall-cmd --permanent --add-service=kerberos

firewall-cmd --permanent --add-service=kpasswd

Rebooting was required, but after I did that, I was able to go to https://auth-alab.ucex.edu in a browser. The certificates complained but screw that. Approving the exception shows that this certificate expires in 2 years (convenient!). Mine (SHA1) ends in 99:88.

See below for client setup.

Troubleshooting free-ipa

I’m a bit nervous about Free-IPA. The lack of a sensible way to back up and restore the system is frightening (basically the risk of losing everyone’s passwords). And then then I sometimes find some randomly flaky behavior. Sometimes the rube goldberg machine just stops working. Here are some things I turned on to get it working again.

In no particular order.

systemctl restart httpd.service
systemctl restart rngd
systemctl restart dirsrv.target
systemctl restart httpd
systemctl restart sssd
systemctl restart dirsrv.target
systemctl restart krb5kdc
systemctl restart kadmin
systemctl restart pki-tomcatd.target

Maybe check for status first to see what’s up and what’s not. These hints taken from here.

CentOS 7 Server

Note that this Red Hat document says that openldap-server is deprecated. That’s ominous. They say use "Identity Management in RHEL". This is a good time to become aware of FreeIPA.

An ok simple guide. Similar.

Or how about one that addresses the problem with secure TLS connections using port 636. And another.

First make sure to yum install these.

  • openldap

  • compat-openldap

  • openldap-clients

  • openldap-servers

  • openldap-servers-sql

  • openldap-devel

    systemctl start slapd.service
    systemctl enable slapd.service

Check that the server started up.

netstat -antup | grep -i 389

Note this is not the secure port which is 636.

Set a password for the LDAP root.

slappasswd

It will spit out a salted hash which needs to be noted somewhere for use in future steps.

Set up the database by making an ldif file containing this. I put all of these in /root but they can go anywhere sensible.

db.ldif
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=alab,dc=ucex,dc=edu

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=ldapadm,dc=alab,dc=ucex,dc=edu

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: {SSHA}U9999Z/f+P9999N+k99999+X9999999p

Apply this file with this.

ldapmodify -Y EXTERNAL -H ldapi:/// -f ~/db.ldif

Then the same with this which will limit monitor access to ldapadm which seems reasonable.

dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external, cn=auth" read by dn.base="cn=ldapadm,dc=alab,dc=ucex,dc=edu" read by * none

Apply it.

ldapmodify -Y EXTERNAL -H ldapi:/// -f ~/monitor.ldif

Now create a self-signed certificate.

#!/bin/bash

openssl req -new -x509 -nodes -out \
/etc/openldap/certs/myldap.alab.ucex.edu.cert \
-keyout /etc/openldap/certs/myldap.alab.ucex.edu.key \
-days 365

Or look at this method which uses make files that are indeed on CentOS7 ready to go.

And make sure it’s owned by user ldap which should exist if everything is installed and running.

# chown ldap:ldap /etc/openldap/certs/myldap.alab.ucex.edu.cert
# chown ldap:ldap /etc/openldap/certs/myldap.alab.ucex.edu.key

Create this LDIF to configure the system to use these.

Rdn: cn=config
changetype: modify
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/openldap/certs/myldap.alab.ucex.edu.cert

dn: cn=config
changetype: modify
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/openldap/certs/myldap.alab.ucex.edu.key

Load this setting as before.

ldapmodify -Y EXTERNAL -H ldapi:/// -f ~/certs.ldif

Try the following diagnostic command.

# slaptest -u

It should produce this.

config file testing succeeded

Copy this template into the production place.

cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG

Everything but that file should be owned correctly, but just to be sure might as well hit everything.

chown ldap:ldap /var/lib/ldap/*

Now add the normal LDAP schemas which are helpfully provided.

ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif

Create the main layout for the normal application (user log in).

base.ldif
dn: dc=alab,dc=ucex,dc=edu
dc: alab
objectClass: top
objectClass: domain

dn: cn=ldapadm,dc=alab,dc=ucex,dc=edu
objectClass: organizationalRole
cn: ldapadm
description: LDAP Manager

dn: ou=People,dc=alab,dc=ucex,dc=edu
objectClass: organizationalUnit
ou: People

dn: ou=Group,dc=alab,dc=ucex,dc=edu
objectClass: organizationalUnit
ou: Group

Now apply that file with this.

ldapadd -x -W -D "cn=ldapadm,dc=alab,dc=ucex,dc=edu" -f ~/base.ldif

It will prompt for the password that goes with the hash generated previously. It should then spit out these success messages.

adding new entry "dc=alab,dc=ucex,dc=edu"

adding new entry "cn=ldapadm,dc=alab,dc=ucex,dc=edu"

adding new entry "ou=People,dc=alab,dc=ucex,dc=edu"

adding new entry "ou=Group,dc=alab,dc=ucex,dc=edu"

Now normal ldif users can be added and used.

Having firewall annoyances? Or maybe just fending off the inevitable…

firewall-cmd --permanent --add-service=ldap
firewall-cmd --permanent --add-service=ldaps
firewall-cmd --reload

Make sure the ones you need come back with success.

Changing Root Password

Perhaps you started with a terrible password for testing.

Start the process by creating this LDIF.

passwd4dn.ldif
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}kT2***Obtain_from_slappasswd***

Then run this.

ldapadd -Y EXTERNAL -H ldapi:/// -f passwd4dn.ldif

OpenLDAP From Source

First you need to get it. Best to go to OpenLDAP’s official home. Then you can find something like this for version 2.4.33.

To check to see what version you may already have try:

$ /usr/local/libexec/slapd -V
@(#) $OpenLDAP: slapd 2.4.32 (Sep 28 2012 12:53:47) $
    xed@sad.xed.ch:/usr/local/src/ldap/openldap-2.4.32/servers/slapd

None of the packages for the distros are well-behaved. For this reason and because I’m not keen to get locked into a particular fragile distribution where the service works, I am trying to install from the latest sources and configure it generically.

The first problem is that OpenLDAP doesn’t put things neatly where they would go if they were integrated packages. Of course this may be helpful if you need to clear out an old OpenLDAP installation. I had to do things like:

$ cd /etc/openldap; sudo ln -s /usr/local/etc/openldap/schema
$ cd /var/lib; sudo ln -s /usr/local/var/openldap-data
$ sudo mkdir /var/run/slapd

Most of the stuff is in /usr/local by default.

Also you need to put a blank file in the db backend configuration directory or it will complain:

$ sudo touch /var/openldap-data/DB_CONFIG

Server Configuration File

The OpenLDAP server can be configured in two ways. The first and the one I’ve been using is with a static configuration file. This file is sourced when the daemon starts and its settings are applied at that time.

/etc/ldap/slapd.conf
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/inetorgperson.schema
include         /etc/ldap/schema/nis.schema

# SECURITY
access to attrs=userPassword
  by self write
  by anonymous auth
  by dn.base="cn=ldapadmin,dc=alab,dc=ucex,dc=edu" write
  by * none
access to *
  by self write
  by dn.base="cn=ldapadmin,dc=alab,dc=ucex,dc=edu" write
  by * read

# DON'T bother with ARGS file unless you feel strongly
# slapd scripts stop scripts need this to work
pidfile /var/run/slapd/slapd.pid

# enable a lot of logging - we might need it
# but generates huge logs
#loglevel       -1

# MODULELOAD definitions
# not required (comment out) before version 2.3
moduleload back_bdb.la

# TLS-enabled connections
TLSCACertificateFile /etc/ldap/ldapscert.pem
TLSCertificateFile /etc/ldap/ldapscert.pem
TLSCertificateKeyFile /etc/ldap/ldapskey.pem

database bdb
suffix "dc=alab,dc=ucex,dc=edu"

# root or superuser
rootdn "cn=ldapadmin,dc=alab,dc=ucex,dc=edu"
# Apparently the password is plaintext here. Protect well!
rootpw SecretStuff
# The database directory MUST exist prior to running slapd AND
# change path as necessary
directory /var/lib/ldap

# Indices to maintain for this directory
# unique id so equality match only
index   uid     pres,eq
# allows general searching on commonname, etc
index   cn,sn pres,eq,approx,sub
# if searches will include objectClass uncomment following
index objectClass eq
# index objectClass eq
# shows use of default index parameter
index default eq,sub

# other database parameters
# read more in slapd.conf reference section
cachesize 10000
checkpoint 128 15

Might want to sudo chmod 600 /etc/ldap/slapd.conf because of the password in there.

The other way to configure OpenLDAP is to store the configuration information in a directory that the LDAP server manages. Besides being a bit sketchy to configure a server with that running server, I found that some init scripts weren’t flexible with one’s choice of configuration strategies. The upside, in theory, to this strategy is that configuration settings can be adjusted in real time as the server runs and the new settings are applied immediately without any interruption.

Starting Server

Now the server can be started up. This is where it is possible to specify where the config file is. Also you can add some logging output (try slapd -d? for logging options).

$ sudo slapd -f /etc/ldap/slapd.conf -d1023 -h "ldaps://"

Or this is more comprehensive:

$ sudo  /usr/local/libexec/slapd -f /etc/openldap/slapd.conf -d10 -h "ldaps:// ldapi:///"

The d option has logging levels.

Adding Records

Now the server is running and you can prepare LDIFs to populate it. Here’s an LDIF that prepares the base of the tree, the admin account, the users list, and the groups list.

new.ldif
dn: dc=alab,dc=ucex,dc=edu
objectClass: dcObject
objectclass: organization
o: alab.ucex.edu
dc: alab
description: The SysAdmin Lab Root

dn: cn=ldapadmin,dc=alab,dc=ucex,dc=edu
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: ldapadmin
userPassword: SecretStuff
description: LDAP administrator

dn: ou=users,dc=alab,dc=ucex,dc=edu
objectClass: top
objectClass: organizationalUnit
ou: users
description: The SysAdmin Lab User List

dn: ou=groups,dc=alab,dc=ucex,dc=edu
objectClass: organizationalUnit
ou: groups

This can be added with:

$ sudo ldapadd -x -D cn=ldapadmin,dc=alab,dc=ucex,dc=edu -W -f new.ldif

Here’s a sample LDIF that includes a couple of groups and a comprehensive entry for a user. .u+g.ldif

dn: cn=alab,ou=groups,dc=alab,dc=ucex,dc=edu
objectClass: posixGroup
cn: alab
gidNumber: 10000

dn: cn=alabadmin,ou=groups,dc=alab,dc=ucex,dc=edu
objectClass: posixGroup
cn: alabadmin
gidNumber: 10001

# LDIF for Chris X Edwards
dn: uid=xed,ou=users,dc=alab,dc=ucex,dc=edu
objectClass: top
objectClass: posixAccount
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: xed
givenName: Chris
sn: Edwards
cn: Chris X Edwards
cn: Chris Edwards
o: SysAdmin Lab
o: El Xavier Supercomputer Center
o: School of Pharmacy
o: UCEX
ou: users
userPassword: {SSHA}bozJBRxxxxxxxxxxxxxxxxxxx5e81J5g
uidNumber: 1000
gidNumber: 1001
roomNumber: 345E
gecos: Chris X Edwards,,,,
l: El Xavier
st: CA
employeeType: staff
telephoneNumber: Korea95
mail: cxedwards@ucex.edu
mail: chris@xed.ch
loginShell: /bin/bash
homeDirectory: /home/xed
labeledURI: http://xed.name/job Chris' work web page
description: An affable fellow.

This can be added with:

$ sudo ldapadd -x -D cn=ldapadmin,dc=alab,dc=ucex,dc=edu -W -f u+g.ldif

You can test to see if that all worked well with this:

$ sudo ldapsearch -x -D cn=ldapadmin,dc=alab,dc=ucex,dc=edu \
                  -W -b ou=users,dc=alab,dc=ucex,dc=edu 'uid=xed'

Some more examples of populating users: First add the users ou:

$ sudo ldapadd -x -D cn=ldapadmin,dc=alab,dc=ucex,dc=edu -W -f users.ldif
users.ldif
dn: ou=users,dc=alab,dc=ucex,dc=edu
objectClass: top
objectClass: organizationalUnit
ou: users
description: The SysAdmin Lab User List

Now you can add users:

$ sudo ldapadd -x -D cn=ldapadmin,dc=alab,dc=ucex,dc=edu -W -f xed.ldif
# LDIF for Chris X Edwards
dn: uid=xed,ou=users,dc=alab,dc=ucex,dc=edu
objectClass: top
objectClass: posixAccount
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: xed
givenName: Chris
sn: Edwards
cn: Chris X Edwards
cn: Chris Edwards
o: SysAdmin Lab
o: El Xavier Supercomputer Center
o: School of Pharmacy
o: UCEX
ou: users
userPassword: {SSHA}LbwKeFxxxxxxxxxxxxxxxxxxxI9x4uKK
uidNumber: 1000
gidNumber: 1001
roomNumber: 345E
gecos: Chris X Edwards,,,,
l: El Xavier
st: CA
employeeType: staff
telephoneNumber: 6195673295
mail: cxedwards@ucex.edu
mail: chris@xed.ch
loginShell: /bin/bash
homeDirectory: /home/xed
labeledURI: http://xed.name/job Chris' work web page
description: An affable fellow.

Ubuntu 9.10 Using /etc/ldap/slapd.conf

This is the traditional way to configure an OpenLDAP server using a straight forward configuration file. The main problem with this approach is that Ubuntu 9.10 wants to move on to using the directory based configuration system. This means that the start up scripts (/etc/init.d/slapd) won’t work and the server has to be started manually. Another problem is that perhaps in a few years OpenLDAP will cut off this way of configuration.

First of all OpenLDAP needs to be present. Turns out that it’s almost impossible to compile it from source because of the mystical BerkeleyDB requirement. It’s ok then to just use the Ubuntu binary installed in the normal way.

$ sudo apt-get install -y slapd ldapscripts python-ldap

Now that it’s installed, it’s probably running and this is actually not what you want. So stop it.

$ sudo /etc/init.d/slapd stop

Also you need to put a blank file in the db backend configuration directory or it will complain:

$ sudo touch /var/lib/ldap/DB_CONFIG

slapd Init Script

Here is a script I wrote to start, restart, and stop the LDAP server running on Ubuntu 9.10.

slapd_start
#!/bin/bash
### BEGIN INIT INFO
# Provides:          xed_slapd
# Required-Start:    $remote_fs $network $syslog
# Required-Stop:     $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: OpenLDAP standalone server with old slapd.conf config.
### END INIT INFO

function starter {
    if [ -e /var/run/slapd/slapd.pid ]
    then
        echo "There exists a /var/run/slapd/slapd.pid:"
        cat /var/run/slapd/slapd.pid
        echo "Removing old slapd.pid."
        restarter
    else
        echo "Starting LDAP server"
        # Include -d768 (or whatever) for debugging on console.
        # Otherwise it goes to background.
        slapd -f /etc/ldap/slapd.conf -h "ldaps:// ldapi:///"
        if [ -e /var/run/slapd/slapd.pid ]
        then
            echo -n "Server started on: "
            cat /var/run/slapd/slapd.pid
        else
            echo "PROBLEM STARTING SERVER! No PID file."
        fi
    fi
} # End function starter.

function stopper {
    PIDF=/var/run/slapd/slapd.pid
    if [ -e $PIDF ]
    then
        PID=`cat $PIDF`
        if kill -9 "$PID" && rm "$PIDF"
        then
            echo "Killed $PID and removed: $PIDF"
        else
            echo "Something is wrong with the PID file. Or maybe you need to use sudo."
            echo "$PIDF contains: $PID"
            exit
        fi
    else
        echo "Can not find pid file. Checking processes:"
        if ps -ef | grep "[0-9] slapd" >/dev/null
        then
            echo "There is no pid file at $PIDF"
            echo,"but a slapd process is running:"
            ps -ef | grep "[0-9] slapd"
            echo "You should kill that manually."
        fi
        exit
    fi
} # End function stopper.

function restarter {
    stopper
    starter
} # End function restarter.

function statuser {
    PIDF=/var/run/slapd/slapd.pid
    if [ -e $PIDF ]
    then
        echo -n "There is a PID file ($PIDF) containing: "
        cat $PIDF
        ps -ef | grep "[0-9] slapd"
        nmap -p 636,389 127.0.0.1 | grep /tcp
    else
        echo "Can not find pid file. Checking processes:"
        if ps -ef | grep "[0-9] slapd" >/dev/null
        then
            echo "There is no pid file at $PIDF"
            echo,"but a slapd process is running:"
            ps -ef | grep "[0-9] slapd"
        fi
        exit
    fi

} # End function statuser.

if [ "$1" == "start" ]; then starter; exit; fi
if [ "$1" == "stop" ]; then stopper; exit; fi
if [ "$1" == "restart" ]; then restarter; exit; fi
if [ "$1" == "status" ]; then statuser; exit; fi
echo "Usage: slapd_start {start|stop|restart}"
exit

LDAP on Ubuntu 9.10 Using /etc/ldap/slapd.d

This is the "new" way to configure slapd which involves configuring the LDAP server by storing the configuration information in the LDAP server. Let’s repeat that for clarity: use slapd to configure slapd. Obviously this invites some chicken and egg problems. Also there is not as much reasonable information on-line about how to use this kind of configuration system. The Ubuntu start up scripts (/etc/init.d/slapd) uses this system.

Install LDAP related packages.

Note that server runs immediately upon installation. Start by adding the necessary schemas to the directory:

Note that the password is in plain text here. Best use:

$ slappasswd -h {SSHA}

And fix that. This can be done later with ldapmodify.

Create the following ldif files.

sudo apt-get install -y slapd ldapscripts python-ldap
sudo dpkg-reconfigure slapd
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/cosine.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/inetorgperson.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/nis.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// <<EOF1
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulepath: /usr/lib/ldap
olcModuleload: back_hdb
EOF1
sudo ldapadd -Y EXTERNAL -H ldapi:/// <<EOF2
dn: olcDatabase=hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: hdb
olcSuffix: dc=alab,dc=ucex,dc=edu
olcDbDirectory: /var/lib/ldap
olcRootDN: cn=ldapadmin,dc=alab,dc=ucex,dc=edu
olcRootPW: xxxxxxxxxxxxxxxxxx
olcDbIndex: uid pres,eq
olcDbIndex: cn,sn pres,eq,approx,sub
olcDbIndex: objectClass eq
olcAccess: to attrs=userPassword
    by self write
    by anonymous auth
    by dn.base="cn=ldapadmin,dc=alab,dc=ucex,dc=edu" write
    by * none
olcAccess: to *
    by self write
    by dn.base="cn=ldapadmin,dc=alab,dc=ucex,dc=edu" write
    by * read
EOF2

Note that there is sometimes confusing syntax in examples one can correct order of option execution. database?). The special frontend database = {-1}, and the config Or something like that.

Check your work.

$ sudo slapcat

Should show you everything above as the server knows it. If this produces this warning:

hdb_db_open: warning - no DB_CONFIG file found in directory /var/lib/ldap: (2).
Expect poor performance for suffix "dc=alab,dc=ucex,dc=edu".

Then just:

$ sudo touch /var/lib/ldap/DB_CONFIG

and

$ sudo slapcat

again a couple of times.

Gentoo OpenLDAP Server

This is my attempt to get a Gentoo server working as an LDAP server using emerge and the full Gentoo way.

echo 'net-nds/openldap -gdbm berkdb' >> /etc/portage/package.use

/etc/init.d/slapd start /etc/openldap/slapd.conf ←-- Gentoo /etc/conf.d/slapd ←-- Gentoo /usr/lib/openldap/slapd ←-- Gentoo executable lives here

slapd.d configuration directory tree

/etc/openldap/slapd.d - This is the place that the alternate configuration style is specified. It is generated using this command:

sudo slaptest -f slapd.conf -F slapd.d

Seems Ubuntu uses this by default. The problem is that the /etc/init.d/slapd mechanism doesn’t use the -F <dirname> but rather the old -f <slapd.conf>. Don’t know how important it is to make the config file LDAPable.

Managing Accounts With ACL

Maybe you can use Access Control Lists to control things. Here’s a rough outline of an example to stimulate creativity.

In this example organizationalStatus=0 means active:

access to
  attrs=userPassword
  filter=(&(objectClass=inetOrgPerson)(!(organizationalStatus=0)))
    by group="cn=Admins,ou=Groups,ou=example" =wx
    by group="cn=Replicas,ou=Groups,ou=example" read
    by * none

access to
  attrs=userPassword
  filter=(&(objectClass=inetOrgPerson)(organizationalStatus=0))
    by group="cn=Admins,ou=Groups,ou=example" =swx
    by group="cn=Replicas,ou=Groups,ou=example" read
    by self =wx
    by * =x

CLIENT SETUP

CentOS 7 free-ipa

Here is the client setup guide for using the free-ipa system.

The system seems to be very fussy about authentic FQDN (domain names). If you don’t have such a setup, well, that could be problematic.

Checking that system is in order
host xed-ablab.ucsd.edu
cat /etc/hostname
sudo yum update

Once everything is prepared for installation, installing is pretty easy.

sudo yum install freeipa-client
sudo ipa-client-install --force-ntpd

I did the --force-ntpd to suppress a warning and it seemed like the way I would want to do things anyway. When answering questions, it asks for the domain name of the server but I gave it the actual hostname. This means that if you have a tld of thebig.com and your server is at ipa-mygroup.thebig.com, then having failovers muck with thebig.com might be messy. What they’re envisioning, and I am an enthusiastic supporter of doing it this correct way, is something like ipa.mygroup.thebig.com which would allow you to have mygroup.thebig.com be the domain (which won’t mess with higher level thebig.com business) and ipa be the host in that domain. C’est la vie.

Once it all completes, you can check to see if it’s working. Here I check the password list generally. This should not contain nemo, my test user that only the ipa server knows about. Then I specify nemo and if I get back the uid and not an error, we know that the client has received that information from the ipa server. Yea!

getent passwd
getent passwd nemo
ssh -l nemo localhost

Finally try logging in. There will be a password harangue and the weirdest thing to me is that the password has a minimum change default of 1 hour. The maximum of 90 days is totally ridiculous. I changed it to 730 (2 years) by going to Policy→Password_Policies→Max_lifetime on the server control.

CentOS 7 Cleint Setup

Install necessary things.

# yum install openldap-clients nss-pam-ldapd

Do the authconfig. Note I also used an IP address for the ldapserver.

# authconfig --enableldap --enableldapauth --ldapserver=alab.ucex.edu --ldapbasedn="dc=ucex,dc=edu" --enablemkhomedir --update

Previous attempt…

Client LDAP partially working:

# yum install pam_ldap nss-pam-ldapd nscd
# yum erase sssd-client
# authconfig --enableldap --enableldapauth --ldapserver=ldaps://172.99.99.117 --ldapbasedn="dc=alab,dc=ucex,dc=edu" --enablelocauthorize --enablesysnetauth --updateall

After running that, getent passwd and id ${USER} worked.

CentOS 6 Client Setup

Everything was working great in CentOS 5 and then 6 comes along and LDAP is completely a show stopper. It turns out that the main reason for this is that the way the distro is organized to deal with topics like authentication has completely changed. CentOS (and obviously a well-known upstream vendor) decided to add SSSD or System Security Services Daemon. This was intended to simplify some things in some situations but for my set up it just cause a complete failure. To learn more about sssd you might want to look over the SSSD FAQ.

A good diagnostic to run on a clean system is:

authconfig --test

See what’s going on there.

The first and obvious step is probably to install the packages pertinent to LDAP client behavior:

yum install openldap-clients
yum install pam_ldap

Maybe even:

sudo yum install openldap nss-pam-ldapd openldap-clients pam-ldap nscd

Some people believe a step like this is necessary:

authconfig --enableldap --enableldapauth --ldapserver=ldap-alab.ucex.edu --ldapbasedn="dc=alab,dc=ucex,dc=edu" --update

Or, try this:

authconfig --enableldap --enableldapauth --ldapserver=ldaps://ldap-alab.ucex.edu --ldapbasedn="dc=alab,dc=ucex,dc=edu" --enableldaptls --enablelocauthorize --enablesysnetauth --updateall

Or try this which really works:

authconfig --enableldap --enableldapauth --ldapserver=ldaps://ldap-alab.ucex.edu --ldapbasedn="dc=alab,dc=ucex,dc=edu" --enablelocauthorize --enablesysnetauth --updateall

Note the --enableldaptls option should not be in here now. Amazingly this causes it to not authenticate the first time you enter the password; it authenticates on the second attempt! How messed up is that?

I did that step but I’m not 100% sure if it was absolutely necessary. I don’t think it was necessary for the ldapsearch command that worked.

What if SELinux or an iptables firewall is in the way? Disable them and get things working. Later you can put them back carefully.

service iptables stop
setenforce 0

Edited my /etc/openldap/ldap.conf to be this:

BASE dc=alab,dc=ucex,dc=edu
URI ldap://ldap-alab.ucex.edu/
ldap_version 3
rootbinddn cn=ldapadmin,dc=alab,dc=ucex,dc=edu
timelimit 30
bind_timelimit 30
idle_timelimit 30
s_initgroups_ignoreusers root,ldap,named,avahi,haldaemon,dbus,radvd,tomcat,radiusd,news,mailman,nscd,gdm
TLS_REQCERT never
TLS_CACERT /etc/openldap/cacerts/ldapscert.pem
pam_password md5

Put the TLS cert in the places specified by TLS_REQCERT.

Here’s a way to test LDAP server receptiveness:

ldapsearch -x -H ldaps://ldap-alab.example.edu -b dc=alab,dc=ucex,dc=edu

THIS WORKED!

However, id user did not.

Maybe something called "nslcd" is needed. Apparently this package provides for it:

yum install nss-pam-ldapd

It also installs nscd as a dependency.

Edit the /etc/nslcd.conf to be something like this:

uri ldaps://ldap-alab.ucex.edu
ldap_version 3
rootpwmoddn cn=ldapadmin,dc=alab,dc=ucex,dc=edu
bind_timelimit 30
timelimit 30
idle_timelimit 30
tls_reqcert never
tls_cacertdir /etc/openldap/cacerts/
tls_cacertfile /etc/openldap/cacerts/ldapscert.pem
uid nslcd
gid ldap
uri ldaps://ldap-alab.ucex.edu
base dc=alab,dc=ucex,dc=edu
tls_cacertdir /etc/openldap/cacerts

It does seem that this file is the one that causes trouble. Even when I can get a clean connection and the user database can be dumped with ldapsearch, the id and getent commands don’t work. Here is what eventually worked for me on CentOS 6.4.

ldap_version 3
rootpwmoddn cn=ldapadmin,dc=alab,dc=ucex,dc=edu
bind_timelimit 30
timelimit 30
idle_timelimit 30
tls_reqcert never
tls_cacertdir /etc/openldap/cacerts
tls_cacertfile /etc/openldap/certs/ldapscert.pem
uid nslcd
gid ldap
uri ldaps://ldap-alab.ucex.edu
base dc=alab,dc=ucex,dc=edu
ssl no

Don’t forget to run the

authconfig --enableldap --enableldapauth \
--ldapserver=ldaps://ldap-alab.ucex.edu \
--ldapbasedn="dc=alab,dc=ucex,dc=edu" --enablelocauthorize \
--enablesysnetauth --updateall

Now I was able reduce this command to:

authconfig --enableldap --enableldapauth --enablesysnetauth --updateall

This allowed a system where ldapsearch worked but not id ${USER} t start working.

Note
The tls_cacertfile and tls_cacertdir look suspicious but that’s what worked. My dir was really /etc/openldap/certs. The other was empty. Now I’m just doing ln -s certs cacerts and skipping any problems like that.
Warning
If you use ssl start_tls in this configuration file then it will not work and you’ll get an error: err=1 text=TLS already started Hmm. It seems that the authconfig command puts this incorrect option back in the config file. You must make sure it is not there. I took out the --enableldapstarttls option which then keeps the authconfig from adding that line. Then you must service nslcd restart to get that working right and then it works.

Now fire that up with:

service nslcd start

And now keep an eye on tail -f /var/log/debug and try id user and see if any action happens.

WORKS! Holy shit!

Trying to repeat this on a fresh install of Server CentOS 6.2 it didn’t work. I noticed that there was some messy stuff with sssd which was not present when things worked. So I got rid of it:

yum erase sssd

And then it seemed to make contact with the ldap-server (or try). Still not working though.

CentOS 5 Client Setup

  • Have LDAP client packages installed:

    sudo yum install openldap openldap_clients nss-ldap
  • Make sure there’s a /etc/openldap directory.

  • Make sure there’s a ldapscert.pem in /etc/openldap/cacerts/. This will look a bit like this:

    -----BEGIN CERTIFICATE-----
    MIIEjQPPN3FtNjVONtVWNYFcf0KH5f3EMA0GCSqGSIb3DQEBODHNZVTXZDswCQYD
    <22 lines removed for brevity>
    KVIv7twCP6zCdXFFb8Lh0IxschXizn/qe9lPP2aDuVO3VeNFf1SMgGYN2lcL+vC0
    bnjgoriYrh0m6fUl8l3Guj==
    -----END CERTIFICATE-----
  • Run authconfig to set where the LDAP server is: authconfig --enableldap --enableldapauth --enableldaptls --ldapserver=ldap-alab.ucex.edu --update

  • Make an /etc/ldap.conf that looks like this:

    base dc=alab,dc=ucex,dc=edu
    uri ldaps://ldap-alab.ucex.edu/
    ldap_version 3
    rootbinddn cn=ldapadmin,dc=alab,dc=ucex,dc=edu
    timelimit 30
    bind_timelimit 30
    idle_timelimit 3600
    nss_initgroups_ignoreusers root,ldap,named,avahi,haldaemon,dbus,radvd,tomcat,radiusd,news,mailman,nscd,gdm
    TLS_REQCERT never
    TLS_CACERT /etc/openldap/cacerts/ldapscert.pem
    pam_password md5
  • I think that different things look for this in different places. So make it available everywhere like this:

    rm -f /etc/openldap/ldap.conf ; ln -s /etc/ldap.conf /etc/openldap/
  • Then /etc/nsswitch.conf needs to be set with something sensible like:

    passwd: files ldap
    shadow: files ldap
    group: files ldap

Ubuntu LDAP Client Setup

Install the client stuff:

$ sudo apt-get install libnss-ldap

This installs these packages too:

auth-client-config ldap-auth-client ldap-auth-config libpam-ldap

Maybe consider the nscd package. Upon installation, configuration questions will be asked that will help set things up. You can redo this (and some more) with:

$ sudo dpkg-reconfigure ldap-auth-config

First thing is the URI of the LDAP server:

ldap://abagyan-athena.ucex.edu:389/
ldapi

LDAP over IPC (for local machines?)

ldaps

LDAP over SSL (port 636)

ldap

I think this is the right one for TLS. Not 100% sure.

Next is the ldap-auth-config dn of the LDAP search base.

ou=users,dc=alab,dc=ucex,dc=edu

Next the version, why not:

3

Make local root Database admin:

Probably ok for simple things, but no generally (central admin) Does LDAP database require login? I guess this is about the ACL setup. I think in normal cases, anyone can try their luck authenticating and so it’s a:

No

LDAP account for root (bind dn):

cn=ldapadmin,dc=alab,dc=ucex,dc=edu

LDAP root account password (password for bind dn):

aSecret

Then fix up the nsswitch.conf and pam configuration files. This command seems possibly handy:

sudo auth-client-config -t nss -p lac_ldap

Here’s it’s format:

auth-client-config -p PROFILE -t TYPE

I think that this basically means switching the /etc/nsswitch.conf entries to be these:

passwd: files ldap
group: files ldap
shadow: files ldap

And adding a "pam_ldap.so" entry to the "/etc/pam.d/common-*" files. For example, here’s /etc/pam.d/common-password:

password        [success=2 default=ignore]      pam_unix.so obscure sha512
password        [success=1 user_unknown=ignore default=die] pam_ldap.so use_authtok try_first_pass

Here’s /etc/pam.d/common-auth:

auth    [success=2 default=ignore]      pam_unix.so nullok_secure
auth    [success=1 default=ignore]      pam_ldap.so use_first_pass

Here’s /etc/pam.d/common-account:

account [success=2 new_authtok_reqd=done default=ignore] pam_unix.so
account [success=1 default=ignore]      pam_ldap.so

Make sure pam is 100% happy by doing this:

$ sudo pam-auth-update

Create or modify /etc/ldap.conf file to be:

base dc=alab,dc=ucex,dc=edu
URI ldaps://abagyan-athena.ucex.edu/
ldap_version 3
rootbinddn cn=ldapadmin,dc=alab,dc=ucex,dc=edu
bind_policy soft

TLS_REQCERT never
TLS_CACERT /etc/ldap/ldapscert.pem

More Ubuntu Client Setup

Now to get a remote client working, you need to set up its /etc/ldap/ldap.conf file which controls client things:

base dc=alab,dc=ucex,dc=edu
URI ldaps://abagyan-athena.ucex.edu/
ldap_version 3
rootbinddn cn=ldapadmin,dc=alab,dc=ucex,dc=edu
bind_policy soft
#pam_password md5

# This is important to getting self-signed certs to work!
TLS_REQCERT never
TLS_CACERT /etc/ldap/ldapscert.pem

Also copy ldapscert.pem over and make sure it’s world readable.

A preliminary test useful for troubleshooting:

$ openssl s_client -connect abagyan-athena.ucex.edu:636 -showcerts

To actually test the remote clients:

$ ldapsearch  -x -H ldaps://abagyan-athena.ucex.edu \
              -b ou=users,dc=alab,dc=ucex,dc=edu '*'

A similar test can be used on the server itself if it’s not responding to ldaps:

$ sudo ldapsearch  -x -H ldapi:/// -b ou=users,dc=alab,dc=ucex,dc=edu '*'

To test if TLS is working, check that the secure port (636) is ok with:

$ nmap -v localhost

Then try to connect with openssl’s tester client:

$ openssl s_client -connect localhost:636 -showcerts

On client config:

TLS_REQCERT allow

This allows your OpenLDAP or OpenLDAP-based client software (for example, gq) to accept self-signed server certificates.

And in /etc/ldap.conf:

tls_cert /etc/ldap/ldapscert.pem
tls_key /etc/ldap/ldapskey.pem

Gentoo LDAP Clients

Maybe need these:

  • emerge pam_ldap - mostly includes lib/security/pam_ldap.so

  • emerge nss_ldap - /lib/libnss_ldap-2.12.2.so, /etc/nsswitch.ldap, /etc/ldap.conf

CLIENT FUNCTIONALITY

This command run from the client should make a connection and return a nonsensitive (no hashes) dump of all the users (or whatever you have in there).

# ldapsearch -x -b 'dc=alab,dc=ucex,dc=edu' '(objectclass=*)'

This has been known to work properly on CentOS 5 and 6 both as root and normal users. It is probably a good way to monitor for the LDAP server dying but I’m not sure about that.

To check if user information is being made available to the operating system, try:

# getent passwd someuser

Of course this kind of checking is prone to unproductive hanging if there is a problem.

LDIF Format

LDAP Data Interchange Format

The file format used to communicate with the LDAP server when changing the directory. Used by ldapsearch, ldapadd, and ldapmodify, etc.

LDIF Sample
dn: uid=xed,ou=People,dc=xed,dc=ch
uid: xed
cn: Chris X Edwards
objectClass: account
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword:: e2NyexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxCZ0FnMWJ
 lYklGNEhyVFhQd1VORWxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxaFIvUUcx
shadowLastChange: 14557
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 500
gidNumber: 500
homeDirectory: /home/xed/
gecos: Chris X Edwards
structuralObjectClass: account
entryUUID: 23d6026d-56d5-4b2a-81d5-d673809bf3e1
creatorsName: cn=ldapadmin,dc=xed,dc=ch
createTimestamp: 20091129194112Z
entryCSN: 20091129194112.386639Z#000000#000#000000
modifiersName: cn=ldapadmin,dc=xed,dc=ch
modifyTimestamp: 20091129194112Z

ldapmodify

ldapmodify -x -W -D "cn=ldapadmin,dc=xed,dc=ch"  -f change.ldif

Where "change.ldif" is something like:

dn: cn=Chris Edwards,ou=xed,dc=xed,dc=ch
changetype: modify
replace:uid
uid: 4444
-
replace:employeeNumber
employeeNumber: 98722

This replaces the uid and the employeeNumber. Here’s how to do it on the secure server setup:

ldapmodify -D "cn=ldapadmin,dc=alab,dc=ucex,dc=edu"\
     -H ldaps://localhost -W -f modifysomething.ldif

On the server itself, try this:

ldapmodify -x -W -H ldapi:/// -D "cn=ldapadmin,dc=alab,dc=ucex,dc=edu"\
     -f modifysomething.ldif

ldapadd

Create example.ldif

dn: uid=xed,ou=People,dc=xed,dc=ch
uid: xed
cn: Chris X Edwards
objectClass: account
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword: {crypt}$6$qmOwDkEl$hbTM.....
shadowLastChange: 14557
shadowMax: 99999
shadowWarning: 7
loginShell: /bin/bash
uidNumber: 500
gidNumber: 500
homeDirectory: /home/xed/
gecos: Chris X Edwards
ldapadd -x -D "cn=ldapadmin,dc=xed,dc=ch" -W -f example.ldif

Use ldapadd to add schemas too:

ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/inetorgperson.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/nis.ldif
  • -x = simple authentication instead of SASL

  • -Y <mech> = SASL mechanism (PLAIN, LOGIN, DIGEST-MD5, CRAM-MD5, KERBEROS_V4, EXTERNAL=tls)

  • -H = ldapuri format is protocol://host:port/dn??scope?(cn=Some%20Filter) (see man ldapurl)

  • -f = LDIF file to add

ldapsearch

  • -x = Use simple authentication instead of SASL.

  • -W = Prompt for simple authentication. Not used for SASL.

  • -b = Search base. Starting point on tree for search.

  • -D <binddn> = For simple authentication, the dn to bind with, not for SASL.

  • -Y = SASL "mechanism". A good one seems to be "EXTERNAL".

  • -ZZ = TLS and require success.

  • -H = ldapuri format is protocol://host:port/dn??scope?(cn=Some%20Filter) (see man ldapuri)

This can be used to test to see things are working:

ldapsearch -x -b 'dc=xed,dc=ch' '(objectclass=*)'

Example, find the user xed’s record:

ldapsearch -x -W -D "cn=ldapadmin,dc=xed,dc=ch" -b "dc=xed,dc=ch" "uid=xed"

/usr/bin/ldapdelete

To get rid of an entire record in the directory:

ldapdelete -x -W -H ldapi:/// -D "cn=ldapadmin,dc=alab,dc=ucex,dc=edu" "ou=sudoers,dc=alab,dc=ucex,dc=edu"

Other Utilities

  • /usr/bin/ldapcompare

  • /usr/bin/ldapexop

  • /usr/bin/ldapmodrdn

  • /usr/bin/ldappasswd

  • /usr/bin/ldapurl

  • /usr/bin/ldapwhoami

  • /usr/sbin/slapacl

  • /usr/sbin/slapadd - Add a database

            slapadd -l <inputfile> -f <slapdconfigfile>
                            [-d <debuglevel>] [-n <integer>|-b <suffix>]
    * /usr/sbin/slapauth
    * /usr/sbin/slapcat - Dump the contents of an entire database
  • /usr/sbin/slapdn

  • /usr/sbin/slapindex

  • /usr/sbin/slappasswd- Use to generate passwords and hashes of passwords.

    • slappasswd -g # Generates a random password.

    • slappasswd # Prompts for password and generates hash suitable for LDAP.

  • /usr/sbin/slapschema

  • /usr/sbin/slaptest

REPLICATION

TROUBLESHOOTING

LDAP is trouble so let’s start with how to diagnose problems or verify certain things are actually working.

Logging

LDAP events on the OpenLDAP server generally go to syslog. Watching tail -f /var/log/syslog should tell you if a connection attempt was even made at all. It might also hint at other problems. If no connection attempt was even recorded at the server then it’s not worth trying to debug problems with certificates or other details of that nature.

If you really want to see everything happening on the port, dump those packets with something like this:

# tcpdump -n tcp port ldaps

Error Codes

Of course all that logging will do no good if it is too cryptic to comprehend. This list of LDAP error codes was to the point and exactly what you’d hope to find when trying to decode something like err=49.

Mystery Dotted Decimal Strings

Often the output of slapd verbose logging will contain awful things like this:

545de4ab slap_global_control: unrecognized control: 1.3.6.1.4.1.42.2.27.8.5.1
545de4ab backend_check_controls: unrecognized non-critical control: 1.3.6.1.4.1.42.2.27.8.5.1

"These are not intended to be displayed to users," says the incredibly optimistic RFC2252. That document has a list with some of these things, but it looks like they can be whimsically made up by application programmers. To figure out what these crazy strings are trying to say, I had to go to the source code.

# grep "1.3.6.1.4.1.42.2.27.8.5.1" openldap-2.4.40/include/ldap.h
#define LDAP_CONTROL_PASSWORDPOLICYREQUEST      "1.3.6.1.4.1.42.2.27.8.5.1"
#define LDAP_CONTROL_PASSWORDPOLICYRESPONSE      "1.3.6.1.4.1.42.2.27.8.5.1"

Not exactly helpful but much more helpful than before.

Mystery Death

There is a mysterious mode of failure where the LDAP server stops working. It seems like sometimes it comes back from the dead after a long while but maybe not always. I have tracked it down to very aggressive jobs making tons of requests. The answer in the past has been to manually restart the server.

Further investigation has shown that in /var/log/syslog there will be some stuff like warning: cannot open /etc/hosts.allow: Too many open files. I can’t quite figure out exactly what that means or how to properly cure it but it’s known and discussed here.

I think I’ll try setting up a monitor that uses a simple ldapsearch and when it fails, trigger a restart of the server automatically.

InK’s Excellent Pro Tips

  • Are the versions of OpenLDAP the same?

  • Or are you using a newer version on Gentoo?

  • How are the UID lookups failing? Using ldapsearch? getent passwd?

  • Are you seeing any errors in the client or server logs?

  • Have you started the daemon on the server with debugging turned up?

  • Instead of TLS, have you tried SSL and forcing all communication across 636?

  • One issue I ran into was Ubuntu’s use of GnuTLS vs. OpenSSL - contrary to popular belief/misconception, GnuTLS does not transparently deal with OpenSSL …

Fix passwd functionality

If the passwd command doesn’t work look here:

/etc/pam.d/common-password

and remove this:

use_authtok

Connectivity

Make sure there is an open port on the LDAP server. This will be 389 for LDAP and 636 for LDAPS. Try nmap -p 389,636 ldap.example.com.

Directory Backup And Restore

Here is how to make a dump of the directory database contents. Remember that these files contain password hashes and are therefore kind of sensitive. Ideally you should turn off the server to ensure consistency, but as long as no one is actively modifying the directory (no admin activity or passwd commands) you should be ok.

$ sudo slapcat -v -f /etc/ldap/slapd.conf -l /home/xed/ldap/$(date +%Y%m%d).ldif

Here is a complete routine I used to restore a directory from a backup LDIF. Shut down the server and do this:

$ cd /usr/local/var
$ sudo rm openldap-data/*
$ sudo touch openldap-data/DB_CONFIG
$ sudo slapadd -v -c -l /home/xed/backup.20110711.ldif -f /etc/openldap/slapd.conf
$ sudo slapindex -f /etc/openldap/slapd.conf

TLS SETUP Place the certificate and key where they can be found. See TLS on how to use openssl to generate these certificates.

$ sudo cp ldaps*pem /etc/ldap/

Now prepare a /etc/ldap/slapd.conf file containing as described in the server set up section.

Now the server can be started up. This is where it is possible to specify where the config file is. Also you can add some logging output (try slapd -d? for logging options, or slapd -d0123 to run in the terminal and not fork).

$ sudo slapd -f /etc/ldap/slapd.conf -d1023 -h "ldaps://"

Helpful Utilities ?

ENCRYPTION SETUP

It’s important to not use LDAP for machine authentication without encrypting the traffic. Without encryption, there’s almost no point to using any kind of access mechanism at all.

OpenSSL Key Generation

Start by generating a cert and a key:

$ sudo openssl req -x509 -nodes -newkey rsa:2048 -days 7300 -keyout ldapskey.pem -out ldapscert.pem

Note the default expiration is 30 days, so setting to 20 years is about as trouble free as it’s going to get.

$ sudo chown openldap:openldap *pem
$ sudo chmod 0400 *pem

Note the certificate is the public key and the key is the private key. This is self-signed so this avoids any certificate authority annoyances.

sudo ldapadd -Y EXTERNAL -H ldapi:/// <<EOF3
objectClass: olcGlobal
olcTLSCertificateFile: /etc/ldap/ldapscert.pem
olcTLSCertificateKeyFile: /etc/ldap/ldapskey.pem
EOF3

Need this too?

olcTLSCACertificateFile: /etc/ldap/ldapcacert.pem

Edit:

$ sudo vi /etc/default/slapd to include stricter connections:
SLAPD_SERVICES="ldap://127.0.0.1:389/ ldaps:/// ldapi:///"

or mabye (?)

SLAPD_SERVICES="ldap://127.0.0.1/ ldaps:///"
TLSCertificateFile /etc/ldap/ldapscert.pem

Specifies the file that contains the slapd server certificate.

TLSCertificateKeyFile /etc/ldap/ldapskey.pem

Specifies the file that contains the slapd server private key that matches the certificate stored in the TLSCertificateFile file. Currently, the private key must not be protected with a password, so it is of critical importance that it is protected carefully.

TLSCipherSuite TLSv1+RSA:!NULL

This is to disable the "NULL" ciphers (NULL-SHA and NULL-MD5). You can double check that this value is sensible with $ openssl ciphers -v TLSv1+RSA:!NULL This should produce the list of various encryption methods available. I think that’s what it’s doing. If it doesn’t fail, it’s probably ok.

TLSVerifyClient never

Default. Is this necessary?

disallow bind_anon
require bind
security simple_bind=128

SSL SETUP

Note
LDAP can use TLS (Transport Layer Security) or SSL (Secure Socket Layer). TLS runs on the same port as unencrypted LDAP (389) but an initial TLS Start protocol gets the encryption going. To get TLS functionality, you must compile with --with-tls as a compile option during the OpenLDAP build. SSL runs on a different port (636) and is encrypted from the beginning.

Generating SSL Keys For OpenLDAP

To use OpenLDAP in TLS or SSL mode you will need to generate a PEM format SSL key.

cd /etc/openldap/ssl
/usr/bin/openssl req -newkey rsa:1024 -keyout tempfile1 -nodes -x509 -days 365 -out tempfile2
cat tempfile1 > ldap.pem
echo "" >> ldap.pem
cat tempfile2 >> ldap.pem
rm -f tempfile1 tempfile2

Note that this command creates an RSA key and then self-signs that key. Self-signed keys are not usual in (for example) HTTPS communications, as the keys are generally signed by a third party known as a Certification Authority. In this case, however, a self-signed key is perfectly okay, as most LDAP clients do not check the signature of the key.

Do these certificates work? With the server turned on try this:

$ openssl s_client -connect localhost:636 -showcerts

This web site has good information on using OpenSSL. It discusses how to use s_server and s_client to test the certificates as well as check to see that they’re not expired.

Place the certificate and key where they can be found. See TLS on how to use openssl to generate these certificates.

$ sudo cp ldaps*pem /etc/ldap/

Now prepare a /etc/ldap/slapd.conf file containing:

/etc/ldap/slapd.conf
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/inetorgperson.schema
include         /etc/ldap/schema/nis.schema

# SECURITY
access to attrs=userPassword
  by self write
  by anonymous auth
  by dn.base="cn=ldapadmin,dc=alab,dc=ucex,dc=edu" write
  by * none
access to *
  by self write
  by dn.base="cn=ldapadmin,dc=alab,dc=ucex,dc=edu" write
  by * read

# DON'T bother with ARGS file unless you feel strongly
# slapd scripts stop scripts need this to work
pidfile /var/run/slapd/slapd.pid

# enable a lot of logging - we might need it
# but generates huge logs
#loglevel       -1

# MODULELOAD definitions
# not required (comment out) before version 2.3
moduleload back_bdb.la

# TLS-enabled connections
TLSCACertificateFile /etc/ldap/ldapscert.pem
TLSCertificateFile /etc/ldap/ldapscert.pem
TLSCertificateKeyFile /etc/ldap/ldapskey.pem

database bdb
suffix "dc=alab,dc=ucex,dc=edu"

# root or superuser
rootdn "cn=ldapadmin,dc=alab,dc=ucex,dc=edu"
rootpw SecretStuff
# The database directory MUST exist prior to running slapd AND
# change path as necessary
directory /var/lib/ldap

# Indices to maintain for this directory
# unique id so equality match only
index   uid     pres,eq
# allows general searching on commonname, etc
index   cn,sn pres,eq,approx,sub
# if searches will include objectClass uncomment following
index objectClass eq
# index objectClass eq
# shows use of default index parameter
index default eq,sub

# other database parameters
# read more in slapd.conf reference section
cachesize 10000
checkpoint 128 15

Might want to sudo chmod 600 /etc/ldap/slapd.conf because of the password in there.

REFERENCE

Useful Documents

  • The official definition of how LDAP should work is the RFC4511 protocol standard.

  • Useful HOWTO for Gentoo: link

  • Helpful overview of what LDAP is all about on Linux: link

  • Migration tools to move existing /etc/{passwd|group} to LDIF format: link

  • ldapvi - Use Vi to update LDAP directories: link

  • Useful Howto Ubuntu: link

  • Useful CentOS/Fedora Howto: link

  • Useful Looking CentOS6 Scripts: link

  • General Troubleshooting Helpfulness: link

  • This is pretty handy for knowing what you can sensibly put in an LDAP directory: link

  • This is the nss_ldap man page which is useful for defining fields of the client configuration: link

TLS Documents

  • First an overview of TLS on OpenLDAP: link

  • Even better outline of the process: link Focusing on TLS which seems to be desirable. link

  • Ubuntu specific SSL notes: link

  • This is the most useful for non CA setups: link

Glossary

LDAP

Lightweight Directory Access Protocol, rfc4511.

X.500

The series of protocols which define things like Directory Access Protocol (DAP). Seems to be used only as a base or reference on which to create things like LDAP.

slurpd

Standalone LDAP Update RePlication Daemon replaced by syncrepl (Sync-based replication)

NSS

Name Service Switch sys-auth/nss_ldap - link

DSA

Directory System Agent X.500 term for any DAP or LDAP enabled directory service e.g. an LDAP server.

DSE

DSA Specific Entry (DSE) A control entry in a local directory server.

DIT

Directory Information Tree aka namingContext

SASL

Simple Authentication and Security Layer

TLS

Transport Layer Security ("OpenLDAP clients and servers are capable of using the TLS framework to provide integrity and confidentiality protections and to support LDAP authentication using the SASL EXTERNAL mechanism.")

ASCII Art From rfc4511
               +----------------------+
               |  LDAP message layer  |
               +----------------------+ > LDAP PDUs
               +----------------------+ < data
               |      SASL layer      |
               +----------------------+ > SASL-protected data
               +----------------------+ < data
               |       TLS layer      |
   Application +----------------------+ > TLS-protected data
   ------------+----------------------+ < data
     Transport | transport connection |
               +----------------------+
slapd

Standalone Lightweight Access Protocol Daemon

LDIF

LDAP Data Interchange Format

DN

Distinguished name, a sequence of RDNs connected by commas. Example: "cn=xed,ou=users,dc=alab,dc=ucex,dc=edu"

RDN

Relative distinguished name, an attribute with an asscoiated value in the form attribute=value. Example: dc=edu

DC

Domain component

CN

Common name

OU

Organizational unit

BER

Basic Encoding Rules - The mysterious ber saturates the OpenLDAP source code with absolutely no explanation. It is defined on page 4 of rfc4511 and vaguely here. The LDAP spec says that it uses a "subset" of BER. Seems to relate to how data is packaged for transmission.

PDU

LDAP Message Protocol Data Unit.

Another Useful LDAP Glossary: link

List Of Ubuntu LDAP Package Highlights

slapd - OpenLDAP server (slapd) Contains these useful things:

  • /etc/ldap

  • /etc/ldap/schema

  • /usr/sbin/slapd

  • /usr/sbin/slapacl

  • /usr/sbin/slapadd

  • /usr/sbin/slapauth

  • /usr/sbin/slapcat

  • /usr/sbin/slapdn

  • /usr/sbin/slapindex

  • /usr/sbin/slappasswd

  • /usr/sbin/slaptest - test config files for wholesomeness

ldap-utils - OpenLDAP utilities Contains these useful things:

  • /usr/bin/ldapdelete

  • /usr/bin/ldapmodrdn

  • /usr/bin/ldapsearch

  • /usr/bin/ldapcompare

  • /usr/bin/ldapmodify

  • /usr/bin/ldappasswd

  • /usr/bin/ldapwhoami

  • /usr/bin/ldapexop

  • /usr/bin/ldapurl

ldapscripts - Add and remove user and groups (stored in a LDAP directory) Contains these useful things:

  • /usr/sbin/ldapdeletemachine

  • /usr/sbin/ldapmodifygroup

  • /usr/sbin/ldapsetpasswd

  • /usr/sbin/lsldap

  • /usr/sbin/ldapadduser

  • /usr/sbin/ldapdeleteuser

  • /usr/sbin/ldapsetprimarygroup

  • /usr/sbin/ldapfinger

  • /usr/sbin/ldapid

  • /usr/sbin/ldapmodifymachine

  • /usr/sbin/ldaprenamegroup

  • /usr/sbin/ldapaddgroup

  • /usr/sbin/ldapaddusertogroup

  • /usr/sbin/ldapdeleteuserfromgroup

  • /usr/sbin/ldapinit

  • /usr/sbin/ldapmodifyuser

  • /usr/sbin/ldaprenamemachine

  • /usr/sbin/ldapaddmachine

  • /usr/sbin/ldapdeletegroup

  • /usr/sbin/ldaprenameuser

python-ldap - An LDAP interface module for Python Contains these useful things:

  • /usr/lib/python2.6/dist-packages/ldap

  • /usr/lib/python2.6/dist-packages/ldap/schema

Also notice:

  • /usr/lib/python2.6/dist-packages/ldap/ldapobject.py

  • /usr/lib/python2.6/dist-packages/ldapurl.py

  • /usr/lib/python2.6/dist-packages/ldif.py