4.5 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.

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




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.


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
objectClass: organizationalUnit

Assuming that these entries are stored in a file named /tmp/top.ldif, you can add them to the directory by executing:

root# slapadd -v -l /tmp/top.ldif
added: "dc=plainjoe,dc=org" (00000001)
added: "ou=people,dc=plainjoe,dc=org" (00000002)

The output indicates that the entries were added successfully.

4.5.1 Verifying the Directory's Contents

Next, you will bring the directory online so that you can use it in conjunction with ldapsearch, ldapmodify, and the other tools for working on a live directory:

root# /usr/local/libexec/slapd

After the directory server has started, you can use ldapsearch to query the server. ldapsearch allows you to dig through your directory, test for the existence of data, and test whether access control has been set up correctly.

OpenLDAP's ldapsearch began life as a simple wrapper for the LDAP search operation. The list of search possibilities is lengthy; I won't cover it until Chapter 5. For now, I will focus on very simple searches that assure you the directory is up and running correctly. In its simplest form, a query requires the following information:

  • The LDAP server's hostname or IP address

  • The credentials (i.e., user DN and password) to use to bind to the host

  • The search base in the form of a DN

  • The scope of the directory to search

  • A search filter

  • A list of attributes to return

We'll start with a "Show me everything" search. Here, you ask the directory to return all entries that have a value for the objectClass attribute (which is all entries).

$ ldapsearch -x -b "dc=plainjoe,dc=org" "(objectclass=*)"
version: 2
# filter: (objectclass=*)
# requesting: ALL
# plainjoe,dc=org
dn: dc=plainjoe,dc=org
dc: plainjoe.org
objectClass: dcObject
objectClass: organizationalUnit
ou: PlainJoe Dot Org
# people,dc=plainjoe,dc=org
dn: ou=people,dc=plainjoe,dc=org
ou: people
objectClass: organizationalUnit
# Search result
search: 2
result: 0 Success
# numResponses: 3
# numEntries: 2

The ldapsearch options used here are:


Instructs ldapsearch to perform a simple bind (i.e., do not use SASL for authentication).

-b dc=plainjoe,dc=org

Defines the DN dc=plainjoe,dc=org as the search's base suffix. This DN specifies the point at which the search begins. Therefore, it must be a DN that is held by the LDAP server. All entries located higher in the tree will be ignored.


The search filter. If you are familiar with filename globbing, or just general wildcard patterns, this filter should be familiar. RFC 2254 defines ways to represent an LDAP search filter as a string. The syntax of filters is covered in Chapter 5. For now, it's sufficient to know that this filter matches any value of the objectClass attribute.

The surprising thing about this command is that it doesn't explicitly contain most of the items that I said were necessary for any search. In fact, the only two items that we can clearly see are the search base and the search filter. What's going on? Let's look at the missing items one at a time:

The LDAP server's hostname (or IP address)

ldapsearch queries the local host if the server isn't specified explicitly. The -h hostname option specifies the hostname or IP address. In this case, though, you're running the server locally, so you don't need it.

Credentials used to bind to the directory

The ACL defined in slapd.conf gave read permission to all users. Therefore, you don't need to authenticate to perform this search. When authentication is required, the -D DN and -w password options specify the login DN and password to be used.

The search scope

By default, ldapsearch queries the server for all entries contained in the subtree of the root node defined by the -b option. Other possibilities include searching only the immediate children of the base suffix entry or searching this entry alone. The search scope (-s) option can be used to specify either sub, base, or one.

A list of attributes to return

By default, slapd returns all nonoperational attributes. On a complex directory, you might get an extremely long list of attributes for every entry in the directory. To limit the result to a few specific attributes, list the attributes you want on the command line, separated by commas. Operational attributes such as modifyTimestamp and modifiersName are not returned unless specifically asked for by name or by using the plus character (+) as the attribute list in the search.

The default values for many LDAP client parameters can be controlled via the system-wide ldap.conf configuration file (located in the same directory as slapd.conf) or the user-specific version in $HOME/.ldaprc. For more details, refer to the ldap.conf(5) manpage. Our examples explicitly list all parameters required by the command-line tools unless the compile-time defaults can be used, which was the case in the previous ldapsearch listing.

Table 4-3 and Table 4-4 list all the options and arguments for ldapsearch. Don't worry about understanding them all now.

Table 4-3. Command-line options common to ldapsearch, ldapadd, ldapdelete, ldapmodify, and ldapmodrdn



-d integer

Specifies what debugging information to log. See the loglevel slapd.conf parameter for a listing of log levels.

