rootdn "cn=Manager,dc=plainjoe,dc=org"
## Define the password used with rootdn. This is the base64-encoded MD5 hash of
## "secret."
rootpw {SSHA}2aksIaicAvwc+DhCrXUFlhgWsbBJPLxy
## Directory containing the database files
directory /var/ldap/plainjoe.org
## Files should be created rw for the owner **only**.
mode 0600
## Indexes to maintain
index objectClass eq
index cn pres,eq
## db tuning parameters; cache 2,000 entries in memory
cachesize 2000
# Simple ACL granting read access to the world
access to *
by * read
Defining the Schema
The first step in implementing a directory is determining what information to store in the directory. The naming context of your server has already been defined as:
dc=plainjoe,dc=org
Store contact information for employees in the people organizational unit:
ou=people,dc=plainjoe,dc=org
There are several ways to identify the data that should be placed in an employee's entry. Information stored in an existing Human Resources database can provide a good starting point. Of course, you may not want to place all of this information in your directory. As a general rule, I prefer not to put information in a directory if that data probably won't be used. If it turns out that the data is actually necessary, you can always add it later. Eliminating unnecessary data at the start means that there's less to worry about when you start thinking about protecting the directory against unauthorized access.
An alternative to starting with an existing database is to determine which employee attributes you wish to make available and define a schema to match that list. The reverse also works: you can select a standard schema and use the attributes already defined. I prefer this approach because it makes it easy to change from one server vendor to another. Widely used, standard schemas are more likely to be supported by a wide range of vendors. Custom, in-house schemas may need to be redesigned to adapt to a new vendor (or even a new version from the same vendor).
For your directory, the inetOrgPerson schema defined in RFC 2798 is more than adequate. From Section 3.5.1 in Chapter 3, we know that this object class and associated attributes are defined in OpenLDAP's inetorgperson.schema file. As shown in Figure 4-1, an inetOrgPerson is a descendant of the organizationalPerson , which was itself derived from the person object class.
Figure 4-1. Hierarchy of the inetOrgPerson object class
The union of these object classes defines the set of required and optional attributes that are available. This means that the only required attributes in an inetOrgPerson object are the cn and sn attributes derived from the person object class.
* * *
Tip
From this point on, diagrams of an object class will not include RFC 2252-style schema definitions. If you wish to study the exact syntax of any object class, refer to the schema files included with OpenLDAP or the relevant RFC (or Internet-Draft).
* * *
Your directory will use the cn attribute as the RDN for each entry. Remember that the RDN of an entry must be unique among siblings of a common parent. In larger organizations, two people may have the same first and last name. In these cases, using a more specific value for the cn, such as including a middle name (or initial), can alleviate name collisions.
Another way to reduce the number of name collisions is to redesign the directory layout to reduce the total number of user entries sharing a common parent. In other words, group employees in some type of logical container, such as a departmental organizational unit. Figure 4-2 illustrates how this design avoids namespace conflicts. In this directory the "John Arbuckle" in sales is different from the "John Arbuckle" in engineering because the entries possess different parent nodes.
Figure 4-2. Using organizational unit to avoid collisions of common names (cn)
For our example, going with a single container of ou=people is fine; furthermore, our employee base is small enough to use an employee's common name (cn) without fear of conflict. Figure 4-3 shows the directory namespace developed so far.
Figure 4-3. Directory namespace for company address book
Here is an employee entry that contains the attributes needed for our directory. Notice that the two required attributes outlined in Figure 4-1, cn and sn, are present in addition to several optional attributes.
## LDIF entry for employee "Gerald W. Carter"
dn: cn=Gerald W. Carter,ou=people,dc=plainjoe,dc=org
objectClass: inetOrgPerson
cn: Gerald W. Carter
sn: Carter
mail: [email protected]
mail: [email protected]
labeledURI: http://www.plainjoe.org/
roomNumber: 1234 Dudley Hall
departmentNumber: Engineering
telephoneNumber: 222-555-2345
pager: 222-555-6789
mobile: 222-555-1011
* * *
Deep or Wide?
Is it better to maintain a shallow (and wide) tree or a deep (and narrow) directory? The best structure for your directory depends on two factors.
First, how likely is it for a change to force an entry (in our case, a person) to be moved from one organizational unit to another? The answer to this question is based on a solid understanding of your organization and its needs. Deeper directory trees imply that an entry must meet more requirements in order to be placed in a certain container. For example, rather than placing all employees under the ou=people, using characteristics such as departments, job description, and geographic location makes for a more defined grouping. However, if these characteristics are likely to change frequently, you will only be creating more work for yourself in the long term. It is also good to note that deep directories require longer DNs to reference entries. This can become an annoyance over time.
Second, does the implementation of your LDAP directory server favor one design over another? For OpenLDAP, this answer depends on your needs. The determining factor will be the number of updates, or writes, that will be made to the directory. To update an entry, the slapd server obtains a lock on the parent entry for the requesting client. Now suppose that you have a very shallow directory tree with 10,000 entries under a single parent. If many updates occur at the same time, the contention for the lock on the parent entry will be very high. The end result will be slower updates because processes will block waiting for the lock.
A deeper tree means that you can often make searches more efficient by giving a more detailed search base. For more information on designing LDAP namespaces, you may wish to read Howes, et al., Understanding and Deploying LDAP Directory Services (MacMillan Technical Press).
* * *
Updating slapd.conf
Once the schema has been selected, the next step is to modify slapd.conf to support the selected attribute types and object classes. In order to support the inetOrgPerson object class, you must include inetorgperson.schema , core.schema , and cosine.schema in slapd.conf. The comments that begin inetorgperson.schema outline the dependency on the COSINE schema. Here are the modifications to the global section of slapd.conf:
# /usr/local/etc/openldap/slapd.conf
# Global section
## Include the minimum schema required.
include /usr/local/etc/openldap/schema/core.schema
## Added to support the inetOrgPerson object.
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
## Added logging parameters
. . .
The database section is currently in working condition, so only a few changes are needed. To better support searches for employees, you should modify the set of indexes to include a more complete list of attributes. In addition to creating an index for the cn attribute, you'll also index th
e surname (sn) and email address (mail) attributes. In addition to the equality (eq) index, you'll add a substring (sub) index to support searches such as "All employees whose last names begin with C." Finally, you will add an equality index for the departmentNumber attribute so that users can search for employees within a given department. This index would not be necessary if the directory were laid out as shown in Figure 4-2 because the same effect could be achieved by beginning the search at the department ou. Here are the changes to the database section:
## Indexes to maintain
index objectClass eq
index cn,sn,mail eq,sub
index departmentNumber eq
. . .
At this point, it's a good idea to verify that the location specified by the directory parameter exists and has the proper permissions. In our example, that directory is /var/ldap/plainjoe.org. If this directory does not exist, the following two commands ensure that the filesystem is ready to store data:
root# mkdir -p /var/ldap/plainjoe.org
root# chmod 700 /var/ldap/plainjoe.org
Starting slapd
Once the final tweaks have been added to the configuration file, the next step is to start the slapd daemon by executing the following command as root:
root# /usr/local/libexec/slapd
Use the ps command to verify that slapd is running. On a Linux system, the output should appear similar to:
$ ps -ef | grep slapd
root 8235 1 0 12:37 ? 00:00:00 /usr/local/libexec/slapd
root 8241 8235 0 12:37 ? 00:00:00 /usr/local/libexec/slapd
root 8242 8241 0 12:37 ? 00:00:00 /usr/local/libexec/slapd
On Linux and IRIX, multiple threads of a process will show up as individual entries in the output from ps. On Solaris, slapd will be displayed as a single process.
Stopping the OpenLDAP server requires that the daemon have a chance to flush modified directory data to disk. The best way to do this is to send the parent slapd process an INT signal, as shown here (the pidfile location was defined in the server's configuration file):
root# kill -INT 'cat /var/run/slapd.pid'
Shutting down slapd by more drastic means, such as kill -9 , can result in data corruption and should be avoided at all costs.
In the absence of any command-line options, slapd's behavior is governed by compile-time defaults or options defined in the slapd.conf file. At times, it is necessary to override some of these settings via the command line. Table 4-1 lists the available slapd options.
Table 4-1. Command-line options for the slapd server
Option
Description
-d integer
Specifies the log level to use for logging information. This option causes slapd to log all information to standard output on the controlling terminal; it can be very helpful for quick server debugging sessions. The integer value specified should be a combination of the logging levels associated with the loglevel parameter in slapd.conf.
-f filename
Uses a configuration file other than the compile-time default (slapd.conf).
-h URI_list
Specifies a space-separated list of LDAP URIs that the slapd daemon should serve. The most common URIs are ldap:/// (LDAP on port 389; the default), ldaps:/// (LDAP over SSL on port 636), and ldapi:/// (LDAP over IPC).
-l syslog-local-user
Specifies the local user of the syslog facility. The default value is LOCAL4. Possible values range from LOCAL0 to LOCAL7. This option may not be supported on all systems. Check the syslog(8) manpage to verify the existence of the local-user syslog facility.
-n name
Defines the service name used when logging messages to syslog. This is for convenience only and defaults to the string slapd.
-r directory
Specifies a chroot(1) jail directory to be used by slapd.
-s syslog-level
Defines a syslog level other than the default level to log all syslog messages. Refer to the syslog.conf(5) manpage for available levels on your system.
-u username
-g groupname
Specify the effective user or group ID for slapd.
Of course, starting slapd from the command line is something you do only while testing. In practice, it would be started by one of the system's boot time initialization scripts—either rc.local for BSD systems, or one of the /etc/rc.d/rc?.d/ (or /etc/init.d/ ) scripts for System V hosts. You should refer to the init(8) manpage for a brief description of run levels and which levels are used (and for what functions) on your system. On most Linux systems, the slapd daemon should be launched at run levels 3 and 5. Run level 5 is basically the same as run level 3 with the addition of X11.
Adding the Initial Directory Entries
A directory without data isn't of much use. There are two ways to add information to your directory; which method to use depends on the directory's state. First, slapadd and the other slap* commands were presented in Chapter 3 as database maintenance tools. They allow an administrator to import entries directly into the database files and export the entire directory as an LDIF file. They work directly with the database, and don't interact with slapd at all. Second, the OpenLDAP distribution includes a number of tools, such as ldapmodify , that can update a live directory using the LDAPv3 network operations. These tools access the directory through the server.
What are the advantages and disadvantages of these approaches? The offline tools can be much faster; furthermore, there are circumstances when you can't start the server without first adding data (for example, when restoring the directory's contents from a backup). The disadvantage of the offline tools, of course, is that they must be run locally on the server.
In contrast to the offline tools, the LDAP client utilities are more flexible and allow a directory administrator greater control by forcing user authentication and by using access control lists on directory entries. A good rule of thumb is that the slap* tools are used for getting your LDAP server online, and the ldap* tools are for day-to-day administration of the directory.
* * *
Warning
OpenLDAP 2.1 removed the restriction that slapd must not be running before any of the slap* tools can be used. However, OpenLDAP 2.0 caches data in memory, so using the slap* tools while the directory is running can present an inconsistent view of the directory at best, and corrupt data at worst.
* * *
The tools for offline manipulation of directory information are slapadd, slapcat, slapindex, and slappasswd (covered in Chapter 3). The slapadd tool determines which files and indexes to update based on the slapd.conf file. Because it is possible for a given configuration file to define more than one database partition, slapadd provides options for specifying a database partition by either the directory suffix (-b suffix) or the numbered occurrence (-n integer) in slapd.conf. Referring to a particular database using a numbered instance is confusing and error-prone. It is far more intuitive to refer to the same database by using the directory suffix. Note that the -b and -n options are mutually exclusive. A summary of the various slapadd command-line options is provided in Table 4-2.
Table 4-2. Summary of slapadd command-line arguments
Option
Description
-c
Continues processing input in the event of errors.
-b suffix-n integer
Specify which database in the configuration file to use by the directory's suffix (-b) or by its location (-n) in the slapd.conf file (the first database listed is numbered 0). These options are mutually exclusive.
-d integer
Specifies which debugging information to log. See the loglevel parameter in slapd.conf for a listing of log levels.
-f filename
Specifies which configuration file to read.
-l filename
Specifies the LDIF file to use for input. In the absence of this option, slapadd reads data from standard input.
-v
Enables verbose mode. In this
mode, slapd prints some additional messages on standard output.
The slapcat utility dumps the contents of an entire directory (including persistent operational attributes such as modifyTimeStamp) in LDIF format. The command-line options for slapcat are identical to the options for slapadd (Table 4-2), except that the -l switch specifies an output filename instead of an input filename. In the absence of this switch, slapcat writes all entries to standard output. slapcat can provide a useful means of backing up the directory. Unlike the actual DBM datafiles, which are machine- and version-dependent, LDIF is very portable and allows easier editing in case of corrupted data. I don't mean to discourage you from backing up the DBM files, but you could do worse than backing up the directory in both forms.
The slapindex command can be used to regenerate the indexes for a bdb backend. This might be necessary if a new index was added to slapd.conf after the directory was populated with entries. The slapindex tool shares the same command-line options as slapadd, with the exception of -l. The -l option isn't used for slapindex because neither an input nor an output file is needed.
To start populating your directory, create a file containing the LDIF entries of the top-level nodes. These LDIF entries build the root node and the people organizational unit.
## Build the root node.
dn: dc=plainjoe,dc=org
dc: plainjoe
objectClass: dcObject
objectClass: organizationalUnit
ou: PlainJoe Dot Org
## Build the people ou.
dn: ou=people,dc=plainjoe,dc=org
ou: people
LDAP System Administration Page 9