29.5. Lightweight Directory Access Protocol (LDAP)
Prev | Chapter 29. Network Servers | Next

## 29.5. Lightweight Directory Access Protocol (LDAP)

Originally contributed by Tom Rhodes.
Updates by Rocky Hotas.

The Lightweight Directory Access Protocol (LDAP) is an application layer protocol used to access, modify, and authenticate objects using a distributed directory information service. Think of it as a phone or record book which stores several levels of hierarchical, homogeneous information. It is used in Active Directory and OpenLDAP networks and allows users to access to several levels of internal information utilizing a single account. For example, email authentication, pulling employee contact information, and internal website authentication might all make use of a single user account in the LDAP server's record base.

This section provides a quick start guide for configuring an LDAP server on a FreeBSD system. It assumes that the administrator already has a design plan which includes the type of information to store, what that information will be used for, which users should have access to that information, and how to secure this information from unauthorized access.

### 29.5.1. LDAP Terminology and Structure

LDAP uses several terms which should be understood before starting the configuration. All directory entries consist of a group of attributes. Each of these attribute sets contains a unique identifier known as a Distinguished Name (DN) which is normally built from several other attributes such as the common or Relative Distinguished Name (RDN). Similar to how directories have absolute and relative paths, consider a DN as an absolute path and the RDN as the relative path.

An example LDAP entry looks like the following. This example searches for the entry for the specified user account (`uid`), organizational unit (`ou`), and organization (`o`):

    % ldapsearch -xb "uid=trhodes,ou=users,o=example.com"
    # extended LDIF
    #
    # LDAPv3
    # base <uid=trhodes,ou=users,o=example.com> with scope subtree
    # filter: (objectclass=*)
    # requesting: ALL
    #

    # trhodes, users, example.com
    dn: uid=trhodes,ou=users,o=example.com
    mail: trhodes@example.com
    cn: Tom Rhodes
    uid: trhodes
    telephoneNumber: (123) 456-7890

    # search result
    search: 2
    result: 0 Success

    # numResponses: 2
    # numEntries: 1

This example entry shows the values for the `dn`, `mail`, `cn`, `uid`, and `telephoneNumber` attributes. The cn attribute is the RDN.

More information about LDAP and its terminology can be found at `http://www.openldap.org/doc/admin24/intro.html`.

### 29.5.2. Configuring an LDAP Server

FreeBSD does not provide a built-in LDAP server. Begin the configuration by installing net/openldap-server package or port:

    # pkg install openldap-server

There is a large set of default options enabled in the package. Review them by running `pkg info openldap-server`. If they are not sufficient (for example if SQL support is needed), please consider recompiling the port using the appropriate framework.

The installation creates the directory `/var/db/openldap-data` to hold the data. The directory to store the certificates must be created:

    # mkdir /usr/local/etc/openldap/private

The next phase is to configure the Certificate Authority. The following commands must be executed from `/usr/local/etc/openldap/private`. This is important as the file permissions need to be restrictive and users should not have access to these files. More detailed information about certificates and their parameters can be found in Section 13.6, “OpenSSL”. To create the Certificate Authority, start with this command and follow the prompts:

    # openssl req -days 365 -nodes -new -x509 -keyout ca.key -out ../ca.crt

The entries for the prompts may be generic except for the `Common Name`. This entry must be different than the system hostname. If this will be a self signed certificate, prefix the hostname with `CA` for Certificate Authority.

The next task is to create a certificate signing request and a private key. Input this command and follow the prompts:

    # openssl req -days 365 -nodes -new -keyout server.key -out server.csr

During the certificate generation process, be sure to correctly set the `Common Name` attribute. The Certificate Signing Request must be signed with the Certificate Authority in order to be used as a valid certificate:

    # openssl x509 -req -days 365 -in server.csr -out ../server.crt -CA ../ca.crt -CAkey ca.key -CAcreateserial

The final part of the certificate generation process is to generate and sign the client certificates:

    # openssl req -days 365 -nodes -new -keyout client.key -out client.csr
    # openssl x509 -req -days 3650 -in client.csr -out ../client.crt -CA ../ca.crt -CAkey ca.key

Remember to use the same `Common Name` attribute when prompted. When finished, ensure that a total of eight (8) new files have been generated through the proceeding commands.

The daemon running the OpenLDAP server is `slapd`. Its configuration is performed through `slapd.ldif`: the old `slapd.conf` has been deprecated by OpenLDAP.

