OpenLDAP is an open source implementation of the Lightweight Directory Access Protocol
. It will allow us to create a central repository for information about domain users, groups and computers, and make this information available to Samba (and any other LDAP-aware services) for authentication, authorization and management purposes.
The Lightweight Directory Access Protocol (LDAP) is a networking protocol for accessing X.500-based directory services. A directory is a specialized database optimized for reading, browsing and searching
and supports sophisticated filtering capabilities
([OLDAP]).
Similarly to the Unix file system or the Domain Name System, the structure of this database is a hierarchical inverted tree, with the root at the top; for example:
As in the above picture, the topmost levels of the LDAP tree are often arranged based upon domain names, thus allowing for directory services to be located using the Domain Name System.
Each node in the LDAP tree is called an entry and is uniquely identified by its Distinguished Name (DN), which is made up of the name of the entry itself (called the Relative Distinguished Name, RDN, usually derived from some attribute in the entry), comma-concatenated to the names of its parent entries. For instance, the DN of the entry highlighted in the following picture:
is made up of the sequence "uid=Danix", "ou=Users", "dc=kernel-panic" and "dc=it", and is therefore written as "uid=Danix,ou=Users,dc=kernel-panic,dc=it" (see [RFC4514] for a full description of the DN format).
An entry consists of a set of attributes; each attribute has a name (or type) and one or more values. The name is typically a mnemonic string, like "dc" for "Domain Component" or "cn" for "Common Name", and determines the syntax of the corresponding value. ObjectClasses define the attribute structure of an LDAP entry, i.e. which attributes must and which may be present in a specific LDAP entry. Both ObjectClasses and Attributes are defined within Schemas.
Though LDAP is a binary protocol, entries can be represented in a human-readable format by using the LDIF format; for example:
dn: uid=danix,ou=Users,dc=kernel-panic,dc=it objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount objectClass: sambaSamAccount cn: Daniele Mazzocchio sn: Mazzocchio givenName: Daniele uid: Danix uidNumber: 2000 gidNumber: 513 homeDirectory: /home/danix loginShell: /bin/ksh gecos: Daniele Mazzocchio structuralObjectClass: inetOrgPerson [ ... ]
LDAP queries can be represented by means of URLs, which allow you to specify the scope of the search and the search query, and to select which attibutes to return. The syntax of an LDAP URL is:
ldap://[host[:port]]/[DN[?[attributes][?[scope][?[filter][?extensions]]]]]
Most of the URL components are optional:
For example, the following URL:
ldap://ldap.kernel-panic.it/uid=Danix,ou=Users,dc=kernel-panic,dc=it
refers to all attributes in a specific user entry, and an URL like:
ldap:///dc=kernel-panic,dc=it?sn?sub?(givenName=Daniele)
refers to the sn (surname) attribute of all entries with a givenName of "Daniele". For further details, please refer to [RFC4516].
Enough with the theory for now, and on to practice! OpenLDAP is available through OpenBSD's packages and ports system (note: unfortunately, the bdb flavor, providing support for the bdb and hdb backends, is marked as broken since OpenBSD 4.3); the following is the list of packages to be installed:
And the installation is over! OpenLDAP configuration files are stored in /etc/openldap. Client-side configuration is contained in the ldap.conf(5) file; below is a sample configuration file:
# URI of the LDAP server to which the LDAP library should connect URI ldap://ldap.kernel-panic.it # The default base DN to use when performing LDAP operations BASE dc=kernel-panic,dc=it # Size limit to use when performing searches SIZELIMIT 12 # Time limit to use when performing searches TIMELIMIT 15 # Never derefernce aliases DEREF never
The slapd.conf(5) file provides configuration information for the Standalone LDAP Daemon, slapd(8C):
# Include the necessary schema files. core.schema is required by default, the # other ones are needed for sambaSamAccount. The samba.schema file can be found # here and must be copied in /etc/openldap/schema/. include /etc/openldap/schema/core.schema include /etc/openldap/schema/cosine.schema include /etc/openldap/schema/inetorgperson.schema include /etc/openldap/schema/nis.schema include /etc/openldap/schema/samba.schema # Absolute path to the PID file pidfile /var/run/openldap/slapd.pid # Absolute path to the file that will hold slapd's command line options argsfile /var/run/openldap/slapd.args # Type of database backend database ldbm # DN suffix of queries that will be passed to this backend database suffix "dc=kernel-panic,dc=it" # Database directory directory /var/openldap-data # The Distinguished Name of the administrator of this database rootdn "cn=Manager,dc=kernel-panic,dc=it" # Password (or password hash) for the rootdn. Clear-text passwords are allowed # but strongly discouraged; the password hash can be generated using the # slappasswd(8C) command; e.g.: # # slappasswd # New password: <password> # Re-enter new password: <password> # {SSHA}d1bjQZEA43NFKNL7g48XjaNv/W6DG0fY rootpw {SSHA}d1bjQZEA43NFKNL7g48XjaNv/W6DG0fY # Maintain indices on the most useful attributes to speed up searches made on # the sambaSamAccount, posixAccount and posixGroup objectClasses index objectClass eq index cn pres,sub,eq index sn pres,sub,eq index uid pres,sub,eq index displayName pres,sub,eq index uidNumber eq index gidNumber eq index memberUid eq index sambaSID eq index sambaPrimaryGroupSID eq index sambaDomainName eq index default sub # Access control configuration. The rootdn can always read and write everything access to attrs=userpassword,sambaLMPassword,sambaNTPassword by anonymous auth by self write by * none access to * by self write by * read
We can use the slaptest(8C) command to check the validity of our slapd.conf(5) file:
# install -d -o _openldap /var/run/openldap # slaptest -u config file testing succeeded #
The slapd.conf(5) file, containing the rootpw password, should have restrictive permissions:
# chgrp _openldap /etc/openldap/slapd.conf # chmod 640 /etc/openldap/slapd.conf
Ok, now everything should be ready for starting slapd(8C). The first time you may want to invoke it with the "-d" option to turn on debugging and keep the daemon in the foreground, to immediately notice any error:
# /usr/local/libexec/slapd -4 -d 256 -u _openldap -g _openldap [ ... ] slapd starting
You can check that everything is running correctly by issuing the ldapsearch(1) command:
# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts # extended LDIF # # LDAPv3 # base <> with scope baseObject # filter: (objectclass=*) # requesting: namingContexts # # dn: namingContexts: dc=kernel-panic,dc=it # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1 #
If everything is working fine, we can configure the system to start slapd(8C) on boot, by adding the following line (containing the command line arguments) to /etc/rc.conf.local(8):
slapd_flags="-4 -u _openldap -g _openldap"
and the following commands to /etc/rc.local(8):
if [ "$slapd_flags" != "NO" -a -x /usr/local/libexec/slapd ]; then echo -n ' slapd' install -d -o _openldap /var/run/openldap /usr/local/libexec/slapd $slapd_flags fi
OpenLDAP comes with built-in support for the TLS/SSL protocols to provide integrity and confidentiality to LDAP connections by means of public-key cryptography. Enabling TLS/SSL will prevent traffic from traveling in the clear over the network, thus protecting users' passwords from eavesdroppers.
TLS relies on public key certificates for authentication and therefore requires that you first set up a basic Public Key Infrastructure (PKI) for managing digital certificates. As a preliminary step, we will create the directories where certificates will be stored:
# install -m 700 -d /etc/openldap/ssl/private
The first step in setting up the PKI is the creation of the root CA certificate (/etc/openldap/ssl/ca.crt) and private key (/etc/ssl/private/ca.key) using openssl(1):
# openssl req -days 3650 -nodes -new -x509 -keyout /etc/ssl/private/ca.key \ > -out /etc/openldap/ssl/ca.crt [ ... ] Country Name (2 letter code) []: IT State or Province Name (full name) []: Italy Locality Name (eg, city) []: Milan Organization Name (eg, company) []: Kernel Panic Inc. Organizational Unit Name (eg, section) []: LDAP CA Common Name (eg, fully qualified host name) []: ca.lan.kernel-panic.it Email Address []: <enter> #
The next step is the creation of the private key (/etc/openldap/ssl/private/server.key) and Certificate Signing Request (/etc/openldap/ssl/private/server.csr) for the server:
# openssl req -days 3650 -nodes -new -keyout /etc/openldap/ssl/private/server.key \ > -out /etc/openldap/ssl/private/server.csr [ ... ] Country Name (2 letter code) []: IT State or Province Name (full name) []: Italy Locality Name (eg, city) []: Milan Organization Name (eg, company) []: KP Inc. Organizational Unit Name (eg, section) []: LDAP Server Common Name (eg, fully qualified host name) []: ldap.kernel-panic.it Email Address []: <enter> Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: <enter> An optional company name []: <enter> #
Finally, the CA will generate the signed certificate out of the certificate request:
# openssl x509 -req -days 3650 -in /etc/openldap/ssl/private/server.csr \ > -out /etc/openldap/ssl/server.crt -CA /etc/openldap/ssl/ca.crt \ > -CAkey /etc/ssl/private/ca.key -CAcreateserial Signature ok subject=/C=IT/ST=Italy/L=Milan/O=Kernel Panic Inc./OU=LDAP Server/CN=ldap.kernel-panic.it Getting CA Private Key #
You can generate the client certificate by repeating the last two steps:
# openssl req -days 3650 -nodes -new -keyout /etc/openldap/ssl/private/client.key \ > -out /etc/openldap/ssl/private/client.csr [ ... ] Country Name (2 letter code) []: IT State or Province Name (full name) []: Italy Locality Name (eg, city) []: Milan Organization Name (eg, company) []: KP Inc. Organizational Unit Name (eg, section) []: LDAP Client Common Name (eg, fully qualified host name) []: ldap.kernel-panic.it Email Address []: <enter> Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: <enter> An optional company name []: <enter> # openssl x509 -req -days 3650 -in /etc/openldap/ssl/private/client.csr \ > -out /etc/openldap/ssl/client.crt -CA /etc/openldap/ssl/ca.crt \ > -CAkey /etc/ssl/private/ca.key Signature ok subject=/C=IT/ST=Italy/L=Milan/O=Kernel Panic Inc./OU=LDAP Client/CN=ldap.kernel-panic.it Getting CA Private Key #
As a finishing touch, we need to assign restrictive permissions to the private keys, in order to prevent unauthorized access:
# chown -R _openldap:_openldap /etc/openldap/ssl/private # chmod 600 /etc/openldap/ssl/private/*
Configuring the slapd(8C) daemon for TLS operation simply requires that you add a few lines to slapd.conf(5), right after the rootpw parameter, containing the cipher suites to accept and the paths to the certificates:
# TLS configuration TLSCipherSuite HIGH:MEDIUM:+SSLv3 TLSCACertificateFile /etc/openldap/ssl/ca.crt TLSCertificateFile /etc/openldap/ssl/server.crt TLSCertificateKeyFile /etc/openldap/ssl/private/server.key
In the client configuration file, ldap.conf(5), you have to change the URI scheme to "ldaps" and specify the path to the CA certificate and the acceptable cipher suites:
[ ... ] URI ldaps://ldap.kernel-panic.it # TLS configuration TLS_CACERT /etc/openldap/ssl/ca.crt TLS_CIPHER_SUITE HIGH:MEDIUM:+SSLv3
As a final step, add the "-h ldaps:///" option to the slapd(8C) command line arguments to make the daemon listen only for LDAP over TLS on TCP port 636:
# Only listen for LDAP over TLS (port 636) slapd_flags="-4 -u _openldap -g _openldap -h ldaps:///"
and restart slapd(8C).