Mozilla LDAP C SDK Programmer's Guide
Chapter 6 - Searching the Directory
This chapter explains how to call the LDAP API functions to search the directory, retrieve search results, and get attributes and values from each entry in the search results. The chapter also provides examples of calling synchronous and asynchronous functions to search the directory.
This chapter contains the following sections, which explain how to create and execute a search of the directory:
- Overview: Searching with LDAP API Functions
- Sending a Search Request
- Sorting the Search Results
- Freeing the Results of a Search
- Example: Searching the Directory (Asynchronous)
- Example: Searching the Directory (Synchronous)
- Reading an Entry
- Listing Subentries
Overview: Searching with LDAP API Functions
In the LDAPv3 protocol, a server can send three different types of results back to the client:
- Directory entries found by the search.
- Any search references found within the scope of the search (a search reference is a reference to another LDAP server).
- An LDAP result code specifying the result of the search operation.
Results are represented by
LDAPMessage
structures.
Note that in order to receive search
references from LDAPv3 servers you must identify your client as an
LDAPv3 client. If you do not, the server will return the LDAP error
code LDAP_PARTIAL_RESULTS
and a set of referrals. See
"Specifying the LDAP Version of Your Client" for details.
The Mozilla LDAP C SDK provides functions that allow you to search the directory and retrieve results from the server:
-
You can send a search request by calling the synchronous function
ldap_search_ext_s()
or the asynchronous functionldap_search_ext()
.(For more information about the difference between synchronous and asynchronous functions, see "Calling Synchronous and Asynchronous Functions.")
The server sends back matching entries or search references to your client.
- If you are retrieving the results one at a time, you can call
ldap_result()
to get each result (anLDAPMessage
structure) and determine what type of result (entry or search reference) was sent from the server. -
If you are retrieving a chain of results, you can call
ldap_first_message()
andldap_next_message()
to iterate through the results in the chain.If you are just interested in entries, you can call
ldap_first_entry()
andldap_next_entry()
If you are just interested in search references, you can call
ldap_first_reference()
andldap_next_reference()
. - To get an entry from a result (an
LDAPMessage
structure), callldap_first_entry()
. - To get a search reference from a result (an
LDAPMessage
structure), callldap_parse_reference()
. - To get the LDAP result code for the search operation from a result
(an
LDAPMessage
structure), callldap_parse_result()
.
For more information, refer to the following sections in this chapter: Example: Searching the Directory (Synchronous) and Example: Searching the Directory (Asynchronous).
Sending a Search Request
To search the directory, call ldap_search_ext_s()
or ldap_search_ext()
:
ldap_search_ext_s()
is a synchronous function. This function blocks until all results have been received from the server.ldap_search_ext()
is an asynchronous function. This function sends an LDAP search request to the server. You can do other work while periodically checking to see if the server has returned any results.
These two functions are declared as follows:
LDAP_API(int) LDAP_CALL ldap_search_ext( LDAP *ld, const char *base, int scope, const char *filter, char **attrs, int attrsonly, LDAPControl **serverctrls, LDAPControl **clientctrls, struct timeval *timeoutp, int sizelimit, int *msgidp );
LDAP_API(int) LDAP_CALL ldap_search_ext_s( LDAP *ld, const char *base, int scope, const char *filter, char **attrs, int attrsonly, LDAPControl **serverctrls, LDAPControl **clientctrls, struct timeval *timeoutp, int sizelimit, LDAPMessage **res );
For either function, you specify the search criteria using the following parameters:
-
base
specifies the starting point in the directory, or the base DN (an entry where to start searching).To search entries under "
dc=example,dc=com
", the base DN is "dc=example,dc=com
". See "Specifying the Base DN and Scope" for details. -
scope
specifies the scope of the search (which entries you want to search).You can narrow the scope of the search to search only the base DN, entries at one level under the base DN, or entries at all levels under the base DN. See Specifying the Base DN and Scope for details.
-
filter
specifies a search filter (what to search for).A search filter can be as simple as "find entries where the last name is Jensen" or as complex as "find entries that belong to Dept. #17 and whose first names start with the letter F." See Specifying a Search Filter for details.
-
attrs
andattrsonly
specify the type of information that you want return (which attributes you want to retrieve) and whether you want to retrieve only the attribute type or the attribute type and its valuesFor details, see Specifying the Attributes to Retrieve.
You can also specify that you only want to return the names of attributes (and not the values) by passing a non-zero value for the
attrsonly
argument. -
serverctrls
andclientctrls
specify the LDAPv3 controls associated with this search operationFor details on LDAPv3 controls, see Chapter 14 - Working with LDAP Controls."
-
timeoutp
andsizelimit
specify the search constraints that you want applied to this search.For example, you can specify a different time-out period or maximum number of results that differ from the values of these options for the current session. See Setting Search Preferences for details.
Figure 6-1 illustrates how search criteria works.
Figure 6-1 - Search criteria for an LDAP search operation

Specifying the Base DN and Scope
When sending a search request, you need to specify the base DN and scope of the search to identify the entries that you want searched.
The base DN (the base
argument) is the DN of the
entry that serves as the starting point of the search.
To specify the scope of the search, you pass
one of the following values as the scope
parameter:
-
LDAP_SCOPE_SUBTREE
searches thebase
entry and all entries at all levels below thebase
entry (as illustrated in Figure 6-2).
Figure 6-2 - Example of a search with the scope LDAP_SCOPE_SUBTREE

-
LDAP_SCOPE_ONELEVEL
searches all entries at one level below thebase
entry (as illustrated in Figure 6-3). Thebase
entry is not included in the search. Use this setting if you just want a list of the entries under a given entry. (See "Listing Subentries" for an example.)
Figure 6-3 - Example of a search with the scope LDAP_SCOPE_ONELEVEL

