LDAP operations

There are nine basic LDAP operations:

Update Add, Delete, Modify, Rename (modify DN)
Interrogation Search, Compare
Authentication and Control Bind, Unbind, Abandon

Update operations

add

Add a new record to the directory tree. You present the DN of the entry to be added, and a set of attributes and attribute values which make up the entry.

The entry will only be added if:

delete

Given a DN, this removes the entry from the directory. It must have no children, otherwise the operation will fail, and of course access control may also prevent it from taking place.

modify

This is used to modify the contents of an entry. It will only succeed as long as all the specified attribute modifications succeed, and the resulting record also conforms to the schema. Otherwise, the entire update fails and no change is made.

modify DN

This is used to rename and/or move a entry. In LDAPv2, this was "modify RDN" and could not be used to move an entry within the tree. In LDAPv3 this restriction has been removed, and so changing a DN can move an object within the tree.

ModifyDN has four parameters:

  1. The DN of the entry to be renamed
  2. The new RDN for the entry
  3. Optionally, an argument giving the new parent of the entry; leave this blank if the entry will stay under the same parent
  4. A flag "delete-old-RDN" which is used to specify whether the old RDN should be kept as an additional attribute value, or removed.
Here is an example of renaming an entry:
                                          +--------------+
dn: uid=fred,dc=wibble,dc=org    ----->   | uid: fred    |
                                          +--------------+

After ModifyDN with delete-old-RDN = false:

                                          +--------------+
dn: uid=jim,dc=wibble,dc=org     ----->   | uid: jim     |
                                          | uid: fred    |
                                          +--------------+

But with delete-old-RDN = true:
                                          +--------------+
dn: uid=jim,dc=wibble,dc=org     ----->   | uid: jim     |
                                          +--------------+

Interrogation operations

Search

An LDAP search request takes 8 parameters (!) and returns a set of entries to the client. The parameters are:

Search filters

A search filter is an expression, in parentheses, which is used to select a subset of entries to be returned. Here are some examples of search filters:

(sn=smith)equality
(sn=*smi*th*)substring
(sn~=jones)approximate match (soundalike)
(sn<=smith)less than or equal/greater than or equal
(!(age<=21))There are only LE/GE operators, so
(age>21) is not a valid filter
(telephonenumber=*)presence
(!(sn=smith))negation
(&(sn=smith)(l=London))AND combination
(|(sn=smith)(sn=jones))OR combination
(sn:1.2.3.4.5:=smith)
(sn:dn:1.2.3.4.5:=smith)
server-specific extensions

Note: certain characters in search filters may need to be quoted; the quoting mechanism is different to quoting of DNs!

*\2A
(\28
)\29
\\5C
NUL\00

The LDAP search filter syntax is defined in RFC 2254

Search URLs

You can write an LDAP search in URL form. This has lots of uses, although in particular Exim uses it as its LDAP query syntax.
ldap:// [server [:port]] / basedn [? attributes [? scope [? filter [? extensions ]]]]
server[:port]
Which LDAP server to contact. Port defaults to 389. If not specified, use the client's configured default LDAP server
basedn
The distinguished name of the top of the search
attributes
Comma-separated list of which attributes you want returned. If you leave this empty, defaults to "all user attributes"
scope
base, one or sub. If you leave this empty, defaults to "base", which only accesses the object pointed to by basedn and nothing below it. "one" accesses one level below the basedn, i.e. all its direct children, excluding the basedn itself. "sub" searches the whole subtree rooted at basedn, including basedn itself.
filter
Filter expression. Defaults to "(objectclass=*)"
extensions
Somewhere to add other options, of the form [!]type[=value]. If present, ! means "this is a required (critical) extension, fail if it is not supported". Example: you can use this to specify a dn to bind as, using !bindname=dn

See RFC 2255 for the full definition of the LDAP search URL, with examples.

Compare

The other LDAP interrogation operation is "compare". The client provides a DN, an attribute type, and a value; the server responds saying whether the value you gave matches the value stored in the entry.

Of course, you could obtain the same results using a search to retrieve the given attribute, and check the value yourself. Using compare uses less bandwidth, and also allows you to give a client "compare" access instead of "read" access (which for example would allow the client to check whether a user has the correct password, without being able to read the password)

There is one other difference. If you try to compare an attribute, but the attribute is not present in the entry at all, the server returns a special result code. Hence you can distinguish between "this attribute has a value, but it's a different one", and "this entry does not have any instance of this attribute at all"

Authentication and Control operations

bind

The equivalent of "logging in" to the server, providing credentials to authenticate the directory user

Credentials are typically stored within a "userPassword" entry. So, in a "simple bind" where the client provides a DN and a cleartext password, the LDAP server looks up the entry corresponding to the DN, finds the userPassword entry, and compares the two. userPassword can hold either a cleartext password, or a hash of the password in one of several forms.

userPassword: agent
or
userPassword: {md5}szrtjzE0mWcD3Dn5p8lXgw==

unbind

The equivalent of "logging out". The credentials are forgotten and the TCP connection closed.

abandon

This is used by a client when it is no longer interested in the results of a search operation it started previously. This is the equivalent of an FTP "abort".

Note that the results of the search and the abandon request may cross over 'in flight', so the client still has to be prepared to receive (and discard) the results it asked for. This sort of thing is taken care of by the LDAP API and library which you would normally use when writing an LDAP application.

Every request is tagged with a message ID, which allows multiple requests to be outstanding at the same time - there is no need for the client to open multiple TCP connections to the server to run multiple requests. The abandon operation includes the message ID of the particular request to cancel.