Performing Directory Operations Using the Clients

July 22, 2021

There are a host of OpenLDAP clients, all stored at /usr/bin or /usr/local/bin . The OpenLDAP clients communicate over the LDAP protocol. They are all standards-compliant, and follow the LDAPv3 protocol (which was last updated in June 2006).

While some of the clients provide the basic standardized LDAP operations, such as search, add, and delete, others implement one or more of the LDAP extensions. But since the suite of tools does follow the standards, these tools should work against any standards-compliant LDAP directory server.

In this part of the chapter we will take a brief look at each of the OpenLDAP clients and see how they can be used to interact with an LDAP server. We do not have the space to cover all of the details of each client, so we will focus on the most useful and common features of each client. The OpenLDAP man pages (which are installed with OpenLDAP) are detailed and informative, and they provide a good source of further information for these clients.

Note:

Most of the utilities in the last part required that the SLAPD server must not not be running. All of the tools in this section, however, connect to a SLAPD server. So make sure your server is running before trying the examples in this part.

Common Command-Line Flags

All of the OpenLDAP clients are command-line applications that use UNIX-style flags to pass parameters to the program. For the sake of continuity common flags (like -D, -b, and -H) are used consistently across all of the clients.

In Chapter 2 we configured our directory server to handle basic directory operations. However, we did not configure it to use SASL authentication (which is covered in Chapter 4). To authenticate to the server we will be using what is called simple binding. In simple binding the client authenticates by sending a full DN and password to the server.

The clients require different command-line flags depending on whether they do a simple bind or a SASL bind. Now we will see those necessary for simple binding.

Common Flags

There are command-line flags for the simple binding process. Some of the common flags are as follows:

  • -D: The -D flag is used to specify the full DN of the user who will bind to the directory server (this is used for simple binding).

  • -W, -w, -y: Each of these flags indicates a different source for the password. Let’s see them one by one:

    • The -W flag indicates that the user should be interactively prompted to enter a password.

    • The -w flag takes the password string for a value. We can use it to specify the password on the command line.

    • The -y flag takes a file name as an argument. It will use the contents of the file as a password. These flags are mutually exclusive—you can only use one of these per command.

    Note

    The -y flag uses the entire contents of a file for the password. This means that if there is a line break in the file, it will be treated like part of the password. To create a password file, you can use the echo command with the -n flag: $ echo -n "secret" > my_pw.

  • -x: The -x flag specifies that the client will use a simple bind. If this is not specified, the client will try a SASL bind.

  • -H, -h: These two flags provide different ways of specifying which host to connect to. -H takes an LDAP URL (-H 'ldap://example.com:389'). -h simply takes the host name (-h example.com), and can be used with -p to specify a port. Unless you do not have a choice, use -H. The -h flag is provided only for backward compatibility, and may disappear in future versions.

  • -Z: This flag is used to indicate that the client should issue a Start TLS command to the server, so that traffic is encrypted according to the TLS standard. But if TLS negotiation fails, the client will still continue to operate. Using two Z’s (-ZZ) will make it mandatory that the traffic be encrypted. If negotiation fails, then the client will disconnect. TLS is covered in more detail in the next chapter.

  • -b: This is used to specify a base DN (-b 'dc=example,dc=com').

  • -f: The -f flag takes a filename as a parameter. The client will then read the contents of the file and build requests based on the contents of the file.

  • -v: This flag will turn on verbose output. It is useful when troubleshooting.

These are the common flags used by the clients in the OpenLDAP suite. But these represent only a subset of the flags used by each client, as each client implements the flags needed to accomplish its task.

 

Setting Defaults in ldap.conf

In Chapter 2, in the section entitled Configuring the LDAP Clients, we looked at the ldap.conf file. In that file, we set some useful defaults. In particular we set these three:

URI ldap://localhost
BASE dc=example,dc=com
BINDDN cn=Manager,dc=example,dc=com

If you omit host settings (-H, -h), then the value of URI will be used. If the client needs a base DN, and none is set with the -b flag, then the value of BASE is used. Likewise, if the client uses simple binding (with -x), and doesn’t specify a DN with -D, then the value of BINDDN will be used.

Since we have an ldap.conf file created already, many of the examples will omit the -H and -b flags.

While ldap.conf is shared by all clients, you can create a user-specific LDAP configuration file in your home directory. The LDAP clients will look for user-specific configuration files named ldaprc and .ldaprc in your home directory ($HOME).

Now we are ready to look at the client commands.

 

ldapsearch

The first client we will look at is also the most often used tool: ldapsearch. As the name suggests, this is a tool for searching the directory information tree.

The ldapsearch client connects to the server, authenticates a user, and then (as that user) runs one or more search operations, returning the results in LDIF format. When it is done performing searches, it closes the connection and exits. Since ldapsearch is a network client it can be used to search both local directories or a remote directory server.

 

A Simple Search

Let’s take a look at a simple search command. In this command we will log in as the directory manager and request the record for the entry with the user ID barbara:

$ ldapsearch -x -W -D 'cn=Manager,dc=example,dc=com' -b \ 
    'ou=Users,dc=example,dc=com' '(uid=barbara)'

Here is the result:

Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <ou=Users,dc=example,dc=com> with scope subtree
# filter: (uid=barbara)
# requesting: ALL
#