-D binddn

Specifies the DN to use for binding to the LDAP server.

-e [!]ctrl[=ctrlparam]

Defines an LDAP control to be used on the current operation. See also the -M option for the manageDSAit control.

-f filename

Specifies the file containing the LDIF entries to be used in the operations.


Defines the LDAP URI to be used in the connection request.


Enables the SASL "interactive" mode. By default, the client prompts for information only when necessary.


Enables Kerberos 4 authentication.


Enables only the first step of the Kerberos 4 bind for authentication.


Enable the Manager DSA IT control. This option is necessary when modifying an entry that is a referral or an alias. -MM requires that the Manager DSA IT control be supported by the server.


Does not perform the search; just displays what would be done.

-O security_properties

Defines the SASL security properties for authentication. See previous information on the sasl-secprops parameter in slapd.conf.

-P [2|3]

Defines which protocol version to use in the connection (Version 2 or 3). The default is LDAPv3.


Suppresses SASL-related messages such as the authentication mechanism use, username, and realm.

-R sasl_realm

Defines the realm to be used by the SASL authentication mechanism.

-U username

Defines the username to be used by the SASL authentication mechanism.


Enables verbose mode.

-w password

Specifies the password to be used for authentication.


Instructs the client to prompt for the password.


Enables simple authentication. The default is to use SASL authentication.

-X id

Defines the SASL authorization identity. The identity has the form dn:dn or u:user. The default is to use the same authorization identity as the authenticated user.

-y passwdfile

Instructs the ldap tool to read the password for a simple bind from the given filename.

-Y sasl_mechanism

Instructs the client as to which SASL mechanism should be used. The bind request will fail if the server does not support the chosen mechanism.


Issue a StartTLS request. Use of -ZZ makes the support of this request mandatory for a successful connection.

Table 4-4. Command-line options specific to ldapsearch



-a [never|always|search|find]

Specifies how to handle aliases when located during a search. Possible values include never (the default), always, search, or find.


For any entries found, returns the attribute names but not their values.

-b basedn

Defines the base DN for the directory search.

-F prefix

Defines the URL prefix for filenames. The default is to use the value stored in $LDAP_FILE_URI_PREFIX.

-l limit

Defines a time limit (in seconds) for the server in the search.


Print the resulting output in LDIFv1 format. -LL causes the result to be printed in LDIF format without comments. -LLL prints the resulting output in LDIF format without comments or version information.

-s [sub|base|one]

Defines the scope of the search to be base, one, or sub (the default).

-S attribute

Causes the ldapsearch client to sort the results by the value of attribute.


Write binary values to files in a temporary directory defined by the -T option. -tt specifies that all values should be written to files in a temporary directory defined by the -T option.

-T directory

Defines the directory used to store the resulting output files. The default is the directory specified by $LDAP_TMPDIR.


Includes user-friendly entry names in the output.

-z limit

Specifies the maximum number of entries to return

4.5.2 Updating What Is Already There

Eventually, the information stored in a directory will need to be updated or deleted. While a directory isn't designed to be updated as frequently as a database, there are very few applications in which the data never changes. This section covers how to update the data in the directory using ldapmodify. The name ldapmodify is a little misleading; this utility can add new entries and delete or update existing entries using some of the advanced features of LDIF for its input language.

The following LDIF listing defines two entries that we will add to our directory:

## filename: /tmp/users.ldif
## LDIF entry for "Gerald W. Carter"
dn: cn=Gerald W. Carter,ou=people,dc=plainjoe,dc=org
cn: Gerald W. Carter
sn: Carter
mail: jerry@plainjoe.org
mail: gcarter@valinux.com
labeledURI: http://www.plainjoe.org/
roomNumber: 1234 Dudley Hall
departmentNumber: Engineering
telephoneNumber: 222-555-2345
pager: 222-555-6789
mobile: 222-555-1011
objectclass: inetOrgPerson
## LDIF entry for "Jerry Carter"
dn: cn=Jerry Carter,ou=people,dc=plainjoe,dc=org
cn: Jerry Carter
sn: Carter
mail: carter@nowhere.net
telephoneNumber: 555-123-1234
objectclass: inetOrgPerson

The following command shows how to add these entries to the directory while it is running. Because write privileges are required to add new entries, ldapmodify binds to the directory using the credentials from the rootdn and rootpw slapd.conf parameters.

$ ldapmodify -D "cn=Manager,dc=plainjoe,dc=org" -w secret \
> -x -a -f /tmp/users.ldif
adding new entry "cn=Gerald W. Carter,ou=people,dc=plainjoe,dc=org"
adding new entry "cn=Jerry Carter,ou=people,dc=plainjoe,dc=org"

