o find entries in the directory, you need to specify search criteria and call one of the LDAP API search functions. These functions return a list of matching entries. You can call other API functions to iterate through each entry in the results, retrieving the values of specific attributes in each entry.
This chapter contains the following sections, which explain how to create and execute a search of the directory:
Figure 4.1: Search criteria
Simple Search Syntax
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 slapd.at.conf file for your directory server.
Table 4.1 lists the valid operators you can use.
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)
Advanced Search Syntax
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 4.2 lists the valid boolean operators you can use.
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*)
Initiating a Search
To search the directory, call the ldap_search_s(), ldap_search_st(), or ldap_search() function.
ldap_search_s() is a synchronous function that completes the search operation before returning. Call this function if you need to wait for the operation to finish before continuing.
ldap_search_s() function returns LDAP_SUCCESS if the
operation successfully completed. If an error occurred, the function returns
an error code. (See "Status Codes" for a complete listing of error codes.)
ldap_search_st() is a synchronous function that allows a certain amount of time for the completion of the search operation. Call this function if you need to wait for the operation to complete and if you want to set a timeout period for the operation.
ldap_search() is an asynchronous function that initiates the search operation but does not wait for the operation to complete. Call this function if you want to perform other work (in parallel) while waiting for the operation to complete.
ldap_search() function returns a message ID identifying the
search operation. To determine whether the operation has ended or is still
in progress, call the ldap_result() function.
After the operation is completed, call the ldap_result2error()
function to determine whether the operation was successful. If the
operation completed successfully, the ldap_result2error() function
returns LDAP_SUCCESS. If an error occurred, the function returns an error
code. (See "Status Codes" for a complete listing of error codes.)
Specifying the scope 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 the base entry and all entries at all levels below the base entry (as illustrated in Figure 4.2).
Figure 4.2: Example of a search with the scope LDAP_SCOPE_SUBTREE
LDAP_SCOPE_ONELEVEL searches all entries at one level below the base entry (as illustrated in Figure 4.3). The base 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 4.3: Example of a search with the scope LDAP_SCOPE_ONELEVEL
LDAP_SCOPE_BASE searches only the base entry. Use this setting if you just want to read the attributes of the base entry (as illustrated in Figure 4.4). (See "Reading an Entry" for an example.)
Figure 4.4: Example of a search with the scope LDAP_SCOPE_BASE
Example of a subtree search
The following example initiates a search for all entries with the last name (or surname) "Jensen" in the Ace Industry organization. The search retrieves the names and values of the cn and mail attributes.
#include <stdio.h>
#include <ldap.h>
LDAP *ld;
LDAPMessage *result;
char *my_searchbase = "o=Ace Industry, c=US";
char *my_filter = "(sn=Jensen)";
char *get_attr[] = { "cn", "mail", NULL };
/* Search the directory. */
if ( ldap_search_s( ld, my_searchbase, LDAP_SCOPE_SUBTREE, my_filter,
get_attr, 0, &result ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search_s" );
return( 1 );
}
ldap_search_s() or ldap_search_st() function to search the directory, the result parameter returns a handle to an LDAPMessage structure. This structure represents the search results.
If you use the asynchronous function ldap_search() instead, you need to call ldap_result() to get the handle to the LDAPMessage structure representing the search results.
The search results consist of a chain of entries that match the search criteria. To access individual results, you need to follow this general process:
Figure 4.5: Search results in terms of entries, attributes, and values
Getting Entries from the Results
To get the first entry in the chain of search results, call the ldap_first_entry() function. The function returns a handle to an LDAPMessage structure representing the first entry in the chain of results.
To get subsequent entries, call the ldap_next_entry() function. The function returns a handle to the LDAP message representing the next entry in the chain of results. If the function returns a NULL, there are no more entries in the chain of search results.
If you want to iterate through the entries in the chain of search results, you need to get the number of results. To get this, call the ldap_count_entries() function. The function returns the number of entries in the search results (0 if no search results found).
The following section of code retrieves each entry in a set of search results.
#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result, *e;
char *my_searchbase = "o=Ace Industry, c=US";
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 );
}
/* Check whether any results were found. */
if ( ldap_count_entries( ld, result ) == 0 ) {
printf( "No matching results found.\n" );
return( 0 );
}
/* Retrieve each entry from the search results. */
for ( e = ldap_first_entry( ld, result ); e != NULL;
e = ldap_next_entry( ld, e ) ) {
...
/* code for getting data from the entries */
...
}
/* Free the result when done. */
ldap_msgfree( result );
...
ldap_get_dn() function. The function returns the distinguished name of the entry.
When you are finished working with the distinguished name returned by this function, you should free it from memory by calling the ldap_memfree() function.
The following section of code prints the distinguished name for each entry found in a search.
#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result, *e;
char *dn;
char *my_searchbase = "o=Ace Industry, c=US";
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 );
ldap_explode_dn() and ldap_explode_rdn() functions.
Both functions return a 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.
You can specify whether or not you want the names of the components included in the array by using the notypes parameter.
ldap_explode_dn( "cn=Barbara Jensen, o=Ace Industry, c=US", 0 )The function returns this array:
{ "cn=Barbara Jensen", "o=Ace Industry", "c=US", NULL }
notypes to 1 if you don't want to include the component names in the array.
ldap_explode_dn( "cn=Barbara Jensen, o=Ace Industry, c=US", 1 )The function returns this array:
{ "Barbara Jensen", "Ace Industry", "US", NULL }
ldap_first_attribute() function.
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 ldap_get_values() or ldap_get_values_len() functions. (See "Getting the Values of an Attribute" for details.)
To get the name of the next attribute, call the ldap_next_attribute() function.
When you are finished iterating through the attributes, you need to free the BerElement structure allocated by the ldap_first_attribute() function, if the structure is not NULL. To free this structure, call the ldap_ber_free() function.
You should also free the attribute name returned by the ldap_first_attribute() function. To free the attribute name, call the ldap_memfree() function.
The following section of code retrieves each attribute of an entry.
#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a;
char *my_searchbase = "o=Ace Industry, c=US";
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 );
}
...
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.
ldap_get_values() function returns a NULL-terminated array of
strings representing the value of the attribute.
ldap_get_values_len() function.
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.
When you have finished working with the values of the attribute, you need to free the values from memory. To do this, call the ldap_value_free() or ldap_value_free_len() function.
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.
#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a;
char **vals;
char *my_searchbase = "o=Ace Industry, c=US";
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 );
}
...
The following section of code gets the first value of the jpegPhoto attribute and saves the JPEG data to a file.
#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 = "o=Ace Industry, c=US";
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 );
}
...
LDAPMessage structure. After you are done working with the search results, you should free this structure from memory.
To free the search results, call the ldap_msgfree() function. The ldap_msgfree function returns the type of the last message freed from memory.
asearch.c and search.c source files in the examples directory.
#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a, *dn;
char **vals;
char *my_searchbase = "o=Ace Industry, c=US";
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, 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 );
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.
The following section of code sorts entries by the roomNumber attribute.
#include <stdio.h>
#include <string.h>
#include <ldap.h>
...
LDAP *ld;
LDAPMessage *result;
char *my_searchbase = "o=Ace Industry, c=US";
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 );
}
...
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.
The following section of code sorts entries first by the roomNumber attribute, then by the telephoneNumber attribute.
#include <stdio.h>
#include <string.h>
#include <ldap.h>
LDAP *ld;
LDAPMessage *res;
char *my_searchbase = "o=Ace Industry, c=US";
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 );
}
ldap_sort_values() function.
In the ldap_sort_values() function, the comparison function must pass parameters of the type char **. You should use the ldap_sort_strcasecmp() function, rather than a function like strcasecmp() (which passes parameters of the type char *).
The following section of code sorts the values of attributes before printing them.
#include <stdio.h>
#include <string.h>
#include <ldap.h>
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a, *dn;
char **vals;
int i;
char *my_searchbase = "o=Ace Industry, c=US";
char *my_filter = "(sn=Jensen)";
...
if ( ( vals = ldap_get_values( ld, e, a ) ) != NULL ) {
/* Sort the values of the attribute */
if (ldap_sort_values(ld, vals, strcasecmp)) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_sort_values" );
return( 1 );
}
/* Print the values of the attribute. */
for ( i = 0; vals[i] != NULL; i++ ) {
printf( "%s: %s\n", a, vals[i] );
}
/* Free the values from memory. */
ldap_value_free( vals );
}
...
LDAP_SCOPE_BASE and specify (objectclass=*) for the search filter.
Using the LDAP_SCOPE_BASE scope to read an entry
rdentry.c source file in the examples directory.
#include <stdio.h>
#include <ldap.h>
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a, *dn;
char **vals;
char *my_searchbase = "cn=Barbara Jensen, o=Ace Industry, c=US";
char *my_filter = "(objectclass=*)";
/* Search the directory. */
if ( ldap_search_s( ld, my_searchbase, LDAP_SCOPE_BASE, 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 );
LDAP_SCOPE_ONELEVEL.
Using the LDAP_SCOPE_ONELEVEL scope to list subentries
#include <stdio.h>
#include <ldap.h>
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a, *dn;
char **vals;
char *my_searchbase = "o=Ace Industry, c=US";
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 );
...
Last modified: March 31, 1997
Copyright © 1997 Netscape
Communications Corporation