# barbara, Users, example.com
dn: uid=barbara,ou=Users,dc=example,dc=com
ou: Users
uid: barbara
sn: Jensen
cn: Barbara Jensen
givenName: Barbara
displayName: Barbara Jensen
mail: barbara@example.com
userPassword:: c2VjcmV0
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

In this example we ran the ldapsearch command with four flags: -x, -W, -D, and -b. For a description of these flags see the Common Command-Line Flags section. In a nutshell though, -x, -W, and -D are all parameters used for authenticating to the directory. They instruct the client to bind to the directory with simple authentication (-x) as the DN specified by -D (the directory manager in this case), then prompt the user to enter a password interactively (-W).

The -b flag sets the base DN for the search. This is set to ou=Users,dc=example,dc=com. Given this, ldapsearch will start searching in the Users OU.

Note:

If we had omitted the -b flag, the value of BASE in ldap.conf would have been used, which would have set the base DN to dc=example,dc=com.

After all of the command-line flags and their arguments, we specified an LDAP filter:

(uid=barbara)

This is the filter that the server will use for searching. We covered search filters in more detail earlier in this chapter, in the section entitled The Search Operation. In this case though, the search filter is straightforward: it matches only records that have the attribute named uid with the attribute value of barbara.

Note:

Many attributes have more than one name (these are properly called attribute descriptions). For example, the attribute that labels user IDs has the attribute descriptions uid and userID. In the case above, a search for (uid=barbara) will also match directory entries with and attribute of the form userID: barbara.

When this command is run, it will first prompt the user to enter a password (because of the -W flag), and then connect to the server and attempt to bind as the specified DN (cn=Manager,dc=example,dc=com). Then, if the bind is successful, it will request all records that match the filter, (uid=barbara). As the example illustrates, the server will return the entire record of the user, or as much of it as the ACLs allow, in the case of a non-manager user.

The results are returned in LDIF format, with comments sprinkled throughout. The first set of comments provides basic information about the search:

# extended LDIF
#
# LDAPv3
# base <ou=Users,dc=example,dc=com> with scope subtree
# filter: (userID=barbara)
# requesting: ALL
#

The first line indicates that this record is in extended LDIF format. This is LDIF version 1.0, plus some comments. Beneath that, we get a summary of the search, including the following:

  • Version of LDAP used (v3)

  • What the base DN is (ou=Users,dc=example,dc=com).

  • What type of search will be performed. In this case, it is a subtree search, which means the server will look in all records beneath the base DN.

  • What the operating search filter is ((userid=barbara)).

  • What attributes the client wants returned. ALL indicates that the client wants all available attributes returned.

The central part of the file contains the full record for Barbara. Beneath the record is a brief summary of the results:

search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

The first line, search, indicates that we performed two search operations (one for binding and one to execute the filtered search).

The second, result, inidcates the result code that the server sent back. 0 Success indicates that our search ran without encountering any errors.

The extended (and thus commented) results add some additional information. numResponses indicates that the server sent two responses back to the client (one for the bind, one for the search). And numEntries indicates how many entries were returned by the search. In this case there was only one—Barbara’s record.

 

Restricting Returned Fields

Sometimes we don’t want to get a DN’s entire record back. Instead, we just want a couple of attributes. This can be accomplished by specifying a list of attributes at the end of the command:

$ ldapsearch -x -w secret -D 'cn=Manager,dc=example,dc=com' -b \ 
          'ou=Users,dc=example,dc=com' -LLL '(userID=matt)' mail cn

Here is the result:

dn: uid=matt,ou=Users,dc=example,dc=com
cn: Matt Butcher
mail: mbutcher@example.com
mail: matt@example.com

Note that in this example we used the -w secret flag to specify the password on the command line. We also used the -LLL flag to suppress all of the extraneous comments printed in the LDIF output.

In addition to the filter, (userID=matt), I also added a list of attributes that I wanted returned: cn and mail. The returned record contained four lines: the dn, the two mail attributes, and the cn attribute. The DN is always returned.

 

Requesting Operational Attributes

You may have noticed that the record returned for Barbara by ldapsearch is quite a bit different than the record returned by slapcat.

Let’s compare the two. First, here’s the ldapsearch output:

$ ldapsearch -x -w secret -D 'cn=Manager,dc=example,dc=com' -b 
'ou=Users,dc=example,dc=com' -LLL '(userID=barbara)'
dn: uid=barbara,ou=Users,dc=example,dc=com
ou: Users
uid: barbara
sn: Jensen
cn: Barbara Jensen
givenName: Barbara
displayName: Barbara Jensen
mail: barbara@example.com
userPassword:: c2VjcmV0
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson

Now, here’s the slapcat output:

$ sudo slapcat -a '(uid=barbara)'
dn: uid=barbara,ou=Users,dc=example,dc=com
ou: Users
uid: barbara
sn: Jensen
cn: Barbara Jensen
givenName: Barbara
displayName: Barbara Jensen
mail: barbara@example.com
userPassword:: c2VjcmV0
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
structuralObjectClass: inetOrgPerson
entryUUID: bec561c4-c5b0-102a-81c0-81bc30f92d57
creatorsName: cn=Manager,dc=example,dc=com
modifiersName: cn=Manager,dc=example,dc=com
createTimestamp: 20060821223300Z
modifyTimestamp: 20060821223300Z
entryCSN: 20060821223300Z#000005#00#000000

The output of slapcat has a host of additional attributes—namely the special operational attributes that the directory maintains internally. We can retrieve the operational attributes with ldapsearch either by specifying them by name along with the list of desired attributes, or by using the special plus sign (+) attribute list specifier at the end of the ldapsearch command:

