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 ldap_pvt_sasl_err2ldap( int saslerr )
507 rc = LDAP_SASL_BIND_IN_PROGRESS;
513 rc = LDAP_OPERATIONS_ERROR;
519 rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
522 rc = LDAP_INVALID_CREDENTIALS;
525 rc = LDAP_INSUFFICIENT_ACCESS;
529 rc = LDAP_INAPPROPRIATE_AUTH;
532 rc = LDAP_OPERATIONS_ERROR;
540 ldap_pvt_sasl_getmechs ( LDAP *ld, LDAP_CONST char *desired, char **pmechlist )
542 /* we need to query the server for supported mechs anyway */
543 LDAPMessage *res, *e;
544 char *attrs[] = { "supportedSASLMechanisms", NULL };
545 char **values, *mechlist, **p;
548 rc = ldap_search_s( ld, NULL, LDAP_SCOPE_BASE,
549 NULL, attrs, 0, &res );
551 if ( rc != LDAP_SUCCESS ) {
555 e = ldap_first_entry( ld, res );
557 if ( ld->ld_errno == LDAP_SUCCESS ) {
558 ld->ld_errno = LDAP_UNAVAILABLE;
563 values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
564 if ( values == NULL ) {
565 ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
570 if ( desired != NULL ) {
571 rc = LDAP_INAPPROPRIATE_AUTH;
573 for ( p = values; *p != NULL; p++ ) {
574 if ( strcmp( *p, desired ) == 0 ) {
580 if ( rc == LDAP_SUCCESS ) {
581 /* just return this */
582 *pmechlist = LDAP_STRDUP( desired );
585 /* couldn't find it */
586 ld->ld_errno = LDAP_INAPPROPRIATE_AUTH;
591 mechlist = array2str( values );
592 if ( mechlist == NULL ) {
593 ld->ld_errno = LDAP_NO_MEMORY;
594 ldap_value_free( values );
599 ldap_value_free( values );
602 *pmechlist = mechlist;
611 LDAP_CONST char *mechanism,
612 LDAP_CONST sasl_callback_t *callbacks,
613 LDAPControl **sctrls,
614 LDAPControl **cctrls )
616 int saslrc, rc, msgid, ssf = 0;
617 struct berval ccred, *scred;
618 char *mechlist = NULL;
620 sasl_interact_t *client_interact = NULL;
622 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_bind\n", 0, 0, 0 );
624 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
625 if (ld->ld_version < LDAP_VERSION3) {
626 ld->ld_errno = LDAP_NOT_SUPPORTED;
631 * This connects to the host, side effect being that
632 * ldap_host_connected_to() works.
634 rc = ldap_pvt_sasl_getmechs( ld, mechanism, &mechlist );
635 if ( rc != LDAP_SUCCESS ) {
639 /* XXX this doesn't work with PF_LOCAL hosts */
640 host = ldap_host_connected_to( &ld->ld_sb );
642 if ( host == NULL ) {
643 LDAP_FREE( mechlist );
644 ld->ld_errno = LDAP_UNAVAILABLE;
648 if ( ld->ld_sasl_context != NULL ) {
649 LDAP_FREE( mechlist );
650 sasl_dispose( &ld->ld_sasl_context );
653 saslrc = sasl_client_new( "ldap", host, callbacks, 0, &ld->ld_sasl_context );
657 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
658 LDAP_FREE( mechlist );
659 ld->ld_errno = ldap_pvt_sasl_err2ldap( rc );
660 sasl_dispose( &ld->ld_sasl_context );
667 saslrc = sasl_client_start( ld->ld_sasl_context,
672 (unsigned int *)&ccred.bv_len,
675 LDAP_FREE( mechlist );
677 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
678 ld->ld_errno = ldap_pvt_sasl_err2ldap( saslrc );
679 sasl_dispose( &ld->ld_sasl_context );
686 sasl_interact_t *client_interact = NULL;
688 rc = ldap_sasl_bind_s( ld, dn, mechanism, &ccred, sctrls, cctrls, &scred );
689 if ( rc == LDAP_SUCCESS ) {
691 } else if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) {
692 if ( ccred.bv_val != NULL ) {
693 LDAP_FREE( ccred.bv_val );
695 sasl_dispose( &ld->ld_sasl_context );
699 if ( ccred.bv_val != NULL ) {
700 LDAP_FREE( ccred.bv_val );
704 saslrc = sasl_client_step( ld->ld_sasl_context,
705 (scred == NULL) ? NULL : scred->bv_val,
706 (scred == NULL) ? 0 : scred->bv_len,
709 (unsigned int *)&ccred.bv_len );
713 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
714 ld->ld_errno = ldap_pvt_sasl_err2ldap( saslrc );
715 sasl_dispose( &ld->ld_sasl_context );
718 } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
720 assert ( rc == LDAP_SUCCESS );
722 if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, (void **)&ssf )
723 == SASL_OK && ssf ) {
724 ldap_pvt_sasl_install( &ld->ld_sb, ld->ld_sasl_context );
730 /* based on sample/sample-client.c */
732 ldap_pvt_sasl_getsecret(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
734 struct berval *passphrase = (struct berval *)context;
737 if ( conn == NULL || psecret == NULL || id != SASL_CB_PASS ) {
738 return SASL_BADPARAM;
741 len = (passphrase != NULL) ? (size_t)passphrase->bv_len: 0;
743 *psecret = (sasl_secret_t *) LDAP_MALLOC( sizeof( sasl_secret_t ) + len );
744 if ( *psecret == NULL ) {
748 (*psecret)->len = passphrase->bv_len;
750 if ( passphrase != NULL ) {
751 memcpy((*psecret)->data, passphrase->bv_val, len);
758 ldap_pvt_sasl_getsimple(void *context, int id, const char **result, int *len)
760 const char *value = (const char *)context;
762 if ( result == NULL ) {
763 return SASL_BADPARAM;
768 case SASL_CB_AUTHNAME:
771 *len = value ? strlen( value ) : 0;
773 case SASL_CB_LANGUAGE:
779 return SASL_BADPARAM;
786 ldap_pvt_sasl_get_option( LDAP *ld, int option, void *arg )
794 case LDAP_OPT_X_SASL_MINSSF:
795 *(int *)arg = ld->ld_options.ldo_sasl_minssf;
797 case LDAP_OPT_X_SASL_MAXSSF:
798 *(int *)arg = ld->ld_options.ldo_sasl_maxssf;
800 case LDAP_OPT_X_SASL_ACTSSF:
801 if ( ld->ld_sasl_context == NULL ) {
805 if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, &ssf )
817 ldap_pvt_sasl_set_option( LDAP *ld, int option, void *arg )
823 case LDAP_OPT_X_SASL_MINSSF:
824 ld->ld_options.ldo_sasl_minssf = *(int *)arg;
826 case LDAP_OPT_X_SASL_MAXSSF:
827 ld->ld_options.ldo_sasl_maxssf = *(int *)arg;
829 case LDAP_OPT_X_SASL_ACTSSF:
830 /* This option is read-only */
838 * ldap_negotiated_sasl_bind_s - bind to the ldap server (and X.500)
839 * using SASL authentication.
841 * This routine attempts to authenticate the user referred by the
842 * authentication id using the provided password. An optional
843 * authorization identity may be provided. An DN is generally not
844 * provided [see AuthMethod].
846 * If the mechanism negotiated does not require a password, the
847 * passwd field is ignored. [A callback mechanism should really
850 * LDAP_SUCCESS is returned upon success, the ldap error code
854 * ldap_negotiated_sasl_bind_s( ld, NULL,
855 * "user@OPENLDAP.ORG", NULL, NULL,
856 * "GSSAPI", NULL, NULL, NULL );
858 * ldap_negotiated_sasl_bind_s( ld, NULL,
859 * "manager", "cn=user,dc=openldap,dc=org", NULL,
860 * "DIGEST-MD5", NULL, NULL, NULL );
862 * ldap_negotiated_sasl_bind_s( ld, NULL,
863 * "root@OPENLDAP.ORG", "u:user@OPENLDAP.ORG", NULL,
864 * "GSSAPI", NULL, NULL, NULL );
866 * ldap_negotiated_sasl_bind_s( ld, NULL,
867 * "manager", "dn:cn=user,dc=openldap,dc=org", NULL,
868 * "DIGEST-MD5", NULL, NULL, NULL );
871 ldap_negotiated_sasl_bind_s(
873 LDAP_CONST char *dn, /* usually NULL */
874 LDAP_CONST char *authenticationId,
875 LDAP_CONST char *authorizationId, /* commonly NULL */
876 LDAP_CONST char *saslMechanism,
877 struct berval *passPhrase,
878 LDAPControl **serverControls,
879 LDAPControl **clientControls)
882 sasl_callback_t callbacks[4];
885 /* SASL Authentication Identity */
886 callbacks[n=0].id = SASL_CB_AUTHNAME;
887 callbacks[n].proc = ldap_pvt_sasl_getsimple;
888 callbacks[n].context = (void *)authenticationId;
890 /* SASL Authorization Identity (userid) */
891 if( authorizationId != NULL ) {
892 callbacks[++n].id = SASL_CB_USER;
893 callbacks[n].proc = ldap_pvt_sasl_getsimple;
894 callbacks[n].context = (void *)authorizationId;
897 callbacks[++n].id = SASL_CB_PASS;
898 callbacks[n].proc = ldap_pvt_sasl_getsecret;
899 callbacks[n].context = (void *)passPhrase;
901 callbacks[++n].id = SASL_CB_LIST_END;
902 callbacks[n].proc = NULL;
903 callbacks[n].context = NULL;
905 rc = ldap_pvt_sasl_bind(ld, dn, saslMechanism, callbacks,
906 serverControls, clientControls);
910 #endif /* HAVE_CYRUS_SASL */