[Previous] [Next] [TOC] [Index]

Chapter 3
Writing LDAP Clients

enerally, an application follows these steps when interacting with an LDAP server:

  1. Initialize a session with the LDAP server, and set any session preferences.

  2. Authenticate itself to the LDAP server.

  3. Perform the LDAP operations.

  4. Close the connection to the LDAP server.
You can perform the operation as a synchronous or asynchronous operation. For example, to search the directory, you can call either the synchronous function ldap_search_s(), or the asynchronous function ldap_search().

This chapter explains how you can add functions to your application in order to interact with an LDAP server. The chapter also covers the differences between synchronous and asynchronous operations.

The chapter includes the following sections:

Initializing an LDAP Session

The first step in performing LDAP operations is initializing a session with an LDAP server. To initialize the LDAP session, call the ldap_init() function.

If the server is using the default port for the LDAP protocol (port 389), you can pass LDAP_PORT as the value of the port parameter.

If successful, the ldap_init() function returns a connection handle, which is a pointer to an LDAP structure containing information about the connection to the LDAP server. When you call API functions to interact with the LDAP server, you need to pass the connection handle as a parameter to the functions. (For example, when you call a function to search the directory, you need to pass the connection handle as a parameter.) The connection handle provides context for the connection.

The following section of code initializes sessions with two LDAP servers, ldap.netscape.com:389 and directory.mcom.com:20000:


#include <stdio.h>
#include <ldap.h>
...
LDAP *ld1, *ld2;

/* Specify the host name of the LDAP server. */
char *ldap_host_1 = "ldap.netscape.com";
char *ldap_host_2 = "directory.mcom.com";

/* If the LDAP server is running on the standard LDAP port (port 389), you can use LDAP_PORT to identify the port number. */
int ldap_port_1 = LDAP_PORT;
int ldap_port_2 = 20000;
...
/* Initialize the session with ldap.netscape.com:389. */
if ( ( ld1 = ldap_init( ldap_host_1, ldap_port_1 ) ) == NULL ) { 
   perror( "ldap_init" );
   return( 1 );
}
/* Initialize the session with directory.mcom.com:20000 */
if ( ( ld2 = ldap_init( ldap_host_2, ldap_port_2 ) ) == NULL ) { 
   perror( "ldap_init" );
   return( 1 );
}
... 
/* Subsequent calls use ld1 and ld2 to connect to and authenticate the client with the LDAP servers and to perform LDAP operations. */
...
After you initialize a session with an LDAP server, you can call API functions to set session options and connect and authenticate to the LDAP server. (Note that the ldap_init() function does not connect to the LDAP server right away.)

Getting and Setting Session Options

After you initialize a session with an LDAP server, you can specify preferences about the session, including these:

To get the setting for a session preference, call the ldap_get_option() function, which is described on page 199.

To apply or change the setting for a session preference, call the ldap_set_option() function, which is described on page 252.

For both functions, the option parameter can have one of the following values:
LDAP_OPT_SIZELIMIT Specifies the maximum number of entries to return in a search. See "Setting Time Limits and Size Limits for Searches" for details.
LDAP_OPT_TIMELIMIT Specifies the maximum number of seconds to spend on a search. See "Setting Time Limits and Size Limits for Searches" for details.
LDAP_OPT_DEREF Specifies how aliases are handled during a search. See "Handling Aliases" for details.
LDAP_OPT_REFERRALS Specifies whether or not the client follows referrals from the LDAP server. See "Handling Referrals" for details.
LDAP_OPT_REFERRAL_HOP_LIMIT Specifies the maximum number of referrals in a sequence that the client can follow. See "Handling Referrals" for details.
LDAP_OPT_IO_FN_PTRS Allows you to use alternate communication stacks. See the description of the ldap_io_fns structure for details.
LDAP_OPT_THREAD_FN_PTRS Allows you to use threads. See "Using Threads" for details.
LDAP_OPT_DESC (ldap_get_option() only) Allows you to get the socket descriptor for the connection with the LDAP server. The data type of the *optdata parameter is LBER_SOCKET, which depends on the type of platform that you are using:
LDAP_OPT_SSL Allows you to specify whether or not SSL is enabled. See "Alternative Method for Connecting Over SSL" for details.

The next sections describe these options in more detail.