$ ldapsearch -x -w secret -D 'cn=Manager,dc=example,dc=com' -b 
       'ou=Users,dc=example,dc=com' -LLL '(userID=barbara)' +

And, this is what we get:

dn: uid=barbara,ou=Users,dc=example,dc=com
structuralObjectClass: inetOrgPerson
entryUUID: bec561c4-c5b0-102a-81c0-81bc30f92d57
creatorsName: cn=Manager,dc=example,dc=com
modifiersName: cn=Manager,dc=example,dc=com
createTimestamp: 20060821223300Z
modifyTimestamp: 20060821223300Z
entryCSN: 20060821223300Z#000005#00#000000
entryDN: uid=barbara,ou=Users,dc=example,dc=com
subschemaSubentry: cn=Subschema
hasSubordinates: FALSE

Specifying the + list does not return all attributes—only the operational attributes. To get all of the regular attributes and all of the operational attributes, you will need both the + specifier and the * (asterisk) specifier. The * specifier indicates that we want all of the standard attributes. This is the output:

$ ldapsearch -x -w secret -D 'cn=Manager,dc=example,dc=com' -b 
     'ou=Users,dc=example,dc=com' -LLL '(userID=barbara)' '*' +
dn: uid=barbara,ou=Users,dc=example,dc=com
ou: Users
uid: barbara
sn: Jensen
cn: Barbara Jensen
givenName: Barbara
displayName: Barbara Jensen
mail: barbara@example.com
userPassword:: c2VjcmV0
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
structuralObjectClass: inetOrgPerson
entryUUID: bec561c4-c5b0-102a-81c0-81bc30f92d57
creatorsName: cn=Manager,dc=example,dc=com
modifiersName: cn=Manager,dc=example,dc=com
createTimestamp: 20060821223300Z
modifyTimestamp: 20060821223300Z
entryCSN: 20060821223300Z#000005#00#000000
entryDN: uid=barbara,ou=Users,dc=example,dc=com
subschemaSubentry: cn=Subschema
hasSubordinates: FALSE

Now we have the complete list of attributes. Using this combination of arguments, we can generate LDIF files suitable for making backups (assuming the ACLs are not preventing access to something). While slapcat will outperform ldapsearch for this task, the fact that ldapsearch can run remotely over the network is attractive in many cases.

Note:

Note that in the given record, ldapsearch has returned three operational attributes that do not show up with slapcatentryDNsubschemaSubentry, and hasSubordinates. These values are generated dynamically at runtime and do not exist in the LDAP backend. For that reason they are not exported with slapcat. Since they are generated dynamically, they are not useful values to back up.

It is also possible to run multiple queries in sequence using ldapsearch. This is done by using an external file to store filter information for multiple searches.

 

Searching Using a File

The ldapsearch client can use a file to build and execute multiple queries. Let’s say we have a plain text list of user IDs, and we want to get the last name for each user ID. The file, userIDs.txt, looks like this:

matt
barbara

We can use ldapsearch to dynamically build a filter and run a search for each user’s surname. To do this, we use the -f flag, and point to the userIDs.txt file, and then we build a special filter. Here is the command line to be executed:

$ ldapsearch -x -D 'cn=Manager,dc=example,dc=com' -b \
     'ou=Users,dc=example,dc=com' -w secret -f userIDs.txt '(uid=%s)' sn

Most of this should look familiar, by now. But notice the filter: '(uid=%s)'. This filter uses the special %s placeholder to indicate where the values from the file ought to be placed. As ldapsearch runs, it will read through the userIDs.txt file line by line, and with each line, it will execute a search, substituting the value of the line for %s in the filter. The results look like this:

# extended LDIF
#
# LDAPv3
# base <ou=Users,dc=example,dc=com> with scope subtree
# filter pattern: (uid=%s)
# requesting: sn 
#

#
# filter: (uid=matt)
#
# matt, Users, example.com
dn: uid=matt,ou=Users,dc=example,dc=com
sn: Butcher

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

#
# filter: (uid=barbara)
#
# barbara, Users, example.com
dn: uid=barbara,ou=Users,dc=example,dc=com
sn: Jensen

# search result
search: 3
result: 0 Success

# numResponses: 2
# numEntries: 1

In this example the ldapsearch client actually ran two different search operations. It first expanded (uid=%s) to (uid=matt) and ran a search; then, it expanded (uid=%s) to (uid=barbara), and ran another search. In each case, it returned only the dn (which is always returned for a match) and the requested sn attribute.

You can also create filters in a file, and have multiple search filters run. For example, we could create a file named filters.txt with the following lines:

&(ou=System)(objectClass=account)
&(uid=b*)(ou=Users)

Since each line will be inserted into a filter, we do not need the outer set of parentheses. Now we can use these lines to dynamically build filters with ldapsearch:

$ ldapsearch -x -D 'cn=Manager,dc=example,dc=com' -b \
      'dc=example,dc=com' -w secret -f filters.txt '(%s)' cn description

We will get this output:

# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope subtree
# filter pattern: (%s)
# requesting: cn description 
#

#
# filter: (&(ou=System)(objectClass=account))
#
# authenticate, System, example.com
dn: uid=authenticate,ou=System,dc=example,dc=com
description: Special account for authenticating users

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

