richm%stanfordalumni.org dd758b072f initial import of docbook contribution from Sun
git-svn-id: svn://10.0.0.236/trunk@228382 18797224-902f-48f8-a5cc-f745e15eee43
2007-06-20 14:26:52 +00:00

769 lines
33 KiB
Plaintext

<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-client"><title>Writing an LDAP Client With &DirectorySDKForC;</title>
<highlights>
<para>With &DirectorySDKForC;, you can write a new application. You can
also enable an existing application to interact with a Lightweight Directory
Access Protocol (LDAP) server. This chapter explains how to connect to an
LDAP server, authenticate, request operations, and disconnect from the server.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdacb">Designing an LDAP Client With Directory
SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdacc">Initializing an LDAP Session With
Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdacj">Binding and Authenticating to an
LDAP Server With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdacs">Performing LDAP Operations With Directory
SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdact">Closing the Connection to an LDAP
Server With Directory SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdacb"><title>Designing an LDAP Client With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>designing LDAP client</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>designing with C SDK</secondary>
</indexterm>
<para>The following procedure outlines a typical process for communicating
with an LDAP server.</para>
<task><title>To Communicate With an LDAP Server</title>
<procedure>
<step><para>Initialize an LDAP session.</para><para>See <olink targetptr="bdacc">
Initializing an LDAP Session With Directory SDK for C</olink> for details.</para>
</step>
<step><para>Bind to the LDAP server, if necessary.</para><para>See <olink targetptr="bdacj">Binding and Authenticating to an LDAP Server With Directory
SDK for C</olink> for details.</para></step>
<step><para>Perform LDAP operations, such as searching the directory or modifying
entries in the directory.</para><para>See <olink targetptr="bdacs">Performing
LDAP Operations With Directory SDK for C</olink> for details.</para></step>
<step><para>Close the connection to the LDAP server when finished.</para><para>See <olink targetptr="bdact">Closing the Connection to an LDAP Server With Directory
SDK for C</olink> for details.</para></step>
</procedure>
<example id="csdk-search-example">
<title>Performing an LDAP Search</title>
<indexterm>
<primary>example programs</primary>
<secondary>LDAP search</secondary>
</indexterm>
<para>This sample source code shows a client that requests an LDAP search
operation from a server. The LDAP server runs on the local system on port <literal>
389</literal>. The client searches the directory for entries with the last
name <literal>Jensen</literal> (<literal>sn=Jensen</literal>), and prints
the distinguished name (DN) of any matching entry.</para>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
/* Specify the search criteria here. */
#define HOSTNAME "localhost"
#define PORTNUMBER 389
#define BASEDN "dc=example,dc=com"
#define SCOPE LDAP_SCOPE_SUBTREE
#define FILTER "(sn=Jensen)"
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *result, *e;
char *dn;
int version, rc;
/* Print out an informational message. */
printf( "Connecting to host %s at port %d...\n\n", HOSTNAME,
PORTNUMBER );
/* STEP 1: Get a handle to an LDAP connection and
set any session preferences. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Use the LDAP_OPT_PROTOCOL_VERSION session preference to specify
that the client is an LDAPv3 client. */
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
/* STEP 2: Bind to the server.
In this example, the client binds anonymously to the server
(no DN or credentials are specified). */
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_simple_bind_s: %s\n", ldap_err2string(rc));
return( 1 );
}
/* Print out an informational message. */
printf( "Searching the directory for entries\n"
" starting from the base DN %s\n"
" within the scope %d\n"
" matching the search filter %s...\n\n",
BASEDN, SCOPE, FILTER );
/* STEP 3: Perform the LDAP operations.
In this example, a simple search operation is performed.
The client iterates through each of the entries returned and
prints out the DN of each entry. */
rc = ldap_search_ext_s( ld, BASEDN, SCOPE, FILTER, NULL, 0,
NULL, NULL, NULL, 0, &amp;result );
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_search_ext_s: %s\n", ldap_err2string(rc));
return( 1 );
}
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 );
}
}
ldap_msgfree( result );
/* STEP 4: Disconnect from the server. */
ldap_unbind( ld );
return( 0 );
}
...</programlisting>
</example>
</task>
</sect1>
<sect1 id="bdacc"><title>Initializing an LDAP Session With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>initializing an LDAP session</secondary>
</indexterm><indexterm>
<primary>LDAP session</primary>
<secondary>initializing</secondary>
</indexterm>
<para>Before connecting to an LDAP server, you must initialize a session.
As part of this process, you create an <structname>LDAP</structname> structure
that contains information about the LDAP server and session. You then pass
this <structname>LDAP</structname> structure, usually as a pointer, to all
subsequent functions in order to identify the LDAP server with which you are
working. Sample code for initializing an LDAP session is provided in <olink targetptr="bdacf">Example Session Initialization</olink>.</para>
<note><para>If you plan to connect to the LDAP server over the Secure Sockets
Layer (SSL) protocol, the procedure for initializing an LDAP session is different.
For details, see <olink targetptr="csdk-ssl">Chapter&nbsp;15, SSL Connections
With Directory SDK for C</olink>.</para></note>
<sect2 id="bdacd"><title>Specifying a Single LDAP Server</title>
<para>To initialize an LDAP session, call <function>ldap_init</function>,
or <function>prldap_init</function> for IPv6 support, with the host name and
port number of the LDAP server. If the server is using the default port <literal>
389</literal> for the LDAP server, pass <literal>LDAP_PORT</literal> as the
value for the <parameter>defport</parameter> parameter as shown here.</para>
<example id="csdk-init-example"><title>Passing an LDAP Server With the Default
LDAP Port</title>
<programlisting>...
LDAP *ld
...
ld = ldap_init( "directory.example.com", LDAP_PORT );</programlisting>
</example>
<para>If successful, <function>ldap_init</function>, or <function>prldap_init</function>,
returns a connection handle to the LDAP server. A <firstterm>connection handle</firstterm> is
a pointer to the <structname>LDAP</structname> structure that contains information
about the connection. You must pass this pointer to the API for connecting,
authenticating, and performing LDAP operations on a server. For example, when
you search the directory, you pass the connection handle as a parameter to
provide a context for the connection.</para>
<note><para>The initialization function does not open a connection to the
LDAP server. The actual opening of a connection occurs when the first operation
is attempted.</para></note>
</sect2>
<sect2 id="bdace"><title>Specifying a List of LDAP Servers</title>
<para>When initializing the LDAP session, you can also specify a list of LDAP
servers for which you want to attempt connections. If the first LDAP server
in the list does not respond, the client attempts to connect to the next server
in the list. To specify a list of LDAP servers, pass a space-delimited list
of the host names as the first argument to the <function>ldap_init</function> or <function>
prldap_init</function> function. In the following example, the LDAP client
attempts to connect to the LDAP server on <literal>ld1.example.com</literal>,
port <literal>389</literal>. If that server does not respond, the client attempts
to connect to the LDAP server on <literal>ld2.example2.com</literal>, port <literal>
389</literal>. If that server does not respond, the client uses the server
on <literal>ld3.example.com</literal>, port <literal>389</literal>.</para>
<example id="csdk-init-mult-example"><title>Passing Multiple LDAP Servers
With the Default LDAP Port</title>
<programlisting>...
LDAP *ld
...
ld = ldap_init( "ld1.example.com ld2.example2.com
ld3.example.com", LDAP_PORT );</programlisting>
</example>
<para>If any servers do not use the default LDAP port, use the <replaceable>host</replaceable><literal>
:</literal><replaceable>port</replaceable> format to specify the server name
and port number. In the following example, that means <literal>ld1.example.com</literal>,
port <literal>389</literal>. If that server does not respond, the client attempts
to connect to the LDAP server on <literal>ld2.example.com</literal>, port <literal>
1389</literal>.</para>
<example id="csdk-init-mult2-example"><title>Passing Non-Default LDAP Ports</title>
<programlisting>...
LDAP *ld
...
ld = ldap_init( "ld1.example.com ld2.example.com:1389",
LDAP_PORT );</programlisting>
</example>
</sect2>
<sect2 id="bdacf"><title>Example Session Initialization</title>
<indexterm>
<primary>example programs</primary>
<secondary>initializing an LDAP session</secondary>
</indexterm>
<para>The following example initializes a session with an LDAP server, specifying
a list of LDAP servers to try: <literal>ldap.example.com:389</literal> and <literal>
directory.example.com:1389</literal>. The example also sets a session preference
that identifies the client as an LDAP v3 client. This session initialization
code uses the <function>prldap_init</function> function, which works on IPv6
networks. Notice that <function>prldap_init</function> does not connect to
the LDAP server right away.</para>
<para>After you initialize a session with an LDAP server, you can set session
preferences. For information, see<olink targetptr="bdacg">Setting Session
Preferences With Directory SDK for C</olink>. </para>
<example id="csdk-init2-example"><title>Initializing an LDAP Session</title>
<programlisting>#include &lt;stdio.h>
#include "ldappr.h"
#include "ldap.h"
...
LDAP *ld;
int ldap_default_port, version;
/* Specify list of LDAP servers that you want to try connecting to. */
char *ldap_host = "ldap.example.com directory.example.com:1389";
/* If the LDAP server is running on the standard LDAP port (port 389),
* you can use LDAP_PORT to identify the port number. */
ldap_default_port = LDAP_PORT;
...
/* Initialize the session with the LDAP servers. */
if ( ( ld = prldap_init( ldap_host, ldap_default_port, NULL ) ) == NULL ) {
perror( "prldap_init" );
return( 1 );
}
/* Specify the LDAP version supported by the client. */
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
...
/* Subsequent calls pass ld as argument to identify the LDAP server. */
...</programlisting>
</example>
</sect2>
<sect2 id="bdacg"><title>Setting Session Preferences With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>setting LDAP session preferences</secondary>
</indexterm>
<para>With &DirectorySDKForC;, you can set preferences for your client
that you want applied to all LDAP sessions. To get or set the value of a preference,
call the <function>ldap_get_option</function> or <function>ldap_set_option</function> functions
respectively.</para>
<itemizedlist>
<para>Both functions pass two parameters in addition to the <parameter>ld</parameter> parameter,
which represents the connection to the server:</para>
<listitem><para>The <parameter>option</parameter> parameter identifies the
option that you want to get or set.</para></listitem>
<listitem><para>The <parameter>value</parameter> parameter is either a pointer
to a place to put the value to get, or a pointer to the value to set.</para>
</listitem>
</itemizedlist>
<para>You can set a preference for all connections by passing <literal>NULL</literal> as
the first argument, not an <structname>LDAP</structname> structure that specifies
the connection.</para>
<sect3 id="bdach"><title>Reconnecting Automatically</title>
<para>If communication with the LDAP server is interrupted, the server returns <errorcode>
LDAP_SERVER_DOWN</errorcode>. If you want your client to continue to attempt
communication with the server, you can set the <literal>LDAP_OPT_RECONNECT</literal> preference
for the session. Once set, if your connection is lost, the client attempts
another bind with the same authentication to reestablish the connection.</para>
<para>The following example shows that to set the reconnect preference, call
the <function>ldap_set_option</function> function and pass <literal>LDAP_OPT_RECONNECT
</literal> as the value of the <parameter>option</parameter> parameter. To
resume LDAP I/O operations automatically, set the <parameter>optdata</parameter> parameter
to <literal>LDAP_OPT_ON</literal>. This setting specifies the same connection
handle that can be used to reconnect to the server. </para>
<example><title>Passing Restart Preferences</title>
<programlisting>ldap_set_option( ld, LDAP_OPT_RECONNECT, LDAP_OPT_ON );</programlisting>
</example>
<para>To avoid resuming I/O operations, you would set the <parameter>optdata</parameter> parameter
to <literal>LDAP_OPT_OFF</literal>. This setting specifies that you want to
create a new connection handle to connect to the server. By default, the <parameter>
optdata</parameter> parameter is set to <literal>LDAP_OPT_OFF</literal>. Both <literal>
LDAP_OPT_OFF</literal> and <literal>LDAP_OPT_ON</literal> are cast to <literal>(void
*)</literal>.</para></sect3>
<sect3 id="bdaci"><title>Specifying the LDAP Version of Your Client</title>
<para>If you plan to call functions that use LDAP v3 features such as controls
or extended operations, set the protocol version to LDAP v3. By default, clients
built with &DirectorySDKForC; identify themselves to LDAP servers as LDAP
v3 clients, but that was not the case with previous versions.</para>
<para>To specify the LDAP version supported by your client, call the <function>ldap_set_option
</function> function and set the <literal>LDAP_OPT_PROTOCOL_VERSION</literal> option
to the value <literal>3</literal>.</para>
<example><title>Passing the LDAP Protocol Version Number</title>
<programlisting>...
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
...</programlisting>
</example>
<para>After setting this option, as part of the authentication process, your
client sends the supported LDAP version number to the server. By setting the
version, you allow the server to determine whether or not to enable LDAP v3
features.</para>
<para>LDAP v3 allows you to perform LDAP operations without first binding
to the server. An LDAP v3 server assumes that the client is LDAP v3 compliant
if the client issues non-bind operations before the client issues a bind.</para>
</sect3>
<sect3 id="setting-connection-timeout"><title>Setting Connection Timeout</title>
<para>Clients that use &DirectorySDKForC; can control the TCP/IP level
timeout. When the TCP/IP timeout option is not set, an attempt to connect
to a server blocks until the connection completes or the system times out.
By using the <literal>LDAP_X_OPT_CONNECT_TIMEOUT</literal> option, you can
adjust how long to wait for a connection.</para>
<para>You specify the timeout as an <literal>int</literal> number of milliseconds,
then call the <function>ldap_set_option</function> function, passing the <literal>
LDAP_X_OPT_CONNECT_TIMEOUT</literal> option.</para>
<example><title>Passing Connection Timeout Preferences</title>
<para>The following example sets the connection timeout to one second.</para>
<programlisting>int timeout = 1000; /* 1000 milliseconds == 1 second */
ldap_set_option( ld, LDAP_X_OPT_CONNECT_TIMEOUT, &amp;timeout );</programlisting>
</example>
<itemizedlist>
<para>The <literal>LDAP_X_OPT_CONNECT_TIMEOUT</literal> option can be set
using the following values as well:</para>
<listitem><para><literal>LDAP_X_IO_TIMEOUT_NO_WAIT</literal></para><para>Return
immediately if the server cannot be reached.</para></listitem>
<listitem><para><literal>LDAP_X_IO_TIMEOUT_NO_TIMEOUT</literal></para><para>Wait
indefinitely for the server to connect.</para></listitem>
</itemizedlist>
<para>By passing <literal>NULL</literal> as the first parameter to the <function>
ldap_set_option</function> function, you can set the default timeout for all
connections used by your application.</para></sect3>
</sect2>
</sect1>
<sect1 id="bdacj"><title>Binding and Authenticating to an LDAP Server With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>binding and authenticating</secondary>
</indexterm><indexterm>
<primary>binding</primary>
<secondary>with C SDK</secondary>
</indexterm>
<para>When connecting to the LDAP server, your client might need to send a
bind request.</para>
<itemizedlist>
<para>A bind request should be sent if either of the following are true.</para>
<listitem><para>You want to authenticate to the server to add or modify entries
in a directory that requires authentication as a user with certain access
privileges.</para></listitem>
<listitem><para>You are connecting to an LDAP v2 server. LDAP v2 servers typically
require clients to bind before any operations can be performed.</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>The bind request should contain the following information:</para>
<listitem><para> LDAP version of the client</para></listitem>
<listitem><para> Method of authentication to use</para></listitem>
<listitem><para> DN that the client is attempting to authenticate as</para>
</listitem>
<listitem><para> Credentials to be used for authentication</para></listitem>
</itemizedlist>
<para>LDAP clients can also bind anonymously to the LDAP server if, for example,
the server is configured not to require authentication for a simple directory
search.</para>
<sect2 id="bdaco"><?Pub Caret1><title>Using Simple Authentication With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>methods of authentication</secondary>
<tertiary>simple authentication</tertiary>
</indexterm><indexterm>
<primary>authentication</primary>
<secondary>C SDK</secondary>
<tertiary>simple</tertiary>
</indexterm>
<itemizedlist>
<para>If you plan to use simple authentication, call one of the following
functions:</para>
<listitem><para><function>ldap_simple_bind_s</function> is a synchronous function
for use if you want to wait for the bind operation to complete before the
function returns.</para><para>See <olink targetptr="bdacp">Performing a Synchronous
Authentication Operation</olink></para></listitem>
<listitem><para><function>ldap_simple_bind</function> is an asynchronous function
for use if you do not want to wait for the bind operation to complete. With
this function, you can perform other work while periodically checking for
the results of the bind operation.</para><para>See <olink targetptr="bdacq">Performing
an Asynchronous Authentication Operation</olink></para></listitem>
</itemizedlist>
<para>For more information about the differences between the types of functions,
see <olink targetptr="bdacv">Synchronous and Asynchronous Functions</olink>.</para>
<sect3 id="bdacp"><title>Performing a Synchronous Authentication Operation</title>
<para>If you want to wait for the bind operation to complete before continuing,
call <function>ldap_simple_bind_s</function>. This function returns <errorcode>LDAP_SUCCESS
</errorcode> if the operation completed successfully, or an LDAP result code
if a problem occurred. See <function>ldap_simple_bind_s</function> in <olink targetptr="bdavj">ldap_simple_bind_s</olink> for a list of result codes returned.
</para>
<para>If you specify a DN but no password, your client binds to the server
anonymously. If you want a <literal>NULL</literal> password to be rejected
as incorrect, you must write code to perform the check before you call <function>
ldap_simple_bind_s</function>.</para>
<para>The following example uses the synchronous <function>ldap_simple_bind_s</function> function
to authenticate user Barbara Jensen to the LDAP server.</para>
<example id="csdk-sync-auth-example"><title>Performing Synchronous Authentication
</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define BIND_PW "hifalutin"
LDAP *ld;
int rc;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Print out an informational message. */
printf( "Binding to server %s:%d\n", HOSTNAME, PORTNUMBER );
printf( "as the DN %s ...\n", BIND_DN );
/* Bind to the LDAP server. */
rc = ldap_simple_bind_s( ld, BIND_DN, BIND_PW );
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_simple_bind_s: %s\n\n", ldap_err2string(rc));
return( 1 );
} else {
printf( "Bind operation successful.\n" );
}
...
/* If you want, you can perform LDAP operations here. */
...
/* Disconnect from the server when done. */
ldap_unbind( ld );
return( 0 );
...</programlisting>
</example>
</sect3>
<sect3 id="bdacq"><title>Performing an Asynchronous Authentication Operation</title>
<para>If you want to perform other work in parallel while waiting for the
bind operation to complete, call <function>ldap_simple_bind</function>. This
function sends an LDAP bind request to the server and returns a message ID
identifying the bind operation. To see if your client has received the results
of the bind operation, call the <function>ldap_result</function> function
with the message ID. If your client has received the results, <function>ldap_result
</function> passes back the information in an <structname>LDAPMessage</structname> structure.
To retrieve error information from <structname>LDAPMessage</structname>, you
can pass the message ID to the <function>ldap_parse_result</function> function. <function>
ldap_parse_result</function> gets the LDAP result code of the operation and
any error messages sent back from the server. This function also retrieves
any controls sent back.</para>
<para>If you specify a DN but no password, your client binds to the server
anonymously. If you want a <literal>NULL</literal> password to be rejected
as incorrect, you need to write code to perform the check before you call <function>
ldap_simple_bind</function>.</para>
<para>The following example uses the asynchronous <function>ldap_simple_bind</function> function
to authenticate user Barbara Jensen to the LDAP server.</para>
<example id="csdk-async-auth-example"><title>Performing Asynchronous Authentication
</title>
<indexterm>
<primary>example programs</primary>
<secondary>asynchronous authentication</secondary>
</indexterm>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
void do_other_work();
int global_counter = 0;
...
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define BIND_PW "hifalutin"
...
LDAP *ld;
LDAPMessage *res;
int msgid = 0, rc = 0, parse_rc = 0, finished = 0;
char *matched_msg = NULL, *error_msg = NULL;
char **referrals;
LDAPControl **serverctrls;
struct timeval zerotime;
/* Specify the timeout period for ldap_result(),
which specifies how long the function should block when waiting
for results from the server. */
zerotime.tv_sec = zerotime.tv_usec = 0L;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Print out an informational message. */
printf( "Binding to server %s:%d\n", HOSTNAME, PORTNUMBER );
printf( "as the DN %s ...\n", BIND_DN );
/* Send an LDAP bind request to the server. */
msgid = ldap_simple_bind( ld, BIND_DN, BIND_PW );
/* If the returned message ID is less than zero, an error occurred. */
if ( msgid &lt; 0 ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf(stderr, "ldap_simple_bind : %s\n", ldap_err2string(rc));
ldap_unbind( ld );
return( 1 );
}
/* Check to see if the bind operation completed. */
while ( !finished ) {
rc = ldap_result( ld, msgid, 0, &amp;zerotime, &amp;res );
switch ( rc ) {
/* If ldap_result() returns -1, error occurred. */
case -1:
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return ( 1 );
/* If ldap_result() returns 0, the timeout (specified by the
timeout argument) has been exceeded before the client received
the results from the server. Continue calling ldap_result()
to poll for results from the server. */
case 0:
break;
default:
/* The client has received the result of the bind operation. */
finished = 1;
/* Parse this result to determine if the operation was successful.
Note that a non-zero value is passed as the last parameter,
which indicates that the LDAPMessage structure res should be
freed when done. (No need to call ldap_msgfree().) */
parse_rc = ldap_parse_result( ld, res, &amp;rc, &amp;matched_msg,
&amp;error_msg, &amp;referrals, &amp;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 operation. */
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_simple_bind: %s\n",
ldap_err2string( rc ) );
/* If the server sent an additional error message,
print it out. */
if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
/* If an entry specified by a DN could not be found,
the server may also return the portion of the DN
that identifies an existing entry. */
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
ldap_unbind( ld );
return( 1 );
} else {
printf( "Bind operation successful.\n" );
printf( "Counted to %d while waiting for bind op.\n",
global_counter );
}
break;
}
/* Do other work here while waiting for results from the server. */
if ( !finished ) {
do_other_work();
}
}
...
/* If you want, you can perform LDAP operations here. */
...
/* Disconnect from the server when done. */
ldap_unbind( ld );
return( 0 );
...
/* Function that does work while waiting for results from the server. */
void do_other_work() {
global_counter++;
}
...</programlisting>
</example>
</sect3>
</sect2>
<sect2 id="bdacr"><title>Binding Anonymously With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>methods of authentication</secondary>
<tertiary>anonymous authentication</tertiary>
</indexterm><indexterm>
<primary>authentication</primary>
<secondary>C SDK</secondary>
<tertiary>anonymous</tertiary>
</indexterm>
<para>In some cases, you do not need to authenticate to the LDAP server. For
example, if users are performing a search that has no special access permissions,
you need not authenticate before performing the search. To bind as an anonymous
user, call <function>ldap_simple_bind</function> or <function>ldap_simple_bind_s</function>,
and pass <literal>NULL</literal> values for the <parameter>who</parameter> and <parameter>
passwd</parameter> parameters.</para>
<programlisting>rc = ldap_simple_bind_s( ld, NULL, NULL );
</programlisting>
<para>With LDAP v2, the client is required to send a bind request, even when
binding anonymously. That is, bind without specifying a name or password.
With LDAP v3, the client is no longer required to bind to the server if the
client does not need to authenticate.</para></sect2>
</sect1>
<sect1 id="bdacs"><title>Performing LDAP Operations With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP operations</secondary>
</indexterm><indexterm>
<primary>LDAP operations</primary>
<secondary>with C SDK</secondary>
</indexterm>
<para>After initializing a session with a server and completing the authentication
process, you can perform LDAP operations. The LDAP operations include searching
the directory, adding new entries, updating existing entries, and removing
entries. The following lists LDAP operations and the functions that you can
call to perform the operations.</para>
<table frame="topbot" id="csdk-fcns-ldap-ops"><title>Functions for Performing
LDAP Operations</title>
<tgroup cols="2"><colspec colnum="1" colwidth="50*"><colspec colnum="2"
colwidth="50*">
<thead>
<row>
<entry>
<para>To Perform This Operation</para></entry>
<entry>
<para>Call This API Function</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>Search for entries</para></entry>
<entry>
<para><function>ldap_search_ext</function></para>
<para><function>ldap_search_ext_s</function></para></entry>
</row>
<row>
<entry>
<para>Determine an attribute&rsquo;s value</para></entry>
<entry>
<para><function>ldap_compare_ext</function></para>
<para><function>ldap_compare_ext_s</function></para></entry>
</row>
<row>
<entry>
<para>Add entries</para></entry>
<entry>
<para><function>ldap_add_ext</function></para>
<para><function>ldap_add_ext_s</function></para></entry>
</row>
<row>
<entry>
<para>Modify entries</para></entry>
<entry>
<para><function>ldap_modify_ext</function></para>
<para><function>ldap_modify_ext_s</function></para></entry>
</row>
<row>
<entry>
<para>Delete entries</para></entry>
<entry>
<para><function>ldap_delete_ext</function></para>
<para><function>ldap_delete_ext_s</function></para></entry>
</row>
<row>
<entry>
<para>Change DN of entries</para></entry>
<entry>
<para><function>ldap_rename_ext</function></para>
<para><function>ldap_rename_ext_s</function></para></entry>
</row>
</tbody>
</tgroup>
</table>
<para>Most LDAP operations can be performed synchronously or asynchronously.
The functions with names that end in <literal>_s</literal> are synchronous.
The remaining ones are asynchronous. For more information about the distinction
between the functions, see <olink targetptr="bdaau">Synchronous and Asynchronous
Operations</olink>.</para></sect1>
<sect1 id="bdact"><title>Closing the Connection to an LDAP Server With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>closing an LDAP server connection</secondary>
</indexterm>
<para>When you have finished performing all necessary LDAP operations, you
need to close the connection to the LDAP server. After you close the connection,
you can no longer use the <structname>LDAP</structname> structure because
the structure is freed from memory.</para>
<itemizedlist>
<para>To close a connection to an LDAP server, call one of the following functions:
</para>
<listitem><para><function>ldap_unbind</function></para></listitem>
<listitem><para><function>ldap_unbind_s</function></para></listitem>
<listitem><para><function>ldap_unbind_ext</function></para></listitem>
</itemizedlist>
<para>Both <function>ldap_unbind</function> and <function>ldap_unbind_s</function> are
identical synchronous functions. These functions use different names so that
each function has a corresponding authentication function, <function>ldap_simple_bind
</function> and <function>ldap_simple_bind_s</function>, to close the server
connection. </para>
<para>The <function>ldap_unbind_ext</function> function allows you to include
explicitly both server and client controls in your unbind request. However,
as the server does not respond to an unbind request, you cannot receive a
response from a server control attached to your unbind request. </para>
<para>The following example closes the current connection with the LDAP server.</para>
<example id="csdk-close-conn-example"><title>Closing an LDAP Server Connection</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
LDAP *ld;
int rc;
...
/* After completing your LDAP operations with the server, close
the connection. */
rc = ldap_unbind( ld );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_unbind: %s\n", ldap_err2string( rc ) );
}
...</programlisting>
</example>
</sect1>
</chapter>