Setting Time Limits and Size Limits for Searches

To specify the maximum number of entries returned in a search, call ldap_set_option() and pass LDAP_OPT_SIZELIMIT as the value of the option parameter. To specify the maximum number of seconds spent on a search, call ldap_set_option() and pass LDAP_OPT_TIMELIMIT as the value of the option parameter.

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.


#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
int max_ret, max_tim;
char *host = "ldap.netscape.com";
...
/* Initialize a session with the LDAP server ldap.netscape.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;
if (ldap_set_option(ld, LDAP_OPT_SIZELIMIT, 
      (void *)&max_ret) != LDAP_SUCCESS){
   ldap_perror( ld, "ldap_set_option" );
   return( 1 );
}

/* Set the maximum number of seconds to wait. */
max_tim = 30;
if (ldap_set_option( ld, LDAP_OPT_TIMELIMIT, 
         (void *)&max_tim) != LDAP_SUCCESS) {
   ldap_perror( ld, "ldap_set_option" );
   return( 1 );
}
...

Handling Aliases

To specify how aliases are handled when searching the directory, call ldap_set_option() and pass LDAP_OPT_DEREF as the value of the option parameter. Use the optdata parameter to specify the method for handling aliases.

You can pass one of the following values to the optdata parameter:
LDAP_DEREF_NEVER Specifies that aliases are never dereferenced.
LDAP_DEREF_FINDING Specifies that aliases are dereferenced when finding the starting point for the search (but not when searching under that starting entry).
LDAP_DEREF_SEARCHING Specifies that aliases are dereferenced when searching the entries beneath the starting point of the search (but not when finding the starting entry).
LDAP_DEREF_ALWAYS Specifies that aliases are always dereferenced (both when finding the starting point for the search and when searching under that starting entry).

This example sets up the session so that aliases are always dereferenced.


#include <stdio.h>
#include <ldap.h>
LDAP *ld;
int deref = LDAP_DEREF_ALWAYS;
char *host = "ldap.netscape.com";
/* Initialize a session with the LDAP server ldap.netscape.com:389. */
if ( ( ld = ldap_init( host, LDAP_PORT ) ) == NULL ) { 
   perror( "ldap_init" );
   return( 1 );
}
/* Always dereference aliases. */
if (ldap_set_option(ld,LDAP_OPT_DEREF,(void *)&deref) != LDAP_SUCCESS){
   ldap_perror( ld, "ldap_set_option" );
   return( 1 );
}

Handling Referrals

If you send a request for an entry that an LDAP server does not contain, the server may refer you to another LDAP server. By default, clients built with the LDAP API automatically follow these referrals to other servers.

To change the way referrals are handled, call the ldap_set_option() function and pass LDAP_OPT_REFERRALS as the value of the option parameter.

Note that both LDAP_OPT_OFF and LDAP_OPT_ON are already cast to (void *). You can pass these parameters directly to the function (see the example below).

If you set up the client to automatically handle referrals, you can specify the maximum number of referral hops that should be followed in a sequence of referrals. (For example, suppose you set a limit of 1 referral hop. If your client is referred to another LDAP server which in turn refers you to yet another LDAP server, the client will not follow the second referral.)

To set this limit, pass LDAP_OPT_REFERRAL_HOP_LIMIT as the value of the option parameter and pass the maximum number of hops as value of the optdata parameter.

The following example prevents the client from automatically following referrals to other LDAP servers.


#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
int refer;
char *host = "ldap.netscape.com";
...
/* Initialize a session with the LDAP server ldap.netscape.com:389. */
if ( ( ld = ldap_init( host, LDAP_PORT ) ) == NULL ) { 
   perror( "ldap_init" );
   return( 1 );
}

/* Never follow referrals. */
if (ldap_set_option(ld,LDAP_OPT_REFERRALS,LDAP_OPT_OFF)!=LDAP_SUCCESS){
   ldap_perror( ld, "ldap_set_option" );
   return( 1 );
}
...

Using Threads

To write a multithreaded LDAP client, you need to specify the functions that need to be called to lock and unlock critical sections of code and to get and set errors.

Use the ldap_thread_fns structure to specify pointers to the functions that need to be called. For details on setting up this structure, see the section "Writing Multithreaded Clients".

Initializing a Session Over SSL

