]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/sasl.c
Merge remote branch 'origin/mdb.master'
[openldap] / libraries / libldap / sasl.c
index 6aa8cce49791cda8720636d6f88c8589c4cee24d..fc995bee449dee8acf63378e509fc3bedc3222bc 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2010 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
@@ -733,8 +790,9 @@ sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
                return ret;
        } else if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
                /* partial write? pretend nothing got written */
-               len2 = 0;
                p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE;
+               sock_errset(EAGAIN);
+               len2 = -1;
        }
 
        /* return number of bytes encoded, not written, to ensure