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). The dn, mechanism, and
41 * credentials of the entry to which to bind are supplied. The message id
42 * of the request initiated is provided upon successful (LDAP_SUCCESS) return.
45 * ldap_sasl_bind( ld, "cn=manager, o=university of michigan, c=us",
46 * "mechanism", "secret", NULL, NULL, &msgid )
53 LDAP_CONST char *mechanism,
62 Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 );
65 assert( LDAP_VALID( ld ) );
66 assert( msgidp != NULL );
68 if( msgidp == NULL ) {
69 ld->ld_errno = LDAP_PARAM_ERROR;
73 if( mechanism == LDAP_SASL_SIMPLE ) {
74 if( dn == NULL && cred != NULL ) {
75 /* use default binddn */
76 dn = ld->ld_defbinddn;
79 } else if( ld->ld_version < LDAP_VERSION3 ) {
80 ld->ld_errno = LDAP_NOT_SUPPORTED;
88 /* create a message to send */
89 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
90 ld->ld_errno = LDAP_NO_MEMORY;
94 assert( BER_VALID( ber ) );
96 if( mechanism == LDAP_SASL_SIMPLE ) {
98 rc = ber_printf( ber, "{it{istO}" /*}*/,
99 ++ld->ld_msgid, LDAP_REQ_BIND,
100 ld->ld_version, dn, LDAP_AUTH_SIMPLE,
103 } else if ( cred == NULL ) {
104 /* SASL bind w/o creditials */
105 rc = ber_printf( ber, "{it{ist{s}}" /*}*/,
106 ++ld->ld_msgid, LDAP_REQ_BIND,
107 ld->ld_version, dn, LDAP_AUTH_SASL,
111 /* SASL bind w/ creditials */
112 rc = ber_printf( ber, "{it{ist{sO}}" /*}*/,
113 ++ld->ld_msgid, LDAP_REQ_BIND,
114 ld->ld_version, dn, LDAP_AUTH_SASL,
119 ld->ld_errno = LDAP_ENCODING_ERROR;
124 /* Put Server Controls */
125 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
130 if ( ber_printf( ber, /*{*/ "}" ) == -1 ) {
131 ld->ld_errno = LDAP_ENCODING_ERROR;
137 if ( ld->ld_cache != NULL ) {
138 ldap_flush_cache( ld );
140 #endif /* !LDAP_NOCACHE */
142 /* send the message */
143 *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber );
156 LDAP_CONST char *mechanism,
158 LDAPControl **sctrls,
159 LDAPControl **cctrls,
160 struct berval **servercredp )
164 struct berval *scredp = NULL;
166 Debug( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n", 0, 0, 0 );
168 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
169 if( servercredp != NULL ) {
170 if (ld->ld_version < LDAP_VERSION3) {
171 ld->ld_errno = LDAP_NOT_SUPPORTED;
177 rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid );
179 if ( rc != LDAP_SUCCESS ) {
183 if ( ldap_result( ld, msgid, 1, NULL, &result ) == -1 ) {
184 return( ld->ld_errno ); /* ldap_result sets ld_errno */
187 /* parse the results */
189 if( servercredp != NULL ) {
190 rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 );
193 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
194 ldap_msgfree( result );
198 rc = ldap_result2error( ld, result, 1 );
200 if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
201 if( servercredp != NULL ) {
202 *servercredp = scredp;
205 } else if (scredp != NULL ) {
214 * Parse BindResponse:
216 * BindResponse ::= [APPLICATION 1] SEQUENCE {
217 * COMPONENTS OF LDAPResult,
218 * serverSaslCreds [7] OCTET STRING OPTIONAL }
220 * LDAPResult ::= SEQUENCE {
221 * resultCode ENUMERATED,
223 * errorMessage LDAPString,
224 * referral [3] Referral OPTIONAL }
228 ldap_parse_sasl_bind_result(
231 struct berval **servercredp,
235 struct berval* scred;
240 Debug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
242 assert( ld != NULL );
243 assert( LDAP_VALID( ld ) );
244 assert( res != NULL );
246 if ( ld == NULL || res == NULL ) {
247 return LDAP_PARAM_ERROR;
250 if( servercredp != NULL ) {
251 if( ld->ld_version < LDAP_VERSION2 ) {
252 return LDAP_NOT_SUPPORTED;
257 if( res->lm_msgtype != LDAP_RES_BIND ) {
258 ld->ld_errno = LDAP_PARAM_ERROR;
264 if ( ld->ld_error ) {
265 LDAP_FREE( ld->ld_error );
268 if ( ld->ld_matched ) {
269 LDAP_FREE( ld->ld_matched );
270 ld->ld_matched = NULL;
275 ber = ber_dup( res->lm_ber );
278 ld->ld_errno = LDAP_NO_MEMORY;
282 if ( ld->ld_version < LDAP_VERSION2 ) {
283 tag = ber_scanf( ber, "{ia}",
284 &errcode, &ld->ld_error );
286 if( tag == LBER_ERROR ) {
288 ld->ld_errno = LDAP_DECODING_ERROR;
295 tag = ber_scanf( ber, "{iaa" /*}*/,
296 &errcode, &ld->ld_matched, &ld->ld_error );
298 if( tag == LBER_ERROR ) {
300 ld->ld_errno = LDAP_DECODING_ERROR;
304 tag = ber_peek_tag(ber, &len);
306 if( tag == LDAP_TAG_REFERRAL ) {
308 if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
310 ld->ld_errno = LDAP_DECODING_ERROR;
314 tag = ber_peek_tag(ber, &len);
317 if( tag == LDAP_TAG_SASL_RES_CREDS ) {
318 if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) {
320 ld->ld_errno = LDAP_DECODING_ERROR;
328 if ( servercredp != NULL ) {
329 *servercredp = scred;
331 } else if ( scred != NULL ) {
335 ld->ld_errno = errcode;
341 return( ld->ld_errno );
344 #ifdef HAVE_CYRUS_SASL
346 * Various Cyrus SASL related stuff.
349 static int sasl_setup( Sockbuf *sb, void *arg );
350 static int sasl_remove( Sockbuf *sb );
351 static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t len );
352 static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len );
353 static int sasl_close( Sockbuf *sb );
355 static Sockbuf_IO sasl_io=
364 #define HAS_SASL( sb ) ((sb)->sb_io==&sasl_io)
367 array2str( char **a )
372 for ( v = a; *v != NULL; v++ ) {
373 len += strlen( *v ) + 1; /* for a space */
380 s = LDAP_MALLOC ( len ); /* last space holds \0 */
387 for ( v = a; *v != NULL; v++ ) {
391 strncpy( p, " ", 1 );
395 strncpy( p, *v, len );
404 int ldap_pvt_sasl_init( void )
406 /* XXX not threadsafe */
407 static int sasl_initialized = 0;
409 if ( sasl_initialized ) {
413 sasl_set_alloc( ber_memalloc, ber_memcalloc, ber_memrealloc, ber_memfree );
414 #endif /* CSRIMALLOC */
416 if ( sasl_client_init( NULL ) == SASL_OK ) {
417 sasl_initialized = 1;
424 int ldap_pvt_sasl_install( Sockbuf *sb, void *ctx_arg )
426 /* don't install the stuff unless security has been negotiated */
428 if ( !HAS_SASL( sb ) ) {
429 ber_pvt_sb_clear_io( sb );
430 ber_pvt_sb_set_io( sb, &sasl_io, ctx_arg );
436 static int sasl_setup( Sockbuf *sb, void *arg )
442 static int sasl_remove( Sockbuf *sb )
447 static ber_slen_t sasl_read( Sockbuf *sb, void *buf, ber_len_t buflen )
450 unsigned recv_tok_len;
451 sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
453 if ((ber_pvt_sb_io_tcp.sbi_read)( sb, buf, buflen ) != buflen ) {
457 if ( sasl_decode( conn, buf, buflen, &recv_tok, &recv_tok_len ) != SASL_OK ) {
461 if ( recv_tok_len > buflen ) {
462 LDAP_FREE( recv_tok );
466 memcpy( buf, recv_tok, recv_tok_len );
468 LDAP_FREE( recv_tok );
473 static ber_slen_t sasl_write( Sockbuf *sb, void *buf, ber_len_t len )
476 unsigned wrapped_tok_len;
477 sasl_conn_t *conn = (sasl_conn_t *)sb->sb_iodata;
479 if ( sasl_encode( conn, (const char *)buf, len,
480 &wrapped_tok, &wrapped_tok_len ) != SASL_OK ) {
484 if ((ber_pvt_sb_io_tcp.sbi_write)( sb, wrapped_tok, wrapped_tok_len ) != wrapped_tok_len ) {
485 LDAP_FREE( wrapped_tok );
489 LDAP_FREE( wrapped_tok );
494 static int sasl_close( Sockbuf *sb )
496 (ber_pvt_sb_io_tcp.sbi_close)( sb );
500 ldap_pvt_sasl_err2ldap( int saslerr )
506 rc = LDAP_SASL_BIND_IN_PROGRESS;
512 rc = LDAP_OPERATIONS_ERROR;
518 rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
521 rc = LDAP_INVALID_CREDENTIALS;
524 rc = LDAP_INSUFFICIENT_ACCESS;
528 rc = LDAP_INAPPROPRIATE_AUTH;
531 rc = LDAP_OPERATIONS_ERROR;
539 ldap_pvt_sasl_getmechs ( LDAP *ld, LDAP_CONST char *desired, char **pmechlist )
541 /* we need to query the server for supported mechs anyway */
542 LDAPMessage *res, *e;
543 char *attrs[] = { "supportedSASLMechanisms", NULL };
544 char **values, *mechlist, **p;
547 rc = ldap_search_s( ld, NULL, LDAP_SCOPE_BASE,
548 "(objectclass=*)", attrs, 0, &res );
550 if ( rc != LDAP_SUCCESS ) {
554 e = ldap_first_entry( ld, res );
556 if ( ld->ld_errno == LDAP_SUCCESS ) {
557 ld->ld_errno = LDAP_UNAVAILABLE;
562 values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
563 if ( values == NULL ) {
564 ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
569 if ( desired != NULL ) {
570 rc = LDAP_INAPPROPRIATE_AUTH;
572 for ( p = values; *p != NULL; p++ ) {
573 if ( strcmp( *p, desired ) == 0 ) {
579 if ( rc == LDAP_SUCCESS ) {
580 /* just return this */
581 *pmechlist = LDAP_STRDUP( desired );
584 /* couldn't find it */
585 ld->ld_errno = LDAP_INAPPROPRIATE_AUTH;
590 mechlist = array2str( values );
591 if ( mechlist == NULL ) {
592 ld->ld_errno = LDAP_NO_MEMORY;
593 ldap_value_free( values );
598 ldap_value_free( values );
601 *pmechlist = mechlist;
610 LDAP_CONST char *mechanism,
611 LDAP_CONST sasl_callback_t *callbacks,
612 LDAPControl **sctrls,
613 LDAPControl **cctrls )
615 int saslrc, rc, msgid, ssf = 0;
616 struct berval ccred, *scred;
617 char *mechlist = NULL;
619 sasl_interact_t *client_interact = NULL;
621 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_bind\n", 0, 0, 0 );
623 /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
624 if (ld->ld_version < LDAP_VERSION3) {
625 ld->ld_errno = LDAP_NOT_SUPPORTED;
630 * This connects to the host, side effect being that
631 * ldap_host_connected_to() works.
633 rc = ldap_pvt_sasl_getmechs( ld, mechanism, &mechlist );
634 if ( rc != LDAP_SUCCESS ) {
638 /* XXX this doesn't work with PF_LOCAL hosts */
639 host = ldap_host_connected_to( &ld->ld_sb );
641 if ( host == NULL ) {
642 LDAP_FREE( mechlist );
643 ld->ld_errno = LDAP_UNAVAILABLE;
647 if ( ld->ld_sasl_context != NULL ) {
648 LDAP_FREE( mechlist );
649 sasl_dispose( &ld->ld_sasl_context );
652 saslrc = sasl_client_new( "ldap", host, callbacks, 0, &ld->ld_sasl_context );
656 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
657 LDAP_FREE( mechlist );
658 ld->ld_errno = ldap_pvt_sasl_err2ldap( rc );
659 sasl_dispose( &ld->ld_sasl_context );
666 saslrc = sasl_client_start( ld->ld_sasl_context,
671 (unsigned int *)&ccred.bv_len,
674 LDAP_FREE( mechlist );
676 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
677 ld->ld_errno = ldap_pvt_sasl_err2ldap( saslrc );
678 sasl_dispose( &ld->ld_sasl_context );
685 sasl_interact_t *client_interact = NULL;
687 rc = ldap_sasl_bind_s( ld, dn, mechanism, &ccred, sctrls, cctrls, &scred );
688 if ( rc == LDAP_SUCCESS ) {
690 } else if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) {
691 if ( ccred.bv_val != NULL ) {
692 LDAP_FREE( ccred.bv_val );
694 sasl_dispose( &ld->ld_sasl_context );
698 if ( ccred.bv_val != NULL ) {
699 LDAP_FREE( ccred.bv_val );
703 saslrc = sasl_client_step( ld->ld_sasl_context,
704 (scred == NULL) ? NULL : scred->bv_val,
705 (scred == NULL) ? 0 : scred->bv_len,
708 (unsigned int *)&ccred.bv_len );
712 if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
713 ld->ld_errno = ldap_pvt_sasl_err2ldap( saslrc );
714 sasl_dispose( &ld->ld_sasl_context );
717 } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
719 assert ( rc == LDAP_SUCCESS );
721 if ( sasl_getprop( ld->ld_sasl_context, SASL_SSF, (void **)&ssf )
722 == SASL_OK && ssf ) {
723 ldap_pvt_sasl_install( &ld->ld_sb, ld->ld_sasl_context );
729 /* based on sample/sample-client.c */
731 ldap_pvt_sasl_getsecret(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
733 struct berval *passphrase = (struct berval *)context;
736 if ( conn == NULL || psecret == NULL || id != SASL_CB_PASS ) {
737 return SASL_BADPARAM;
740 len = (passphrase != NULL) ? (size_t)passphrase->bv_len: 0;
742 *psecret = (sasl_secret_t *) LDAP_MALLOC( sizeof( sasl_secret_t ) + len );
743 if ( *psecret == NULL ) {
747 (*psecret)->len = passphrase->bv_len;
749 if ( passphrase != NULL ) {
750 memcpy((*psecret)->data, passphrase->bv_val, len);
757 ldap_pvt_sasl_getsimple(void *context, int id, const char **result, int *len)
759 const char *value = (const char *)context;
761 if ( result == NULL ) {
762 return SASL_BADPARAM;
767 case SASL_CB_AUTHNAME:
770 *len = value ? strlen( value ) : 0;
772 case SASL_CB_LANGUAGE:
778 return SASL_BADPARAM;
785 * ldap_negotiated_sasl_bind_s - bind to the ldap server (and X.500)
786 * using SASL authentication.
788 * This routine attempts to authenticate the user referred by the
789 * authentication id using the provided password. An optional
790 * authorization identity may be provided. An DN is generally not
791 * provided [see AuthMethod].
793 * If the mechanism negotiated does not require a password, the
794 * passwd field is ignored. [A callback mechanism should really
797 * LDAP_SUCCESS is returned upon success, the ldap error code
801 * ldap_negotiated_sasl_bind_s( ld, NULL,
802 * "user@OPENLDAP.ORG", NULL, NULL,
803 * "GSSAPI", NULL, NULL, NULL );
805 * ldap_negotiated_sasl_bind_s( ld, NULL,
806 * "manager", "cn=user,dc=openldap,dc=org", NULL,
807 * "DIGEST-MD5", NULL, NULL, NULL );
809 * ldap_negotiated_sasl_bind_s( ld, NULL,
810 * "root@OPENLDAP.ORG", "u:user@OPENLDAP.ORG", NULL,
811 * "GSSAPI", NULL, NULL, NULL );
813 * ldap_negotiated_sasl_bind_s( ld, NULL,
814 * "manager", "dn:cn=user,dc=openldap,dc=org", NULL,
815 * "DIGEST-MD5", NULL, NULL, NULL );
818 ldap_negotiated_sasl_bind_s(
820 LDAP_CONST char *dn, /* usually NULL */
821 LDAP_CONST char *authenticationId,
822 LDAP_CONST char *authorizationId, /* commonly NULL */
823 LDAP_CONST char *saslMechanism,
824 struct berval *passPhrase,
825 LDAPControl **serverControls,
826 LDAPControl **clientControls)
829 sasl_callback_t callbacks[4];
833 * Cyrus uses screwy terms. The authname is the
834 * SASL "username" or authentication identity.
835 * The user is the authorization identity.
838 callbacks[n=0].id = SASL_CB_AUTHNAME;
839 callbacks[n].proc = ldap_pvt_sasl_getsimple;
840 callbacks[n].context = (void *)authenticationId;
842 if( authorizationId != NULL ) {
843 callbacks[++n].id = SASL_CB_USER;
844 callbacks[n].proc = ldap_pvt_sasl_getsimple;
845 callbacks[n].context = (void *)authorizationId;
848 callbacks[++n].id = SASL_CB_PASS;
849 callbacks[n].proc = ldap_pvt_sasl_getsecret;
850 callbacks[n].context = (void *)passPhrase;
852 callbacks[++n].id = SASL_CB_LIST_END;
853 callbacks[n].proc = NULL;
854 callbacks[n].context = NULL;
856 rc = ldap_pvt_sasl_bind(ld, dn, saslMechanism, callbacks,
857 serverControls, clientControls);
861 #endif /* HAVE_CYRUS_SASL */