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