enerally, an application follows these steps when interacting with an LDAP server:
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:
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.)
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:
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 );
}
...
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: 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 );
}
ldap_set_option() function and pass LDAP_OPT_REFERRALS as the value of the option parameter.
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 );
}
...
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:
ldapssl_client_init() function)
ldapssl_init() function)
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 */
...
ldapssl_init() function, you can do the following:
ldap_init() function)
ldapssl_install_routines() function)
LDAP struct for using SSL (call the standard ldap_set_option() function)
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 */
...
ldap_simple_bind_s() function (see "Performing a Synchronous Authentication Operation")
ldap_simple_bind() function (see "Performing an Asynchronous Authentication Operation")
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 );
}
...
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 );
}
}
}
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 );
}
...
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:
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:
ldap_search() and ldap_search_s() search for matching entries in the directory (see "Searching the Directory" for details).
ldap_compare() and ldap_compare_s() determine whether an attribute contains a certain value (see "Comparing the Value of an Attribute" for details).
ldap_add() and ldap_add_s() add entries to the directory (see "Adding a New Entry" for details).
ldap_modify() and ldap_modify_s() update entries in the directory (see "Modifying an Existing Entry" for details).
ldap_delete() and ldap_delete_s() delete entries from the directory (see "Deleting an Entry" for details).
ldap_modrdn2() and ldap_modrdn2_s() rename entries in the directory (see "Changing the Name of an Entry" for details).
_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 );
...
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 );
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
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 objectIf 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 );
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 ) ); ...
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 );
}
_s (for example, ldap_search_s()).
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.
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.
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 );
}
}
}
...
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 );
}
Last modified: March 31, 1997
Copyright © 1997 Netscape
Communications Corporation