Configuration examples for `slapd.ldif` are available and can also be found in `/usr/local/etc/openldap/slapd.ldif.sample`. Options are documented in slapd-config(5). Each section of `slapd.ldif`, like all the other LDAP attribute sets, is uniquely identified through a DN. Be sure that no blank lines are left between the `dn:` statement and the desired end of the section. In the following example, TLS will be used to implement a secure channel. The first section represents the global configuration:

    #
    # See slapd-config(5) for details on configuration options.
    # This file should NOT be world readable.
    #
    dn: cn=config
    objectClass: olcGlobal
    cn: config
    #
    #
    # Define global ACLs to disable default read access.
    #
    olcArgsFile: /var/run/openldap/slapd.args
    olcPidFile: /var/run/openldap/slapd.pid
    olcTLSCertificateFile: /usr/local/etc/openldap/server.crt
    olcTLSCertificateKeyFile: /usr/local/etc/openldap/private/server.key
    olcTLSCACertificateFile: /usr/local/etc/openldap/ca.crt
    #olcTLSCipherSuite: HIGH
    olcTLSProtocolMin: 3.1
    olcTLSVerifyClient: never

The Certificate Authority, server certificate and server private key files must be specified here. It is recommended to let the clients choose the security cipher and omit option `olcTLSCipherSuite` (incompatible with TLS clients other than `openssl`). Option `olcTLSProtocolMin` lets the server require a minimum security level: it is recommended. While verification is mandatory for the server, it is not for the client: `olcTLSVerifyClient: never`.

The second section is about the backend modules and can be configured as follows:

    #
    # Load dynamic backend modules:
    #
    dn: cn=module,cn=config
    objectClass: olcModuleList
    cn: module
    olcModulepath:	/usr/local/libexec/openldap
    olcModuleload:	back_mdb.la
    #olcModuleload:	back_bdb.la
    #olcModuleload:	back_hdb.la
    #olcModuleload:	back_ldap.la
    #olcModuleload:	back_passwd.la
    #olcModuleload:	back_shell.la

The third section is devoted to load the needed `ldif` schemas to be used by the databases: they are essential.

    dn: cn=schema,cn=config
    objectClass: olcSchemaConfig
    cn: schema

    include: file:///usr/local/etc/openldap/schema/core.ldif
    include: file:///usr/local/etc/openldap/schema/cosine.ldif
    include: file:///usr/local/etc/openldap/schema/inetorgperson.ldif
    include: file:///usr/local/etc/openldap/schema/nis.ldif

Next, the frontend configuration section:

    # Frontend settings
    #
    dn: olcDatabase={-1}frontend,cn=config
    objectClass: olcDatabaseConfig
    objectClass: olcFrontendConfig
    olcDatabase: {-1}frontend
    olcAccess: to * by * read
    #
    # Sample global access control policy:
    #	Root DSE: allow anyone to read it
    #	Subschema (sub)entry DSE: allow anyone to read it
    #	Other DSEs:
    #		Allow self write access
    #		Allow authenticated users read access
    #		Allow anonymous users to authenticate
    #
    #olcAccess: to dn.base="" by * read
    #olcAccess: to dn.base="cn=Subschema" by * read
    #olcAccess: to *
    #	by self write
    #	by users read
    #	by anonymous auth
    #
    # if no access controls are present, the default policy
    # allows anyone and everyone to read anything but restricts
    # updates to rootdn.  (e.g., "access to * by * read")
    #
    # rootdn can always read and write EVERYTHING!
    #
    olcPasswordHash: {SSHA}
    # {SSHA} is already the default for olcPasswordHash

Another section is devoted to the configuration backend, the only way to later access the OpenLDAP server configuration is as a global super-user.

    dn: olcDatabase={0}config,cn=config
    objectClass: olcDatabaseConfig
    olcDatabase: {0}config
    olcAccess: to * by * none
    olcRootPW: {SSHA}iae+lrQZILpiUdf16Z9KmDmSwT77Dj4U

The default administrator username is `cn=config`. Type `slappasswd` in a shell, choose a password and use its hash in `olcRootPW`. If this option is not specified now, before `slapd.ldif` is imported, no one will be later able to modify the global configuration section.

The last section is about the database backend:

    #######################################################################
    # LMDB database definitions
    #######################################################################
    #
    dn: olcDatabase=mdb,cn=config
    objectClass: olcDatabaseConfig
    objectClass: olcMdbConfig
    olcDatabase: mdb
    olcDbMaxSize: 1073741824
    olcSuffix: dc=domain,dc=example
    olcRootDN: cn=mdbadmin,dc=domain,dc=example
    # Cleartext passwords, especially for the rootdn, should
    # be avoided.  See slappasswd(8) and slapd-config(5) for details.
    # Use of strong authentication encouraged.
    olcRootPW: {SSHA}X2wHvIWDk6G76CQyCMS1vDCvtICWgn0+
    # The database directory MUST exist prior to running slapd AND
    # should only be accessible by the slapd and slap tools.
    # Mode 700 recommended.
    olcDbDirectory:	/var/db/openldap-data
    # Indices to maintain
    olcDbIndex: objectClass eq

This database hosts the actual contents of the LDAP directory. Types other than `mdb` are available. Its super-user, not to be confused with the global one, is configured here: a (possibly custom) username in `olcRootDN` and the password hash in `olcRootPW`; `slappasswd` can be used as before.

