]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ldap/bind.c
TS#4315 fix prev commit, spinning in ldap_back_dobind
[openldap] / servers / slapd / back-ldap / bind.c
index 2000f829eaaf979cc28d98ced0345388d15ca90d..8fb0a7ad081d4f02baa9d0f5c613d2eab0c2272b 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1999-2005 The OpenLDAP Foundation.
+ * Copyright 1999-2006 The OpenLDAP Foundation.
  * Portions Copyright 2000-2003 Pierangelo Masarati.
  * Portions Copyright 1999-2003 Howard Chu.
  * All rights reserved.
@@ -56,7 +56,7 @@ ldap_back_bind( Operation *op, SlapReply *rs )
        int rc = 0;
        ber_int_t msgid;
 
-       lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
+       lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR );
        if ( !lc ) {
                return rs->sr_err;
        }
@@ -336,7 +336,7 @@ retry:;
                                                rc = ldap_install_tls( ld );
 
                                        } else if ( rc == LDAP_REFERRAL ) {
-                                               rc = LDAP_OTHER;
+                                               rc = LDAP_UNWILLING_TO_PERFORM;
                                                *text = "unwilling to chase referral returned by Start TLS exop";
                                        }
 
@@ -415,6 +415,10 @@ ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_bac
        /* Set LDAP version. This will always succeed: If the client
         * bound with a particular version, then so can we.
         */
+       if ( vers == 0 ) {
+               /* assume it's an internal op; set to LDAPv3 */
+               vers = LDAP_VERSION3;
+       }
        ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers );
 
        /* automatically chase referrals ("[dont-]chase-referrals" statement) */
@@ -485,21 +489,35 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
                }
        }
 
-       /* Searches for a ldapconn in the avl tree */
-       ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+       /* Explicit Bind requests always get their own conn */
+       if ( sendok & LDAP_BACK_BINDING ) {
+               lc = NULL;
+       } else {
+               /* Searches for a ldapconn in the avl tree */
+retry_lock:
+               ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
-       lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree, 
-                       (caddr_t)&lc_curr, ldap_back_conn_cmp );
-       if ( lc != NULL ) {
-               refcnt = ++lc->lc_refcnt;
+               lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree, 
+                               (caddr_t)&lc_curr, ldap_back_conn_cmp );
+               if ( lc != NULL ) {
+                       refcnt = ++lc->lc_refcnt;
+                       /* Don't reuse connections while they're still binding */
+                       if ( LDAP_BACK_CONN_BINDING( lc )) {
+                               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+                               ldap_pvt_thread_yield();
+                               goto retry_lock;
+                       }
+               }
+               ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
        }
-       ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
        /* Looks like we didn't get a bind. Open a new session... */
        if ( lc == NULL ) {
                if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) {
                        return NULL;
                }
+               if ( sendok & LDAP_BACK_BINDING )
+                       LDAP_BACK_CONN_BINDING_SET( lc );
 
                lc->lc_conn = lc_curr.lc_conn;
                ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn );
@@ -581,9 +599,22 @@ ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
                }
 
        } else {
-               Debug( LDAP_DEBUG_TRACE,
-                       "=>ldap_back_getconn: conn %p fetched (refcnt=%u)\n",
-                       (void *)lc, refcnt, 0 );
+               if ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout ) {
+                       /* in case of failure, it frees/taints lc and sets it to NULL */
+                       if ( ldap_back_retry( &lc, op, rs, sendok ) ) {
+                               lc = NULL;
+                       }
+               }
+
+               if ( lc ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "=>ldap_back_getconn: conn %p fetched (refcnt=%u)\n",
+                               (void *)lc, refcnt, 0 );
+               }
+       }
+
+       if ( li->li_idle_timeout && lc ) {
+               lc->lc_time = op->o_time;
        }
 
 done:;
@@ -601,6 +632,7 @@ ldap_back_release_conn(
        ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
        assert( lc->lc_refcnt > 0 );
        lc->lc_refcnt--;
+       LDAP_BACK_CONN_BINDING_CLEAR( lc );
        ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 }
 
@@ -633,6 +665,12 @@ ldap_back_dobind_int(
                return rc;
        }
 
+       while ( lc->lc_refcnt > 1 ) {
+               ldap_pvt_thread_yield();
+               if (( rc = LDAP_BACK_CONN_ISBOUND( lc )))
+                       return rc;
+       }
+
        /*
         * FIXME: we need to let clients use proxyAuthz
         * otherwise we cannot do symmetric pools of servers;
@@ -838,7 +876,7 @@ ldap_back_op_result(
 
 retry:;
                /* if result parsing fails, note the failure reason */
