3 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Portions Copyright (C) The Internet Society (1997)
8 * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
12 * BindRequest ::= SEQUENCE {
14 * name DistinguishedName, -- who
15 * authentication CHOICE {
16 * simple [0] OCTET STRING -- passwd
17 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
18 * krbv42ldap [1] OCTET STRING
19 * krbv42dsa [2] OCTET STRING
21 * sasl [3] SaslCredentials -- LDAPv3
25 * BindResponse ::= SEQUENCE {
26 * COMPONENTS OF LDAPResult,
27 * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3
36 #include <ac/socket.h>
37 #include <ac/stdlib.h>
38 #include <ac/string.h>
45 * ldap_sasl_bind - bind to the ldap server (and X.500).
46 * The dn (usually NULL), mechanism, and credentials are provided.
47 * The message id of the request initiated is provided upon successful
48 * (LDAP_SUCCESS) return.
51 * ldap_sasl_bind( ld, NULL, "mechanism",
52 * cred, NULL, NULL, &msgid )
59 LDAP_CONST char *mechanism,
70 LDAP_LOG ( TRANSPORT, ENTRY, "ldap_sasl_bind\n", 0, 0, 0 );
72 Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 );
76 assert( LDAP_VALID( ld ) );
77 assert( msgidp != NULL );
79 /* check client controls */
80 rc = ldap_int_client_controls( ld, cctrls );
81 if( rc != LDAP_SUCCESS ) return rc;
83 if( mechanism == LDAP_SASL_SIMPLE ) {
84 if( dn == NULL && cred != NULL && cred->bv_len ) {
85 /* use default binddn */
86 dn = ld->ld_defbinddn;
89 } else if( ld->ld_version < LDAP_VERSION3 ) {
90 ld->ld_errno = LDAP_NOT_SUPPORTED;
98 /* create a message to send */
99 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
100 ld->ld_errno = LDAP_NO_MEMORY;
104 assert( LBER_VALID( ber ) );
106 LDAP_NEXT_MSGID( ld, id );
107 if( mechanism == LDAP_SASL_SIMPLE ) {
109 rc = ber_printf( ber, "{it{istON}" /*}*/,
111 ld->ld_version, dn, LDAP_AUTH_SIMPLE,
114 } else if ( cred == NULL || cred->bv_val == NULL ) {
115 /* SASL bind w/o creditials */
116 rc = ber_printf( ber, "{it{ist{sN}N}" /*}*/,
118 ld->ld_version, dn, LDAP_AUTH_SASL,
122 /* SASL bind w/ creditials */
123 rc = ber_printf( ber, "{it{ist{sON}N}" /*}*/,
125 ld->ld_version, dn, LDAP_AUTH_SASL,
130 ld->ld_errno = LDAP_ENCODING_ERROR;
135 /* Put Server Controls */
136 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
141 if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
142 ld->ld_errno = LDAP_ENCODING_ERROR;
148 /* send the message */
149 *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber, id );
162 LDAP_CONST char *mechanism,
164 LDAPControl **sctrls,
165 LDAPControl **cctrls,
166 struct berval **servercredp )
170 struct berval *scredp = NULL;
173 LDAP_LOG ( TRANSPORT, ENTRY, "ldap_sasl_bind_s\n", 0, 0, 0 );
175 Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 );
178 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
179 if( servercredp != NULL ) {
180 if (ld->ld_version < LDAP_VERSION3) {
181 ld->ld_errno = LDAP_NOT_SUPPORTED;
187 rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid );
189 if ( rc != LDAP_SUCCESS ) {
193 #ifdef LDAP_CONNECTIONLESS
194 if (LDAP_IS_UDP(ld)) {
199 if ( ldap_result( ld, msgid, 1, NULL, &result ) == -1 ) {
200 return( ld->ld_errno ); /* ldap_result sets ld_errno */
203 /* parse the results */
205 if( servercredp != NULL ) {
206 rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 );
209 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
210 ldap_msgfree( result );
214 rc = ldap_result2error( ld, result, 1 );
216 if ( rc == LDAP_SUCCESS || rc == LDAP_SASL_BIND_IN_PROGRESS ) {
217 if( servercredp != NULL ) {
218 *servercredp = scredp;
223 if ( scredp != NULL ) {
232 * Parse BindResponse:
234 * BindResponse ::= [APPLICATION 1] SEQUENCE {
235 * COMPONENTS OF LDAPResult,
236 * serverSaslCreds [7] OCTET STRING OPTIONAL }
238 * LDAPResult ::= SEQUENCE {
239 * resultCode ENUMERATED,
241 * errorMessage LDAPString,
242 * referral [3] Referral OPTIONAL }
246 ldap_parse_sasl_bind_result(
249 struct berval **servercredp,
253 struct berval* scred;
259 LDAP_LOG ( TRANSPORT, ENTRY, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
261 Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
264 assert( ld != NULL );
265 assert( LDAP_VALID( ld ) );
266 assert( res != NULL );
268 if( servercredp != NULL ) {
269 if( ld->ld_version < LDAP_VERSION2 ) {
270 return LDAP_NOT_SUPPORTED;
275 if( res->lm_msgtype != LDAP_RES_BIND ) {
276 ld->ld_errno = LDAP_PARAM_ERROR;
282 if ( ld->ld_error ) {
283 LDAP_FREE( ld->ld_error );
286 if ( ld->ld_matched ) {
287 LDAP_FREE( ld->ld_matched );
288 ld->ld_matched = NULL;
293 ber = ber_dup( res->lm_ber );
296 ld->ld_errno = LDAP_NO_MEMORY;
300 if ( ld->ld_version < LDAP_VERSION2 ) {
301 tag = ber_scanf( ber, "{ia}",
302 &errcode, &ld->ld_error );
304 if( tag == LBER_ERROR ) {
306 ld->ld_errno = LDAP_DECODING_ERROR;
313 tag = ber_scanf( ber, "{iaa" /*}*/,
314 &errcode, &ld->ld_matched, &ld->ld_error );
316 if( tag == LBER_ERROR ) {
318 ld->ld_errno = LDAP_DECODING_ERROR;
322 tag = ber_peek_tag(ber, &len);
324 if( tag == LDAP_TAG_REFERRAL ) {
326 if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
328 ld->ld_errno = LDAP_DECODING_ERROR;
332 tag = ber_peek_tag(ber, &len);
335 if( tag == LDAP_TAG_SASL_RES_CREDS ) {
336 if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) {
338 ld->ld_errno = LDAP_DECODING_ERROR;
346 if ( servercredp != NULL ) {
347 *servercredp = scred;
349 } else if ( scred != NULL ) {
353 ld->ld_errno = errcode;
359 return( ld->ld_errno );
363 ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist )
365 /* we need to query the server for supported mechs anyway */
366 LDAPMessage *res, *e;
367 char *attrs[] = { "supportedSASLMechanisms", NULL };
368 char **values, *mechlist;
372 LDAP_LOG ( TRANSPORT, ENTRY, "ldap_pvt_sasl_getmech\n", 0, 0, 0 );
374 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n", 0, 0, 0 );
377 rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE,
378 NULL, attrs, 0, &res );
380 if ( rc != LDAP_SUCCESS ) {
384 e = ldap_first_entry( ld, res );
387 if ( ld->ld_errno == LDAP_SUCCESS ) {
388 ld->ld_errno = LDAP_NO_SUCH_OBJECT;
393 values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
394 if ( values == NULL ) {
396 ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
400 mechlist = ldap_charray2str( values, " " );
401 if ( mechlist == NULL ) {
402 LDAP_VFREE( values );
404 ld->ld_errno = LDAP_NO_MEMORY;
408 LDAP_VFREE( values );
411 *pmechlist = mechlist;
417 * ldap_sasl_interactive_bind_s - interactive SASL authentication
419 * This routine uses interactive callbacks.
421 * LDAP_SUCCESS is returned upon success, the ldap error code
425 ldap_sasl_interactive_bind_s(
427 LDAP_CONST char *dn, /* usually NULL */
428 LDAP_CONST char *mechs,
429 LDAPControl **serverControls,
430 LDAPControl **clientControls,
432 LDAP_SASL_INTERACT_PROC *interact,
437 #if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
438 ldap_pvt_thread_mutex_lock( &ldap_int_sasl_mutex );
440 #ifdef LDAP_CONNECTIONLESS
441 if( LDAP_IS_UDP(ld) ) {
442 /* Just force it to simple bind, silly to make the user
443 * ask all the time. No, we don't ever actually bind, but I'll
444 * let the final bind handler take care of saving the cdn.
446 rc = ldap_simple_bind( ld, dn, NULL );
447 rc = rc < 0 ? rc : 0;
451 if( mechs == NULL || *mechs == '\0' ) {
454 rc = ldap_pvt_sasl_getmechs( ld, &smechs );
455 if( rc != LDAP_SUCCESS ) {
460 LDAP_LOG ( TRANSPORT, DETAIL1,
461 "ldap_sasl_interactive_bind_s: server supports: %s\n",
464 Debug( LDAP_DEBUG_TRACE,
465 "ldap_sasl_interactive_bind_s: server supports: %s\n",
473 LDAP_LOG ( TRANSPORT, DETAIL1,
474 "ldap_sasl_interactive_bind_s: user selected: %s\n",
477 Debug( LDAP_DEBUG_TRACE,
478 "ldap_sasl_interactive_bind_s: user selected: %s\n",
483 rc = ldap_int_sasl_bind( ld, dn, mechs,
484 serverControls, clientControls,
485 flags, interact, defaults );
488 #if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
489 ldap_pvt_thread_mutex_unlock( &ldap_int_sasl_mutex );