RFC 1823
The LDAP Application Program Interface
The LDAP Application Program Interface π
Okay bestie, let's get into RFC 1823 π It's by T. Howes and M. Smith from the University of Michigan, dated August 1995. It's filed as Informational, which means it's sharing info with the Internet community, not an official standard πΈ The header doesn't list anything it obsoletes or updates, so it's a fresh start β¨
Status of This Memo π
This memo gives information to the Internet community π It does not specify an Internet standard of any kind, and distribution of it is unlimited π
1. Introduction β¨
Okay so this document defines a C language application program interface (API) for the lightweight directory access protocol (LDAP) π¦ The LDAP API is designed to be powerful but still simple to use, and it gives you compatible synchronous and asynchronous interfaces so it can suit a wide variety of apps π
It gives a quick overview of the LDAP model first, then explains how an application uses the API to get LDAP info. After that come the detailed API calls, and an appendix with example code to show it all in action π§
2. Overview of the LDAP Model πΈ
LDAP is the lightweight directory access protocol, described in [2] and [7] π It can be a lightweight frontend to the X.500 directory [1], or it can run as a stand-alone service. Either way, it's based on a client-server model where a client makes a TCP connection to an LDAP server, then sends requests and receives responses over it π₯
The LDAP information model is built around the entry, which holds info about some object (like a person) π Entries are made of attributes, and each attribute has a type and one or more values. Every attribute also has a syntax that decides what kinds of values are allowed (ASCII characters, a jpeg photograph, etc.) and how those values behave during directory operations (like whether case matters during comparisons) π
Entries are organized in a tree, usually based on political, geographical, and organizational boundaries π³ Each entry is uniquely named relative to its siblings by its relative distinguished name (RDN), which is made of one or more distinguished attribute values from the entry. At most one value from each attribute MAY be used in the RDN π For example, Babs Jensen's entry might be named with the "Barbara Jensen" value from the commonName attribute π¦
A globally unique name for an entry, called a distinguished name or DN, is built by joining the sequence of RDNs from the root of the tree down to the entry π So if Babs worked at the University of Michigan, her U-M entry's DN might be "cn=Barbara Jensen, o=University of Michigan, c=US". The DN format used by LDAP is defined in [4] π§
LDAP supports operations to authenticate, search for and retrieve info, modify info, and add and delete entries from the tree π The next sections cover how the API is used, plus detailed descriptions of the calls that make all of this happen β¨
3. Overview of LDAP API Use π
An application generally uses the LDAP API in four simple steps π«Ά
- Open a connection to an LDAP server. The
ldap_open()call returns a handle to the connection, and you can have multiple connections open at once π¦ - Authenticate to the LDAP server and/or the X.500 DSA. The
ldap_bind()call and friends support a variety of authentication methods π - Perform some LDAP operations and get some results.
ldap_search()and friends return results, which you can parse withldap_result2error(),ldap_first_entry(),ldap_next_entry(), etc. π - Close the connection. The
ldap_unbind()call closes it π
Operations can be done synchronously or asynchronously π Synchronous calls end in _s. For example, a synchronous search is done with ldap_search_s(), and an asynchronous search is started with ldap_search() π All synchronous routines return an indication of how the operation turned out (like the constant LDAP_SUCCESS or some other error code) β¨ Asynchronous routines return the message id of the operation they started, and you can use that id in later ldap_result() calls to get the result(s) π§ You can abandon an asynchronous operation by calling ldap_abandon() π
ββοΈ
Results and errors come back in an opaque structure called LDAPMessage. There are routines to parse that structure, step through the entries and attributes returned, and so on. There are also routines to interpret errors, and the next sections describe all of them π
4. Calls for Performing LDAP Operations π₯
This section breaks down each LDAP operation API call in detail π Every call takes a "connection handle," which is a pointer to an LDAP structure holding per-connection info π Lots of routines return results in an LDAPMessage structure, and those structures (plus a few others) get described as needed below πΈ
4.1. Opening a connection π¦
ldap_open() opens a connection to the LDAP server π
typedef struct ldap {
/* ... opaque parameters ... */
int ld_deref;
int ld_timelimit;
int ld_sizelimit;
int ld_errno;
char *ld_matched;
char *ld_error;
/* ... opaque parameters ... */
} LDAP;
LDAP *ldap_open( char *hostname, int portno );
Here are the parameters π§
hostnamecontains a space-separated list of hostnames or dotted strings representing the IP address of hosts running an LDAP server to connect to. The hosts are tried in the order listed, and it stops with the first one that gets a successful connection πportnocontains the TCP port number to connect to. The default LDAP port can be obtained by supplying the constantLDAP_PORTβ¨
ldap_open() returns a "connection handle," which is a pointer to an LDAP structure that gets passed to later calls about the connection π«Ά It returns NULL if the connection can't be opened. One of the ldap_bind calls described below MUST be completed before any other operations can be performed on the connection β οΈ
The calling program SHOULD assume nothing about the order of the fields in the LDAP structure π There MAY be other fields in the structure for internal library use. The fields shown above are described as needed in the descriptions of other calls below π
4.2. Authenticating to the directory π
ldap_bind() and friends are used to authenticate to the directory π
int ldap_bind( LDAP *ld, char *dn, char *cred, int method );
int ldap_bind_s( LDAP *ld, char *dn, char *cred, int method );
int ldap_simple_bind( LDAP *ld, char *dn, char *passwd );
int ldap_simple_bind_s( LDAP *ld, char *dn, char *passwd );
int ldap_kerberos_bind( LDAP *ld, char *dn );
int ldap_kerberos_bind_s( LDAP *ld, char *dn );
Here's what the parameters mean π
ldis the connection handle;dnis the name of the entry to bind as;credholds the credentials to authenticate with;methodis one ofLDAP_AUTH_SIMPLE,LDAP_AUTH_KRBV41, orLDAP_AUTH_KRBV42, indicating the authentication method to use;passwdis, forldap_simple_bind(), the password to compare to the entry'suserPasswordattribute;
There are three types of bind calls: simple authentication, Kerberos authentication, and general routines that can do either one π¦ With Kerberos version 4 authentication through the general ldap_bind() routines, the credentials are ignored, because those routines assume a valid ticket granting ticket already exists that can be used to retrieve the right service tickets πΈ
Synchronous versions of these routines have names ending in _s π They return the result of the bind: LDAP_SUCCESS if it worked, or another LDAP error code if it didn't. Check the error handling section below for more about possible errors and how to read them π₯
Asynchronous versions return the message id of the bind operation they started π You can then call ldap_result(), described below, to get the result of the bind. If something goes wrong, these routines return -1 and set the ld_errno field in the LDAP structure accordingly π
Note that no other operations over the connection SHOULD be attempted before a bind call has successfully completed π ββοΈ Subsequent bind calls can be used to re-authenticate over the same connection π
4.3. Closing the connection π
ldap_unbind() is used to unbind from the directory and close the connection π§
int ldap_unbind( LDAP *ld );
Parameter:
ldis the connection handle π
ldap_unbind() works synchronously: it unbinds from the directory, closes the connection, and frees up the ld structure before it returns β¨ It returns LDAP_SUCCESS, or another LDAP error code if the request can't be sent to the LDAP server π«Ά After you call ldap_unbind(), the ld connection handle is invalid, so don't touch it again π
4.4. Searching β¨
Okay so searching is where it gets spicy π₯ ldap_search() and its friends let you search the LDAP directory and get back a requested set of attributes for every entry that matches. There are three variations, bestie π
struct timeval {
long tv_sec;
long tv_usec;
};
int ldap_search(
LDAP *ld,
char *base,
int scope,
char *filter,
char *attrs[],
int attrsonly
);
int ldap_search_s(
LDAP *ld,
char *base,
int scope,
char *filter,
char *attrs[],
int attrsonly,
LDAPMessage **res
);
int ldap_search_st(
LDAP *ld,
char *base,
int scope,
char *filter,
char *attrs[],
int attrsonly,
struct timeval *timeout,
LDAPMessage **res
);
Here's what each parameter does:
ld: the connection handle πbase: the dn of the entry where the search starts πΈscope: one ofLDAP_SCOPE_BASE,LDAP_SCOPE_ONELEVEL, orLDAP_SCOPE_SUBTREE, showing how wide the search goes π¦filter: a character string as described in RFC 1558 [3], which is the search filter β¨attrs: a NULL-terminated array of strings naming which attributes to return for each matching entry. Passing NULL here means all available attributes get retrieved πattrsonly: a boolean that should be zero if you want both attribute types and values back, and non-zero if you only want the types πtimeout: forldap_search_st()only, the local search timeout value β³res: for the synchronous calls, a result parameter that holds the results of the search once the call finishes π
Three fields in the ld connection handle control how the search runs.
ld_sizelimit: a limit on how many entries come back from the search. Zero means no limit πld_timelimit: a limit on how many seconds the search can spend. Zero means no limit π§ld_deref: one ofLDAP_DEREF_NEVER,LDAP_DEREF_SEARCHING,LDAP_DEREF_FINDING, orLDAP_DEREF_ALWAYS, specifying how aliases get handled during the search.LDAP_DEREF_SEARCHINGmeans aliases get dereferenced during the search but not when locating the base object of the search.LDAP_DEREF_FINDINGmeans aliases get dereferenced when locating the base object but not during the search. π
An asynchronous search starts when you call ldap_search(). It gives back the message id of the search it started. You grab the results with a later call to ldap_result(), then parse them with the result parsing routines we'll get into later. If something goes wrong, you get -1 back and the ld_errno field in the LDAP structure gets set appropriately π
A synchronous search happens when you call ldap_search_s() or ldap_search_st(). The two are identical, except ldap_search_st() takes an extra parameter for a search timeout. Both return an indication of the result, either LDAP_SUCCESS or some error (see Error Handling below). Any entries from the search live in the res parameter. That parameter is opaque to you, so pull out entries, attributes, values, etc. with the parsing routines described below. Once you're done with the results in res, free them by calling ldap_msgfree(), which we'll cover later π§Ή
4.5. Reading an entry π
LDAP doesn't support a read operation directly π so reading gets faked with a search. You set base to the DN of the entry you want to read, scope to LDAP_SCOPE_BASE, and filter to "(objectclass=*)". attrs holds the list of attributes to return.
4.6. Listing the children of an entry π³
Same trick for listing. LDAP has no list operation, so it's emulated with a search. You set base to the DN of the entry you want to list, scope to LDAP_SCOPE_ONELEVEL, and filter to "(objectclass=*)". attrs holds the list of attributes to return for each child entry.
4.7. Modifying an entry βοΈ
ldap_modify() and ldap_modify_s() are the routines for changing an existing LDAP entry.
typedef struct ldapmod {
int mod_op;
char *mod_type;
union {
char **modv_strvals;
struct berval **modv_bvals;
} mod_vals;
} LDAPMod;
#define mod_values mod_vals.modv_strvals
#define mod_bvalues mod_vals.modv_bvals
int ldap_modify( LDAP *ld, char *dn, LDAPMod *mods[] );
int ldap_modify_s( LDAP *ld, char *dn, LDAPMod *mods[] );
Parameters:
ld: the connection handle πdn: the name of the entry to modify πΈmods: a NULL-terminated array of modifications to make to the entry β¨
The fields in the LDAPMod structure mean the following:
mod_op: the modification operation to perform. It should be one ofLDAP_MOD_ADD,LDAP_MOD_DELETE, orLDAP_MOD_REPLACE. This field also tells you what type of values are in themod_valsunion. It is ORed withLDAP_MOD_BVALUESto select themod_bvaluesform. Otherwise, themod_valuesform is used π¦mod_type: the type of the attribute to modify πmod_vals: the values (if any) to add, delete, or replace. Only one of themod_valuesormod_bvaluesvariants should be used, selected by ORing themod_opfield with the constantLDAP_MOD_BVALUES.mod_valuesis a NULL-terminated array of zero-terminated strings, andmod_bvaluesis a NULL-terminated array of berval structures that can be used to pass binary values such as images πΌοΈ
For LDAP_MOD_ADD modifications, the given values get added to the entry, and the attribute gets created if it's needed. For LDAP_MOD_DELETE modifications, the given values get deleted from the entry, and the attribute gets removed if no values remain. If the entire attribute is to be deleted, the mod_vals field should be set to NULL. For LDAP_MOD_REPLACE modifications, the attribute will have the listed values after the modification, and it gets created if necessary. All modifications are performed in the order they're listed π
ldap_modify_s() returns the LDAP error code resulting from the modify operation. You can interpret that code with ldap_perror() and friends π§
ldap_modify() returns the message id of the request it starts, or -1 on error. You get the result of the operation by calling ldap_result() π
4.8. Modifying the RDN of an entry π·οΈ
ldap_modrdn() and ldap_modrdn_s() are how you change the name of an LDAP entry.
int ldap_modrdn(
LDAP *ld,
char *dn,
char *newrdn,
int deleteoldrdn
);
int ldap_modrdn_s(
LDAP *ld,
char *dn,
char *newrdn,
int deleteoldrdn
);
Parameters:
ld: the connection handle πdn: the name of the entry whose RDN is to be changed πΈnewrdn: the new RDN to give the entry β¨deleteoldrdn: a boolean value. If it's non-zero, the old RDN value(s) should be removed. If it's zero, the old RDN value(s) should be kept as non-distinguished values of the entry π¦
ldap_modrdn_s() is the synchronous one, and it returns the LDAP error code showing how the operation turned out π
ldap_modrdn() is asynchronous. It returns the message id of the operation it starts, or -1 if there's trouble. You get the result by calling ldap_result() π
4.9. Adding an entry β
ldap_add() and ldap_add_s() add entries to the LDAP directory.
int ldap_add( LDAP *ld, char *dn, LDAPMod *attrs[] );
int ldap_add_s( LDAP *ld, char *dn, LDAPMod *attrs[] );
Parameters:
ld: the connection handle πdn: the name of the entry to add πΈattrs: the entry's attributes, specified using the LDAPMod structure defined forldap_modify(). Themod_typeandmod_valsfields should be filled in. Themod_opfield is ignored unless it's ORed with the constantLDAP_MOD_BVALUES, which is used to select themod_bvaluescase of themod_valsunion β¨
Heads up bestie: the parent of the entry must already exist before you add it π¨
ldap_add_s() is synchronous, and it returns the LDAP error code showing the outcome of the operation π
ldap_add() is asynchronous. It returns the message id of the operation it starts, or -1 in case of trouble. You get the result of the operation by calling ldap_result() π¦
4.10. Deleting an entry ποΈ
ldap_delete() and ldap_delete_s() delete entries from the LDAP directory.
int ldap_delete( LDAP *ld, char *dn );
int ldap_delete_s( LDAP *ld, char *dn );
Parameters:
ld: the connection handle πdn: the name of the entry to delete πΈ
Note that the entry you delete must be a leaf entry (i.e., it must have no children). Deleting entire subtrees isn't supported by LDAP, so no shortcuts there π
ldap_delete_s() is synchronous, and it returns the LDAP error code showing the outcome of the operation π
ldap_delete() is asynchronous. It returns the message id of the operation it starts, or -1 in case of trouble. You get the result of the operation by calling ldap_result() π¦
5. Calls for abandoning an operation π
ldap_abandon() is how you abandon an operation that's in progress.
int ldap_abandon( LDAP *ld, int msgid );
ldap_abandon() abandons the operation with message id msgid. It returns zero if the abandon was successful, and -1 otherwise. After a successful call to ldap_abandon(), results with the given message id are never returned from a call to ldap_result() π
ββοΈβ¨
6. Calls for obtaining results β¨
Okay bestie, so ldap_result() is how you grab the result of an operation you started asynchronously π
. And ldap_msgfree() is the cleanup crew π§Ή. It frees results you got from an earlier ldap_result() call, or from a synchronous search routine.
int ldap_result(
LDAP *ld,
int msgid,
int all,
struct timeval *timeout,
LDAPMessage **res
);
int ldap_msgfree( LDAPMessage *res );
Here's the parameter rundown π:
ldThe connection handle;msgidThe message id of the operation whose results you want back, or the constantLDAP_RES_ANYif you'll take any result π¦;allA boolean that only matters for search results. If it's non-zero, all the results of a search get retrieved before any of them are returned. If it's zero, search entries come back one at a time as they arrive πΈ;timeoutHow long to wait for results. A NULL value makesldap_result()block until results are available. A timeout of zero seconds means polling π§;resForldap_result(), this is the result parameter that will hold the result(s) of the operation. Forldap_msgfree(), it's the result chain to be freed, which you got from a previous call toldap_result(),ldap_search_s()orldap_search_st()β¨.
When ldap_result() succeeds, it returns the type of the result in the res parameter π. That type is one of these constants:
LDAP_RES_BIND
LDAP_RES_SEARCH_ENTRY
LDAP_RES_SEARCH_RESULT
LDAP_RES_MODIFY
LDAP_RES_ADD
LDAP_RES_DELETE
LDAP_RES_MODRDN
LDAP_RES_COMPARE
ldap_result() returns 0 if the timeout expired, and -1 if an error happens. In that second case, the ld_errno field of the ld structure gets set accordingly π.
ldap_msgfree() frees the result structure that res points to, and it returns the type of the message it freed π«Ά.
7. Calls for error handling π
These calls help you make sense of errors that other LDAP API routines throw back at you π.
int ldap_result2error(
LDAP *ld,
LDAPMessage *res,
int freeit
);
char *ldap_err2string( int err );
void ldap_perror( LDAP *ld, char *msg );
Parameters, no cap:
ldThe connection handle;resThe result of an LDAP operation, as returned byldap_result()or by one of the synchronous API operation calls;freeitA boolean that says whetherresshould be freed (non-zero) or not (zero) π;errAn LDAP error code, as returned byldap_result2error()or by one of the synchronous API operation calls;msgA message to show before the LDAP error message.
ldap_result2error() takes the LDAP result message you got from ldap_result(), or the res returned by one of the synchronous calls, and turns it into a numeric LDAP error code π₯. It also parses the ld_matched and ld_error parts of the result message and stashes them in the connection handle information. Every synchronous operation routine calls ldap_result2error() before it returns, which is how those fields stay correct. The relevant fields in the connection structure are:
ld_matchedWhen you get anLDAP_NO_SUCH_OBJECTerror, this holds the extent of the DN that matched;ld_errorThis holds the error message the LDAP server sent in the result;ld_errnoThe LDAP error code showing the outcome of the operation. It's one of these constants:
LDAP_SUCCESS
LDAP_OPERATIONS_ERROR
LDAP_PROTOCOL_ERROR
LDAP_TIMELIMIT_EXCEEDED
LDAP_SIZELIMIT_EXCEEDED
LDAP_COMPARE_FALSE
LDAP_COMPARE_TRUE
LDAP_STRONG_AUTH_NOT_SUPPORTED
LDAP_STRONG_AUTH_REQUIRED
LDAP_NO_SUCH_ATTRIBUTE
LDAP_UNDEFINED_TYPE
LDAP_INAPPROPRIATE_MATCHING
LDAP_CONSTRAINT_VIOLATION
LDAP_TYPE_OR_VALUE_EXISTS
LDAP_INVALID_SYNTAX
LDAP_NO_SUCH_OBJECT
LDAP_ALIAS_PROBLEM
LDAP_INVALID_DN_SYNTAX
LDAP_IS_LEAF
LDAP_ALIAS_DEREF_PROBLEM
LDAP_INAPPROPRIATE_AUTH
LDAP_INVALID_CREDENTIALS
LDAP_INSUFFICIENT_ACCESS
LDAP_BUSY
LDAP_UNAVAILABLE
LDAP_UNWILLING_TO_PERFORM
LDAP_LOOP_DETECT
LDAP_NAMING_VIOLATION
LDAP_OBJECT_CLASS_VIOLATION
LDAP_NOT_ALLOWED_ON_NONLEAF
LDAP_NOT_ALLOWED_ON_RDN
LDAP_ALREADY_EXISTS
LDAP_NO_OBJECT_CLASS_MODS
LDAP_RESULTS_TOO_LARGE
LDAP_OTHER
LDAP_SERVER_DOWN
LDAP_LOCAL_ERROR
LDAP_ENCODING_ERROR
LDAP_DECODING_ERROR
LDAP_TIMEOUT
LDAP_AUTH_UNKNOWN
LDAP_FILTER_ERROR
LDAP_USER_CANCELLED
LDAP_PARAM_ERROR
LDAP_NO_MEMORY
ldap_err2string() turns a numeric LDAP error code, like one from ldap_result2error() or a synchronous call, into a readable NULL-terminated string that describes the error π. It returns a pointer to static data.
ldap_perror() prints the message you pass in msg, then shows the error from the ld_errno field of the ld connection handle, all to standard error π£.
8. Calls for parsing search entries π§
These calls parse the entries that ldap_search() and friends return π¦. The entries come back in an opaque structure, which you should only touch through the routines below. There are routines to step through the entries, step through an entry's attributes, get an entry's name, and get the values tied to a given attribute in an entry π.
8.1. Stepping through a set of entries
ldap_first_entry() and ldap_next_entry() let you step through the entries in a search result π. ldap_count_entries() counts how many entries came back.
LDAPMesage *ldap_first_entry( LDAP *ld, LDAPMessage *res );
LDAPMesage *ldap_next_entry( LDAP *ld, LDAPMessage *entry );
int ldap_count_entries( LDAP *ld, LDAPMessage *res );
Parameters:
ldThe connection handle;resThe search result, as obtained from one of the synchronous search routines or fromldap_result();entryThe entry returned by a previous call toldap_first_entry()orldap_next_entry().
ldap_first_entry() and ldap_next_entry() return NULL when there are no more entries left π. They also return NULL if an error happens while you're stepping, and then the ld_errno field of the ld connection handle gets set to show the error.
ldap_count_entries() returns how many entries are in a chain of entries. You can also call it with an entry from ldap_first_entry() or ldap_next_entry() to count the entries still left in the chain β¨.
8.2. Stepping through the attributes of an entry
ldap_first_attribute() and ldap_next_attribute() step through the list of attribute types that comes back with an entry π.
char *ldap_first_attribute(
LDAP *ld,
LDAPMessage *entry,
void **ptr
);
char *ldap_next_attribute(
LDAP *ld,
LDAPMessage *entry,
void *ptr
);
Parameters:
ldThe connection handle;entryThe entry whose attributes you want to step through, as returned byldap_first_entry()orldap_next_entry();ptrInldap_first_attribute(), this is the address of a pointer used internally to track the current position in the entry. Inldap_next_attribute(), it's the pointer returned by a previous call toldap_first_attribute()π·.
ldap_first_attribute() and ldap_next_attribute() return NULL when the attributes run out, or if there's an error. In the error case, the ld_errno field in the ld connection handle gets set to show the problem π¬.
Both routines return a pointer to a per-connection buffer that holds the current attribute name. Treat that buffer like static data π«§. ldap_first_attribute() allocates a BerElement to track the current position, and it returns a pointer to that BerElement in ptr. You pass that pointer to later calls of ldap_next_attribute() so you can keep stepping through the entry's attributes.
The attribute names returned are ready to pass to ldap_get_values() and friends, so you can grab the values that go with them π.
8.3. Retrieving the values of an attribute
ldap_get_values() and ldap_get_values_len() pull the values of a given attribute out of an entry π§. ldap_count_values() and ldap_count_values_len() count the values you got back. ldap_value_free() and ldap_value_free_len() free them.
typedef struct berval {
unsigned long bv_len;
char *bv_val;
};
char **ldap_get_values(
LDAP *ld,
LDAPMessage *entry,
char *attr
);
struct berval **ldap_get_values_len(
LDAP *ld,
LDAPMessage *entry,
char *attr
);
int ldap_count_values( char **vals );
int ldap_count_values_len( struct berval **vals );
int ldap_value_free( char **vals );
int ldap_value_free_len( struct berval **vals );
Parameters:
ldThe connection handle;entryThe entry to get values from, as returned byldap_first_entry()orldap_next_entry();attrThe attribute whose values you want. This comes fromldap_first_attribute()orldap_next_attribute(), or it can be a string you supply yourself, like "mail" π;valsThe values returned by a previous call toldap_get_values()orldap_get_values_len().
There are two forms of most of these calls π¦. The first form only works for non-binary character string data. The second _len form works with any kind of data.
Heads up, bestie: the values returned are malloc'ed, so you need to free them withldap_value_free()orldap_value_free_len()once you're done with them π«Ά.
8.4. Retrieving the name of an entry πͺͺ
okay bestie, so to get an entry's name you call ldap_get_dn() π
Then you can chop it into pieces with ldap_explode_dn(), and ldap_dn2ufn() turns it into a more "user friendly" format so people don't have to read raw DN soup π«Ά
char *ldap_get_dn( LDAP *ld, LDAPMessage *entry );
char **ldap_explode_dn( char *dn, int notypes );
char *ldap_dn2ufn( char *dn );
Here's what each parameter does β¨
ld The connection handle;
entry The entry whose name is to be retrieved, as returned by
ldap_first_entry() or ldap_next_entry();
dn The dn to explode, as returned by ldap_get_dn();
notypes A boolean parameter, if non-zero indicating that the dn com-
ponents should have their type information stripped off
(i.e., "cn=Babs" would become "Babs").
ldap_get_dn() gives you back NULL if something goes wrong while parsing the dn π When that happens it sets ld_errno in the ld connection handle so you know what went wrong. If it works, you get a pointer to malloc'ed space, and you're responsible for calling free() on it once you're done. The DN format it returns is described in [4] πΈ
ldap_explode_dn() returns a char * array holding the RDN components of your DN. Whether the type info is kept depends on notypes π¦ When you're finished with the array, free it with ldap_value_free(), not free(). Yes, it's a different function, and yes, it matters π
ldap_dn2ufn() converts the DN into the user friendly format described in [5] π§ The UFN it returns is malloc'ed too, so call free() on it when you don't need it anymore π
9. Security Considerations π
β οΈ Heads up, this one is a little scary: LDAP supports minimal security during connection authentication. Don't assume the connection is locked down just because you authenticated π
10. Acknowledgements π
This material is based upon work supported by the National Science Foundation under Grant No. NCR-9416667. Thank you, NSF, you're iconic π
11. Bibliography π
- [1] The Directory: Selected Attribute Syntaxes. CCITT, Recommendation X.520.
- [2] Howes, T., Kille, S., Yeong, W., and C. Robbins, "The String Representation of Standard Attribute Syntaxes", University of Michigan, ISODE Consortium, Performance Systems International, NeXor Ltd., RFC 1778, March 1995.
- [3] Howes, T., "A String Representation of LDAP Search Filters", RFC 1558, University of Michigan, December 1993.
- [4] Kille, S., "A String Representation of Distinguished Names", RFC 1779, ISODE Consortium, March 1995.
- [5] Kille, S., "Using the OSI Directory to Achieve User Friendly Naming", RFC 1781, ISODE Consortium, March 1995.
- [6] S.P. Miller, B.C. Neuman, J.I. Schiller, J.H. Saltzer, "Kerberos Authentication and Authorization System", MIT Project Athena Documentation Section E.2.1, December 1987
- [7] Yeong, W., Howes, T., and S. Kille, "Lightweight Directory Access Protocol," RFC 1777, Performance Systems International, University of Michigan, ISODE Consortium, March 1995.
12. Authors' Addresses π
These are the people who made it happen, so here they are, exactly as listed π«Ά
Tim Howes
University of Michigan
ITD Research Systems
535 W William St.
Ann Arbor, MI 48103-4943
USA
Phone: +1 313 747-4454
EMail: tim@umich.edu
Mark Smith
University of Michigan
ITD Research Systems
535 W William St.
Ann Arbor, MI 48103-4943
USA
Phone: +1 313 764-2277
EMail: mcs@umich.edu
13. Appendix A - Sample LDAP API Code π§βπ»
And finally, the full example, so you can see every single call working together β¨ This is the whole thing from connecting to unbinding π¦
#include <ldap.h>
main()
{
LDAP *ld;
LDAPMessage *res, *e;
int i;
char *a, *dn;
void *ptr;
char **vals;
/* open a connection */
if ( (ld = ldap_open( "dotted.host.name", LDAP_PORT ))
== NULL )
exit( 1 );
/* authenticate as nobody */
if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_simple_bind_s" );
exit( 1 );
}
/* search for entries with cn of "Babs Jensen",
return all attrs */
if ( ldap_search_s( ld, "o=University of Michigan, c=US",
LDAP_SCOPE_SUBTREE, "(cn=Babs Jensen)", NULL, 0, &res )
!= LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search_s" );
exit( 1 );
}
/* step through each entry returned */
for ( e = ldap_first_entry( ld, res ); e != NULL;
e = ldap_next_entry( ld, e ) ) {
/* print its name */
dn = ldap_get_dn( ld, e );
printf( "dn: %s0, dn );
free( dn );
/* print each attribute */
for ( a = ldap_first_attribute( ld, e, &ptr );
a != NULL;
a = ldap_next_attribute( ld, e, ptr ) ) {
printf( "attribute: %s0, a );
/* print each value */
vals = ldap_get_values( ld, e, a );
for ( i = 0; vals[i] != NULL; i++ ) {
printf( "value: %s0, vals[i] );
}
ldap_value_free( vals );
}
}
/* free the search results */
ldap_msgfree( res );
/* close and free connection resources */
ldap_unbind( ld );
}
π¦ where this page comes from
- ietf: rfc1823 1995-08
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms