<!--

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-sasl"><title>SASL Authentication With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Simple Authentication and Security Layer (SASL)</secondary>
</indexterm><highlights>
<para>This chapter describes the process of using a Simple Authentication
and Security Layer (SASL) mechanism to authenticate an LDAP client to an LDAP
server.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdaig">Understanding SASL and Directory
SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaih">Determining Supported SASL Mechanisms
With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaii">Authenticating Using SASL With Directory
SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdaig"><title>Understanding SASL and &DirectorySDKForC;</title>
<para>The ability to authenticate to an LDAP server with a SASL mechanism
is a feature that is new to LDAP v3. LDAP v2 servers do not support this method
of authentication.</para>
<para>SASL is described in <ulink url="http://www.ietf.org/rfc/rfc4422.txt"
type="text_url"><?Pub Caret>RFC 4422</ulink>, <citetitle>Simple Authentication
and Security Layer (SASL)</citetitle>.</para></sect1>
<sect1 id="bdaih"><title>Determining Supported SASL Mechanisms With &DirectorySDKForC;
</title>
<para>To determine the SASL mechanisms supported by an LDAP v3 server, get
the root DSE of the server, and check the <literal>supportedSASLMechanisms</literal> attribute.
The values of this attribute are the names of the SASL mechanisms supported
by the server.</para>
<para>If the root DSE does not have a <literal>supportedSASLMechanisms</literal> attribute,
the server does not support any SASL mechanisms.</para>
<para>For information about getting the root DSE, see <olink targetptr="bdahv">To
Get the Root DSE</olink>.</para></sect1>
<sect1 id="bdaii"><title>Authenticating Using SASL With &DirectorySDKForC;</title>
<itemizedlist>
<para>To authenticate to the server with a SASL mechanism, call one of the
following:</para>
<listitem><para>The synchronous <function>ldap_sasl_bind_s</function> function</para>
</listitem>
<listitem><para>The asynchronous <function>ldap_sasl_bind</function> function</para>
<para>If you call the asynchronous function <function>ldap_sasl_bind</function>,
you need to call the <function>ldap_result</function> and <function>ldap_parse_sasl_bind_result
</function> functions to get the result of the SASL bind operation.</para>
</listitem>
</itemizedlist>
<para>Authentication with a SASL mechanism can take one or more round&mdash;trips
between your client and the server. The server might send a number of <firstterm>
challenges</firstterm> to the client. You might need to call <function>ldap_sasl_bind_s
</function> several times, or <function>ldap_sasl_bind</function>, <function>ldap_result
</function>, and <function>ldap_parse_sasl_bind_result</function> several
times in order to respond to each server challenge.</para>
<para>Before calling the function to perform a SASL bind operation, make sure
to specify that your client is LDAP v3 compliant. If you do not, an <errorcode>LDAP_NOT_SUPPORTED
</errorcode> result code is returned. See <olink targetptr="bdaci">Specifying
the LDAP Version of Your Client</olink>.</para>
<sect2 id="bdaij"><title>Synchronous SASL Bind Operation</title>
<para>If you want to wait for the results of the SASL bind operation to complete
before continuing, call the synchronous <function>ldap_sasl_bind_s</function> function.
This function sends a SASL bind request to the server. This function blocks
other work until the server sends the results of the operation back to your
client.</para>
<itemizedlist>
<para><function>ldap_sasl_bind_s</function> returns one of the following values:</para>
<listitem><para><errorcode>LDAP_SUCCESS</errorcode> if your client has successfully
authenticated.</para></listitem>
<listitem><para><errorcode>LDAP_SASL_BIND_IN_PROGRESS</errorcode> if the server
sends a challenge to your client. If you receive this result code, check the <literal>
servercredp</literal> argument for the <structname>berval</structname> structure
that contains the server&rsquo;s challenge. Call the <function>ldap_sasl_bind</function> function
again to send a response to that challenge.</para></listitem>
<listitem><para>An LDAP error code if a problem occurred or if authentication
failed. See the <olink targetptr="bdaux">ldap_sasl_bind_s</olink> function
documentation for a list of the possible result codes.</para></listitem>
</itemizedlist>
</sect2>
<sect2 id="bdaik"><title>Asynchronous SASL Bind Operation</title>
<para>If you want to perform other work in parallel while waiting for the
SASL bind operation to complete, use the following procedure.</para>
<task><title>To Bind Asynchronously Over SASL</title>
<procedure>
<step><para>Call the asynchronous <function>ldap_sasl_bind</function> function
to send an LDAP SASL bind request.</para><para>This function returns an <errorcode>
LDAP_SUCCESS</errorcode> result code if the request was successfully sent,
or an LDAP result code if an error occurred while sending the request. The
function also sets the <literal>msgidp</literal> argument to point to a message
ID identifying the SASL bind operation.</para></step>
<step><para>Call the <function>ldap_result</function> function, passing in
this message ID to determine whether the server sent a response for this operation
to your client.</para><para>The <function>ldap_result</function> function
uses the message ID to determine if the server sent a SASL bind response.
The function passes back the response in an <structname>LDAPMessage</structname> structure.
</para></step>
<step><para>Call the <function>ldap_parse_sasl_bind_result</function> function
to parse the <structname>LDAPMessage</structname> structure and retrieve information
from the server&rsquo;s response.</para><para>If the server sent a challenge
to your client, the challenge is specified in the <structname>berval</structname> structure
passed back as the <literal>servercredp</literal> argument.</para></step>
<step><para>Call the <function>ldap_get_lderrno</function> function to get
the LDAP result code for the operation.</para>
<itemizedlist>
<para>The function can return one of the following values:</para>
<listitem><para><errorcode>LDAP_SUCCESS</errorcode> if your client successfully
authenticated to the server.</para></listitem>
<listitem><para><errorcode>LDAP_SASL_BIND_IN_PROGRESS</errorcode> if the server
sent a challenge to your client.</para><para>If the server returned an <errorcode>
LDAP_SASL_BIND_IN_PROGRESS</errorcode> result code, check the <literal>servercredp
</literal> argument for the <structname>berval</structname> structure that
contains the server&rsquo;s challenge.</para></listitem>
<listitem><para>An LDAP error code if a problem occurred or if authentication
failed.</para><para>See the <function>ldap_sasl_bind</function> function documentation
for a list of result codes that the server can return for this operation.</para>
</listitem>
</itemizedlist>
</step>
<step><para>If the result code is <errorcode>LDAP_SASL_BIND_IN_PROGRESS</errorcode> and
if the server passed back another challenge, determine the response to that
challenge by calling the <function>ldap_sasl_bind</function> function again
to send that response to the server.</para><para>You can call <function>ldap_result
</function> and <function>ldap_parse_sasl_bind_result</function> again to
get the next challenge sent from the server, if the result is again <errorcode>LDAP_SASL_BIND_IN_PROGRESS
</errorcode>.</para></step>
</procedure>
<example>
<title>Authenticating Over SASL</title>
<para>This example shows an LDAP client that authenticates using the SASL
mechanism that is named <literal>babsmechanism</literal>.</para>
<programlisting>#include &lt;stdio.h>
#include &lt;stdlib.h>
#include &lt;string.h>
#include &lt;time.h>
#include "ldap.h"

