1 /* $OpenLDAP: pkg/ldap/libraries/libldap/sasl.c,v 1.64.2.4 2008/02/11 23:26:41 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
17 * BindRequest ::= SEQUENCE {
19 * name DistinguishedName, -- who
20 * authentication CHOICE {
21 * simple [0] OCTET STRING -- passwd
22 * krbv42ldap [1] OCTET STRING -- OBSOLETE
23 * krbv42dsa [2] OCTET STRING -- OBSOLETE
24 * sasl [3] SaslCredentials -- LDAPv3
28 * BindResponse ::= SEQUENCE {
29 * COMPONENTS OF LDAPResult,
30 * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3
39 #include <ac/socket.h>
40 #include <ac/stdlib.h>
41 #include <ac/string.h>
48 * ldap_sasl_bind - bind to the ldap server (and X.500).
49 * The dn (usually NULL), mechanism, and credentials are provided.
50 * The message id of the request initiated is provided upon successful
51 * (LDAP_SUCCESS) return.
54 * ldap_sasl_bind( ld, NULL, "mechanism",
55 * cred, NULL, NULL, &msgid )
62 LDAP_CONST
char *mechanism
,
72 Debug( LDAP_DEBUG_TRACE
, "ldap_sasl_bind\n", 0, 0, 0 );
75 assert( LDAP_VALID( ld
) );
76 assert( msgidp
!= NULL
);
78 /* check client controls */
79 rc
= ldap_int_client_controls( ld
, cctrls
);
80 if( rc
!= LDAP_SUCCESS
) return rc
;
82 if( mechanism
== LDAP_SASL_SIMPLE
) {
83 if( dn
== NULL
&& cred
!= NULL
&& cred
->bv_len
) {
84 /* use default binddn */
85 dn
= ld
->ld_defbinddn
;
88 } else if( ld
->ld_version
< LDAP_VERSION3
) {
89 ld
->ld_errno
= LDAP_NOT_SUPPORTED
;
97 /* create a message to send */
98 if ( (ber
= ldap_alloc_ber_with_options( ld
)) == NULL
) {
99 ld
->ld_errno
= LDAP_NO_MEMORY
;
103 assert( LBER_VALID( ber
) );
105 LDAP_NEXT_MSGID( ld
, id
);
106 if( mechanism
== LDAP_SASL_SIMPLE
) {
108 rc
= ber_printf( ber
, "{it{istON}" /*}*/,
110 ld
->ld_version
, dn
, LDAP_AUTH_SIMPLE
,
113 } else if ( cred
== NULL
|| cred
->bv_val
== NULL
) {
114 /* SASL bind w/o credentials */
115 rc
= ber_printf( ber
, "{it{ist{sN}N}" /*}*/,
117 ld
->ld_version
, dn
, LDAP_AUTH_SASL
,
121 /* SASL bind w/ credentials */
122 rc
= ber_printf( ber
, "{it{ist{sON}N}" /*}*/,
124 ld
->ld_version
, dn
, LDAP_AUTH_SASL
,
129 ld
->ld_errno
= LDAP_ENCODING_ERROR
;
134 /* Put Server Controls */
135 if( ldap_int_put_controls( ld
, sctrls
, ber
) != LDAP_SUCCESS
) {
140 if ( ber_printf( ber
, /*{*/ "N}" ) == -1 ) {
141 ld
->ld_errno
= LDAP_ENCODING_ERROR
;
147 /* send the message */
148 *msgidp
= ldap_send_initial_request( ld
, LDAP_REQ_BIND
, dn
, ber
, id
);
161 LDAP_CONST
char *mechanism
,
163 LDAPControl
**sctrls
,
164 LDAPControl
**cctrls
,
165 struct berval
**servercredp
)
169 struct berval
*scredp
= NULL
;
171 Debug( LDAP_DEBUG_TRACE
, "ldap_sasl_bind_s\n", 0, 0, 0 );
173 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
174 if( servercredp
!= NULL
) {
175 if (ld
->ld_version
< LDAP_VERSION3
) {
176 ld
->ld_errno
= LDAP_NOT_SUPPORTED
;
182 rc
= ldap_sasl_bind( ld
, dn
, mechanism
, cred
, sctrls
, cctrls
, &msgid
);
184 if ( rc
!= LDAP_SUCCESS
) {
188 #ifdef LDAP_CONNECTIONLESS
189 if (LDAP_IS_UDP(ld
)) {
194 if ( ldap_result( ld
, msgid
, LDAP_MSG_ALL
, NULL
, &result
) == -1 || !result
) {
195 return( ld
->ld_errno
); /* ldap_result sets ld_errno */
198 /* parse the results */
200 if( servercredp
!= NULL
) {
201 rc
= ldap_parse_sasl_bind_result( ld
, result
, &scredp
, 0 );
204 if ( rc
!= LDAP_SUCCESS
) {
205 ldap_msgfree( result
);
209 rc
= ldap_result2error( ld
, result
, 1 );
211 if ( rc
== LDAP_SUCCESS
|| rc
== LDAP_SASL_BIND_IN_PROGRESS
) {
212 if( servercredp
!= NULL
) {
213 *servercredp
= scredp
;
218 if ( scredp
!= NULL
) {
227 * Parse BindResponse:
229 * BindResponse ::= [APPLICATION 1] SEQUENCE {
230 * COMPONENTS OF LDAPResult,
231 * serverSaslCreds [7] OCTET STRING OPTIONAL }
233 * LDAPResult ::= SEQUENCE {
234 * resultCode ENUMERATED,
236 * errorMessage LDAPString,
237 * referral [3] Referral OPTIONAL }
241 ldap_parse_sasl_bind_result(
244 struct berval
**servercredp
,
248 struct berval
* scred
;
253 Debug( LDAP_DEBUG_TRACE
, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
255 assert( ld
!= NULL
);
256 assert( LDAP_VALID( ld
) );
257 assert( res
!= NULL
);
259 if( servercredp
!= NULL
) {
260 if( ld
->ld_version
< LDAP_VERSION2
) {
261 return LDAP_NOT_SUPPORTED
;
266 if( res
->lm_msgtype
!= LDAP_RES_BIND
) {
267 ld
->ld_errno
= LDAP_PARAM_ERROR
;
273 if ( ld
->ld_error
) {
274 LDAP_FREE( ld
->ld_error
);
277 if ( ld
->ld_matched
) {
278 LDAP_FREE( ld
->ld_matched
);
279 ld
->ld_matched
= NULL
;
284 ber
= ber_dup( res
->lm_ber
);
287 ld
->ld_errno
= LDAP_NO_MEMORY
;
291 if ( ld
->ld_version
< LDAP_VERSION2
) {
292 tag
= ber_scanf( ber
, "{iA}",
293 &errcode
, &ld
->ld_error
);
295 if( tag
== LBER_ERROR
) {
297 ld
->ld_errno
= LDAP_DECODING_ERROR
;
304 tag
= ber_scanf( ber
, "{eAA" /*}*/,
305 &errcode
, &ld
->ld_matched
, &ld
->ld_error
);
307 if( tag
== LBER_ERROR
) {
309 ld
->ld_errno
= LDAP_DECODING_ERROR
;
313 tag
= ber_peek_tag(ber
, &len
);
315 if( tag
== LDAP_TAG_REFERRAL
) {
317 if( ber_scanf( ber
, "x" ) == LBER_ERROR
) {
319 ld
->ld_errno
= LDAP_DECODING_ERROR
;
323 tag
= ber_peek_tag(ber
, &len
);
326 if( tag
== LDAP_TAG_SASL_RES_CREDS
) {
327 if( ber_scanf( ber
, "O", &scred
) == LBER_ERROR
) {
329 ld
->ld_errno
= LDAP_DECODING_ERROR
;
337 if ( servercredp
!= NULL
) {
338 *servercredp
= scred
;
340 } else if ( scred
!= NULL
) {
344 ld
->ld_errno
= errcode
;
350 return( LDAP_SUCCESS
);
354 ldap_pvt_sasl_getmechs ( LDAP
*ld
, char **pmechlist
)
356 /* we need to query the server for supported mechs anyway */
357 LDAPMessage
*res
, *e
;
358 char *attrs
[] = { "supportedSASLMechanisms", NULL
};
359 char **values
, *mechlist
;
362 Debug( LDAP_DEBUG_TRACE
, "ldap_pvt_sasl_getmech\n", 0, 0, 0 );
364 rc
= ldap_search_s( ld
, "", LDAP_SCOPE_BASE
,
365 NULL
, attrs
, 0, &res
);
367 if ( rc
!= LDAP_SUCCESS
) {
371 e
= ldap_first_entry( ld
, res
);
374 if ( ld
->ld_errno
== LDAP_SUCCESS
) {
375 ld
->ld_errno
= LDAP_NO_SUCH_OBJECT
;
380 values
= ldap_get_values( ld
, e
, "supportedSASLMechanisms" );
381 if ( values
== NULL
) {
383 ld
->ld_errno
= LDAP_NO_SUCH_ATTRIBUTE
;
387 mechlist
= ldap_charray2str( values
, " " );
388 if ( mechlist
== NULL
) {
389 LDAP_VFREE( values
);
391 ld
->ld_errno
= LDAP_NO_MEMORY
;
395 LDAP_VFREE( values
);
398 *pmechlist
= mechlist
;
404 * ldap_sasl_interactive_bind_s - interactive SASL authentication
406 * This routine uses interactive callbacks.
408 * LDAP_SUCCESS is returned upon success, the ldap error code
412 ldap_sasl_interactive_bind_s(
414 LDAP_CONST
char *dn
, /* usually NULL */
415 LDAP_CONST
char *mechs
,
416 LDAPControl
**serverControls
,
417 LDAPControl
**clientControls
,
419 LDAP_SASL_INTERACT_PROC
*interact
,
425 #if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
426 ldap_pvt_thread_mutex_lock( &ldap_int_sasl_mutex
);
428 #ifdef LDAP_CONNECTIONLESS
429 if( LDAP_IS_UDP(ld
) ) {
430 /* Just force it to simple bind, silly to make the user
431 * ask all the time. No, we don't ever actually bind, but I'll
432 * let the final bind handler take care of saving the cdn.
434 rc
= ldap_simple_bind( ld
, dn
, NULL
);
435 rc
= rc
< 0 ? rc
: 0;
440 #ifdef HAVE_CYRUS_SASL
441 if( mechs
== NULL
|| *mechs
== '\0' ) {
442 mechs
= ld
->ld_options
.ldo_def_sasl_mech
;
446 if( mechs
== NULL
|| *mechs
== '\0' ) {
447 rc
= ldap_pvt_sasl_getmechs( ld
, &smechs
);
448 if( rc
!= LDAP_SUCCESS
) {
452 Debug( LDAP_DEBUG_TRACE
,
453 "ldap_sasl_interactive_bind_s: server supports: %s\n",
459 Debug( LDAP_DEBUG_TRACE
,
460 "ldap_sasl_interactive_bind_s: user selected: %s\n",
464 rc
= ldap_int_sasl_bind( ld
, dn
, mechs
,
465 serverControls
, clientControls
,
466 flags
, interact
, defaults
);
469 #if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
470 ldap_pvt_thread_mutex_unlock( &ldap_int_sasl_mutex
);
472 if ( smechs
) LDAP_FREE( smechs
);