#
# filter: (&(uid=b*)(ou=Users))
#
# barbara, Users, example.com
dn: uid=barbara,ou=Users,dc=example,dc=com
cn: Barbara Jensen
# search result
search: 3
result: 0 Success

# numResponses: 2
# numEntries: 1

In this case the filter (%s) was expanded in the first case to (&(ou=System)(objectClass=account)), and in the second case to (&(uid=b*)(ou=Users)).

Using techniques like this it becomes possible to execute a number of complex searches with one command.

We will continue using the ldapsearch client throughout this book. Now that we have a basic idea as to how it works, we will move on to the next client in the OpenLDAP suite.

 

ldapadd

This is a command-line program used for adding new entries to an LDAP directory. The ldapadd command is not actually a stand-alone client. It is just a link to the ldapmodify program. When ldapmodify sees that it has been called as ldapadd, it will assume that it should request that the server perform an add operation, instead of requesting a modify operation.

In the most simple case, ldapadd can be used to enter a new record from the command line:

$ ldapadd -x -W -D 'cn=Manager,dc=example,dc=com'
Enter LDAP Password: 

Once we have been successfully authenticated, the cursor will move to the next line and wait for the input. We can directly enter a record. As soon as we hit Enter twice (creating a blank line, which indicates the end of a record), ldapadd will send the record to the server:

dn: uid=adam,ou=Users,dc=example,dc=com
cn: Adam Smith
sn: Smith
uid: adam
ou: Users
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson

adding new entry "uid=adam,ou=Users,dc=example,dc=com"

The highlighted portion is the text that we entered. It specifies one entire record (a record for a user named Adam Smith).

After we pressed the return key twice, inserting a blank line, the record was sent to the server. The client indicated that it was adding the record: adding new entry "uid=adam,ou=Users,dc=example,dc=com". No error message followed. This means that the add was successful.

Once a record is added the cursor will move to a blank line, waiting for the dn attribute of the next record.

dn: cn=Foo,dc=example,dc=com
farble: gork
objectClass: account

adding new entry "cn=Foo,dc=example,dc=com"
ldap_add: Undefined attribute type (17)
        additional info: farble: attribute type undefined

In this example the record that we entered (again, highlighted) contained an undefined attribute, and the server balked with the same error message. In cases where the server sends an error message, the ldapadd client prints the error message and exits. To re-enter the record you will have to re-run ldapadd.

But as long as new records are valid and the server does not report an error, ldapadd will continue prompting (or rather listening) for new records. When finished, use the CTRLC key combination to exit the program.

 

Adding Records from a File

While typing a record directly into the client may be useful on occasion, in most cases it is far more convenient (and less error prone) to create the records in a plain text file, and then load them all at once with the ldapadd program.

As usual, the records in the text file should be formated in LDIF. Here, for example, are the contents of the file user_records.ldif:

dn: uid=david,ou=Users,dc=example,dc=com
cn: David Hume
sn: Hume
uid: david
ou: Users
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson

dn: uid=immanuel,ou=Users,dc=example,dc=com
cn: Immanuel Kant
sn: Kant
uid: immanuel
ou: Users
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson

We can add all of the records in a file:

$ ldapadd -x -w secret -D 'cn=Manager,dc=example,dc=com' -f \
     user_records.ldif
adding new entry "uid=david,ou=Users,dc=example,dc=com"

adding new entry "uid=immanuel,ou=Users,dc=example,dc=com"

Just as when we added records interactively, here the absence of an error message indicates that the record was successfully added.

Next we will look at modifying records that already exist in the directory.

 

ldapmodify

The ldapmodify program is used to modify an existing entry. It can add, change, and delete the attributes of a entries in the directory. It can also be used to add new entries (together with attributes for the entry).

Like ldapadd, ldapmodify can be run interactively. It can be used to add, modify, and remove records.

 

Adding a Record with ldapmodify

The syntax for adding a record is almost identical in ldapmodify to that of ldapadd:

$ ldapmodify -w secret -x -D 'cn=Manager,dc=example,dc=com'

Here is the result:

dn: uid=nicholas,ou=Users,dc=example,dc=com
changetype: add
cn: Nicholas Malebranche
sn: Malebranche
uid: nicholas
ou: Users
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson

adding new entry "uid=nicholas,ou=Users,dc=example,dc=com"

The only difference is the addition of the changetype instruction after the dn. This tells ldapmodify what sort of LDAP operation should be performed on this record.

Note:

The changetype instruction is not an attribute, though it looks like one. It is not part of the record, but rather an instruction (in LDIF format) to tell the server what operation it should use.

There are four possible values for changetype:

  • add

  • modify

  • modrdn

  • delete

Each of these corresponds to an LDAP operation. The add change-type is used to add a new record (essentially performing the same add operation as ldapadd). The modify change-type takes an existing record and modifies it in some way (for example, by adding, replacing, or removing attributes). The modrdn change-type changes the relative DN (or RDN) of a record. The delete change-type deletes the entire record from the directory server.

 

Modifying Existing Records

Usually it is easier to add records with ldapadd. Where the ldapmodify client really shines is in its ability to modify existing records, adding, removing, or replacing attributes within a record.

Let’s add a givenName field to one of the records we added in the last section:

$ ldapmodify -x -W -D 'cn=Manager,dc=example,dc=com'

This gives the following output:

Enter LDAP Password: 
dn: uid=david,ou=Users,dc=example,dc=com
changetype: modify
add: givenName
givenName: David 

modifying entry "uid=david,ou=Users,dc=example,dc=com"

