+
+ /* wait for pending operations to finish */
+ /* FIXME: may become a bottleneck! */
+ if ( lc->lc_refcnt != lc->lc_binding ) {
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
+ ldap_pvt_thread_yield();
+ goto retry_lock;
+ }
+
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
+
+#if 0
+ while ( lc->lc_refcnt > 1 ) {
+ ldap_pvt_thread_yield();
+ rc = LDAP_BACK_CONN_ISBOUND( lc );
+ if ( rc ) {
+ return rc;
+ }
+ }
+
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ }
+ LDAP_BACK_CONN_BINDING_SET( lc );
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
+#endif
+
+ /*
+ * FIXME: we need to let clients use proxyAuthz
+ * otherwise we cannot do symmetric pools of servers;
+ * we have to live with the fact that a user can
+ * authorize itself as any ID that is allowed
+ * by the authzTo directive of the "proxyauthzdn".
+ */
+ /*
+ * NOTE: current Proxy Authorization specification
+ * and implementation do not allow proxy authorization
+ * control to be provided with Bind requests
+ */
+ /*
+ * if no bind took place yet, but the connection is bound
+ * and the "idassert-authcDN" (or other ID) is set,
+ * then bind as the asserting identity and explicitly
+ * add the proxyAuthz control to every operation with the
+ * dn bound to the connection as control value.
+ * This is done also if this is the authrizing backend,
+ * but the "override" flag is given to idassert.
+ * It allows to use SASL bind and yet proxyAuthz users
+ */
+ if ( op->o_conn != NULL &&
+ !op->o_do_not_cache &&
+ ( BER_BVISNULL( &lc->lc_bound_ndn ) ||
+ ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
+ {
+ (void)ldap_back_proxy_authz_bind( lc, op, rs, sendok );
+ goto done;
+ }
+
+#ifdef HAVE_CYRUS_SASL
+ if ( LDAP_BACK_CONN_ISPRIV( lc )
+ && li->li_acl_authmethod == LDAP_AUTH_SASL )
+ {
+ void *defaults = NULL;
+
+ if ( li->li_acl_secprops != NULL ) {
+ rc = ldap_set_option( lc->lc_ld,
+ LDAP_OPT_X_SASL_SECPROPS, li->li_acl_secprops);
+
+ if ( rc != LDAP_OPT_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
+ "(%s,SECPROPS,\"%s\") failed!\n",
+ li->li_uri, li->li_acl_secprops, 0 );
+ goto done;
+ }
+ }
+
+ defaults = lutil_sasl_defaults( lc->lc_ld,
+ li->li_acl_sasl_mech.bv_val,
+ li->li_acl_sasl_realm.bv_val,
+ li->li_acl_authcID.bv_val,
+ li->li_acl_passwd.bv_val,
+ NULL );
+
+ rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld,
+ li->li_acl_authcDN.bv_val,
+ li->li_acl_sasl_mech.bv_val, NULL, NULL,
+ LDAP_SASL_QUIET, lutil_sasl_interact,
+ defaults );
+
+ lutil_sasl_freedefs( defaults );
+
+ rs->sr_err = slap_map_api2result( rs );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
+ send_ldap_result( op, rs );
+
+ } else {
+ LDAP_BACK_CONN_ISBOUND_SET( lc );
+ }
+ goto done;
+ }
+#endif /* HAVE_CYRUS_SASL */
+
+retry:;
+ rs->sr_err = ldap_sasl_bind( lc->lc_ld,
+ lc->lc_bound_ndn.bv_val,
+ LDAP_SASL_SIMPLE, &lc->lc_cred,
+ NULL, NULL, &msgid );
+
+ if ( rs->sr_err == LDAP_SERVER_DOWN ) {
+ if ( retries != LDAP_BACK_RETRY_NEVER ) {
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ }
+
+ assert( lc->lc_refcnt > 0 );
+ if ( lc->lc_refcnt == 1 ) {
+ ldap_unbind_ext( lc->lc_ld, NULL, NULL );
+ lc->lc_ld = NULL;
+
+ /* lc here must be the regular lc, reset and ready for init */
+ rs->sr_err = ldap_back_prepare_conn( &lc, op, rs, sendok );
+ if ( rs->sr_err != LDAP_SUCCESS ) {
+ lc->lc_binding--;
+ lc->lc_refcnt = 0;
+ }
+ }
+
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
+
+ if ( rs->sr_err == LDAP_SUCCESS ) {
+ if ( retries > 0 ) {
+ retries--;
+ }
+ goto retry;
+ }
+
+ } else {
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ }
+ lc->lc_binding--;
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
+ }
+
+ ldap_back_freeconn( op, lc, dolock );
+ rs->sr_err = slap_map_api2result( rs );
+
+ return 0;
+ }
+
+ rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
+ if ( rc == LDAP_SUCCESS ) {
+ LDAP_BACK_CONN_ISBOUND_SET( lc );
+ }
+
+done:;
+ lc->lc_binding--;
+ LDAP_BACK_CONN_BINDING_CLEAR( lc );
+ rc = LDAP_BACK_CONN_ISBOUND( lc );
+ if ( !rc ) {
+ ldap_back_release_conn_lock( op, rs, lc, dolock );
+ }
+