X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Fsasl.c;h=fc995bee449dee8acf63378e509fc3bedc3222bc;hb=7d13ef7e42f1514dd99878835a13a700da4f4b69;hp=5fb209ace00c1a8c10c5307f178fee295c4916f2;hpb=4af9eb971559e3a1f0432615e93ec870dc753ddb;p=openldap diff --git a/libraries/libldap/sasl.c b/libraries/libldap/sasl.c index 5fb209ace0..fc995bee44 100644 --- a/libraries/libldap/sasl.c +++ b/libraries/libldap/sasl.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2009 The OpenLDAP Foundation. + * Copyright 1998-2012 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -401,15 +401,16 @@ ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist ) } /* - * ldap_sasl_interactive_bind_s - interactive SASL authentication + * ldap_sasl_interactive_bind - interactive SASL authentication * * This routine uses interactive callbacks. * * LDAP_SUCCESS is returned upon success, the ldap error code - * otherwise. + * otherwise. LDAP_SASL_BIND_IN_PROGRESS is returned if further + * calls are needed. */ int -ldap_sasl_interactive_bind_s( +ldap_sasl_interactive_bind( LDAP *ld, LDAP_CONST char *dn, /* usually NULL */ LDAP_CONST char *mechs, @@ -417,13 +418,16 @@ ldap_sasl_interactive_bind_s( LDAPControl **clientControls, unsigned flags, LDAP_SASL_INTERACT_PROC *interact, - void *defaults ) + void *defaults, + LDAPMessage *result, + const char **rmech, + int *msgid ) { - int rc; char *smechs = NULL; + int rc; -#if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL ) - ldap_pvt_thread_mutex_lock( &ldap_int_sasl_mutex ); +#if defined( HAVE_CYRUS_SASL ) + LDAP_MUTEX_LOCK( &ldap_int_sasl_mutex ); #endif #ifdef LDAP_CONNECTIONLESS if( LDAP_IS_UDP(ld) ) { @@ -437,6 +441,9 @@ ldap_sasl_interactive_bind_s( } else #endif + /* First time */ + if ( !result ) { + #ifdef HAVE_CYRUS_SASL if( mechs == NULL || *mechs == '\0' ) { mechs = ld->ld_options.ldo_def_sasl_mech; @@ -444,36 +451,86 @@ ldap_sasl_interactive_bind_s( #endif if( mechs == NULL || *mechs == '\0' ) { + /* FIXME: this needs to be asynchronous too; + * perhaps NULL should be disallowed for async usage? + */ rc = ldap_pvt_sasl_getmechs( ld, &smechs ); if( rc != LDAP_SUCCESS ) { goto done; } Debug( LDAP_DEBUG_TRACE, - "ldap_sasl_interactive_bind_s: server supports: %s\n", + "ldap_sasl_interactive_bind: server supports: %s\n", smechs, 0, 0 ); mechs = smechs; } else { Debug( LDAP_DEBUG_TRACE, - "ldap_sasl_interactive_bind_s: user selected: %s\n", + "ldap_sasl_interactive_bind: user selected: %s\n", mechs, 0, 0 ); } - + } rc = ldap_int_sasl_bind( ld, dn, mechs, serverControls, clientControls, - flags, interact, defaults ); + flags, interact, defaults, result, rmech, msgid ); done: -#if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL ) - ldap_pvt_thread_mutex_unlock( &ldap_int_sasl_mutex ); +#if defined( HAVE_CYRUS_SASL ) + LDAP_MUTEX_UNLOCK( &ldap_int_sasl_mutex ); #endif if ( smechs ) LDAP_FREE( smechs ); return rc; } +/* + * ldap_sasl_interactive_bind_s - interactive SASL authentication + * + * This routine uses interactive callbacks. + * + * LDAP_SUCCESS is returned upon success, the ldap error code + * otherwise. + */ +int +ldap_sasl_interactive_bind_s( + LDAP *ld, + LDAP_CONST char *dn, /* usually NULL */ + LDAP_CONST char *mechs, + LDAPControl **serverControls, + LDAPControl **clientControls, + unsigned flags, + LDAP_SASL_INTERACT_PROC *interact, + void *defaults ) +{ + const char *rmech = NULL; + LDAPMessage *result = NULL; + int rc, msgid; + + do { + rc = ldap_sasl_interactive_bind( ld, dn, mechs, + serverControls, clientControls, + flags, interact, defaults, result, &rmech, &msgid ); + + ldap_msgfree( result ); + + if ( rc != LDAP_SASL_BIND_IN_PROGRESS ) + break; + +#ifdef LDAP_CONNECTIONLESS + if (LDAP_IS_UDP(ld)) { + break; + } +#endif + + if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) { + return( ld->ld_errno ); /* ldap_result sets ld_errno */ + } + } while ( rc == LDAP_SASL_BIND_IN_PROGRESS ); + + return rc; +} + #ifdef HAVE_CYRUS_SASL #ifdef HAVE_SASL_SASL_H @@ -503,6 +560,7 @@ sb_sasl_generic_setup( Sockbuf_IO_Desc *sbiod, void *arg ) p->ops = i->ops; p->ops_private = i->ops_private; p->sbiod = sbiod; + p->flags = 0; ber_pvt_sb_buf_init( &p->sec_buf_in ); ber_pvt_sb_buf_init( &p->buf_in ); ber_pvt_sb_buf_init( &p->buf_out ); @@ -678,13 +736,14 @@ sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) { struct sb_sasl_generic_data *p; int ret; + ber_len_t len2; assert( sbiod != NULL ); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt; - /* Are there anything left in the buffer? */ + /* Is there anything left in the buffer? */ if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); if ( ret < 0 ) return ret; @@ -696,14 +755,22 @@ sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) } } - /* now encode the next packet. */ - p->ops->reset_buf( p, &p->buf_out ); + len2 = p->max_send - 100; /* For safety margin */ + len2 = len > len2 ? len2 : len; - if ( len > p->max_send - 100 ) { - len = p->max_send - 100; /* For safety margin */ + /* If we're just retrying a partial write, tell the + * caller it's done. Let them call again if there's + * still more left to write. + */ + if ( p->flags & LDAP_PVT_SASL_PARTIAL_WRITE ) { + p->flags ^= LDAP_PVT_SASL_PARTIAL_WRITE; + return len2; } - ret = p->ops->encode( p, buf, len, &p->buf_out ); + /* now encode the next packet. */ + p->ops->reset_buf( p, &p->buf_out ); + + ret = p->ops->encode( p, buf, len2, &p->buf_out ); if ( ret != 0 ) { ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, @@ -714,10 +781,24 @@ sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); + if ( ret < 0 ) { + /* error? */ + int err = sock_errno(); + /* caller can retry this */ + if ( err == EAGAIN || err == EWOULDBLOCK || err == EINTR ) + p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE; + return ret; + } else if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { + /* partial write? pretend nothing got written */ + p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE; + sock_errset(EAGAIN); + len2 = -1; + } + /* return number of bytes encoded, not written, to ensure * no byte is encoded twice (even if only sent once). */ - return len; + return len2; } static int