The output indicates that both entries were added successfully. The -D, -w, and -x options to ldapmodify should be familiar; they specify the DN to use for the modification, specify the password for the modification, and request simple authentication, respectively. This leaves only two new options to discuss:


Entries are to be added to the directory. The default for ldapmodify is to update existing information.

-f filename

Reads the new entries from the given filename. By default, ldapmodify reads from standard input.

If ldapmodify returns an error message such as the following, try enabling verbose messages via the -v command-line switch:

ldap_add: Invalid syntax
additional info: value contains invalid data

There are two common causes of this error message. You may have forgotten to include all the necessary schema files in slapd.conf, or you may have extra whitespace at the end of line in the LDIF file. The set list command in vi can help you track down extra whitespace.

Refer again to Table 4-3 for a list of the common options for all of these ldap client tools. Table 4-5 lists those options specific to ldapmodify and ldapadd. Note that ldapadd and ldapmodify are the same executable; ldapadd is only a hard link to ldapmodify. The commands differ only in their default behavior, which depends on the name by which the program was invoked.

Table 4-5. Command-line options specific to ldapadd and ldapmodify




Adds entries. This option is the default for ldapadd.


Replaces (or modifies) entries and values. This is the default for ldapmodify.


Forces all change records to be used from the input.

Now let's see how a modification works. Suppose you want to add a URL to the entry for cn=Jerry Carter,ou=people,dc=plainjoe,dc=org. To add a URL, use the labeledURI attribute:

labeledURI: http://www.plainjoe.org/~jerry/

In addition, you should delete the gcarter@valinux.com email address for "Gerald W. Carter" because it has become invalid. You can place both changes in a single LDIF file:

## /tmp/update.ldif
## Add a web page location to Jerry Carter.
dn: cn=Jerry Carter,ou=people,dc=plainjoe,dc=org
changetype: modify
add: labeledURI
labeledURI: http://www.plainjoe.org/~jerry/
## Remove an email address from Gerald W. Carter.
dn: cn=Gerald W. Carter,ou=people,dc=plainjoe,dc=org
changetype: modify
delete: mail
mail: gcarter@valinux.com

The changetype keyword in the LDIF file is the key to modifying existing entries. This keyword can accept the following values:


Adds the entry to the directory.


Deletes the entry from the directory.


Modifies the attributes of an entry. With this keyword, you can both add and delete attribute values.


Changes the RDN of an entry.


Changes the DN of an entry.

This LDIF file tells ldapmodify what changes to make. We'll invoke ldapmodify with the verbose (-v) option so you can follow the update operations more closely. The -a option isn't needed because you're not adding new entries.

$ ldapmodify -D "cn=Manager,dc=plainjoe,dc=org" -w secret 
> -x -v -f /tmp/update.ldif
ldap_initialize( <DEFAULT> )
add labeledURI:
modifying entry "cn=Jerry Carter,ou=people,dc=plainjoe,dc=org"
modify complete
delete mail:
modifying entry "cn=Gerald W. Carter,ou=people,dc=plainjoe,dc=org"
modify complete

Notice that the LDIF file is parsed sequentially from the top. Therefore, later LDIF entries can modify entries created previously in the file. You can also create an LDIF file with entries having different changetype values. For example, the follow LDIF file adds an entry for user Peabody Soup, adds a new telephoneNumber to Jerry Carter's entry, and finally deletes the previously created entry for Peabody Soup.

## /tmp/changetypes.ldif
## Add entry for Peabody Soup.
dn: cn=Peabody Soup,ou=people,dc=plainjoe,dc=org
changetype: add
cn: Peabody Soup
sn: Soup
objectclass: inetOrgPerson
## Add new telephoneNumber for Jerry Carter.
dn: cn=Jerry Carter,ou=people,dc=plainjoe,dc=org
changetype: modify
delete: telephoneNumber
telephoneNumber: 555-123-1234
add: telephoneNumber
telephoneNumber: 234-555-6789
## Remove the entry for Peabody Soup.
dn: cn=Peabody Soup,ou=people,dc=plainjoe,dc=org
changetype: delete

A couple of facts about this LDIF file are worth mentioning:

  • Entries are separated by a blank line, as noted earlier.

  • Multiple changes to a single entry using the modify changetype are separated by a single dash (-) on a line by itself. These should be handled as a single change by the server. Either all the changes for this DN take effect or none are applied.

