/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1998-2008 The OpenLDAP Foundation.
+ * Copyright 1998-2012 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
}
/*
- * 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,
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) ) {
} else
#endif
+ /* First time */
+ if ( !result ) {
+
#ifdef HAVE_CYRUS_SASL
if( mechs == NULL || *mechs == '\0' ) {
mechs = ld->ld_options.ldo_def_sasl_mech;
#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
#include <sasl.h>
#endif
-#if SASL_VERSION_MAJOR >= 2
-#define SASL_CONST const
-#else
-#define SASL_CONST
-#endif
-
#endif /* HAVE_CYRUS_SASL */
static int
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 );
{
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;
}
}
- /* 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,
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