The Directory SDK includes functions to enable your application to connect to an LDAP server over a Secure Sockets Layer (SSL). The primary goal of the SSL Protocol is to provide privacy and reliability between two communicating applications.

SSL is only supported by some LDAP servers. The Netscape Enterprise server only supports SSL 3.0. In addition, this SDK only supports server authentication and encryption; client authentication is not currently supported.

For more information on SSL, see the following resources:

For details on how to prepare your application to call LDAP SSL functions and connect to a secure LDAP server, see the release notes provided with the SDK.

Enabling Your Client to Connect Over SSL

To connect to an LDAP server using SSL, you need to:

  1. initialize your client (call the ldapssl_client_init() function)

  2. initialize an LDAP session with the secure server (call the ldapssl_init() function)
Note that you need to initialize your client before initializing the LDAP session. The process of initializing the client opens the certificate database.

The following example prepares a client to connect to a secure LDAP server over SSL.


if ( ldapssl_client_init( "/u/mozilla/.netscape/cert5.db", NULL ) < 0) { 
   printf( "Failed to initialize SSL client...\n" ); 
   return( 1 ); 
} 
/* get a handle to an LDAP connection */ 
if ( (ld = ldapssl_init( "cert.netscape.com", LDAPS_PORT, 1 )) == NULL { 
   perror( "ldapssl_init" ); 
   return( 1 ); 
} 
...
/* Client can now perform LDAP operations on the secure LDAP server */
...

Alternative Method for Connecting Over SSL

As an alternative to calling the ldapssl_init() function, you can do the following:

  1. initialize an LDAP session with the server (call the standard ldap_init() function)

  2. load the SSL I/O routines (call the ldapssl_install_routines() function)

  3. set the option in the LDAP struct for using SSL (call the standard ldap_set_option() function)
The effect of calling these three functions is the same as calling the ldapssl_init() function.

Note that you need to initialize your client before initializing the LDAP session. The process of initializing the client opens the certificate database.

The following example prepares a client to connect to a secure LDAP server over SSL.


if ( ldapssl_client_init( "/u/mozilla/.netscape/cert5.db", NULL ) < 0) { 
   printf( "Failed to initialize SSL client...\n" ); 
   return( 1 ); 
} 
/* get a handle to an LDAP connection */ 
if ( (ld = ldapssl_init( "cert.netscape.com", LDAPS_PORT, 1 )) == NULL { 
   perror( "ldapssl_init" ); 
   return( 1 ); 
} 
/* Initialize LDAP session */
if ( (ld = ldap_init( MY_HOST, LDAPS_PORT )) == NULL ) { 
   perror( "ldap_init" ); 
   return( 1 ); 
} 

/* Load SSL routines */ 
if ( ldapssl_install_routines( ld ) != LDAP_SUCCESS ) { 
   ldap_perror( ld, "ldapssl_install_routines" ); 
   return( 1 ); 
} 
/* Set up option in LDAP struct for using SSL */
if ( ldap_set_option( ld, LDAP_OPT_SSL, LDAP_OPT_ON ) != LDAP_SUCCESS) { 
   ldap_perror( ld, "ldap_set_option" ); 
   return( 1 ); 
} 
/* Client can now perform LDAP operations on the secure LDAP server */
...

Authenticating the client to an LDAP Server

Before you perform any LDAP operations, you need to authenticate the client to the LDAP server.

In either case, to authenticate to the server, you must call one of the following functions:

(For more information about the difference between synchronous and asynchronous functions, see "Synchronous and Asynchronous Functions".)

Performing a Synchronous Authentication Operation

If you want to wait for the authentication process to complete before continuing, call the ldap_simple_bind_s() function. The ldap_simple_bind_s() function returns LDAP_SUCCESS if the operation successfully completed or an error code if a problem occurred. (See "Status Codes" for a complete listing.)

The following section of code uses the synchronous ldap_simple_bind_s() function to authenticate the user Barbara Jensen to the LDAP server. (For an example of anonymous authentication, see "Authenticating as an Anonymous User".)


#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
char *host = "ldap.netscape.com";
char *dn = "cn=Barbara Jensen, ou=New Department, o=Ace Industry, c=US";
char *pw = "23skidoo";
...
/* Initialize a session with the LDAP server ldap.netscape.com:389. */
if ( ( ld = ldap_init( host, LDAP_PORT ) ) == NULL ) { 
   perror( "ldap_init" );
   return( 1 );
}
/* Attempt authentication. */
if ( ldap_simple_bind_s( ld, dn, pw ) != LDAP_SUCCESS ) {
   ldap_perror( ld, "ldap_simple_bind_s" );
   return( 1 );
}
...

Performing an Asynchronous Authentication Operation

If you want to perform other work (in parallel) while waiting for the authentication process to complete, call the ldap_simple_bind() function. The ldap_simple_bind() function returns a message ID identifying the authentication operation. To determine whether the operation has completed or is still in progress, call the ldap_result() function.

After the operation is completed, call the ldap_result2error() function to determine if the operation was successful. The ldap_result2error() function returns LDAP_SUCCESS if the operation completed successfully or an error code if a problem occurred. (See "Status Codes" for a complete listing.)

The following section of code uses the asynchronous ldap_simple_bind() function to authenticate the user Barbara Jensen to the LDAP server. (For an example of anonymous authentication, see "Authenticating as an Anonymous User".)


#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
char *host = "ldap.netscape.com";
char *dn = "cn=Barbara Jensen, ou=New Department, o=Ace Industry, c=US";
char *pw = "23skidoo";
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
...
/* Initialize a session with the LDAP server ldap.netscape.com:389. */
if ( ( ld = ldap_init( host, LDAP_PORT ) ) == NULL ) { 
   perror( "ldap_init" );
   return( 1 );
}
/* Attempt authentication. */
msgid = ldap_simple_bind( ld, dn, pw ); 

/* Initialize the value returned by ldap_result(). */
rc = 0;

/* While the operation is still running, do this: */
while ( rc == 0 ) {
   ... /* Do other work while waiting. */...
   
   /* Check the status of the LDAP operation. */
   rc = ldap_result( ld, msgid, NULL, &zerotime, &result );
   switch( rc ) {

      /* If -1 was returned, an error occurred. */
      case -1:
         ldap_perror( ld, "ldap_result" );
         return( 1 );

      /* If 0 was returned, the operation is still in progress. */
      case 0:
         continue;

      /* If any other value is returned, assume we are done. */
      default:
         /* Check if the authentication operation was successful. */
         if ( ldap_result2error( result ) != LDAP_SUCCESS ) {
            ldap_perror( ld, "ldap_simple_bind" );
            return( 1 );
            }
   }
}

Authenticating as an Anonymous User

In some cases, you might not want to pass a specific name and password to the LDAP server for authentication. For example, if you are writing a client to search the directory (and if users don't need special access permissions to search), you might not need to authenticate users to the LDAP server before searching.

To provide anonymous authentication (in which the user does not specify a name and password), pass NULL values for the who and passwd parameters.

The following section of code uses the synchronous ldap_simple_bind_s() function to authenticate an anonymous user to the LDAP server. No user or password is specified, so NULL values are passed to the who and passwd parameters.


#include <stdio.h>
#include <ldap.h>
...
LDAP *ld;
char *host = "ldap.netscape.com";
...
/* Initialize a session with the LDAP server ldap.netscape.com:389. */
if ( ( ld = ldap_init( host, LDAP_PORT ) ) == NULL ) { 
   perror( "ldap_init" );
   return( 1 );
}
/* Attempt authentication. */
if ( ldap_simple_bind_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
   ldap_perror( ld, "ldap_simple_bind_s" );
   return( 1 );
}
...

Reauthentication When Clients Are Referred to Other Servers

If the session is set up so that referrals are always followed (see "Handling Referrals" for more information), clients might be referred to other LDAP servers. During this process, the clients need to go through the authentication process again with the new server.

By default, the reauthentication is done anonymously (the name and password are not sent to the new server for authentication). If you want to authenticate a specific user, you need to set up your own function for getting the name and password to use for authentication.

You need to write a function that has the following prototype:


int rebindproc( LDAP *ld, char **dnp, char **passwdp, int *authmethodp, int freeit, void *arg );
The parameters for this prototype are described below:
Parameter Name Description
ld

The connection handle to the LDAP server.
dnp

A pointer to the distinguished name of the user (or entity) who wants to perform the LDAP operations. Your function needs to set this value.
passwdp

A pointer to the user's (or entity's) password. Your function needs to set this value.
authmethodp

A pointer to the method of authentication. Your function needs to set this value. Currently, LDAP_AUTH_SIMPLE is the only supported method of authentication.
freeit

Specifies whether or not to free the memory allocated by the previous rebindproc() function call (in the event that this function is called more than once). If freeit is set to a non-zero value, your function should free the memory allocated by the previous call.
arg

A pointer to data that can be passed to your function.

Once you have a function that follows this prototype, you need to call the LDAP API function ldap_set_rebind_proc() so that your function is called during referrals.

Performing LDAP Operations

Once you initialize a session with an LDAP server and complete the authentication process, you can perform LDAP operations, such as searching the directory, adding new entries, updating existing entries, and removing entries (provided the server's access control allows these operations).

To perform LDAP operations, call these API functions:

Most LDAP operations can be performed synchronously or asynchronously. The functions with names ending in _s are synchronous functions, and the remaining functions are asynchronous functions. (For more information on the distinction between calling synchronous and asynchronous functions, see "Synchronous and Asynchronous Functions".)

Closing the Connection to the Server

When you have finished performing all necessary LDAP operations, you need to close the connection to the LDAP server.

To close a connection to an LDAP server, call one of the following functions:

ldap_unbind() and ldap_unbind_s() are both synchronous functions. These functions are identical; they use different names so that each authentication function (ldap_simple_bind() and ldap_simple_bind_s()) has a corresponding function for closing the server connection.

After you close the connection, you can no longer use the LDAP structure. The LDAP structure is freed from memory.

The following code closes the current connection with the LDAP server:


#include <ldap.h>
...
LDAP *ld;
...
/* After completing your LDAP operations with the server, close the connection. */ 
if ( ldap_unbind( ld ) != LDAP_SUCCESS ) {
   ldap_perror( ld, "ldap_unbind" );
   return( 1 );
...

Freeing Memory

Several API functions allocate memory when called. When you have finished working with the data in memory, you should free the memory.

Table 3.1 lists some of the API functions that allocate memory and the corresponding functions that you must call to free the memory.
Table 3.1: API functions that allocate and free memory
Function allocating memory Type of data allocated Function to free memory
ldap_result(), ldap_search_s(), ldap_search_st() LDAPMessage ldap_msgfree()
ldap_first_attribute() BerElement ldap_ber_free()
ldap_get_values() char ** ldap_value_free()
ldap_get_values_len() struct berval ** ldap_value_free_len()
ldap_friendly_name() FriendlyMap ldap_free_friendlymap()
ldap_url_parse() LDAPURLDesc ldap_free_urldesc()
ldap_init_getfilter(), ldap_init_getfilter_buf() LDAPFiltDesc ldap_getfilter_free()
malloc( ) LDAPMod ** ldap_mods_free()

To free memory allocated by other API functions, call the ldap_memfree() function.

This example frees the memory allocated by the ldap_get_dn() function.


#include <ldap.h>
LDAP *ld;
char *dn;
LDAPMessage *entry;
/* Get the distinguished name (DN) for an entry. */
dn = ldap_get_dn( ld, entry );
/* When you are done working with the DN, free the DN from memory. */
ldap_memfree( dn );

Checking for Errors

If the function fails to perform an LDAP operation, you can use the connection handle to get more information about the error that occurred. For example, you can get the following information:

You can also set up your own error codes to be retrieved through the connection handle (in the same way that the standard error codes can be retrieved).

Printing Out Error Messages

To print out the error message describing the last error that occurred, call the ldap_perror() function. The ldap_perror() function uses the connection handle to retrieve and print the error message for the last operation performed.

This example prints a message if a function fails to delete an entry in the server.


#include <ldap.h>
LDAP *ld;
char *dn = "cn=Barbara Jensen, o=Ace Industry, c=US";
...
if ( ldap_delete_s( ld, dn ) != LDAP_SUCCESS ) {
   ldap_perror( ld, "ldap_delete_s" );
   return( 1 );
}
...
In the preceding example, the client prints out this error message if it does not have access permissions to delete the entry:


ldap_delete_s: Insufficient access

Getting Information About the Error

If you want to access the error code, error message, or the extent of a distinguished name that could not be matched, call the ldap_get_lderrno() function. The function returns the error code of the last error that occurred.

The following section of code attempts to add a new user to the directory. If components of the user's distinguished name do not exist (components other than the user's common name), matched is set to the portion of the distinguished name that matched. errmsg is set to the error message corresponding to the error code returned.


#include <ldap.h>
LDAP *ld;
char *dn = "cn=Barbara Jensen, ou=New Department, o=Ace Industry, c=US";
LDAPMod **list_of_attrs;
char *matched;
char *errmsg
if ( ldap_add_s( ld, dn, list_of_attrs ) != LDAP_SUCCESS ) {
   ldap_get_lderrno( ld, &matched, &errmsg );
   return( 1 );
}
...
In the preceding example, matched is set to this value if no organizational unit named New Department exists:


o=Ace Industry, c=US
errmsg is set to this value if no organizational unit named New Department exists:


No such object
If you do not need to use the parameters returned by the ldap_get_lderrno() function, set the parameters to a NULL value. For example, if you do not need to get the matched parameter, pass a NULL value for the parameter.


ldap_get_lderrno( ld, NULL, &errmsg );

Converting an Error Code to an Error Message

If you have an error code and want to retrieve its corresponding error message, call the ldap_err2string() function. The function returns a pointer to the error message.

The following section of code sets errmsg to the error message corresponding to the error code returned by the ldap_simple_bind_s() function.


#include <ldap.h>
...
LDAP *ld;
char *dn = "cn=Barbara Jensen, o=Ace Industry, c=US";
char *pw = "23skidoo";
char *errmsg;
...
errmsg = ldap_err2string( ldap_simple_bind_s( ld, dn, pw ) );
...

Setting error codes

The error code and error information are specified in the opaque LDAP structure (which is identified by the connection handle that you pass to LDAP API functions). When an LDAP operation is performed, the error information from the operation is set in the LDAP structure. This error information is accessible through the ldap_perror() and ldap_get_lderrno() functions.

If you want to set error codes and error information in the LDAP structure, call the ldap_set_lderrno() function.

The following section of code attempts to perform an operation that you've defined. If the operation fails, the LDAP_PARAM_ERROR error code is placed in the LDAP structure.


#include <ldap.h>
LDAP *ld;
char *errmsg = "Invalid parameter";
if ( ldap_my_function() != LDAP_SUCCESS ) {
   ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, errmsg );
   return( 1 );
}

Synchronous and Asynchronous Functions

You can call synchronous or asynchronous functions to perform operations on the LDAP server. In general, the synchronous functions have names ending with the characters _s (for example, ldap_search_s()).

Calling Synchronous Functions

When you call a synchronous function, your client waits for the operation to complete before executing any subsequent lines of code. Synchronous functions return LDAP_SUCCESS if successful and an LDAP error code if not successful. (For a list of LDAP error codes and their corresponding error messages, see "Status Codes".)

This example calls a synchronous function to delete an entry in the directory.


/ * Delete an entry and wait for the operation to complete. */
if ( ldap_delete_s( ld, dn ) != LDAP_SUCCESS ) {
   ldap_perror( ld, "ldap_delete_s" );
   return( 1 );
}
To see additional sample programs that call synchronous functions, see the source files in the examples directory of the Netscape Enterprise server.

Calling Asynchronous Functions

When you call an asynchronous function, your client does not need to wait for the operation to complete. The client can continue performing other tasks (such as initiating other LDAP operations) while the LDAP operation is executing.

An asynchronous function returns a unique message ID that identifies the operation being performed. You can pass this message ID to the ldap_result() function to check the status of the LDAP operation.

To see sample programs that call synchronous functions see the source files in the examples directory of the Netscape Enterprise server.

Checking the Status of the LDAP Operation

To check the status of the LDAP operation and retrieve any results, call the ldap_result() function, and pass the message ID as a parameter. The ldap_result() function returns one of the following values:

The result parameter is a pointer to an LDAPMessage structure. Part of the information stored in this structure is the error code returned by the LDAP operation.

For an example of calling the ldap_result() function, see "Example of Calling an Asynchronous Function".

Determining Whether the Operation Was Successful

To determine whether or not the LDAP operation completed successfully, you need to get the error code from the LDAPMessage structure.

To get the error code, call the ldap_result2error() function. Most operations that complete successfully generate an LDAP_SUCCESS status code. You can check for this value to determine if the operation completed successfully.

For an example of calling the ldap_result2error() function, see "Example of Calling an Asynchronous Function".

Canceling an Operation in Progress

If you need to cancel the LDAP operation, call the ldap_abandon() function. The function returns LDAP_SUCCESS if successful or a -1 value if an error occurs. Once you cancel an LDAP operation, you cannot retrieve the results of that operation. (In other words, calling ldap_result() does not return any results.)

Example of Calling an Asynchronous Function

The following section of code calls an asynchronous function to delete an entry in the directory. The code calls ldap_result() within a loop to poll the results of the LDAP delete operation.


...
/* Delete an entry in the directory and wait for the operation to complete. */
msgid = ldap_delete( ld, dn ); 

/* Initialize the value returned by ldap_result(). */
rc = 0;

/* While the operation is still running, do this: */
while ( rc == 0 ) {
   ... 
   /* Do other work while waiting. */
   ...
   
   /* Check the status of the LDAP operation. */
   rc = ldap_result( ld, msgid, NULL, &zerotime, &result );
   switch( rc ) {

      /* If -1 is returned, an error occurred. */
      case -1:
         ldap_perror( ld, "ldap_result" );
         return( 1 );

      /* If 0 is returned, the operation is still in progress. */
      case 0:
         continue;

      /* If any other value is returned, assume you are done. */
      default:
         /* Check whether the delete operation was successful. */
         if ( ldap_result2error( result ) != LDAP_SUCCESS ) {
            ldap_perror( ld, "ldap_delete" );
            return( 1 );
         }
   }
}
...

A Simple Example

The following is the source code for a program that retrieves the full name, last name, email address, and telephone number of Barbara Jensen. You can find this program in the getattr.c file in the examples directory.


#define MY_HOST "localhost"
#define MY_PORT LDAP_PORT
#define ENTRYDN "cn=Barbara Jensen, ou=Product Development, o=Ace Industry, c=US"
int main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *result, *e;
char **vals, *attrs[ 5 ];
int i;

/* Get a handle to an LDAP connection. */
if ( (ld = ldap_init( MY_HOST, MY_PORT )) == NULL ) {
   perror( "ldap_init" );
   return( 1 );
}

attrs[ 0 ] = "cn"; /* Get common name(s) (full name) */
attrs[ 1 ] = "sn"; /* Get surname(s) (last name) */
attrs[ 2 ] = "mail"; /* Get email address(es) */
attrs[ 3 ] = "telephonenumber"; /* Get telephone number(s) */
attrs[ 4 ] = NULL;
if ( ldap_search_s( ld, ENTRYDN, LDAP_SCOPE_BASE,
      "(objectclass=*)", attrs, 0, &result ) != LDAP_SUCCESS ) {
   ldap_perror( ld, "ldap_search_s" );
   return( 1 );
}
/* Print out the entry. */
if (( e = ldap_first_entry( ld, result )) != NULL ) {
   if (( vals = ldap_get_values( ld, e, "cn" )) != NULL ) {
      printf( "Full name:\n" );
      for ( i = 0; vals[i] != NULL; i++ ) {
         printf( "\t%s\n", vals[i] );
      }
      ldap_value_free( vals );
   }
   if (( vals = ldap_get_values( ld, e, "sn" )) != NULL ) {
      printf( "Last name (surname):\n" );
      for ( i = 0; vals[i] != NULL; i++ ) {
         printf( "\t%s\n", vals[i] );
      }
      ldap_value_free( vals );
   }
   if (( vals = ldap_get_values( ld, e, "mail" )) != NULL ) {
      printf( "Email address:\n" );
      for ( i = 0; vals[i] != NULL; i++ ) {
         printf( "\t%s\n", vals[i] );
      }
      ldap_value_free( vals );
   }
   if ((vals = ldap_get_values( ld, e, "telephonenumber" )) != NULL) {
      printf( "Telephone number:\n" );
      for ( i = 0; vals[i] != NULL; i++ ) {
         printf( "\t%s\n", vals[i] );
      }
      ldap_value_free( vals );
   }
}
ldap_msgfree( result );
ldap_unbind( ld );
return( 0 );
}


[Previous] [Next] [TOC] [Index]

Last modified: March 31, 1997
Copyright © 1997 Netscape Communications Corporation