The modify changetype supports add and delete keywords for adding and deleting attribute values. In order to delete the value of an attribute, the delete: must immediately be followed by an attributetype:value pair. It's necessary to specify the value you're deleting because some attributes can hold multiple values. Specifying which value to remove eliminates any ambiguity about what you want to do. When the last value of an attribute is removed from an entry, that attribute is no longer present in the entry.

Here's how to apply this second set of changes to the directory. Again, we've specified the -v option to see how ldapmodify processes the LDIF file.

$ ldapmodify -D "cn=Manager,dc=plainjoe,dc=org" -w secret -x -v -f 
ldap_initialize( <DEFAULT> )
add cn:
        Peabody Soup
add sn:
add objectclass:
adding new entry "cn=Peabody Soup,ou=people,dc=plainjoe,dc=org"
modify complete
delete telephoneNumber:
add telephoneNumber:
modifying entry "cn=Jerry Carter,ou=people,dc=plainjoe,dc=org"
modify complete
deleting entry "cn=Peabody Soup,ou=people,dc=plainjoe,dc=org"
delete complete

Modifying the RDN of an entry takes a little more thought than adding an entry or changing an attribute of an entry. If the entry is not a leaf node, changing its RDN orphans the children in the directory because the DN of their parent has changed. You should make sure that you don't leave orphaned nodes in the directory?you should move the nodes with their parent or give them a new parent. With that in mind, let's think about how to change the RDN of the entry:

dn: cn=Jerry Carter,ou=people,dc=plainjoe,dc=org

from cn: Jerry Carter to cn: Gerry Carter. Here's the LDIF file that makes the changes:

## /tmp/modrdn.ldif
## Change the RDN from "Jerry Carter" to "Gerry Carter."
dn: cn=Jerry Carter,ou=people,dc=plainjoe,dc=org
changetype: modrdn
newrdn: cn=Gerry Carter 
deleteoldrdn: 1

You can also use the ldapmodrdn command to perform the same task:

$ ldapmodrdn \
> "cn=Jerry Carter,ou=people,dc=plainjoe,dc=org" \
> "cn=Gerry Carter"

Not counting the DN of the entry to be changed and the new RDN value, the ldapmodrdn tool has three command-line options besides those common to the other OpenLDAP client tools (Table 4-3). These additional options are listed in Table 4-6.

Table 4-6. Command-line options specific to ldapmodrdn




Instructs ldapmodrdn to continue if errors occur. By default, it terminates if there is an error.


Removes the old RDN value. The default behavior is to add another RDN value and leave the old value intact. The default behavior makes it easier to modify a directory without leaving orphaned entries.

-s new_superior_node

Defines the new superior, or parent, entry under which the renamed entry should be located.

If an entire subtree of the directory needs to be moved, a better solution may be to export the subtree to an LDIF file, modify all occurrences of the changed attribute in all the DNs, and finally re-add the subtree to the new location. Once the information has been entered correctly into a location, you can then use a recursive ldapdelete to remove the old subtree.

ldapdelete possesses all of the command-line options common to ldapsearch and ldapmodify. The only new option is -r (recursive), which deletes all entries below the one specified on the command line, in addition to the named entry. Note that this deletion is not atomic; entries are deleted individually. The following command deletes the entire ou=people subtree:

$ ldapdelete -D "cn=Manager,dc=plainjoe,dc=org" -w secret -x \
>  -r -v "ou=people,dc=plainjoe,dc=org"
ldap_initialize( <DEFAULT> )
deleting entry "ou=people,dc=plainjoe,dc=org"
deleting children of: ou=people,dc=plainjoe,dc=org
deleting children of: cn=Gerald W. Carter,ou=people,dc=plainjoe,dc=org
    removing cn=Gerald W. Carter,ou=people,dc=plainjoe,dc=org
    cn=Gerald W. Carter,ou=people,dc=plainjoe,dc=org removed
deleting children of: cn=Gerry Carter,ou=people,dc=plainjoe,dc=org
   removing cn=Gerry Carter,ou=people,dc=plainjoe,dc=org
   cn=Gerry Carter,ou=people,dc=plainjoe,dc=org removed
Delete Result: Success (0)

Now that you have a working directory, a good exercise would be to experiment with various ACLs to restrict access to certain attributes. This exercise will also help you become more comfortable with the tools presented in this chapter. Use the slapcat tool to dump the directory to an LDIF file and start over from scratch until you are comfortable with adding, deleting, and modifying entries. The next chapter explores creating a distributed directory, replicating information to multiple servers, more searching techniques, and some advanced ACL configurations.