3 * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
8 * BindRequest ::= SEQUENCE {
10 * name DistinguishedName, -- who
11 * authentication CHOICE {
12 * simple [0] OCTET STRING -- passwd
13 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
14 * krbv42ldap [1] OCTET STRING
15 * krbv42dsa [2] OCTET STRING
17 * sasl [3] SaslCredentials -- LDAPv3
21 * BindResponse ::= SEQUENCE {
22 * COMPONENTS OF LDAPResult,
23 * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3
32 #include <ac/socket.h>
33 #include <ac/string.h>
40 * ldap_sasl_bind - bind to the ldap server (and X.500).
41 * The dn (usually NULL), mechanism, and credentials are provided.
42 * The message id of the request initiated is provided upon successful
43 * (LDAP_SUCCESS) return.
46 * ldap_sasl_bind( ld, NULL, "mechanism",
47 * cred, NULL, NULL, &msgid )
54 LDAP_CONST char *mechanism,
63 Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 );
66 assert( LDAP_VALID( ld ) );
67 assert( msgidp != NULL );
69 if( msgidp == NULL ) {
70 ld->ld_errno = LDAP_PARAM_ERROR;
74 if( mechanism == LDAP_SASL_SIMPLE ) {
75 if( dn == NULL && cred != NULL ) {
76 /* use default binddn */
77 dn = ld->ld_defbinddn;
80 } else if( ld->ld_version < LDAP_VERSION3 ) {
81 ld->ld_errno = LDAP_NOT_SUPPORTED;
89 /* create a message to send */
90 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
91 ld->ld_errno = LDAP_NO_MEMORY;
95 assert( BER_VALID( ber ) );
97 if( mechanism == LDAP_SASL_SIMPLE ) {
99 rc = ber_printf( ber, "{it{istO}" /*}*/,
100 ++ld->ld_msgid, LDAP_REQ_BIND,
101 ld->ld_version, dn, LDAP_AUTH_SIMPLE,
104 } else if ( cred == NULL ) {
105 /* SASL bind w/o creditials */
106 rc = ber_printf( ber, "{it{ist{s}}" /*}*/,
107 ++ld->ld_msgid, LDAP_REQ_BIND,
108 ld->ld_version, dn, LDAP_AUTH_SASL,
112 /* SASL bind w/ creditials */
113 rc = ber_printf( ber, "{it{ist{sO}}" /*}*/,
114 ++ld->ld_msgid, LDAP_REQ_BIND,
115 ld->ld_version, dn, LDAP_AUTH_SASL,
120 ld->ld_errno = LDAP_ENCODING_ERROR;
125 /* Put Server Controls */
126 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
131 if ( ber_printf( ber, /*{*/ "}" ) == -1 ) {
132 ld->ld_errno = LDAP_ENCODING_ERROR;
138 if ( ld->ld_cache != NULL ) {
139 ldap_flush_cache( ld );
141 #endif /* !LDAP_NOCACHE */
143 /* send the message */
144 *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber );
157 LDAP_CONST char *mechanism,
159 LDAPControl **sctrls,
160 LDAPControl **cctrls,
161 struct berval **servercredp )
165 struct berval *scredp = NULL;
167 Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 );
169 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
170 if( servercredp != NULL ) {
171 if (ld->ld_version < LDAP_VERSION3) {
172 ld->ld_errno = LDAP_NOT_SUPPORTED;
178 rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid );
180 if ( rc != LDAP_SUCCESS ) {
184 if ( ldap_result( ld, msgid, 1, NULL, &result ) == -1 ) {
185 return( ld->ld_errno ); /* ldap_result sets ld_errno */
188 /* parse the results */
190 if( servercredp != NULL ) {
191 rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 );
194 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
195 ldap_msgfree( result );
199 rc = ldap_result2error( ld, result, 1 );
201 if ( rc == LDAP_SUCCESS || rc == LDAP_SASL_BIND_IN_PROGRESS ) {
202 if( servercredp != NULL ) {
203 *servercredp = scredp;
208 if ( scredp != NULL ) {
217 * Parse BindResponse:
219 * BindResponse ::= [APPLICATION 1] SEQUENCE {
220 * COMPONENTS OF LDAPResult,
221 * serverSaslCreds [7] OCTET STRING OPTIONAL }
223 * LDAPResult ::= SEQUENCE {
224 * resultCode ENUMERATED,
226 * errorMessage LDAPString,
227 * referral [3] Referral OPTIONAL }
231 ldap_parse_sasl_bind_result(
234 struct berval **servercredp,
238 struct berval* scred;
243 Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
245 assert( ld != NULL );
246 assert( LDAP_VALID( ld ) );
247 assert( res != NULL );
249 if ( ld == NULL || res == NULL ) {
250 return LDAP_PARAM_ERROR;
253 if( servercredp != NULL ) {
254 if( ld->ld_version < LDAP_VERSION2 ) {
255 return LDAP_NOT_SUPPORTED;
260 if( res->lm_msgtype != LDAP_RES_BIND ) {
261 ld->ld_errno = LDAP_PARAM_ERROR;
267 if ( ld->ld_error ) {
268 LDAP_FREE( ld->ld_error );
271 if ( ld->ld_matched ) {
272 LDAP_FREE( ld->ld_matched );
273 ld->ld_matched = NULL;
278 ber = ber_dup( res->lm_ber );
281 ld->ld_errno = LDAP_NO_MEMORY;
285 if ( ld->ld_version < LDAP_VERSION2 ) {
286 tag = ber_scanf( ber, "{ia}",
287 &errcode, &ld->ld_error );
289 if( tag == LBER_ERROR ) {
291 ld->ld_errno = LDAP_DECODING_ERROR;
298 tag = ber_scanf( ber, "{iaa" /*}*/,
299 &errcode, &ld->ld_matched, &ld->ld_error );
301 if( tag == LBER_ERROR ) {
303 ld->ld_errno = LDAP_DECODING_ERROR;
307 tag = ber_peek_tag(ber, &len);
309 if( tag == LDAP_TAG_REFERRAL ) {
311 if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
313 ld->ld_errno = LDAP_DECODING_ERROR;
317 tag = ber_peek_tag(ber, &len);
320 if( tag == LDAP_TAG_SASL_RES_CREDS ) {
321 if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) {
323 ld->ld_errno = LDAP_DECODING_ERROR;
331 if ( servercredp != NULL ) {
332 *servercredp = scred;
334 } else if ( scred != NULL ) {
338 ld->ld_errno = errcode;
344 return( ld->ld_errno );
347 #ifdef HAVE_CYRUS_SASL
349 * Various Cyrus SASL related stuff.
352 static int sasl_setup( Sockbuf *sb, void *arg );
353 static int sasl_remove( Sockbuf *sb );
354 static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t len );
355 static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len );
356 static int sasl_close( Sockbuf *sb );
358 static Sockbuf_IO sasl_io=
367 #define HAS_SASL( sb ) ((sb)->sb_io==&sasl_io)
370 array2str( char **a )
375 for ( v = a; *v != NULL; v++ ) {
376 len += strlen( *v ) + 1; /* for a space */
383 s = LDAP_MALLOC ( len ); /* last space holds \0 */
390 for ( v = a; *v != NULL; v++ ) {
394 strncpy( p, " ", 1 );
398 strncpy( p, *v, len );
407 int ldap_pvt_sasl_init( void )
409 /* XXX not threadsafe */
410 static int sasl_initialized = 0;
412 if ( sasl_initialized ) {
416 sasl_set_alloc( ber_memalloc, ber_memcalloc, ber_memrealloc, ber_memfree );
417 #endif /* CSRIMALLOC */
419 if ( sasl_client_init( NULL ) == SASL_OK ) {
420 sasl_initialized = 1;
427 int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
429 /* don't install the stuff unless security has been negotiated */
431 if ( !HAS_SASL( sb ) ) {
432 ber_pvt_sb_clear_io( sb );
433 ber_pvt_sb_set_io( sb, &sasl_io, ctx_arg );
439 static int sasl_setup( Sockbuf *sb, void *arg )
445 static int sasl_remove( Sockbuf *sb )
450 static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t buflen )
453 unsigned recv_tok_len;
454 sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
456 if ((ber_pvt_sb_io_tcp.sbi_read)( sb, buf, buflen ) != buflen ) {
460 if ( sasl_decode( conn, buf, buflen, &recv_tok, &recv_tok_len ) != SASL_OK ) {
464 if ( recv_tok_len > buflen ) {
465 LDAP_FREE( recv_tok );
469 memcpy( buf, recv_tok, recv_tok_len );
471 LDAP_FREE( recv_tok );
476 static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len )
479 unsigned wrapped_tok_len;
480 sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
482 if ( sasl_encode( conn, (const char *)buf, len,
483 &wrapped_tok, &wrapped_tok_len ) != SASL_OK ) {
487 if ((ber_pvt_sb_io_tcp.sbi_write)( sb, wrapped_tok, wrapped_tok_len ) != wrapped_tok_len ) {
488 LDAP_FREE( wrapped_tok );
492 LDAP_FREE( wrapped_tok );
497 static int sasl_close( Sockbuf *sb )
499 (ber_pvt_sb_io_tcp.sbi_close)( sb );
503 sasl_err2ldap( int saslerr )
509 rc = LDAP_MORE_RESULTS_TO_RETURN;
515 rc = LDAP_LOCAL_ERROR;
521 rc = LDAP_AUTH_UNKNOWN;
524 rc = LDAP_AUTH_UNKNOWN;
527 rc = LDAP_PARAM_ERROR;
531 rc = LDAP_AUTH_UNKNOWN;
534 rc = LDAP_LOCAL_ERROR;
538 assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) );
543 ldap_pvt_sasl_getmechs ( LDAP *ld, LDAP_CONST char *desired, char **pmechlist )
545 /* we need to query the server for supported mechs anyway */
546 LDAPMessage *res, *e;
547 char *attrs[] = { "supportedSASLMechanisms", NULL };
548 char **values, *mechlist, **p;
551 rc = ldap_search_s( ld, NULL, LDAP_SCOPE_BASE,
552 NULL, attrs, 0, &res );
554 if ( rc != LDAP_SUCCESS ) {
558 e = ldap_first_entry( ld, res );
560 if ( ld->ld_errno == LDAP_SUCCESS ) {
561 ld->ld_errno = LDAP_UNAVAILABLE;
566 values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
567 if ( values == NULL ) {
568 ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
573 if ( desired != NULL ) {
574 rc = LDAP_INAPPROPRIATE_AUTH;
576 for ( p = values; *p != NULL; p++ ) {
577 if ( strcmp( *p, desired ) == 0 ) {
583 if ( rc == LDAP_SUCCESS ) {
584 /* just return this */
585 *pmechlist = LDAP_STRDUP( desired );
588 /* couldn't find it */
589 ld->ld_errno = LDAP_INAPPROPRIATE_AUTH;
594 mechlist = array2str( values );
595 if ( mechlist == NULL ) {
596 ld->ld_errno = LDAP_NO_MEMORY;
597 ldap_value_free( values );
602 ldap_value_free( values );
605 *pmechlist = mechlist;
614 LDAP_CONST char *mechanism,
615 LDAP_CONST sasl_callback_t *callbacks,
616 LDAPControl **sctrls,
617 LDAPControl **cctrls )
619 int saslrc, rc, msgid, ssf = 0;
620 struct berval ccred, *scred;
621 char *mechlist = NULL;
623 sasl_interact_t *client_interact = NULL;
625 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_bind\n", 0, 0, 0 );
627 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
628 if (ld->ld_version < LDAP_VERSION3) {
629 ld->ld_errno = LDAP_NOT_SUPPORTED;
634 * This connects to the host, side effect being that
635 * ldap_host_connected_to() works.
637 rc = ldap_pvt_sasl_getmechs( ld, mechanism, &mechlist );
638 if ( rc != LDAP_SUCCESS ) {
642 /* XXX this doesn't work with PF_LOCAL hosts */
643 host = ldap_host_connected_to( &ld->ld_sb );
645 if ( host == NULL ) {
646 LDAP_FREE( mechlist );
647 ld->ld_errno = LDAP_UNAVAILABLE;
651 if ( ld->ld_sasl_context != NULL ) {
652 LDAP_FREE( mechlist );
653 sasl_dispose( &ld->ld_sasl_context );
656 saslrc = sasl_client_new( "ldap", host, callbacks, 0, &ld->ld_sasl_context );
660 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
661 LDAP_FREE( mechlist );
662 ld->ld_errno = sasl_err2ldap( rc );
663 sasl_dispose( &ld->ld_sasl_context );
670 saslrc = sasl_client_start( ld->ld_sasl_context,
675 (unsigned int *)&ccred.bv_len,
678 LDAP_FREE( mechlist );
680 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
681 ld->ld_errno = sasl_err2ldap( saslrc );
682 sasl_dispose( &ld->ld_sasl_context );
689 sasl_interact_t *client_interact = NULL;
691 rc = ldap_sasl_bind_s( ld, dn, mechanism, &ccred, sctrls, cctrls, &scred );
692 if ( rc == LDAP_SUCCESS ) {
694 } else if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) {
695 if ( ccred.bv_val != NULL ) {
696 LDAP_FREE( ccred.bv_val );
698 sasl_dispose( &ld->ld_sasl_context );
702 if ( ccred.bv_val != NULL ) {
703 LDAP_FREE( ccred.bv_val );
707 saslrc = sasl_client_step( ld->ld_sasl_context,
708 (scred == NULL) ? NULL : scred->bv_val,
709 (scred == NULL) ? 0 : scred->bv_len,
712 (unsigned int *)&ccred.bv_len );
716 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
717 ld->ld_errno = sasl_err2ldap( saslrc );
718 sasl_dispose( &ld->ld_sasl_context );
721 } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
723 assert ( rc == LDAP_SUCCESS );
725 if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, (void **)&ssf )
726 == SASL_OK && ssf ) {
727 ldap_pvt_sasl_install( &ld->ld_sb, ld->ld_sasl_context );
733 /* based on sample/sample-client.c */
735 ldap_pvt_sasl_getsecret(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
737 struct berval *passphrase = (struct berval *)context;
740 if ( conn == NULL || psecret == NULL || id != SASL_CB_PASS ) {
741 return SASL_BADPARAM;
744 len = (passphrase != NULL) ? (size_t)passphrase->bv_len: 0;
746 *psecret = (sasl_secret_t *) LDAP_MALLOC( sizeof( sasl_secret_t ) + len );
747 if ( *psecret == NULL ) {
751 (*psecret)->len = passphrase->bv_len;
753 if ( passphrase != NULL ) {
754 memcpy((*psecret)->data, passphrase->bv_val, len);
761 ldap_pvt_sasl_getsimple(void *context, int id, const char **result, int *len)
763 const char *value = (const char *)context;
765 if ( result == NULL ) {
766 return SASL_BADPARAM;
771 case SASL_CB_AUTHNAME:
774 *len = value ? strlen( value ) : 0;
776 case SASL_CB_LANGUAGE:
782 return SASL_BADPARAM;
789 ldap_pvt_sasl_get_option( LDAP *ld, int option, void *arg )
797 case LDAP_OPT_X_SASL_MINSSF:
798 *(int *)arg = ld->ld_options.ldo_sasl_minssf;
800 case LDAP_OPT_X_SASL_MAXSSF:
801 *(int *)arg = ld->ld_options.ldo_sasl_maxssf;
803 case LDAP_OPT_X_SASL_ACTSSF:
804 if ( ld->ld_sasl_context == NULL ) {
808 if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, &ssf )
820 ldap_pvt_sasl_set_option( LDAP *ld, int option, void *arg )
826 case LDAP_OPT_X_SASL_MINSSF:
827 ld->ld_options.ldo_sasl_minssf = *(int *)arg;
829 case LDAP_OPT_X_SASL_MAXSSF:
830 ld->ld_options.ldo_sasl_maxssf = *(int *)arg;
832 case LDAP_OPT_X_SASL_ACTSSF:
833 /* This option is read-only */
841 * ldap_negotiated_sasl_bind_s - bind to the ldap server (and X.500)
842 * using SASL authentication.
844 * This routine attempts to authenticate the user referred by the
845 * authentication id using the provided password. An optional
846 * authorization identity may be provided. An DN is generally not
847 * provided [see AuthMethod].
849 * If the mechanism negotiated does not require a password, the
850 * passwd field is ignored. [A callback mechanism should really
853 * LDAP_SUCCESS is returned upon success, the ldap error code
857 * ldap_negotiated_sasl_bind_s( ld, NULL,
858 * "user@OPENLDAP.ORG", NULL, NULL,
859 * "GSSAPI", NULL, NULL, NULL );
861 * ldap_negotiated_sasl_bind_s( ld, NULL,
862 * "manager", "cn=user,dc=openldap,dc=org", NULL,
863 * "DIGEST-MD5", NULL, NULL, NULL );
865 * ldap_negotiated_sasl_bind_s( ld, NULL,
866 * "root@OPENLDAP.ORG", "u:user@OPENLDAP.ORG", NULL,
867 * "GSSAPI", NULL, NULL, NULL );
869 * ldap_negotiated_sasl_bind_s( ld, NULL,
870 * "manager", "dn:cn=user,dc=openldap,dc=org", NULL,
871 * "DIGEST-MD5", NULL, NULL, NULL );
874 ldap_negotiated_sasl_bind_s(
876 LDAP_CONST char *dn, /* usually NULL */
877 LDAP_CONST char *authenticationId,
878 LDAP_CONST char *authorizationId, /* commonly NULL */
879 LDAP_CONST char *saslMechanism,
880 struct berval *passPhrase,
881 LDAPControl **serverControls,
882 LDAPControl **clientControls)
885 sasl_callback_t callbacks[4];
888 /* SASL Authentication Identity */
889 callbacks[n=0].id = SASL_CB_AUTHNAME;
890 callbacks[n].proc = ldap_pvt_sasl_getsimple;
891 callbacks[n].context = (void *)authenticationId;
893 /* SASL Authorization Identity (userid) */
894 if( authorizationId != NULL ) {
895 callbacks[++n].id = SASL_CB_USER;
896 callbacks[n].proc = ldap_pvt_sasl_getsimple;
897 callbacks[n].context = (void *)authorizationId;
900 callbacks[++n].id = SASL_CB_PASS;
901 callbacks[n].proc = ldap_pvt_sasl_getsecret;
902 callbacks[n].context = (void *)passPhrase;
904 callbacks[++n].id = SASL_CB_LIST_END;
905 callbacks[n].proc = NULL;
906 callbacks[n].context = NULL;
908 rc = ldap_pvt_sasl_bind(ld, dn, saslMechanism, callbacks,
909 serverControls, clientControls);
913 #endif /* HAVE_CYRUS_SASL */