This repository contains four examples of `slapd.ldif`. To convert an existing `slapd.conf` into `slapd.ldif`, refer to this page (please note that this may introduce some unuseful options).

When the configuration is completed, `slapd.ldif` must be placed in an empty directory. It is recommended to create it as:

    # mkdir /usr/local/etc/openldap/slapd.d/

Import the configuration database:

    # /usr/local/sbin/slapadd -n0 -F /usr/local/etc/openldap/slapd.d/ -l /usr/local/etc/openldap/slapd.ldif

Start the `slapd` daemon:

    # /usr/local/libexec/slapd -F /usr/local/etc/openldap/slapd.d/

Option `-d` can be used for debugging, as specified in slapd(8). To verify that the server is running and working:

    # ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
    # extended LDIF
    #
    # LDAPv3
    # base <> with scope baseObject
    # filter: (objectclass=*)
    # requesting: namingContexts
    #

    #
    dn:
    namingContexts: dc=domain,dc=example

    # search result
    search: 2
    result: 0 Success

    # numResponses: 2
    # numEntries: 1

The server must still be trusted. If that has never been done before, follow these instructions. Install the OpenSSL package or port:

    # pkg install openssl

From the directory where `ca.crt` is stored (in this example, `/usr/local/etc/openldap`), run:

    # c_rehash .

Both the CA and the server certificate are now correctly recognized in their respective roles. To verify this, run this command from the `server.crt` directory:

    # openssl verify -verbose -CApath . server.crt

If `slapd` was running, restart it. As stated in `/usr/local/etc/rc.d/slapd`, to properly run `slapd` at boot the following lines must be added to `/etc/rc.conf`:

    lapd_enable="YES"
    slapd_flags='-h "ldapi://%2fvar%2frun%2fopenldap%2fldapi/
    ldap://0.0.0.0/"'
    slapd_sockets="/var/run/openldap/ldapi"
    slapd_cn_config="YES"

`slapd` does not provide debugging at boot. Check `/var/log/debug.log`, `dmesg -a` and `/var/log/messages` for this purpose.

The following example adds the group `team` and the user `john` to the `domain.example` LDAP database, which is still empty. First, create the file `domain.ldif`:

    # cat domain.ldif
    dn: dc=domain,dc=example
    objectClass: dcObject
    objectClass: organization
    o: domain.example
    dc: domain

    dn: ou=groups,dc=domain,dc=example
    objectClass: top
    objectClass: organizationalunit
    ou: groups

    dn: ou=users,dc=domain,dc=example
    objectClass: top
    objectClass: organizationalunit
    ou: users

    dn: cn=team,ou=groups,dc=domain,dc=example
    objectClass: top
    objectClass: posixGroup
    cn: team
    gidNumber: 10001

    dn: uid=john,ou=users,dc=domain,dc=example
    objectClass: top
    objectClass: account
    objectClass: posixAccount
    objectClass: shadowAccount
    cn: John McUser
    uid: john
    uidNumber: 10001
    gidNumber: 10001
    homeDirectory: /home/john/
    loginShell: /usr/bin/bash
    userPassword: secret

See the OpenLDAP documentation for more details. Use `slappasswd` to replace the plain text password `secret` with a hash in `userPassword`. The path specified as `loginShell` must exist in all the systems where `john` is allowed to login. Finally, use the `mdb` administrator to modify the database:

    # ldapadd -W -D "cn=mdbadmin,dc=domain,dc=example" -f domain.ldif

Modifications to the global configuration section can only be performed by the global super-user. For example, assume that the option `olcTLSCipherSuite: HIGH:MEDIUM:SSLv3` was initially specified and must now be deleted. First, create a file that contains the following:

    # cat global_mod
    dn: cn=config
    changetype: modify
    delete: olcTLSCipherSuite

Then, apply the modifications:

    # ldapmodify -f global_mod -x -D "cn=config" -W

When asked, provide the password chosen in the configuration backend section. The username is not required: here, `cn=config` represents the DN of the database section to be modified. Alternatively, use `ldapmodify` to delete a single line of the database, `ldapdelete` to delete a whole entry.

If something goes wrong, or if the global super-user cannot access the configuration backend, it is possible to delete and re-write the whole configuration:

    # rm -rf /usr/local/etc/openldap/slapd.d/

`slapd.ldif` can then be edited and imported again. Please, follow this procedure only when no other solution is available.

This is the configuration of the server only. The same machine can also host an LDAP client, with its own separate configuration.

Prev | Up | Next
29.4. Network Information System (NIS) | Home | 29.6. Dynamic Host Configuration Protocol (DHCP)

All FreeBSD documents are available for download at https://download.freebsd.org/ftp/doc/

Questions that are not answered by the documentation may be sent to <freebsd-questions@FreeBSD.org>.
Send questions about this document to <freebsd-doc@FreeBSD.org>.