Just as with ldapadd, once the authentication phase has been done, ldapmodify waits for a DN to be given. After the dn attribute is specified, the changetype should follow.

When using a modify change-type, as we do here, we must also specify exactly what attributes we are going to change, and how we will change them. The modify change-type is the only type that requires this further specification. Here is the figure displaying the several change-types:

Directory operation

In this case, we want to add a new attribute to the the uid=david, ou=Users, dc=example, dc=com record. And the attribute we want to add is givenName. So, the line that specifies that we will add a givenName attribute reads add: givenName.

Next, we want to specify the attribute and attribute value:

givenName: David

Then, by hitting Enter twice, we indicate that the record is complete. Just as with ldapadd, ldapmodify indicates which record it is modifying. If the server does not return an error, ldapmodify will wait for another modify record.

The add modification type is one of three that ldapmodify supports. Operations can only be specified if the change-type is set to modify. The three modification types are:

  • add: Adds new attributes to an existing record

  • replace: Replaces existing attribute values with new attribute values

  • delete: Removes attributes from the record

More than one of these operations can be done in a single transaction:

$ ldapmodify -w secret -x -D 'cn=Manager,dc=example,dc=com'
dn: uid=immanuel,ou=Users,dc=example,dc=com
changetype: modify
add: givenName
givenName: Manny
-
replace: cn
cn: Manny Kant

modifying entry "uid=immanuel,ou=Users,dc=example,dc=com"

In this example we first add givenName, and then replace the existing cn value with a new one. Between the two modification requests we use a dash (-) to indicate that we are still working on the same record. Remember, a blank line indicates that we are done with the record. Now, if we look up the record with ldapsearch, it looks like this:

$ ldapsearch -x -w secret -D 'cn=Manager,dc=example,dc=com' -LLL \
     '(uid=immanuel)'

dn: uid=immanuel,ou=Users,dc=example,dc=com
sn: Kant
uid: immanuel
ou: Users
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
givenName: Manny
cn: Manny Kant

The cn has been replaced, and the givenName attribute has been added.

If the modification is adding several attributes, rather than splitting the additions up using dashes, you can group them together:

dn: uid=nicholas,ou=Users,dc=example,dc=com
changetype: modify
add: description title
description: This is a test
title: Cartesian philosopher

Note that, in this case, the add line has two attribute names (description and title), followed by both attributes. And just as with ldapadd, we can put these change records into a plain text file, and then use the -f flag, which takes the path to a file, to have ldapmodify read the commands from the file instead of from the interactive prompt:

$ ldapmodify -x -w secret -D 'cn=Manager,dc=example,dc=com' -f \
     change-nicholas.ldif 
modifying entry "uid=nicholas,ou=Users,dc=example,dc=com"

Using the modify change-type we can delete an attribute:

dn: uid=nicholas,ou=Users,dc=example,dc=com
changetype: modify
delete: title

Deleting an attribute from the record has the result of deleting all of the attribute values from the record. For example, if Nicholas had two titles specified, the above would remove them both.

To delete just one specific attribute, the request must also name the attribute value to be deleted:

dn: uid=nicholas,ou=Users,dc=example,dc=com
changetype: modify
delete: title
title: Cartesian philosopher

That will delete any title attribute values that contain the exact string “Cartesian philosopher”, leaving any other attribute values intact.

 

Modifying the Relative DN

The third change type is for modifying relative DNs—the portion of the DN that identifies the current record (see the discussion at the beginning of this chapter).

For example, we can change the RDN portion of the DN for our user uid=immanuel,ou=Users,dc=example,dc=com:

$ ldapmodify -w secret -x -D 'cn=Manager,dc=example,dc=com'
dn: uid=immanuel,ou=Users,dc=example,dc=com
changetype: modrdn
newrdn: uid=manny
deleteoldrdn: 0

modifying rdn of entry "uid=immanuel,ou=Users,dc=example,dc=com"
rename completed

In this example, we use the modrdn change-type to instruct SLAPD to change the RDN portion of the user’s DN. The newrdn instruction supplies the new RDN portion, and the deleteoldrdn instruction determines whether the old attribute value (uid=immanuel) will be deleted or retained. Setting 0 indicates that the old attribute value should not be deleted, while 1 will result in the old attribute value’s removal.

Now, if we search for that user, we can observe the modification:

$ ldapsearch -x -W -D 'cn=manager,dc=example,dc=com' -LL \
     '(sn=kant)' uid
Enter LDAP Password: 
version: 1

dn: uid=manny,ou=Users,dc=example,dc=com
uid: immanuel
uid: manny

In some cases we don’t want the old RDN attribute value to be kept. In such cases, setting the deleteoldrdn value to 1 will remove the old RDN attribute values:

$ ldapmodify -w secret -x -D 'cn=Manager,dc=example,dc=com'
dn: uid=manny,ou=Users,dc=example,dc=com
changetype: modrdn
newrdn: uid=immanuel
deleteoldrdn: 1

modifying rdn of entry "uid=manny,ou=Users,dc=example,dc=com"
rename completed

This changes the RDN back to uid=immanuel, and since deleteoldrdn is set to 1, the old UID value (manny) should be deleted. We can verify this with ldapsearch:

$ ldapsearch -x -W -D 'cn=manager,dc=example,dc=com' -LL \ 
     '(sn=kant)' uid
Enter LDAP Password: 
version: 1