-               rc = ldap_result( lc->lc_ld, msgid, 1, &tv, &res );
+               rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
                switch ( rc ) {
                case 0:
                        if ( timeout ) {
@@ -925,6 +963,9 @@ ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_
        int             rc = 0;
        ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
 
+       assert( lcp != NULL );
+       assert( *lcp != NULL );
+
        ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
        if ( (*lcp)->lc_refcnt == 1 ) {
@@ -940,7 +981,11 @@ ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_
 
                /* lc here must be the regular lc, reset and ready for init */
                rc = ldap_back_prepare_conn( lcp, op, rs, sendok );
-               if ( rc == LDAP_SUCCESS ) {
+               if ( rc != LDAP_SUCCESS ) {
+                       rc = 0;
+                       *lcp = NULL;
+
+               } else {
                        rc = ldap_back_dobind_int( *lcp, op, rs, sendok, 0, 0 );
                        if ( rc == 0 ) {
                                *lcp = NULL;
@@ -959,10 +1004,18 @@ ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs )
        ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
        struct berval   binddn = slap_empty_bv;
        struct berval   bindcred = slap_empty_bv;
+       struct berval   ndn;
        int             dobind = 0;
        int             msgid;
        int             rc;
 
+       if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+               ndn = op->o_conn->c_ndn;
+
+       } else {
+               ndn = op->o_ndn;
+       }
+
        /*
         * FIXME: we need to let clients use proxyAuthz
         * otherwise we cannot do symmetric pools of servers;
@@ -988,7 +1041,7 @@ ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs )
         * is authorized */
        switch ( li->li_idassert_mode ) {
        case LDAP_BACK_IDASSERT_LEGACY:
-               if ( !BER_BVISNULL( &op->o_conn->c_ndn ) && !BER_BVISEMPTY( &op->o_conn->c_ndn ) ) {
+               if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
                        if ( !BER_BVISNULL( &li->li_idassert_authcDN ) && !BER_BVISEMPTY( &li->li_idassert_authcDN ) )
                        {
                                binddn = li->li_idassert_authcDN;
@@ -1000,14 +1053,29 @@ ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs )
 
        default:
                /* NOTE: rootdn can always idassert */
-               if ( li->li_idassert_authz && !be_isroot( op ) ) {
+               if ( BER_BVISNULL( &ndn ) && li->li_idassert_authz == NULL ) {
+                       if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
+                               rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
+                               send_ldap_result( op, rs );
+                               LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
+
+                       } else {
+                               rs->sr_err = LDAP_SUCCESS;
+                               binddn = slap_empty_bv;
+                               bindcred = slap_empty_bv;
+                               break;
+                       }
+
+                       goto done;
+
+               } else if ( li->li_idassert_authz && !be_isroot( op ) ) {
                        struct berval authcDN;
 
-                       if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+                       if ( BER_BVISNULL( &ndn ) ) {
                                authcDN = slap_empty_bv;
 
                        } else {
-                               authcDN = op->o_conn->c_ndn;
+                               authcDN = ndn;
                        }       
                        rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz,
                                        &authcDN, &authcDN );
@@ -1054,16 +1122,16 @@ ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs )
                                break;
 
                        case LDAP_BACK_IDASSERT_SELF:
-                               if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+                               if ( BER_BVISNULL( &ndn ) ) {
                                        /* connection is not authc'd, so don't idassert */
                                        BER_BVSTR( &authzID, "dn:" );
                                        break;
                                }
-                               authzID.bv_len = STRLENOF( "dn:" ) + op->o_conn->c_ndn.bv_len;
+                               authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
                                authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
                                AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
                                AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
-                                               op->o_conn->c_ndn.bv_val, op->o_conn->c_ndn.bv_len + 1 );
+                                               ndn.bv_val, ndn.bv_len + 1 );
                                freeauthz = 1;
                                break;
 
@@ -1178,7 +1246,8 @@ ldap_back_proxy_authz_ctrl(
        LDAPControl     **ctrls = NULL;
        int             i = 0,
                        mode;
-       struct berval   assertedID;
+       struct berval   assertedID,
+                       ndn;
 
        *pctrls = NULL;
 
@@ -1197,6 +1266,13 @@ ldap_back_proxy_authz_ctrl(
                goto done;
        }
 
+       if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+               ndn = op->o_conn->c_ndn;
+
+       } else {
+               ndn = op->o_ndn;
+       }
+
        if ( li->li_idassert_mode == LDAP_BACK_IDASSERT_LEGACY ) {
                if ( op->o_proxy_authz ) {
                        /*
@@ -1220,7 +1296,7 @@ ldap_back_proxy_authz_ctrl(
                        goto done;
                }
 
-               if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+               if ( BER_BVISNULL( &ndn ) ) {
                        goto done;
                }
 
@@ -1230,13 +1306,13 @@ ldap_back_proxy_authz_ctrl(
 
        } else if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
                if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ )
-                               /* && ( !BER_BVISNULL( &op->o_conn->c_ndn )
+                               /* && ( !BER_BVISNULL( &ndn )
                                        || LDAP_BACK_CONN_ISBOUND( lc ) ) */ )
                {
                        /* already asserted in SASL via native authz */
                        /* NOTE: the test on lc->lc_bound is used to trap
                         * native authorization of anonymous users,
-                        * since in that case op->o_conn->c_ndn is NULL */
+                        * since in that case ndn is NULL */
                        goto done;
                }
 
@@ -1244,17 +1320,17 @@ ldap_back_proxy_authz_ctrl(
                int             rc;
                struct berval authcDN;
 
-               if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+               if ( BER_BVISNULL( &ndn ) ) {
                        authcDN = slap_empty_bv;
                } else {
-                       authcDN = op->o_conn->c_ndn;
+                       authcDN = ndn;
                }
                rc = slap_sasl_matches( op, li->li_idassert_authz,
                                &authcDN, & authcDN );
                if ( rc != LDAP_SUCCESS ) {
                        if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE )
                        {
-                               /* op->o_conn->c_ndn is not authorized
+                               /* ndn is not authorized
                                 * to use idassert */
                                return rc;
                        }
@@ -1296,10 +1372,10 @@ ldap_back_proxy_authz_ctrl(
        case LDAP_BACK_IDASSERT_SELF:
                /* original behavior:
                 * assert the client's identity */
-               if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+               if ( BER_BVISNULL( &ndn ) ) {
                        assertedID = slap_empty_bv;
                } else {
-                       assertedID = op->o_conn->c_ndn;
+                       assertedID = ndn;
                }
                break;