769 lines
33 KiB
Plaintext
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 <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, &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, &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 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 <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, &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, &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, &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 <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 <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 < 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, &zerotime, &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, &rc, &matched_msg,
|
|
&error_msg, &referrals, &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 && *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 && *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’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 <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>
|