X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Fsasl.c;h=fc995bee449dee8acf63378e509fc3bedc3222bc;hb=7d13ef7e42f1514dd99878835a13a700da4f4b69;hp=1764eabe121c6b4511550195148ee4ae2373a7da;hpb=f7484f78e67085b7fb19c23a08b6f5e426e5a1e7;p=openldap
diff --git a/libraries/libldap/sasl.c b/libraries/libldap/sasl.c
index 1764eabe12..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-2008 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
@@ -482,12 +539,6 @@ done:
#include
#endif
-#if SASL_VERSION_MAJOR >= 2
-#define SASL_CONST const
-#else
-#define SASL_CONST
-#endif
-
#endif /* HAVE_CYRUS_SASL */
static int
@@ -509,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 );
@@ -684,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;
@@ -702,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,
@@ -720,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