dn: uid=immanuel,ou=Users,dc=example,dc=com
uid: immanuel

Note that, in addition to the changed DN, the old uid attribute value (manny) is no longer present in the record. It has been replaced.

We will take another look at modifying relative DNs when we examine the ldapmodrdn client.

 

Moving a Record with modrdn

The modrdn change-type can be used for more than just changing the RDN. It can be used for changing a record’s superior entry, essentially relocating a record within the directory information tree.

For this operation to work however, the backend database type must support this sort of modification. Currently, the only storage database that supports this is HDB. In Chapter 2, we set up slapd.conf to store the dc=example,dc=com tree in an HDB backend.

Now, we can issue a compound ModRDN operation, in which we change the record’s RDN, and move the record to a different OU:

$ ldapmodify -w secret -x -D 'cn=Manager,dc=example,dc=com'
dn: uid=manny,ou=users,dc=example,dc=com
changetype: modrdn
newrdn: uid=immanuel
deleteoldrdn: 1
newsuperior: ou=system,dc=example,dc=com

In this example, we change the user’s UID from manny back to immanuel. Since deleteoldrdn is 1, the old RDN (uid=manny) will be removed from the record.

The newsuperior instruction tells SLAPD what the new base portion of the DN ought to be. This will effectively move the record from the ou=users branch to the ou=system branch of our directory information tree.

Note:

Unlike modifying a user’s RDN, changing a record’s superior will not modify any of the fields in the record. Thus, our record above would still have the ou=Users attribute.

Again, we can use ldapsearch to see the newly modified record:

$ ldapsearch -x -W -D 'cn=manager,dc=example,dc=com' -LL 
       '(sn=kant)' uid

And, we get:

Enter LDAP Password: 
version: 1

dn: uid=immanuel,ou=system,dc=example,dc=com
uid: immanuel

Notice that not only has the uid changed, but also the ou in the DN.

In order to use the newsuperior instruction, you must first specify a modrdn. Thus, if we wanted to move the record for this user back to the users OU, we would still have to specify the user’s new RDN.

So how do you move a record without changing the RDN?

Since the modrdn change-type does not require that the new RDN be different from the old one, a record can be moved with modrdn simply by setting the newrdn to be the same as the old RDN:

$ ldapmodify -w secret -x -D 'cn=Manager,dc=example,dc=com'
dn: uid=immanuel,ou=system,dc=example,dc=com
changetype: modrdn
newrdn: uid=immanuel
deleteoldrdn: 1
newsuperior: ou=users,dc=example,dc=com

modifying rdn of entry "uid=immanuel,ou=system,dc=example,dc=com"
rename completed

In this case, newrdn: uid=immanuel does not actually change the RDN of the user. But this is necessary in order to change the superior.

The newsuperior instruction indicates that the record should be moved (back) to the ou=users,dc=example,dc=com tree. One last ldapsearch of this record shows us the results of that change:

$ ldapsearch -x -W -D 'cn=manager,dc=example,dc=com' -LL 
     '(sn=kant)' uid
Enter LDAP Password: 
version: 1

dn: uid=immanuel,ou=users,dc=example,dc=com
uid: immanuel

Once again, the record is back in the Users OU.

 

Deleting Entire Records

Finally, using the delete change-type, we can delete an entire record with ldapmodify:

$ ldapmodify -w secret -x -D 'cn=Manager,dc=example,dc=com'

dn: uid=nicholas,ou=Users,dc=example,dc=com
changetype: delete

deleting entry "uid=nicholas,ou=Users,dc=example,dc=com"

When deleting a record all we need to specify are the DN and the change-type.

Essentially, using the delete change-type performs the same task as is done using the ldapdelete client.

 

ldapdelete

The ldapdelete tool is used to delete one or more records from the directory. It performs the same operation as the delete change-type used in ldapmodify.

If you want to delete a record with ldapdelete, you must know its DN. This tool will not search for, say, all records that have a specified address, and then delete them all.

The syntax of the ldapdelete command is simple:

$ ldapdelete -x -w secret -D 'cn=Manager,dc=example,dc=com' \
      'uid=nicholas,ou=Users,dc=example,dc=com'

After the usual flags (-x, -w, -D), ldapdelete takes the DN that is to be deleted (this is the DN for uid=nicholas on the second line of the command). Upon execution it will request that the server delete the record. Assuming that the record exists and the user is allowed (by the server’s ACLs) to delete the record, then the record will be removed from the directory.

 

ldapcompare

This tool is used to ask the server whether a particular entry (identified by a DN) has a particular attribute that matches the attribute specified. If the entry does have a matching attribute, then ldapcompare returns TRUE. Otherwise, it returns FALSE.

Here is a pair of examples:

$ ldapcompare -x -w secret -D 'cn=Manager,dc=example,dc=com' \
    'uid=david,ou=Users,dc=example,dc=com' 'givenName:David'
TRUE

$ ldapcompare -x -w secret -D 'cn=Manager,dc=example,dc=com' \
    'uid=david,ou=Users,dc=example,dc=com' 'cn:Dave Hume'
FALSE

In the first example ldapcompare requested that the server examine the record for uid=david,ou=Users,dc=example,dc=com to see if it had the attribute givenName with the value David. The record did have an attribute givenName: David, and so the return value is TRUE.

The second example performed a similar compare on the same record; it looked for the attribute cn with the value Dave Hume. While the record does have a cn attribute, the value of that attribute is David Hume, not Dave Hume. So the server returned FALSE.

