]> 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 0531d46f5933cefd1c49b783aab5fa1720d2178c..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;
        }
@@ -489,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 );
@@ -618,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 );
 }
 
@@ -650,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;
@@ -983,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;
@@ -1012,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;
@@ -1024,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 );
@@ -1078,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;
 
@@ -1202,7 +1246,8 @@ ldap_back_proxy_authz_ctrl(
        LDAPControl     **ctrls = NULL;
        int             i = 0,
                        mode;
-       struct berval   assertedID;
+       struct berval   assertedID,
+                       ndn;
 
        *pctrls = NULL;
 
@@ -1221,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 ) {
                        /*
@@ -1244,7 +1296,7 @@ ldap_back_proxy_authz_ctrl(
                        goto done;
                }
 
-               if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+               if ( BER_BVISNULL( &ndn ) ) {
                        goto done;
                }
 
@@ -1254,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;
                }
 
@@ -1268,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;
                        }
@@ -1320,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;