There are nine basic LDAP operations:
||Add, Delete, Modify, Rename (modify DN)
|Authentication and Control
||Bind, Unbind, Abandon
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
The entry will only be added if:
- The parent of the new entry already exists
- There is not an already existing entry with the same DN
- The new entry conforms to the schema - that is, it has the
correct attributes and they are correctly formatted
- Access control permits the operation
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.
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.
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
ModifyDN has four parameters:
Here is an example of renaming an entry:
- The DN of the entry to be renamed
- The new RDN for the entry
- Optionally, an argument giving the new parent of the entry; leave this
blank if the entry will stay under the same parent
- A flag "delete-old-RDN" which is used to specify whether the old RDN
should be kept as an additional attribute value, or removed.
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 |
An LDAP search request takes 8 parameters (!) and returns a set of entries
to the client. The parameters are:
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~=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
Note: certain characters in search filters may need to be quoted; the
quoting mechanism is different to quoting of DNs!
The LDAP search filter syntax is defined in
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]]
[? extensions ]]]]
- Which LDAP server to contact. Port defaults to 389. If not specified, use
the client's configured default LDAP server
- The distinguished name of the top of the search
- Comma-separated list of which attributes you want returned. If you leave
this empty, defaults to "all user attributes"
- 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 expression. Defaults to "(objectclass=*)"
- 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.
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
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.
The equivalent of "logging out". The credentials
are forgotten and the TCP connection closed.
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
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.