Note:

Base-64 Encoding with ldapcompare

In cases where the value to compare is not an ASCII string, you should base-64 encode the value and use the double colon syntax (::) that we used in our LDIF files. Example: givenName::RGF2aWQ=

An LDAP compare operation is often much faster than a search operation. In cases where the same task can be accomplished with ldapsearch and ldapcompare, it is often more efficient to use ldapcompare.

 

ldapmodrdn

The ldapmodrdn client is used to change the Relative DN (RDN) portion of a DN. This client requests a ModifyDN operation. ldapmodrdn takes the full DN of an existing record, and the relative DN that should replace the existing RDN for the record:

$ ldapmodrdn -x -w secret -D 'cn=Manager,dc=example,dc=com' 
      'uid=immanuel,ou=Users,dc=example,dc=com' 'uid=manny'

This example requests that the RDN for uid=immanual,ou=Users,dc=example,dc=com be changed from uid=immanuel to uid=manny.

Now let’s take a look at the record after the change. We will search by the sn field:

$ ldapsearch -x -w secret -D 'cn=Manager,dc=example,dc=com' -LLL \ 
    '(sn=Kant)' uid

dn: uid=manny,ou=Users,dc=example,dc=com
uid: immanuel
uid: manny

Here, the filter is looking for records with the surname Kant and requesting that only the uid attribute be returned. Recall that we did not ever add a uid attribute with the value manny—we only had uid: immanuel.

But looking at the results, we can see that not only has the DN been modified, but a new user ID attribute has been added for us. In some cases it is fine that the modification of the RDN results in adding (rather than replacing) an attribute value. But in other cases this is inconvenient or even illegal (because of the schema).

For example, we might have a record in the directory that describes a subtree of records that have to do with the company website. Such a record might look like this:

dn: dc=www,dc=example,dc=com
dc: www
ou: Website
objectClass: organizationalUnit
objectClass: dcObject

Now, say we wanted to change the RDN to point not to www, but to web. Using ldapmodrdn the way we did earlier would generate an error:

$ ldapmodrdn -x -w secret -D 'cn=Manager,dc=example,dc=com' \
    'dc=www,dc=example,dc=com' 'dc=web'

Rename Result: Constraint violation (19)
Additional info: attribute 'dc' cannot have multiple values

The reason for this error is that the schema definition for dc specifies that there can be only one dc attribute value per record.

Note:

The dc (or domainComponent) attribute is defined in core.schema.

The solution to this problem is to use the -r flag for ldapmodrdn.

$ ldapmodrdn -x -w secret -D 'cn=Manager,dc=example,dc=com' -r 
      'dc=www,dc=example,dc=com' 'dc=web'

The -r flag causes ldapmodrdn to replace, rather than add, the existing attribute value. Now the resulting record looks like this:

dn: dc=web,dc=example,dc=com
ou: Website
objectClass: organizationalUnit
objectClass: dcObject
dc: web

There is only one dc attribute listed, and it has the newly set value, web.

 

Modifying the Superior DN with ldapmodrdn

Just as we saw earlier with the modrdn change-type for ldapmodify, we can change the superior DN (the base portion of a record’s DN) with ldapmodrdn.

Note:

The Right Backend

Not all backends support this type of renaming. Currently, the HDB backend is the only storage backend to support changing the superior reference in a DN. Other non-storage backends (like ldap) may pass on these operations to the underlying storage mechanism, which in turn may or may not support this degree of renaming.

Also, as with the modrdn change type, ldapmodrdn must specify a replacement RDN even if that RDN is the same as the current one. In other words, an RDN is required, even if the RDN is not a new RDN. We will see an example of this below.

The -s flag for ldapmodrdn specifies the new superior DN. Thus, to move the entry uid=barbara,ou=users,dc=example,dc=com to the ou=system branch of the directory, we can use a command like this:

  ldapmodrdn -x -w secret -D 'cn=Manager,dc=example,dc=com' \
       -s "ou=system,dc=example,dc=com" -r \
          "uid=barbara,ou=users,dc=example,dc=com" "uid=barbara"

This is a long command, and it is thus broken up into three lines:

  • The first line contains the flags that handle binding to the directory, and these should be familiar by now.

  • The second line begins with the -s flag, which takes a DN for a parameter. This is the flag that specifies what the new superior DN will be. In this case, it is ou=system,dc=example,dc=com.

    The -r flag, as we have seen before, instructs SLAPD to replace the old RDN with the new one.

  • On the third line is the DN for the entry we want to modify, uid=barbar,ou=users,dc=example,dc=com, and the new RDN. Since we want to keep the same RDN (but move the record to a new subtree), we set this last value to uid=barbara, which is the RDN that the existing record has.

After we run this command we can see the results with ldapsearch:

$ ldapsearch -x -W -D 'cn=manager,dc=example,dc=com' -LL 
    '(uid=barbara)' uid ou
Enter LDAP Password: 
version: 1

dn: uid=barbara,ou=system,dc=example,dc=com
ou: Users
uid: barbara

The base portion of Barbara’s new record is now ou=system,dc=example,dc=com.

Just as with the modrdn changetype for ldapmodify, changing a superior entry will not change any attributes in the record. Thus, even though this record is now in the sytem OU, it still has the attribute ou: Users.

It is possible to construct Relative DNs that have more than one attribute value. For example, I can use a combination of uid and l (for location) in the RDN portion:

