Mozilla LDAP C SDK Programmer's Guide
Chapter 13 - Using SASL Authentication
This chapter describes the process of using a SASL mechanism to authenticate an LDAP client to an LDAP server.
The chapter includes the following sections:
Understanding SASL
Simple Authentication and Security Layer (SASL) is described in RFC 2222, which you can find at this location:
http://www.ietf.org/rfc/rfc2222.txt
SASL provides the means to use mechanisms other than simple authentication and SSL to authenticate to the Mozilla LDAP C SDK.
The ability to authenticate to an LDAP server using a SASL mechanism is a feature new to LDAPv3 (LDAPv2 servers do not support this method of authentication).
Determining the SASL Mechanisms Supported
To determine the SASL mechanisms supported
by an LDAPv3 server, get the root DSE
of the server, and check the supportedSASLMechanisms
attribute. The values of this attribute are the names of the SASL
mechanisms supported by the server.
If the root DSE does not have a supportedSASLMechanisms
attribute, the server does not support any SASL mechanisms.
For information on getting the root DSE, see "Getting the Root DSE".
Authenticating Using a SASL Mechanism
To authenticate to the server using a SASL mechanism, call one of the following functions:
-
The synchronous
ldap_sasl_bind_s()
function (see Performing a Synchronous SASL Bind Operation"). -
The asynchronous
ldap_sasl_bind()
function (see "Performing a Synchronous SASL Bind Operation").
For more information about the difference between synchronous and asynchronous functions, see "Calling Synchronous and Asynchronous Functions".
If you call the asynchronous function
ldap_sasl_bind()
,
you need to call the
ldap_result()
and
ldap_parse_sasl_bind_result()
functions to get the result of the SASL bind operation.
Authentication using a SASL mechanism may take one or more
round trips between your LDAP client and the server. (The server
may send a number of "challenges" to the client.) You may need
to call ldap_sasl_bind_s()
several times (or
ldap_sasl_bind()
,
ldap_result()
, and
ldap_parse_sasl_bind_result()
several times) in order to respond to each server challenge.
Before calling the function to perform a SASL bind operation,
make sure to specify that your client is LDAPv3 compliant. If you
do not, an LDAP_NOT_SUPPORTED
result code is returned.
For details, see "Specifying the LDAP
Version of Your Client".
Performing a Synchronous SASL Bind Operation
If you want to wait for the results of the SASL bind operation
to complete before continuing, call the synchronous
ldap_sasl_bind_s()
function. This function sends a SASL bind request to the server
and blocks until the server sends the results of the operation
back to your client.
The ldap_sasl_bind_s()
function returns one of the
following values:
-
LDAP_SUCCESS
if your client has successfully authenticated. -
LDAP_SASL_BIND_IN_PROGRESS
if the server sends a challenge to your client. If you receive this result code, check theservercredp
argument for theberval
structure containing the server's challenge. Call theldap_sasl_bind_s()
function again to send a response to that challenge. - An LDAP error code, if a problem occurred or if authentication failed.
See the documentation on the
ldap_sasl_bind_s()
function for a list of the possible result codes.
Performing an Asynchronous SASL Bind Operation
If you want to perform other work (in parallel) while waiting the SASL bind operation to complete, do the following:
-
To send an LDAP SASL bind request, call the asynchronous
ldap_sasl_bind()
function. This function returns anLDAP_SUCCESS
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 themsgidp
argument to point to a message ID identifying the SASL bind operation. -
To determine whether the server sent a response for this operation
to your client, call the
ldap_result()
function and pass in this message ID. Theldap_result()
function uses the message ID to determine if the server sent a SASL bind response. The function passes back the response in anLDAPMessage
structure. -
Call the
ldap_parse_sasl_bind_result()
function to parse theLDAPMessage
structure and retrieve information from the server's response. If the server sent a challenge to your client, the challenge is specified in theberval
structure passed back as theservercredp
argument. -
Call the
ldap_get_lderrno()
function to get the LDAP result code for the operation. The function can return one of the following values:-
LDAP_SUCCESS
if your client successfully authenticated to the server. -
LDAP_SASL_BIND_IN_PROGRESS
if the server sent a challenge to your client. - An LDAP error code, if a problem occurred or if authentication failed.
ldap_sasl_bind_s()
function for a list of result codes that the server can return for this operation. If the server returned anLDAP_SASL_BIND_IN_PROGRESS
result code, check theservercredp
argument for theberval
structure containing the server's challenge. -
-
If the result code is
LDAP_SASL_BIND_IN_PROGRESS
and the server passed back another challenge, determine the response to that challenge and call theldap_sasl_bind()
function again to send that response to the server. You can callldap_result()
andldap_parse_sasl_bind_result()
again to get the next challenge sent from the server, if the result isLDAP_SASL_BIND_IN_PROGRESS
again.
The following example is an LDAP client that
authenticates using the SASL mechanism named babsmechanism
.
Code Example 13-1 - Authenticating over SASL
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <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 */ 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, &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", &cred, NULL, NULL, &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( &now ); sprintf( buf, "This entry was modified with the modattrs program on %s", ctime( &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 ] = &mod0; mods[ 1 ] = &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 ); }