int
main( int argc, char **argv )
{
    LDAP        *ld;
    LDAPMod     mod0;
    LDAPMod     mod1;
    LDAPMod     *mods[ 3 ];
    char        *vals0[ 2 ];
    char        *vals1[ 2 ];
    time_t      now;
    char        buf[ 128 ];
    struct berval   cred;
    struct berval   *servcred;
    int         version;
    /* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
    if ( (ld = ldap_init( "localhost", 389 )) == NULL ) {
      perror( "ldap_init" );
      return( 1 );
    }
    /* Set the LDAP protocol version supported by the client
       to 3. (By default, this is set to 2. SASL authentication
       is part of version 3 of the LDAP protocol.) */
    version = LDAP_VERSION3;
    ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
    /* authenticate */
    cred.bv_val = "magic";
    cred.bv_len = sizeof( "magic" ) - 1;
    if ( ldap_sasl_bind_s( ld, "uid=bjensen,ou=people,dc=example,dc=com",
                           "babsmechanism", &amp;cred, NULL, NULL,
                           &amp;servcred ) != LDAP_SUCCESS ) {
      ldap_perror( ld, "ldap_sasl_bind_s" );
      return( 1 );
    }
    /* get and print the credentials returned by the server */
    printf( "Server credentials: %s\n", servcred->bv_val );
    /* construct the list of modifications to make */
    mod0.mod_op = LDAP_MOD_REPLACE;
    mod0.mod_type = "mail";
    vals0[0] = "babs@example.com";
    vals0[1] = NULL;
    mod0.mod_values = vals0;
    mod1.mod_op = LDAP_MOD_ADD;
    mod1.mod_type = "description";
    time( &amp;now );
    sprintf( buf, "This entry was modified with the modattrs program on %s",
      ctime( &amp;now ));
    /* Get rid of \n which ctime put on the end of the time string */
    if ( buf[ strlen( buf ) - 1 ] == '\n' ) {
      buf[ strlen( buf ) - 1 ] = '\0';
    }
    vals1[ 0 ] = buf;
    vals1[ 1 ] = NULL;
    mod1.mod_values = vals1;
    mods[ 0 ] = &amp;mod0;
    mods[ 1 ] = &amp;mod1;
    mods[ 2 ] = NULL;
    /* make the change */
    if ( ldap_modify_s(ld, "uid=bjensen,ou=people,dc=example,dc=com", mods)
      != LDAP_SUCCESS ) {
      ldap_perror( ld, "ldap_modify_s" );
      return( 1 );
    }
    ldap_unbind( ld );
    printf( "modification was successful\n" );
    return( 0 );
}</programlisting>
</example>
</task>
</sect2>
</sect1>
</chapter>
