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;
206 } else if (scredp != NULL ) {
215 * Parse BindResponse:
217 * BindResponse ::= [APPLICATION 1] SEQUENCE {
218 * COMPONENTS OF LDAPResult,
219 * serverSaslCreds [7] OCTET STRING OPTIONAL }
221 * LDAPResult ::= SEQUENCE {
222 * resultCode ENUMERATED,
224 * errorMessage LDAPString,
225 * referral [3] Referral OPTIONAL }
229 ldap_parse_sasl_bind_result(
232 struct berval **servercredp,
236 struct berval* scred;
241 Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
243 assert( ld != NULL );
244 assert( LDAP_VALID( ld ) );
245 assert( res != NULL );
247 if ( ld == NULL || res == NULL ) {
248 return LDAP_PARAM_ERROR;
251 if( servercredp != NULL ) {
252 if( ld->ld_version < LDAP_VERSION2 ) {
253 return LDAP_NOT_SUPPORTED;
258 if( res->lm_msgtype != LDAP_RES_BIND ) {
259 ld->ld_errno = LDAP_PARAM_ERROR;
265 if ( ld->ld_error ) {
266 LDAP_FREE( ld->ld_error );
269 if ( ld->ld_matched ) {
270 LDAP_FREE( ld->ld_matched );
271 ld->ld_matched = NULL;
276 ber = ber_dup( res->lm_ber );
279 ld->ld_errno = LDAP_NO_MEMORY;
283 if ( ld->ld_version < LDAP_VERSION2 ) {
284 tag = ber_scanf( ber, "{ia}",
285 &errcode, &ld->ld_error );
287 if( tag == LBER_ERROR ) {
289 ld->ld_errno = LDAP_DECODING_ERROR;
296 tag = ber_scanf( ber, "{iaa" /*}*/,
297 &errcode, &ld->ld_matched, &ld->ld_error );
299 if( tag == LBER_ERROR ) {
301 ld->ld_errno = LDAP_DECODING_ERROR;
305 tag = ber_peek_tag(ber, &len);
307 if( tag == LDAP_TAG_REFERRAL ) {
309 if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
311 ld->ld_errno = LDAP_DECODING_ERROR;
315 tag = ber_peek_tag(ber, &len);
318 if( tag == LDAP_TAG_SASL_RES_CREDS ) {
319 if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) {
321 ld->ld_errno = LDAP_DECODING_ERROR;
329 if ( servercredp != NULL ) {
330 *servercredp = scred;
332 } else if ( scred != NULL ) {
336 ld->ld_errno = errcode;
342 return( ld->ld_errno );
345 #ifdef HAVE_CYRUS_SASL
347 * Various Cyrus SASL related stuff.
350 static int sasl_setup( Sockbuf *sb, void *arg );
351 static int sasl_remove( Sockbuf *sb );
352 static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t len );
353 static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len );
354 static int sasl_close( Sockbuf *sb );
356 static Sockbuf_IO sasl_io=
365 #define HAS_SASL( sb ) ((sb)->sb_io==&sasl_io)
368 array2str( char **a )
373 for ( v = a; *v != NULL; v++ ) {
374 len += strlen( *v ) + 1; /* for a space */
381 s = LDAP_MALLOC ( len ); /* last space holds \0 */
388 for ( v = a; *v != NULL; v++ ) {
392 strncpy( p, " ", 1 );
396 strncpy( p, *v, len );
405 int ldap_pvt_sasl_init( void )
407 /* XXX not threadsafe */
408 static int sasl_initialized = 0;
410 if ( sasl_initialized ) {
414 sasl_set_alloc( ber_memalloc, ber_memcalloc, ber_memrealloc, ber_memfree );
415 #endif /* CSRIMALLOC */
417 if ( sasl_client_init( NULL ) == SASL_OK ) {
418 sasl_initialized = 1;
425 int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
427 /* don't install the stuff unless security has been negotiated */
429 if ( !HAS_SASL( sb ) ) {
430 ber_pvt_sb_clear_io( sb );
431 ber_pvt_sb_set_io( sb, &sasl_io, ctx_arg );
437 static int sasl_setup( Sockbuf *sb, void *arg )
443 static int sasl_remove( Sockbuf *sb )
448 static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t buflen )
451 unsigned recv_tok_len;
452 sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
454 if ((ber_pvt_sb_io_tcp.sbi_read)( sb, buf, buflen ) != buflen ) {
458 if ( sasl_decode( conn, buf, buflen, &recv_tok, &recv_tok_len ) != SASL_OK ) {
462 if ( recv_tok_len > buflen ) {
463 LDAP_FREE( recv_tok );
467 memcpy( buf, recv_tok, recv_tok_len );
469 LDAP_FREE( recv_tok );
474 static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len )
477 unsigned wrapped_tok_len;
478 sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
480 if ( sasl_encode( conn, (const char *)buf, len,
481 &wrapped_tok, &wrapped_tok_len ) != SASL_OK ) {
485 if ((ber_pvt_sb_io_tcp.sbi_write)( sb, wrapped_tok, wrapped_tok_len ) != wrapped_tok_len ) {
486 LDAP_FREE( wrapped_tok );
490 LDAP_FREE( wrapped_tok );
495 static int sasl_close( Sockbuf *sb )
497 (ber_pvt_sb_io_tcp.sbi_close)( sb );
501 sasl_err2ldap( int saslerr )
507 rc = LDAP_MORE_RESULTS_TO_RETURN;
513 rc = LDAP_LOCAL_ERROR;
519 rc = LDAP_AUTH_UNKNOWN;
522 rc = LDAP_AUTH_UNKNOWN;
525 rc = LDAP_PARAM_ERROR;
529 rc = LDAP_AUTH_UNKNOWN;
532 rc = LDAP_LOCAL_ERROR;
536 assert( rc == LDAP_SUCCESS || LDAP_API_ERROR( rc ) );
541 ldap_pvt_sasl_getmechs ( LDAP *ld, LDAP_CONST char *desired, char **pmechlist )
543 /* we need to query the server for supported mechs anyway */
544 LDAPMessage *res, *e;
545 char *attrs[] = { "supportedSASLMechanisms", NULL };
546 char **values, *mechlist, **p;
549 rc = ldap_search_s( ld, NULL, LDAP_SCOPE_BASE,
550 NULL, attrs, 0, &res );
552 if ( rc != LDAP_SUCCESS ) {
556 e = ldap_first_entry( ld, res );
558 if ( ld->ld_errno == LDAP_SUCCESS ) {
559 ld->ld_errno = LDAP_UNAVAILABLE;
564 values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
565 if ( values == NULL ) {
566 ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
571 if ( desired != NULL ) {
572 rc = LDAP_INAPPROPRIATE_AUTH;
574 for ( p = values; *p != NULL; p++ ) {
575 if ( strcmp( *p, desired ) == 0 ) {
581 if ( rc == LDAP_SUCCESS ) {
582 /* just return this */
583 *pmechlist = LDAP_STRDUP( desired );
586 /* couldn't find it */
587 ld->ld_errno = LDAP_INAPPROPRIATE_AUTH;
592 mechlist = array2str( values );
593 if ( mechlist == NULL ) {
594 ld->ld_errno = LDAP_NO_MEMORY;
595 ldap_value_free( values );
600 ldap_value_free( values );
603 *pmechlist = mechlist;
612 LDAP_CONST char *mechanism,
613 LDAP_CONST sasl_callback_t *callbacks,
614 LDAPControl **sctrls,
615 LDAPControl **cctrls )
617 int saslrc, rc, msgid, ssf = 0;
618 struct berval ccred, *scred;
619 char *mechlist = NULL;
621 sasl_interact_t *client_interact = NULL;
623 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_bind\n", 0, 0, 0 );
625 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
626 if (ld->ld_version < LDAP_VERSION3) {
627 ld->ld_errno = LDAP_NOT_SUPPORTED;
632 * This connects to the host, side effect being that
633 * ldap_host_connected_to() works.
635 rc = ldap_pvt_sasl_getmechs( ld, mechanism, &mechlist );
636 if ( rc != LDAP_SUCCESS ) {
640 /* XXX this doesn't work with PF_LOCAL hosts */
641 host = ldap_host_connected_to( &ld->ld_sb );
643 if ( host == NULL ) {
644 LDAP_FREE( mechlist );
645 ld->ld_errno = LDAP_UNAVAILABLE;
649 if ( ld->ld_sasl_context != NULL ) {
650 LDAP_FREE( mechlist );
651 sasl_dispose( &ld->ld_sasl_context );
654 saslrc = sasl_client_new( "ldap", host, callbacks, 0, &ld->ld_sasl_context );
658 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
659 LDAP_FREE( mechlist );
660 ld->ld_errno = sasl_err2ldap( rc );
661 sasl_dispose( &ld->ld_sasl_context );
668 saslrc = sasl_client_start( ld->ld_sasl_context,
673 (unsigned int *)&ccred.bv_len,
676 LDAP_FREE( mechlist );
678 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
679 ld->ld_errno = sasl_err2ldap( saslrc );
680 sasl_dispose( &ld->ld_sasl_context );
687 sasl_interact_t *client_interact = NULL;
689 rc = ldap_sasl_bind_s( ld, dn, mechanism, &ccred, sctrls, cctrls, &scred );
690 if ( rc == LDAP_SUCCESS ) {
692 } else if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) {
693 if ( ccred.bv_val != NULL ) {
694 LDAP_FREE( ccred.bv_val );
696 sasl_dispose( &ld->ld_sasl_context );
700 if ( ccred.bv_val != NULL ) {
701 LDAP_FREE( ccred.bv_val );
705 saslrc = sasl_client_step( ld->ld_sasl_context,
706 (scred == NULL) ? NULL : scred->bv_val,
707 (scred == NULL) ? 0 : scred->bv_len,
710 (unsigned int *)&ccred.bv_len );
714 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
715 ld->ld_errno = sasl_err2ldap( saslrc );
716 sasl_dispose( &ld->ld_sasl_context );
719 } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
721 assert ( rc == LDAP_SUCCESS );
723 if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, (void **)&ssf )
724 == SASL_OK && ssf ) {
725 ldap_pvt_sasl_install( &ld->ld_sb, ld->ld_sasl_context );
731 /* based on sample/sample-client.c */
733 ldap_pvt_sasl_getsecret(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
735 struct berval *passphrase = (struct berval *)context;
738 if ( conn == NULL || psecret == NULL || id != SASL_CB_PASS ) {
739 return SASL_BADPARAM;
742 len = (passphrase != NULL) ? (size_t)passphrase->bv_len: 0;
744 *psecret = (sasl_secret_t *) LDAP_MALLOC( sizeof( sasl_secret_t ) + len );
745 if ( *psecret == NULL ) {
749 (*psecret)->len = passphrase->bv_len;
751 if ( passphrase != NULL ) {
752 memcpy((*psecret)->data, passphrase->bv_val, len);
759 ldap_pvt_sasl_getsimple(void *context, int id, const char **result, int *len)
761 const char *value = (const char *)context;
763 if ( result == NULL ) {
764 return SASL_BADPARAM;
769 case SASL_CB_AUTHNAME:
772 *len = value ? strlen( value ) : 0;
774 case SASL_CB_LANGUAGE:
780 return SASL_BADPARAM;
787 ldap_pvt_sasl_get_option( LDAP *ld, int option, void *arg )
795 case LDAP_OPT_X_SASL_MINSSF:
796 *(int *)arg = ld->ld_options.ldo_sasl_minssf;
798 case LDAP_OPT_X_SASL_MAXSSF:
799 *(int *)arg = ld->ld_options.ldo_sasl_maxssf;
801 case LDAP_OPT_X_SASL_ACTSSF:
802 if ( ld->ld_sasl_context == NULL ) {
806 if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, &ssf )
818 ldap_pvt_sasl_set_option( LDAP *ld, int option, void *arg )
824 case LDAP_OPT_X_SASL_MINSSF:
825 ld->ld_options.ldo_sasl_minssf = *(int *)arg;
827 case LDAP_OPT_X_SASL_MAXSSF:
828 ld->ld_options.ldo_sasl_maxssf = *(int *)arg;
830 case LDAP_OPT_X_SASL_ACTSSF:
831 /* This option is read-only */
839 * ldap_negotiated_sasl_bind_s - bind to the ldap server (and X.500)
840 * using SASL authentication.
842 * This routine attempts to authenticate the user referred by the
843 * authentication id using the provided password. An optional
844 * authorization identity may be provided. An DN is generally not
845 * provided [see AuthMethod].
847 * If the mechanism negotiated does not require a password, the
848 * passwd field is ignored. [A callback mechanism should really
851 * LDAP_SUCCESS is returned upon success, the ldap error code
855 * ldap_negotiated_sasl_bind_s( ld, NULL,
856 * "user@OPENLDAP.ORG", NULL, NULL,
857 * "GSSAPI", NULL, NULL, NULL );
859 * ldap_negotiated_sasl_bind_s( ld, NULL,
860 * "manager", "cn=user,dc=openldap,dc=org", NULL,
861 * "DIGEST-MD5", NULL, NULL, NULL );
863 * ldap_negotiated_sasl_bind_s( ld, NULL,
864 * "root@OPENLDAP.ORG", "u:user@OPENLDAP.ORG", NULL,
865 * "GSSAPI", NULL, NULL, NULL );
867 * ldap_negotiated_sasl_bind_s( ld, NULL,
868 * "manager", "dn:cn=user,dc=openldap,dc=org", NULL,
869 * "DIGEST-MD5", NULL, NULL, NULL );
872 ldap_negotiated_sasl_bind_s(
874 LDAP_CONST char *dn, /* usually NULL */
875 LDAP_CONST char *authenticationId,
876 LDAP_CONST char *authorizationId, /* commonly NULL */
877 LDAP_CONST char *saslMechanism,
878 struct berval *passPhrase,
879 LDAPControl **serverControls,
880 LDAPControl **clientControls)
883 sasl_callback_t callbacks[4];
886 /* SASL Authentication Identity */
887 callbacks[n=0].id = SASL_CB_AUTHNAME;
888 callbacks[n].proc = ldap_pvt_sasl_getsimple;
889 callbacks[n].context = (void *)authenticationId;
891 /* SASL Authorization Identity (userid) */
892 if( authorizationId != NULL ) {
893 callbacks[++n].id = SASL_CB_USER;
894 callbacks[n].proc = ldap_pvt_sasl_getsimple;
895 callbacks[n].context = (void *)authorizationId;
898 callbacks[++n].id = SASL_CB_PASS;
899 callbacks[n].proc = ldap_pvt_sasl_getsecret;
900 callbacks[n].context = (void *)passPhrase;
902 callbacks[++n].id = SASL_CB_LIST_END;
903 callbacks[n].proc = NULL;
904 callbacks[n].context = NULL;
906 rc = ldap_pvt_sasl_bind(ld, dn, saslMechanism, callbacks,
907 serverControls, clientControls);
911 #endif /* HAVE_CYRUS_SASL */