dn: uid=matt+l=Chicago,ou=Users,dc=example,dc=com

In such cases, the plus sign (+) is used to indicate that both the attribute are to be considered part of the RDN.

ldapmodrdn is smart enough to handle these cases. It will add (or replace) all of the attributes used in the RDN.

In the case where the -r flag is specified, there are some things to be aware of. First, ldapmodrdn will replace all of the fields used in the new RDN. Second, if there is a value in the initial RDN that is removed from the RDN, then the attribute value will be removed from the record as well. For example, here is our starting record:

dn: cn=Matt Butcher+l=Chicago,dc=example,dc=com
cn: Matt Butcher
sn: Butcher
l: Chicago
objectClass: person
objectClass: organizationalPerson

Notice that the DN uses both the cn and the l attributes, both of which are present in the body of the record. Now, if we use ldapmodrdn with the -r flag and replace cn=Matt Butcher+l=Chicago with cn=Matt Butcher, the l: Chicago attribute will be removed from the record:

dn: cn=Matt Butcher,dc=example,dc=com
sn: Butcher
objectClass: person
objectClass: organizationalPerson
cn: Matt Butcher

So, when using ldapmodrdn with multi-attribute RDNs, be judicious when using the -r flag.

 

ldappasswd

In the utilities section we looked at encrypting passwords with slappasswd. That tool was used to generate encrypted values for inclusion in LDIF files. The ldappasswd client, in contrast, connects to the server and changes a password value in the directory. If needed it can be used to automatically generate a password, as well.

Unlike ldapadd and ldapmodify, which use the LDAP v.3 standard Add and Modify operations, the ldappasswd client uses an extension operation—the LDAP Password Modify Extended Operation as defined in RFC 3062 (http://rfc-editor.org/rfc/rfc3062.txt).

Note:

When loading passwords from an LDIF file, or from ldapadd or ldapmodify, if you send the server a cleartext password, the password will be stored in the directory in an unencrypted string. This is not safe. You should either use slappasswd to generate an encrypted password for inclusion in an LDIF, or you should use ldappasswd to set the password.

As long as the ACLs permit, a user can change her or his password with the ldappasswd client:

$ ldappasswd -x -W -S -D 'uid=matt,ou=Users,dc=example,dc=com'
New password: 
Re-enter new password: 
Enter LDAP Password: 

Result: Success (0)

The -S flag is the only new flag used here. It indicates that ldappasswd should prompt the user to enter (and re-enter) a new password. The -W flag, as you may recall, prompts the user to enter a current password interactively.

The order in which the user enters the passwords differs from the norm. The user is prompted to first enter and re-enter a new password, and then to enter the current password.

It is also possible for an administrator (or one with write permissions to the userPassword attribute of a given record) to change a password for another user:

$ ldappasswd -x -w secret -D 'cn=Manager,dc=example,dc=com' -s secret \ 'uid=barbara,ou=Users,dc=example,dc=com'

Result: Success (0)

In this case the directory manager is changing the value of the userPassword attribute for uid=barbara,ou=Users,dc=example,dc=com. Rather than using -S and entering the password at an interactive prompt, the password has been specified on the command line: -s secret.

The password, when changed through ldappasswd, is automatically encrypted by the server before it is stored in the record:

# barbara, Users, example.com
dn: uid=barbara,ou=Users,dc=example,dc=com
userPassword:: e1NTSEF9UzFTUnQ1bkkvcHZGOGt3UklVU3J3TkRHZHFSS3hOQ1Y=

If we decode the userPassword value, it reads: {SSHA}S1SRt5nI/pvF8kwRIUSrwNDGdqRKxNCV. The password is stored in an irreversible SSHA hash.

Note:

Setting the Default Encryption Scheme

You can specify which encryption scheme the server should choose when encrypting passwords. To specify the algorithm, use the password-hash directive in slapd.conf. Example: password-hash {SMD5}

Finally, ldappasswd can request that the server generate a strong password for that DN. If no flag is set that indicates, the source of the password (for example -s-S, or -T), then ldappasswd requests that one be generated. Here is the request:

$ ldappasswd -x -w secret -D 'cn=Manager,dc=example,dc=com'  \
    'uid=barbara,ou=Users,dc=example,dc=com'

New password: dS9R4Kvc
Result: Success (0)

The server responded to this request with a generated password, New password: dS9R4Kvc, which has already been encrypted and stored in the userPassword attribute on the server.

 

ldapwhoami

The last client in the OpenLDAP suite is ldapwhoami. This client provides a client implementation of the “Who am I?” Extended Operation. This operation provides information about the DN who is currently bound to the directory.

The ldapwhoami command simply requires enough information to authenticate to the directory server:

$ ldapwhoami -x -w secret -D 'cn=Manager,dc=example,dc=com'

dn:cn=Manager,dc=example,dc=com
Result: Success (0)

As you can see from this example, all this client does is reply with the DN of the user we connected with. This tool comes in useful when debugging SASL authentication, which does not require a DN to connect. We will look at SASL configuration in the next chapter.

Related Articles

How to add swap space on Ubuntu 21.04 Operating System

How to add swap space on Ubuntu 21.04 Operating System

The swap space is a unique space on the disk that is used by the system when Physical RAM is full. When a Linux machine runout the RAM it use swap space to move inactive pages from RAM. Swap space can be created into Linux system in two ways, one we can create a...

read more

Lorem ipsum dolor sit amet consectetur

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

19 − nineteen =