3 * Copyright 1998-2000 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 return (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, 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;
551 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n", 0, 0, 0 );
553 rc = ldap_search_s( ld, NULL, LDAP_SCOPE_BASE,
554 NULL, attrs, 0, &res );
556 if ( rc != LDAP_SUCCESS ) {
560 e = ldap_first_entry( ld, res );
562 if ( ld->ld_errno == LDAP_SUCCESS ) {
563 ld->ld_errno = LDAP_UNAVAILABLE;
568 values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
569 if ( values == NULL ) {
570 ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
575 mechlist = array2str( values );
576 if ( mechlist == NULL ) {
577 ld->ld_errno = LDAP_NO_MEMORY;
578 ldap_value_free( values );
583 ldap_value_free( values );
586 *pmechlist = mechlist;
595 LDAP_CONST char *mechs,
596 LDAP_CONST sasl_callback_t *callbacks,
597 LDAPControl **sctrls,
598 LDAPControl **cctrls )
601 int saslrc, rc, ssf = 0;
603 struct berval ccred, *scred;
605 sasl_interact_t *client_interact = NULL;
607 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_bind\n", 0, 0, 0 );
609 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
610 if (ld->ld_version < LDAP_VERSION3) {
611 ld->ld_errno = LDAP_NOT_SUPPORTED;
615 if( ! ber_pvt_sb_in_use( &ld->ld_sb ) ) {
616 /* not connected yet */
617 int rc = ldap_open_defconn( ld );
619 if( rc < 0 ) return ld->ld_errno;
622 /* XXX this doesn't work with PF_LOCAL hosts */
623 host = ldap_host_connected_to( &ld->ld_sb );
625 if ( host == NULL ) {
626 ld->ld_errno = LDAP_UNAVAILABLE;
630 if ( ld->ld_sasl_context != NULL ) {
631 sasl_dispose( &ld->ld_sasl_context );
634 saslrc = sasl_client_new( "ldap", host, callbacks, 0, &ld->ld_sasl_context );
638 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
639 ld->ld_errno = sasl_err2ldap( rc );
640 sasl_dispose( &ld->ld_sasl_context );
647 saslrc = sasl_client_start( ld->ld_sasl_context,
655 ccred.bv_len = credlen;
657 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
658 ld->ld_errno = sasl_err2ldap( saslrc );
659 sasl_dispose( &ld->ld_sasl_context );
667 sasl_interact_t *client_interact = NULL;
669 rc = ldap_sasl_bind_s( ld, dn, mech, &ccred, sctrls, cctrls, &scred );
670 if ( rc == LDAP_SUCCESS ) {
672 } else if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) {
673 if ( ccred.bv_val != NULL ) {
674 LDAP_FREE( ccred.bv_val );
676 sasl_dispose( &ld->ld_sasl_context );
680 if ( ccred.bv_val != NULL ) {
681 LDAP_FREE( ccred.bv_val );
685 saslrc = sasl_client_step( ld->ld_sasl_context,
686 (scred == NULL) ? NULL : scred->bv_val,
687 (scred == NULL) ? 0 : scred->bv_len,
692 ccred.bv_len = credlen;
695 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
696 ld->ld_errno = sasl_err2ldap( saslrc );
697 sasl_dispose( &ld->ld_sasl_context );
700 } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
702 assert ( rc == LDAP_SUCCESS );
704 if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, (void **)&ssf )
705 == SASL_OK && ssf ) {
706 ldap_pvt_sasl_install( &ld->ld_sb, ld->ld_sasl_context );
712 /* based on sample/sample-client.c */
714 ldap_pvt_sasl_getsecret(sasl_conn_t *conn,
715 void *context, int id, sasl_secret_t **psecret)
717 struct berval *passphrase = (struct berval *)context;
720 if ( conn == NULL || psecret == NULL || id != SASL_CB_PASS ) {
721 return SASL_BADPARAM;
724 len = (passphrase != NULL) ? (size_t)passphrase->bv_len: 0;
726 *psecret = (sasl_secret_t *) LDAP_MALLOC( sizeof( sasl_secret_t ) + len );
727 if ( *psecret == NULL ) {
731 (*psecret)->len = passphrase->bv_len;
733 if ( passphrase != NULL ) {
734 memcpy((*psecret)->data, passphrase->bv_val, len);
741 ldap_pvt_sasl_getsimple(void *context, int id, const char **result, int *len)
743 const char *value = (const char *)context;
745 if ( result == NULL ) {
746 return SASL_BADPARAM;
751 case SASL_CB_AUTHNAME:
754 *len = value ? strlen( value ) : 0;
756 case SASL_CB_LANGUAGE:
762 return SASL_BADPARAM;
769 ldap_pvt_sasl_get_option( LDAP *ld, int option, void *arg )
777 case LDAP_OPT_X_SASL_MINSSF:
778 *(int *)arg = ld->ld_options.ldo_sasl_minssf;
780 case LDAP_OPT_X_SASL_MAXSSF:
781 *(int *)arg = ld->ld_options.ldo_sasl_maxssf;
783 case LDAP_OPT_X_SASL_ACTSSF:
784 if ( ld->ld_sasl_context == NULL ) {
788 if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF,
789 (void **) &ssf ) != SASL_OK )
802 ldap_pvt_sasl_set_option( LDAP *ld, int option, void *arg )
808 case LDAP_OPT_X_SASL_MINSSF:
809 ld->ld_options.ldo_sasl_minssf = *(int *)arg;
811 case LDAP_OPT_X_SASL_MAXSSF:
812 ld->ld_options.ldo_sasl_maxssf = *(int *)arg;
814 case LDAP_OPT_X_SASL_ACTSSF:
815 /* This option is read-only */
823 * ldap_negotiated_sasl_bind_s - bind to the ldap server (and X.500)
824 * using SASL authentication.
826 * This routine attempts to authenticate the user referred by the
827 * authentication id using the provided password. An optional
828 * authorization identity may be provided. An DN is generally not
829 * provided [see AuthMethod].
831 * If the mechanism negotiated does not require a password, the
832 * passwd field is ignored. [A callback mechanism should really
835 * LDAP_SUCCESS is returned upon success, the ldap error code
839 * ldap_negotiated_sasl_bind_s( ld, NULL,
841 * NULL, NULL, NULL, NULL );
843 * ldap_negotiated_sasl_bind_s( ld, NULL,
844 * "user@OPENLDAP.ORG", NULL, NULL,
845 * "GSSAPI", NULL, NULL, NULL );
847 * ldap_negotiated_sasl_bind_s( ld, NULL,
848 * "manager", "dn:cn=user,dc=openldap,dc=org", NULL,
849 * "DIGEST-MD5", NULL, NULL, NULL );
851 * ldap_negotiated_sasl_bind_s( ld, NULL,
852 * "root@OPENLDAP.ORG", "u:user@OPENLDAP.ORG", NULL,
853 * "GSSAPI", NULL, NULL, NULL );
855 * ldap_negotiated_sasl_bind_s( ld, NULL,
856 * "manager", "dn:cn=user,dc=openldap,dc=org", NULL,
857 * "DIGEST-MD5", NULL, NULL, NULL );
860 ldap_negotiated_sasl_bind_s(
862 LDAP_CONST char *dn, /* usually NULL */
863 LDAP_CONST char *authenticationId,
864 LDAP_CONST char *authorizationId, /* commonly NULL */
865 LDAP_CONST char *saslMechanism,
866 struct berval *passPhrase,
867 LDAPControl **serverControls,
868 LDAPControl **clientControls)
871 sasl_callback_t callbacks[4];
874 Debug( LDAP_DEBUG_TRACE, "ldap_negotiated_sasl_bind_s\n", 0, 0, 0 );
876 if( saslMechanism == NULL || *saslMechanism == '\0' ) {
878 rc = ldap_pvt_sasl_getmechs( ld, &mechs );
880 if( rc != LDAP_SUCCESS ) {
884 saslMechanism = mechs;
887 /* SASL Authentication Identity */
888 callbacks[n=0].id = SASL_CB_AUTHNAME;
889 callbacks[n].proc = ldap_pvt_sasl_getsimple;
890 callbacks[n].context = (void *)authenticationId;
892 /* SASL Authorization Identity (userid) */
893 if( authorizationId != NULL ) {
894 callbacks[++n].id = SASL_CB_USER;
895 callbacks[n].proc = ldap_pvt_sasl_getsimple;
896 callbacks[n].context = (void *)authorizationId;
899 callbacks[++n].id = SASL_CB_PASS;
900 callbacks[n].proc = ldap_pvt_sasl_getsecret;
901 callbacks[n].context = (void *)passPhrase;
903 callbacks[++n].id = SASL_CB_LIST_END;
904 callbacks[n].proc = NULL;
905 callbacks[n].context = NULL;
907 assert( n * sizeof(sasl_callback_t) < sizeof(callbacks) );
909 rc = ldap_pvt_sasl_bind(ld, dn, saslMechanism, callbacks,
910 serverControls, clientControls);
914 #endif /* HAVE_CYRUS_SASL */