-
LDAP_SCOPE_BASE
searches only thebase
entry. Use this setting if you just want to read the attributes of thebase
entry (as illustrated in Figure 6-4). (See Reading an Entry for an example.)
Figure 6-4 - Example of a search with the scope LDAP_SCOPE_BASE

Specifying a Search Filter
When you search the directory, you use a search filter to define the search. Here is the basic syntax for a search filter:
(attribute operator value)
Here is a simple example of a search filter:
(cn=Barbara Jensen)
In this example, cn
is the
attribute, =
is the operator, and
Barbara Jensen
is the value. The filter finds
entries with the common name Barbara Jensen.
For a listing of valid attributes that you can use in your search filter, see the documentation for the LDAP server you are using.
Table 6-1 lists the valid operators you can use.
Table 6-1 - Basic operators for search filters
Operator | Description | Example |
---|---|---|
= |
Returns entries whose attribute is equal to the value. | (cn=Barbara Jensen) finds the entry " cn=Barbara Jensen "
|
= |
Returns entries whose attribute is greater than or equal to the value. |
(sn >= jensen) finds all entries from " sn=jensen " to
"sn=z... "
|
<= |
Returns entries whose attribute is less than or equal to the value. |
(sn <= jensen) finds all entries from " sn=a... " to
"sn=jensen "
|
=* |
Returns entries that have a value set for that attribute. |
(sn =*) finds all entries that have the sn attribute.
|
~= |
Returns entries whose attribute value approximately matches the specified value. Typically, this is an algorithm that matches words that sound alike. |
(sn ~= jensen) finds the entry "s n = jansen "
|
Note that when comparing values containing letters, the letter
a
is less than the value z
. For example,
the following filter finds all entries with last names beginning
with a
through jensen
:
(sn<=jensen)
Using Boolean operators and parentheses, you can combine different sets of conditions. Here is the syntax for combining search filters:
( boolean_operator (filter1)(filter2)(filter3) )
Table 6-2 lists the valid Boolean operators you can use.
Table 6-2 - Boolean operators for search filters
Boolean Operator | Description |
---|---|
& |
Returns entries matching all specified filter criteria. |
| |
Returns entries matching one or more of the filter criteria. |
! |
Returns entries for which the filter is not true. You can only apply
this operator to a single filter. For example, you can use:(!(filter) but not: (!(filter1)(filter2))
|
For example, you can use this filter to
search for all entries with the last name Jensen
or the
last name Johnson
:
(|(sn=Jensen)(sn=Johnson))
You can also include wildcards to search for
entries that start with, contain, or end with a given value. For
example, you can use this filter to search for all entries whose
names begin with the letter F
:
(givenName=F*)
Specifying the Attributes to Retrieve
Using the attrs
argument, you
can either retrieve all attributes in entries returned by the
search, or you can specify the attributes that you want returned in
the search results. For example, you can specify that you want to
return the following attributes:
- To return selected attributes, pass an array of the attribute
names as the
attrs
argument. For example, to return only email addresses and phone numbers (by passing the NULL-terminated array{"mail", "telephoneNumber", NULL}
as theattrs
argument. - To return all attributes in an entry, pass
NULL
as theattrs
argument. - To return none of the attributes from an entry, pass
LDAP_NO_ATTRS
as theattrs
argument.
Note that if you plan to sort the results on your client (see Sorting the Search Results), you need to return the attributes that you plan to use for sorting. For example, if you plan to sort by email address, make sure that the mail attribute is returned in the search results.
Some attributes are used by servers for
administering the directory. For example, the creatorsName
attribute specifies the DN of the user who added the entry. These
attributes are called operational attributes.
Servers do not normally return operational
attributes in search results unless you specify the attributes by
name. For example, if you pass NULL
for the
attrs
argument to retrieve all of the attributes in
entries found by the search, the operational attribute
creatorsName
will not be returned to your client. You
need to explicitly specify the creatorsName
attribute
in the attrs
argument.
To return all attributes in an entry and
selected operational attributes, pass a NULL-terminated array
containing LDAP_ALL_USER_ATTRS
and the names of the
operational attributes as the attrs
argument.
The following table lists some of the operational attributes and the information they contain.
Table 6-3 - Information available in operational attributes
Attribute Name | Description of Values |
---|---|
createTimestamp |
The time the entry was added to the directory. |
modifyTimestamp |
The time the entry was last modified. |
creatorsName |
Distinguished name (DN) of the user who added the entry to the directory. |
modifiersName |
Distinguished name (DN) of the user who last modified the entry. |
subschemaSubentry |
Distinguished name (DN) of the subschema entry, which controls the schema for this entry. (See "Getting Schema Information" for details.) |
Setting Search Preferences
For a given search, you can specify the maximum number of results
to be returned or the maximum amount of time to wait for a search.
Use the timeoutp
and sizelimit
arguments
of the ldap_search_ext_s()
or
ldap_search_ext()
functions.
Note the following:
- To specify an infinite time limit (basically, no limit), create a
timeval
structure withtv_sec = tv_usec = 0
, and pass a pointer to this as thetimeoutp
argument. - To use the time limit specified by the
LDAP_OPT_TIMELIMIT
preference for this connection, passNULL
as thetimeoutp
argument. - To specify an infinite size limit (basically, no limit), pass
LDAP_NO_LIMIT
as thesizelimit
argument.
To specify these preferences for all searches
under the current connection, call ldap_set_option()
and set the LDAP_OPT_SIZELIMIT
and
LDAP_OPT_TIMELIMIT
options. If you do not want to
specify a limit (basically, no limit), set the value of the option
to LDAP_NO_LIMIT
.
Note that the LDAP server may already have time and size constraints set up that you cannot override.
The following example sets these session preferences so that a search returns no more than 100 entries and takes no more than 30 seconds.
Code Example 6-1 - Setting session search preferences
#include "ldap.h" ... LDAP *ld; int max_ret, max_tim; char *host = "localhost"; ... /* Initialize a session with the LDAP server ldap.example.com:389. */ if ( ( ld = ldap_init( host, LDAP_PORT ) ) == NULL ) { perror( "ldap_init" ); return( 1 ); } /* Set the maximum number of entries returned. */ max_ret = 100; ldap_set_option(ld, LDAP_OPT_SIZELIMIT, (void *)&max_ret ); /* Set the maximum number of seconds to wait. */ max_tim = 30; ldap_set_option( ld, LDAP_OPT_TIMELIMIT, (void *)&max_tim ); ...
Example of Sending a Search Request
The following example sends a search request to the server
for all entries with the last name (or surname)
"Jensen
" in the example.com
organization.
Code Example 6-2 - Sending a search request
#include <stdio.h> #include "ldap.h" ... #define BASEDN "dc=example,dc=com" #define SCOPE LDAP_SCOPE_SUBTREE #define FILTER "(sn=Jensen)" ... LDAP *ld; int msgid, rc; ... /* Send the search request. */ rc = ldap_search_ext( ld, BASEDN, SCOPE, FILTER, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid ); if ( rc != LDAP_SUCCESS ) { fprintf( stderr, "ldap_search_ext: %s\n", ldap_err2string( rc ) ); ldap_unbind( ld ); return( 1 ); } ...
Getting Search Results
In the LDAPv3 protocol, a server can return the following types of results to your client:
- Directory entries found by the search (those entries matching the search criteria).
- Any search references found within the scope of the search (a search reference is a reference to another LDAP server).
- An LDAP result code specifying the result of the search operation.
The server returns the search results as a
chain of LDAPMessage
structures. Each structure
contains an entry, a search reference, or an LDAP result code.
Because the results are represented as a chain, you should not free
individual LDAPMessage
structures within the chain.
(When you are done working with the results, you can free the chain
itself, rather than individual structures within the chain.)
To access data from entries found by the search, you need to follow this general process:
- Get each entry in the results.
- Get the attributes from each entry.
- Get the values from each attribute.
Figure 6-5 illustrates the relationship between entries, attributes, values, and search results.
This section explains how to get search results and retrieve data
from the search results. Topics covered include: If you called the You can iterate through the results in this chain by calling
different API functions. See the section
Iterating Through a Chain of
Results for details. If you use the asynchronous function You can specify how you want to get the results: If you specify either If specify To determine what type of result was returned, call the
Note that in order to receive search references from an LDAPv3
server you must identify your client as an LDAPv3 client. If you
do not, the server will return the LDAP error code
The following section of code gets results one at a time and
checks the type of result: The results of a search are represented by a chain of
To retrieve results from a chain of search
results, you can call one of the following sets of functions: Note that each If you are iterating through each result, you can determine the
type of the result by calling the Note that in order to receive search references from an LDAPv3
server you must identify your client as an LDAPv3 client. If you do
not, the server will return the LDAP error code
The following section of code retrieves each
result in a chain and determines the type of the result. Because the distinguished name of an entry
differentiates it from other entries, you may want to access the
distinguished names of entries in the search results. You may also
want to parse the name into its individual components. The LDAP API provides functions for both of
these tasks. You can call functions to get the name of an individual
entry and to split the name into its components. To get the distinguished name of an entry,
call the When you are finished working with the
distinguished name returned by this function, you should free it
from memory by calling the Code Example
6-5 prints the distinguished name for each entry found in a
search: Obtaining the distinguished names for entries returned by a
search. If you want to access individual components of a distinguished
name or a relative distinguished name, call the
Both functions return a You can specify whether or not you want the names of the
components included in the array by using the
To get the value of the first attribute in an
entry, call the This function returns the name of the first attribute in the
entry. To get the value of this attribute, you need to pass the
attribute name to the To get the name of the next attribute, call
the Note that operational attributes such as You should also free the attribute name
returned by the The following section of code retrieves each attribute of an entry: The values of an attribute are represented by a
To get the number of values in an attribute, call the
When you have finished working with the
values of the attribute, you need to free the values from memory. To
do this, call the The following section of code gets and
prints the values of an attribute in an entry. This example assumes
that all attributes have string values: The following section of code gets the first value of the
A search reference returned from the server
contains one or more referrals (LDAP URLs that identify other LDAP
servers). To get these referrals, you need to call the
The following section of code gets and prints the referrals
in a search reference: The LDAP API contains functions that you can
use to sort entries and values in the search results. You can either
sort entries on your client, or you can specify that the server
should return sorted results. To sort results on the server, you need to send a server-side
sorting control with the search request. For details, see
"Using the Server-Side Sorting
Control." The rest of this section explains how to sort
results on your client. Topics include: Note that you need to return any attributes that you plan to use
for sorting the results. For example, if you plan to sort the results
by email address, make sure that the mail attribute is one of the
attributes returned in the search. For details on specifying the
attributes returned, see "Specifying the
Attributes to Retrieve." To sort the search results by a particular attribute, call the
The following section of code sorts entries
by the To sort the search results by a particular
attribute, call the The following section of code sorts entries
first by the You can also sort the values of a particular attribute. To do
this, call the The following section of code sorts the
values of attributes before printing them. The results of the search are returned in an
To free the search results, call the
The following section of code prints out the
values of all attributes in the entries returned by a search. The following section of code prints out the
values of all attributes in the entries returned by a search. You can use the search functions to read a specific entry in the
directory. To read an entry, set the starting point of the search to
the entry, and set the scope of the search to The following section of code prints the
attributes of the entry for Barbara Jensen. You can use the search functions to list the
subentries under a specific entry in the directory. To list the
subentries, set the starting point of the search to the entry, and
set the scope of the search to The following section of code lists all
entries one level below the
Getting Results Synchronously
ldap_search_ext_s()
function to
search the directory synchronously, the function blocks until all
results have been received. The function returns a chain of the
results in the result
parameter (a handle to an
LDAPMessage
structure).Getting Results Asynchronously
ldap_search_ext()
instead, you need to call ldap_result()
to determine
if the server sent back any results:LDAP_API(int) LDAP_CALL ldap_result( LDAP *ld, int msgid, int all,
struct timeval *timeout, LDAPMessage **result );
LDAP_MSG_ONE
as the all
argument.
LDAP_MSG_ALL
as the
all
argument.
LDAP_MSG_RECEIVED
as the all
argument.
LDAP_MSG_ALL
or
LDAP_MSG_RECEIVED
, the function passes back a chain
of search results as the result
argument. For details
on how to retrieve the results from this chain, see
Iterating Through a Chain of Results.LDAP_MSG_ONE
, the function passes back
a single search result as the result
argument. The
function normally returns the type of the first search result; in
this case, since only one result is returned, the function returns
the type of that result. A search result can be one of the
following types:ldap_msgtype()
function. A search result can be one
of the following types:
LDAP_RES_SEARCH_ENTRY
indicates that the result is
an entry found in the search.
You can pass the LDAPMessage
structure representing
the entry to the ldap_get_dn()
function to get the
DN of the entry or the ldap_first_attribute()
and
ldap_next_attribute()
functions to get the attributes
of the entry.
For details, see Getting Distinguished
Names for Each Entry and Getting
Attributes from an Entry.
LDAP_RES_SEARCH_REFERENCE
indicates that the result
is a search reference found within the scope of the search.
You can pass the LDAPMessage
structure representing
the search reference to the ldap_parse_reference()
function to get the referrals (LDAP URLs) to other servers.
For details, see Getting Referrals
from Search References.
LDAP_RES_SEARCH_RESULT
indicates that the result
is the final result sent by the server to indicate the result of
the LDAP search operation.
You can pass the LDAPMessage
structure representing
the result to the ldap_parse_result()
function to
get the LDAP result code for the search operation. (For a list
of possible result codes for an LDAP search operation, see the
result code documentation for the
ldap_search_ext_s()
function.)
For details, see "Getting the
Information from an LDAPMessage Structure".
LDAP_PARTIAL_RESULTS
and a set of referrals. See
"Specifying the LDAP Version of Your Client" for details.Code Example 6-3 - Retrieving search results
#include <stdio.h>
#include "ldap.h"
...
#define BASEDN "dc=example,dc=com"
#define SCOPE LDAP_SCOPE_SUBTREE
#define FILTER "(sn=Jensen)"
...
LDAP *ld;
LDAPMessage *res;
int msgid, rc, parse_rc, finished = 0;
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
...
/* Send the LDAP search request. */
rc = ldap_search_ext( ld, BASEDN, SCOPE, FILTER, NULL, 0, NULL, NULL,
NULL, LDAP_NO_LIMIT, &msgid );
...
/* Poll the server for the results of the search operation. */
while ( !finished ) {
rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &zerotime, &res );
switch ( rc ) {
case -1:
/* An error occurred. */
...
case 0:
/* The timeout period specified by zerotime was exceeded. */
...
case LDAP_RES_SEARCH_ENTRY:
/* The server sent one of the entries found by the search. */
...
case LDAP_RES_SEARCH_REFERENCE:
/* The server sent a search reference .*/
...
case LDAP_RES_SEARCH_RESULT:
/* Parse the final result received from the server. */
...
}
...
}
...
Iterating Through a Chain of Results
LDAPMessage
structures. Each entry and search reference
is contained in an LDAPMessage
structure. The final
result code of the LDAP search operation is also contained in one of
these structures.
ldap_first_message()
and
ldap_next_message()
. Both of these functions return
a pointer to an LDAPMessage
structure that represents
an entry, search reference, or LDAP result code.
You can get the count of the results in the chain by calling
ldap_count_messages()
ldap_first_entry()
and ldap_next_entry()
.
Both of these functions return a pointer to an
LDAPMessage
structure that represents an entry.
You can get the count of the entries in the chain by calling
ldap_count_entries()
ldap_first_reference()
and
ldap_next_reference()
. Both of these functions return
a pointer to an LDAPMessage
structure that represents
a search reference.
You can get the count of the search references in the chain by
calling ldap_count_references()
LDAPMessage
structure is part of a
chain and can point to other structures in the chain. You should
not attempt to free individual LDAPMessage
structures
from memory; you may lose the rest of the results if you do this.ldap_msgtype()
function. A search result can be one of the following types:
LDAP_RES_SEARCH_ENTRY
indicates that the result is
an entry found in the search.
You can pass the LDAPMessage
structure representing
the entry to the ldap_get_dn()
function to get the
DN of the entry or the ldap_first_attribute()
and
ldap_next_attribute()
functions to get the attributes
of the entry.
For details, see Getting Distinguished
Names for Each Entry and "Getting
Attributes from an Entry."
LDAP_RES_SEARCH_REFERENCE
indicates that the result
is a search reference found within the scope of the search.
You can pass the LDAPMessage
structure representing
the search reference to the ldap_parse_reference()
function to get the referrals (LDAP URLs) to other servers.
For details, see Getting Referrals
from Search References.
LDAP_RES_SEARCH_RESULT
indicates that the result is
the final result sent by the server to indicate the result of the
LDAP search operation.
You can pass the LDAPMessage
structure representing
the result to the ldap_parse_result()
function to get
the LDAP result code for the search operation.
For details, see "Getting the
Information from an LDAP Structure."
LDAP_PARTIAL_RESULTS
and a set of referrals. See
"Specifying the LDAP Version of Your
Client" for details.Code Example 6-4 - Retrieving a chain of results
#include <stdio.h>
#include "ldap.h"
...
#define BASEDN "dc=example,dc=com"
#define SCOPE LDAP_SCOPE_SUBTREE
#define FILTER "(sn=Jensen)"
...
LDAP *ld;
LDAPMessage *res, *msg;
BerElement *ber;
char *matched_msg = NULL, *error_msg = NULL;
int rc, msgtype, num_entries = 0, num_refs = 0;
...
/* Perform the search operation. */
rc = ldap_search_ext_s( ld, BASEDN, SCOPE, FILTER, NULL, 0, NULL, NULL,
NULL, LDAP_NO_LIMIT, &res );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
if ( error_msg != NULL && *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
/* If the server cannot find an entry and
returns the portion of the DN that can find
an entry, print it out. (For details, see
"Receiving the Portion of the DN Matching an Entry.") */
if ( matched_msg != NULL && *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
ldap_unbind_s( ld );
return( 1 );
}
...
num_entries = ldap_count_entries( ld, res );
num_refs = ldap_count_references( ld, res );
...
/* Iterate through the results. */
for ( msg = ldap_first_message( ld, res ); msg != NULL;
msg = ldap_next_message( ld, msg ) ) {
/* Determine what type of message was sent from the server. */
msgtype = ldap_msgtype( msg );
switch( msgtype ) {
case LDAP_RES_SEARCH_ENTRY:
/* The result is an entry. */
...
case LDAP_RES_SEARCH_REFERENCE:
/* The result is a search reference. */
...
case LDAP_RES_SEARCH_RESULT:
/* The result is the final result sent by the server. */
...
}
...
}
...
Getting Distinguished Names for Each Entry
Getting the Distinguished Name of an Entry
ldap_get_dn()
function. The function returns
the distinguished name of the entry.ldap_memfree()
function.Code Example 6-5 - Obtaining the distinguished names for entries returned by a search
#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result, *e;
char *dn;
char *my_searchbase = "dc=example,dc=com";
char *my_filter = "(sn=Jensen)";
...
/* Search the directory. */
if ( ldap_search_s( ld, my_searchbase, LDAP_SCOPE_SUBTREE, my_filter,
NULL, 0, &result ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search_s" );
return( 1 );
}
/* For each matching entry found, print the name of the entry.*/
for ( e = ldap_first_entry( ld, result ); e != NULL;
e = ldap_next_entry( ld, e ) ) {
if ( ( dn = ldap_get_dn( ld, e ) ) != NULL ) {
printf( "dn: %s\n", dn );
/* Free the memory used for the DN when done */
ldap_memfree( dn );
}
}
/* Free the result from memory when done. */
ldap_msgfree( result );
Getting the Components of a Distinguished Name
ldap_explode_dn()
and ldap_explode_rdn()
functions.NULL
-terminated array of
the components of the distinguished name. When you are done
working with this array, you should free it by calling the
ldap_value_free()
function.notypes
parameter.
notypes
to 0
if you want to include
component names in the array:
ldap_explode_dn( "uid=bjensen, ou=People, dc=example,dc=com", 0 )
The function returns this array:
{ "uid=bjensen", "ou=People", "dc=example,dc=com", NULL }
notypes
to 1
if you don't want to
include the component names in the array:
ldap_explode_dn( "uid=bjensen, ou=People, dc=example,dc=com", 1 )
The function returns this array:
{ "bjensen", "People", "example.com", NULL }
Getting Attributes from an Entry
ldap_first_attribute()
function.ldap_get_values()
or
ldap_get_values_len()
functions. (See
Getting the Values of an Attribute
for details.)ldap_next_attribute()
function.creatorsName
and modifyTimestamp
are not normally returned in search
results unless you explicitly specify them by name in the search
request. For more information, see "Specifying
the Attributes to Retrieve."ldap_first_attribute()
function, if
the structure is not NULL
. To free this structure,
call the ldap_ber_free()
function.ldap_first_attribute()
function. To free
the attribute name, call the ldap_memfree()
function.Code Example 6-6 - Retrieving entry attributes
#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a;
char *my_searchbase = "dc=example,dc=com";
char *my_filter = "(sn=Jensen)";
...
/* Search the directory. */
if ( ldap_search_s( ld, my_searchbase, LDAP_SCOPE_SUBTREE, my_filter,
NULL, 0, &result ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search_s" );
return( 1 );
}
/* Get the first matching entry.*/
e = ldap_first_entry( ld, result );
/* Retrieve the attributes of the entry. */
for (a = ldap_first_attribute(ld, e, &ber); a != NULL;
a = ldap_next_attribute(ld, e, ber)){
...
/* Code to get and manipulate attribute values */
...
}
ldap_memfree( a );
}
/* Free the BerElement structure from memory when done. */
if ( ber != NULL ) {
ldap_ber_free( ber, 0 );
}
...
Getting the Values of an Attribute
NULL
-terminated array. The values are either a list of
strings (if the attribute contains string data, such as a name or
phone number) or a list of berval
structures (if the
attribute contains binary data, such as a JPEG file or an audio file).
ldap_get_values()
function.
The ldap_get_values()
function returns a
NULL
-terminated array of strings representing the
value of the attribute.
ldap_get_values_len()
function.
The ldap_get_values_len()
function returns a
NULL
-terminated array of berval
structures representing the value of the attribute.
ldap_count_values()
or ldap_count_values_len()
function. Both functions return the number of values in the attribute.ldap_value_free()
or
ldap_value_free_len()
function.Code Example 6-7 - Retrieving attribute values
#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a;
char **vals;
char *my_searchbase = "dc=example,dc=com";
char *my_filter = "(sn=Jensen)";
int i;
...
/* Search the directory. */
if ( ldap_search_s( ld, my_searchbase, LDAP_SCOPE_SUBTREE, my_filter,
NULL, 0, &result ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search_s" );
return( 1 );
}
/* Get the first matching entry.*/
e = ldap_first_entry( ld, result );
/* Get the first matching attribute. */
a = ldap_first_attribute( ld, e, &ber );
/* Get the values of the attribute. */
if ( ( vals = ldap_get_values( ld, e, a ) ) != NULL ) {
for ( i = 0; vals[i] != NULL; i++ ) {
/* Print the name of the attribute and each value */
printf( "%s: %s\n", a, vals[i] );
}
/* Free the attribute values from memory when done. */
ldap_value_free( vals );
}
...
jpegPhoto
attribute and saves the JPEG data to a file:Code Example 6-8 - Getting and saving the first attribute value
#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a;
struct berval photo_data;
struct berval **list_of_photos;
FILE *out;
char *my_searchbase = "dc=example,dc=com";
char *my_filter = "(sn=Jensen)";
...
/* Search the directory. */
if ( ldap_search_s( ld, my_searchbase, LDAP_SCOPE_SUBTREE, my_filter,
NULL, 0, &result ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search_s" );
return( 1 );
}
/* Get the first matching entry.*/
e = ldap_first_entry( ld, result );
/* Find the jpegPhoto attribute. */
a = ldap_first_attribute( ld, e, &ber );
while ( strcasecmp( a, "jpegphoto" ) != 0 ) {
a = ldap_next_attribute( ld, e, ber );
}
/* Get the value of the attribute. */
if ( ( list_of_photos = ldap_get_values_len( ld, e, a ) ) != NULL ) {
/* Prepare to write the JPEG data to a file */
if ( ( out = fopen( "photo.jpg", "wb" ) ) == NULL ) {
perror( "fopen" );
return( 1 );
}
/* Get the first JPEG. */
photo_data = *list_of_photos[0];
/* Write the JPEG data to a file */
fwrite( photo_data.bv_val, photo_data.bv_len, 1, out );
fclose( out );
/* Free the attribute values from memory when done. */
ldap_value_free_len( list_of_photos );
}
...
Getting Referrals from Search References
ldap_parse_reference()
function.Code Example 6-9 - Obtaining a referral
#include <stdio.h>
#include "ldap.h"
...
LDAP *ld;
LDAPMessage *msg;
char **referrals;
int i, rc, parse_rc;
...
parse_rc = ldap_parse_reference( ld, msg, &referrals, NULL, 0 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n",
ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
if ( referrals != NULL ) {
for ( i = 0; referrals[ i ] != NULL; i++ ) {
printf( "Search reference: %s\n\n", referrals[ i ] );
}
ldap_value_free( referrals );
}
...
Sorting the Search Results
Sorting Entries by an Attribute
ldap_sort_entries()
function. Note that if you don't
specify an attribute for sorting (that is, if you pass NULL
for the attr
parameter), the entries are sorted by DN.roomNumber
attribute:Code Example 6-10 - Sorting entries by attribute value
#include <string.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result;
char *my_searchbase = "dc=example,dc=com";
char *my_filter = "(sn=Jensen)";
char *sortby = "roomNumber";
...
/* Search the directory. */
if ( ldap_search_s( ld, my_searchbase, LDAP_SCOPE_SUBTREE, my_filter,
NULL, 0, &result ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search_s" );
return( 1 );
}
/* Sort the results by room number, using strcasecmp. */
if (ldap_sort_entries(ld, &result, sortby, strcasecmp) != LDAP_SUCCESS){
ldap_perror( ld, "ldap_sort_entries" );
return( 1 );
}
...
Sorting Entries by Multiple Attributes
ldap_multisort_entries()
function.
Note that if you don't specify a set of attributes for sorting (that
is, if you pass NULL
for the attr
parameter), the entries are sorted by DN.roomNumber
attribute, then by the
telephoneNumber
attribute.Code Example 6-11 - Sorting entries by multiple values
#include <stdio.h>
#include <string.h>
#include <ldap.h>
LDAP *ld;
LDAPMessage *res;
char *my_searchbase = "dc=example,dc=com";
char *my_filter = "(sn=Jensen)";
char *attrs[2];
attrs[0] = "roomNumber";
attrs[1] = "telephoneNumber";
attrs[2] = NULL;
...
/* Search the directory. */
if ( ldap_search_s( ld, my_searchbase, LDAP_SCOPE_SUBTREE, my_filter,
NULL, 0, &res ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search_s" );
return( 1 );
}
/* Sort the results, using strcasecmp. */
if (ldap_multisort_entries(ld,&res,attrs, strcasecmp) != LDAP_SUCCESS){
ldap_perror( ld, "ldap_sort_entries" );
return( 1 );
}
Sorting the Values of an Attribute
ldap_sort_values()
function.char **
. You
should use the ldap_sort_strcasecmp()
function, rather
than a function like strcasecmp()
(which passes
parameters of the type char *
).Code Example 6-12 - Sorting attribute values
#include
Freeing the Results of a Search
LDAPMessage
structure. After you are done working with
the search results, you should free this structure from memory.ldap_msgfree()
function. The ldap_msgfree()
function returns the type of the last message freed from memory.Example: Searching the Directory (Asynchronous)
Code Example 6-13 - Asynchronous searching
#include <stdio.h>
#include "ldap.h"
void do_other_work();
int global_counter = 0;
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BASEDN "dc=example,dc=com"
#define SCOPE LDAP_SCOPE_SUBTREE
#define FILTER "(sn=Jensen)"
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *res;
BerElement *ber;
LDAPControl **serverctrls;
char *a, *dn, *matched_msg = NULL, *error_msg = NULL;
char **vals, **referrals;
int version, i, msgid, rc, parse_rc, finished = 0,
num_entries = 0, num_refs = 0;
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
/* Get a handle to an LDAP connection. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
version = LDAP_VERSION3;
if ( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ) != LDAP_SUCCESS ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_set_option: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Bind to the server anonymously. */
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
ldap_get_lderrno( ld, &matched_msg, &error_msg );
if ( error_msg != NULL && *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
/* If the server cannot find an entry,
print the portion of the DN that matches
an existing entry. (For details, see
"Receiving the Portion of the DN Matching an Entry.") */
if ( matched_msg != NULL && *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
ldap_unbind_s( ld );
return( 1 );
}
/* Send the LDAP search request. */
rc = ldap_search_ext( ld, BASEDN, SCOPE, FILTER, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Poll the server for the results of the search operation.
Passing LDAP_MSG_ONE indicates that you want to receive
the entries one at a time, as they come in. If the next
entry that you retrieve is NULL, there are no more entries. */
while ( !finished ) {
rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &zerotime, &res );
/* The server can return three types of results back to the client,
and the return value of ldap_result() indicates the result type:
LDAP_RES_SEARCH_ENTRY identifies an entry found by the search,
LDAP_RES_SEARCH_REFERENCE identifies a search reference returned
by the server, and LDAP_RES_SEARCH_RESULT is the last result
sent from the server to the client after the operation completes.
You need to check for each of these types of results. */
switch ( rc ) {
case -1:
/* An error occurred. */
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
case 0:
/* The timeout period specified by zerotime was exceeded.
This means that the server has still not yet sent the
results of the search operation back to your client.
Break out of this switch statement, and continue calling
ldap_result() to poll for results. */
break;
case LDAP_RES_SEARCH_ENTRY:
/* The server sent one of the entries found by the search
operation. Print the DN, attributes, and values of the entry. */
/* Keep track of the number of entries found. */
num_entries++;
/* Get and print the DN of the entry. */
if (( dn = ldap_get_dn( ld, res )) != NULL ) {
printf( "dn: %s\n", dn );
ldap_memfree( dn );
}
/* Iterate through each attribute in the entry. */
for ( a = ldap_first_attribute( ld, res, &ber );
a != NULL; a = ldap_next_attribute( ld, res, ber ) ) {
/* Get and print all values for each attribute. */
if (( vals = ldap_get_values( ld, res, a )) != NULL ) {
for ( i = 0; vals[ i ] != NULL; i++ ) {
printf( "%s: %s\n", a, vals[ i ] );
}
ldap_value_free( vals );
}
ldap_memfree( a );
}
if ( ber != NULL ) {
ber_free( ber, 0 );
}
printf( "\n" );
ldap_msgfree( res );
break;
case LDAP_RES_SEARCH_REFERENCE:
/* The server sent a search reference encountered during the
search operation. */
/* Keep track of the number of search references returned from
the server. */
num_refs++;
/* Parse the result and print the search references.
Ideally, rather than print them out, you would follow the
references. */
parse_rc = ldap_parse_reference( ld, res, &referrals, NULL, 1 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n", ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
if ( referrals != NULL ) {
for ( i = 0; referrals[ i ] != NULL; i++ ) {
printf( "Search reference: %s\n\n", referrals[ i ] );
}
ldap_value_free( referrals );
}
break;
case LDAP_RES_SEARCH_RESULT:
/* Parse the final result received from the server. Note the last
argument is a non-zero value, which indicates that the
LDAPMessage structure will be freed when done. (No need
to call ldap_msgfree().) */
finished = 1;
parse_rc = ldap_parse_result( ld, res, &rc, &matched_msg, &error_msg, NULL, &serverctrls, 1 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n", ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Check the results of the LDAP search operation. */
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext: %s\n", ldap_err2string( rc ) );
ldap_get_lderrno( ld, &matched_msg, &error_msg );
if ( error_msg != NULL & *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
if ( matched_msg != NULL && *matched_msg != '\0' ) {
fprintf( stderr, "Part of the DN that matches an existing entry: %s\n", matched_msg );
}
} else {
printf( "Search completed successfully.\n"
"Entries found: %d\n"
"Search references returned: %d\n"
"Counted to %d while waiting for the search operation.\n",
num_entries, num_refs, global_counter );
}
break;
default:
break;
}
/* Do other work here while waiting for the search operation to complete. */
if ( !finished ) {
do_other_work();
}
}
/* Disconnect when done. */
ldap_unbind( ld );
return( 0 );
}
/*
* Perform other work while polling for results. This doesn't do anything
* useful, but it could.
*/
static void
do_other_work()
{
global_counter++;
}
Example: Searching the Directory (Synchronous)
Code Example 6-14 - Synchronous searching
#include <stdio.h>
#include "ldap.h"
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BASEDN "dc=example,dc=com"
#define SCOPE LDAP_SCOPE_SUBTREE
#define FILTER "(sn=Jensen)"
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *res, *msg;
LDAPControl **serverctrls;
BerElement *ber;
char *a, *dn, *matched_msg = NULL, *error_msg = NULL;
char **vals, **referrals;
int version, i, rc, parse_rc, msgtype, num_entries = 0,
num_refs = 0;
/* Get a handle to an LDAP connection. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
version = LDAP_VERSION3;
if ( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ) !=
LDAP_SUCCESS ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_set_option: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Bind to the server anonymously. */
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
ldap_get_lderrno( ld, &matched_msg, &error_msg );
if ( error_msg != NULL && *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
if ( matched_msg != NULL && *matched_msg != '\0' ) {
fprintf( stderr, "Part of the DN that matches an existing entry: %s\n", matched_msg );
}
ldap_unbind_s( ld );
return( 1 );
}
/* Perform the search operation. */
rc = ldap_search_ext_s( ld, BASEDN, SCOPE, FILTER, NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
if ( error_msg != NULL && *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
if ( matched_msg != NULL && *matched_msg != '\0' ) {
fprintf( stderr, "Part of the DN that matches an existing entry: %s\n", matched_msg );
}
ldap_unbind_s( ld );
return( 1 );
}
num_entries = ldap_count_entries( ld, res );
num_refs = ldap_count_references( ld, res );
/* Iterate through the results. An LDAPMessage structure sent back from
a search operation can contain either an entry found by the search,
a search reference, or the final result of the search operation. */
for ( msg = ldap_first_message( ld, res ); msg != NULL; msg = ldap_next_message( ld, msg ) ) {
/* Determine what type of message was sent from the server. */
msgtype = ldap_msgtype( msg );
switch( msgtype ) {
/* If the result was an entry found by the search, get and print the
attributes and values of the entry. */
case LDAP_RES_SEARCH_ENTRY:
/* Get and print the DN of the entry. */
if (( dn = ldap_get_dn( ld, res )) != NULL ) {
printf( "dn: %s\n", dn );
ldap_memfree( dn );
}
/* Iterate through each attribute in the entry. */
for ( a = ldap_first_attribute( ld, res, &ber );
a != NULL; a = ldap_next_attribute( ld, res, ber ) ) {
/* Get and print all values for each attribute. */
if (( vals = ldap_get_values( ld, res, a )) != NULL ) {
for ( i = 0; vals[ i ] != NULL; i++ ) {
printf( "%s: %s\n", a, vals[ i ] );
}
ldap_value_free( vals );
}
ldap_memfree( a );
}
if ( ber != NULL ) {
ber_free( ber, 0 );
}
printf( "\n" );
break;
case LDAP_RES_SEARCH_REFERENCE:
/* The server sent a search reference encountered during the
search operation. */
/* Parse the result and print the search references.
Ideally, rather than print them out, you would follow the
references. */
parse_rc = ldap_parse_reference( ld, msg, &referrals, NULL, 0 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n", ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
if ( referrals != NULL ) {
for ( i = 0; referrals[ i ] != NULL; i++ ) {
printf( "Search reference: %s\n\n", referrals[ i ] );
}
ldap_value_free( referrals );
}
break;
case LDAP_RES_SEARCH_RESULT:
/* Parse the final result received from the server. Note the last
argument is a non-zero value, which indicates that the
LDAPMessage structure will be freed when done. (No need
to call ldap_msgfree().) */
parse_rc = ldap_parse_result( ld, msg, &rc, &matched_msg, &error_msg, NULL, &serverctrls, 0 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n", ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Check the results of the LDAP search operation. */
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext: %s\n", ldap_err2string( rc ) );
if ( error_msg != NULL & *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
if ( matched_msg != NULL && *matched_msg != '\0' ) {
fprintf( stderr, "Part of the DN that matches an existing entry: %s\n", matched_msg );
}
} else {
printf( "Search completed successfully.\n"
"Entries found: %d\n"
"Search references returned: %d\n",
num_entries, num_refs );
}
break;
default:
break;
}
}
/* Disconnect when done. */
ldap_unbind( ld );
return( 0 );
}Reading an Entry
LDAP_SCOPE_BASE
and specify (objectclass=*)
for the search filter.Figure 6-6 - Using the LDAP_SCOPE_BASE scope to read an entry
Code Example 6-15 - Obtaining a specific entry
#include <stdio.h>
#include "ldap.h"
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORT_NUMBER LDAP_PORT
#define FIND_DN "uid=bjensen, ou=People, dc=example,dc=com"
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a;
char **vals;
int i, rc;
/* Get a handle to an LDAP connection. */
if ( (ld = ldap_init( HOSTNAME, PORT_NUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Bind anonymously to the LDAP server. */
if ( ( rc = ldap_simple_bind_s( ld, NULL, NULL ) ) != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
return( 1 );
}
/* Search for the entry. */
if ( ( rc = ldap_search_ext_s( ld, FIND_DN, LDAP_SCOPE_BASE, "(objectclass=*)",
NULL, 0, NULL, NULL, LDAP_NO_LIMIT, LDAP_NO_LIMIT, &result ) ) != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
return( 1 );
}
/* Since we are doing a base search, there should be only one matching entry. */
e = ldap_first_entry( ld, result );
if ( e != NULL ) {
printf( "\nFound %s:\n\n", FIND_DN );
/* Iterate through each attribute in the entry. */
for ( a = ldap_first_attribute( ld, e, &ber );
a != NULL; a = ldap_next_attribute( ld, e, ber ) ) {
/* For each attribute, print the attribute name and values. */
if ((vals = ldap_get_values( ld, e, a)) != NULL ) {
for ( i = 0; vals[i] != NULL; i++ ) {
printf( "%s: %s\n", a, vals[i] );
}
ldap_value_free( vals );
}
ldap_memfree( a );
}
if ( ber != NULL ) {
ber_free( ber, 0 );
}
}
ldap_msgfree( result );
ldap_unbind( ld );
return( 0 );
}
Listing Subentries
LDAP_SCOPE_ONELEVEL
.
Figure 6-7 - Using the LDAP_SCOPE_ONELEVEL scope to list subentries
dc=example,dc=com
entry
in the directory hierarchy.Code Example 6-16 - Listing subentries
#include <stdio.h>
#include <ldap.h>
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a, *dn;
char **vals;
char *my_searchbase = "dc=example,dc=com";
char *my_filter = "(objectclass=*)"
/* Search one level under the starting point. */
if ( ldap_search_s( ld, my_searchbase, LDAP_SCOPE_ONELEVEL, my_filter,
NULL, 0, &result ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search_s" );
return( 1 );
}
/* For each matching entry, print the entry name and its attributes. */
for ( e = ldap_first_entry( ld, result ); e != NULL;
e = ldap_next_entry( ld, e ) ) {
if ( ( dn = ldap_get_dn( ld, e ) ) != NULL ) {
printf( "dn: %s\n", dn );
ldap_memfree( dn );
}
for ( a = ldap_first_attribute( ld, e, &ber ); a != NULL;
a = ldap_next_attribute( ld, e, ber ) ) {
if ( ( vals = ldap_get_values( ld, e, a ) ) != NULL ) {
for ( i = 0; vals[i] != NULL; i++ ) {
printf( "%s: %s\n", a, vals[i] );
}
ldap_value_free( vals );
}
ldap_memfree( a );
}
if ( ber != NULL ) {
ldap_ber_free( ber, 0 );
}
printf( "\n" );
}
ldap_msgfree( result );
...