]> git.sur5r.net Git - openldap/commitdiff
import fix to ITS#4474
authorPierangelo Masarati <ando@openldap.org>
Tue, 11 Apr 2006 23:26:27 +0000 (23:26 +0000)
committerPierangelo Masarati <ando@openldap.org>
Tue, 11 Apr 2006 23:26:27 +0000 (23:26 +0000)
CHANGES
servers/slapd/back-ldap/back-ldap.h
servers/slapd/back-ldap/bind.c
servers/slapd/back-ldap/config.c
servers/slapd/back-ldap/extended.c
servers/slapd/back-ldap/search.c

diff --git a/CHANGES b/CHANGES
index eb29721fc831f77ed5ed137b526bd7428c9c0ae8..3a987ec8f9f7038386e4ff1ca0f5029649ae18a1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,7 @@
 OpenLDAP 2.3 Change Log
 
 OpenLDAP 2.3.22 Engineering
+       Fixed slapd-ldap fd cleanup (ITS#4474)
 
 OpenLDAP 2.3.21 Release
        Fixed libldap referral chasing issue (ITS#4448)
index f6c25b2496b8af314de41ca64f2e0984c5261eb0..8a19a72c05412c7cab3cae046128426b4b89d26d 100644 (file)
@@ -60,6 +60,7 @@ typedef struct ldapconn_t {
 #define        LDAP_BACK_FCONN_ISPRIV  (0x04)
 #define        LDAP_BACK_FCONN_ISTLS   (0x08)
 #define        LDAP_BACK_FCONN_BINDING (0x10)
+#define        LDAP_BACK_FCONN_TAINTED (0x20)
 
 #define        LDAP_BACK_CONN_ISBOUND(lc)              LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_ISBOUND)
 #define        LDAP_BACK_CONN_ISBOUND_SET(lc)          LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_ISBOUND)
@@ -80,6 +81,9 @@ typedef struct ldapconn_t {
 #define        LDAP_BACK_CONN_BINDING(lc)              LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_BINDING)
 #define        LDAP_BACK_CONN_BINDING_SET(lc)          LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_BINDING)
 #define        LDAP_BACK_CONN_BINDING_CLEAR(lc)        LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_BINDING)
+#define        LDAP_BACK_CONN_TAINTED(lc)              LDAP_BACK_CONN_ISSET((lc), LDAP_BACK_FCONN_TAINTED)
+#define        LDAP_BACK_CONN_TAINTED_SET(lc)          LDAP_BACK_CONN_SET((lc), LDAP_BACK_FCONN_TAINTED)
+#define        LDAP_BACK_CONN_TAINTED_CLEAR(lc)        LDAP_BACK_CONN_CLEAR((lc), LDAP_BACK_FCONN_TAINTED)
 
        unsigned                lc_refcnt;
        unsigned                lc_binding;
index 647e9cf5da23fe7c492ead157ace7127ddee3baf..4c6d731b5501df26d413571ef294abaeae26ea3b 100644 (file)
@@ -51,6 +51,9 @@ ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_b
 static int
 ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
 
+static int
+ldap_back_conndnlc_cmp( const void *c1, const void *c2 );
+
 int
 ldap_back_bind( Operation *op, SlapReply *rs )
 {
@@ -114,6 +117,7 @@ done:;
                        && !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) ) )
        {
                int             lerr = -1;
+               ldapconn_t      *tmplc;
 
                /* wait for all other ops to release the connection */
 retry_lock:;
@@ -125,9 +129,9 @@ retry_lock:;
                }
 
                assert( lc->lc_refcnt == 1 );
-               lc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
-                               ldap_back_conndn_cmp );
-               assert( lc != NULL );
+               tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+                               ldap_back_conndnlc_cmp );
+               assert( tmplc == NULL || lc == tmplc );
 
                if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
                        ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
@@ -136,8 +140,14 @@ retry_lock:;
                }
 
                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
-               if ( lerr == -1 ) {
-                       /* we can do this because lc_refcnt == 1 */
+               switch ( lerr ) {
+               case 0:
+                       break;
+
+               case -1:
+                       /* duplicate; someone else successfully bound
+                        * on the same connection with the same identity;
+                        * we can do this because lc_refcnt == 1 */
                        ldap_back_conn_free( lc );
                        lc = NULL;
                }
@@ -290,17 +300,17 @@ int
 ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock )
 {
        ldapinfo_t      *li = (ldapinfo_t *) op->o_bd->be_private;
+       ldapconn_t      *tmplc;
 
        if ( dolock ) {
                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
        }
 
-       assert( lc->lc_refcnt > 0 );
-       if ( --lc->lc_refcnt == 0 ) {
-               lc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
-                               ldap_back_conndn_cmp );
-               assert( lc != NULL );
-
+       assert( lc->lc_refcnt >= 0 );
+       tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+                       ldap_back_conndnlc_cmp );
+       assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
+       if ( lc->lc_refcnt == 0 ) {
                ldap_back_conn_free( (void *)lc );
        }
 
@@ -485,6 +495,14 @@ ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_bac
        ldap_set_option( ld, LDAP_OPT_REFERRALS,
                LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
 
+       if ( li->li_network_timeout > 0 ) {
+               struct timeval          tv;
+
+               tv.tv_sec = li->li_network_timeout;
+               tv.tv_usec = 0;
+               ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&tv );
+       }
+
 #ifdef HAVE_TLS
        rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
                        li->li_uri, li->li_flags, li->li_nretries, &rs->sr_text );
@@ -654,12 +672,30 @@ retry_lock:
                        (void *)lc, refcnt, binding );
        
                /* Err could be -1 in case a duplicate ldapconn is inserted */
-               if ( rs->sr_err != 0 ) {
+               switch ( rs->sr_err ) {
+               case 0:
+                       break;
+
+               case -1:
+                       if ( !( sendok & LDAP_BACK_BINDING ) ) {
+                               /* duplicate: free and try to get the newly created one */
+                               goto retry_lock;
+                       }
+                       /* taint connection, so that it'll be freed when released */
+                       ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+                       (void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
+                                       ldap_back_conndnlc_cmp );
+                       ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+                       LDAP_BACK_CONN_TAINTED_SET( lc );
+                       break;
+
+               default:
                        ldap_back_conn_free( lc );
                        rs->sr_err = LDAP_OTHER;
+                       rs->sr_text = "proxy bind collision";
                        if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
-                               send_ldap_error( op, rs, LDAP_OTHER,
-                                       "internal server error" );
+                               send_ldap_result( op, rs );
+                               rs->sr_text = NULL;
                        }
                        return NULL;
                }
@@ -679,6 +715,7 @@ retry_lock:
                        (void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
                                        ldap_back_conndnlc_cmp );
                        ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+                       LDAP_BACK_CONN_TAINTED_SET( lc );
                }
 
                {
@@ -712,8 +749,11 @@ ldap_back_release_conn_lock(
                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
        }
        assert( lc->lc_refcnt > 0 );
-       lc->lc_refcnt--;
        LDAP_BACK_CONN_BINDING_CLEAR( lc );
+       lc->lc_refcnt--;
+       if ( LDAP_BACK_CONN_TAINTED( lc ) ) {
+               ldap_back_freeconn( op, lc, 0 );
+       }
        if ( dolock ) {
                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
        }
@@ -902,19 +942,33 @@ retry:;
 
                                /* 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 );
+                       }
                }
 
-               lc->lc_binding--;
                ldap_back_freeconn( op, lc, dolock );
                rs->sr_err = slap_map_api2result( rs );
 
index 38c9a95296473d0a1e571c003b54144226b71ef7..7214eeaf1fad99fa5916854f3a3292f2e6e87165 100644 (file)
@@ -62,6 +62,7 @@ enum {
        LDAP_BACK_CFG_TIMEOUT,
        LDAP_BACK_CFG_IDLE_TIMEOUT,
        LDAP_BACK_CFG_CONN_TTL,
+       LDAP_BACK_CFG_NETWORK_TIMEOUT,
        LDAP_BACK_CFG_REWRITE,
 
        LDAP_BACK_CFG_LAST
@@ -232,6 +233,14 @@ static ConfigTable ldapcfg[] = {
                        "SYNTAX OMsDirectoryString "
                        "SINGLE-VALUE )",
                NULL, NULL },
+       { "network-timeout", "timeout", 2, 0, 0,
+               ARG_MAGIC|LDAP_BACK_CFG_NETWORK_TIMEOUT,
+               ldap_back_cf_gen, "( OLcfgDbAt:3.17 "
+                       "NAME 'olcDbNetworkTimeout' "
+                       "DESC 'connection network timeout' "
+                       "SYNTAX OMsDirectoryString "
+                       "SINGLE-VALUE )",
+               NULL, NULL },
        { "suffixmassage", "[virtual]> <real", 2, 3, 0,
                ARG_STRING|ARG_MAGIC|LDAP_BACK_CFG_REWRITE,
                ldap_back_cf_gen, NULL, NULL, NULL },
@@ -583,6 +592,19 @@ ldap_back_cf_gen( ConfigArgs *c )
                        value_add_one( &c->rvalue_vals, &bv );
                        } break;
 
+               case LDAP_BACK_CFG_NETWORK_TIMEOUT: {
+                       char    buf[ SLAP_TEXT_BUFLEN ];
+
+                       if ( li->li_network_timeout == 0 ) {
+                               return 1;
+                       }
+
+                       snprintf( buf, sizeof( buf ), "%ld",
+                               (long)li->li_network_timeout );
+                       ber_str2bv( buf, 0, 0, &bv );
+                       value_add_one( &c->rvalue_vals, &bv );
+                       } break;
+
                default:
                        /* FIXME: we need to handle all... */
                        assert( 0 );
@@ -668,6 +690,10 @@ ldap_back_cf_gen( ConfigArgs *c )
                        li->li_conn_ttl = 0;
                        break;
 
+               case LDAP_BACK_CFG_NETWORK_TIMEOUT:
+                       li->li_network_timeout = 0;
+                       break;
+
                default:
                        /* FIXME: we need to handle all... */
                        assert( 0 );
@@ -1205,6 +1231,19 @@ done_url:;
                li->li_conn_ttl = (time_t)t;
                } break;
 
+       case LDAP_BACK_CFG_NETWORK_TIMEOUT: {
+               unsigned long   t;
+
+               if ( lutil_parse_time( c->argv[ 1 ], &t ) != 0 ) {
+                       snprintf( c->msg, sizeof( c->msg),
+                               "unable to parse network timeout \"%s\"",
+                               c->argv[ 1 ] );
+                       Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->msg, 0 );
+                       return 1;
+               }
+               li->li_network_timeout = (time_t)t;
+               } break;
+
        case LDAP_BACK_CFG_REWRITE:
                snprintf( c->msg, sizeof( c->msg ),
                        "rewrite/remap capabilities have been moved "
index de7a1c7ad132e92de4d39d94bb93de6fda5bb0f5..225eee430d9cf0eb36685750c4349bcfa76be7fb 100644 (file)
@@ -132,8 +132,7 @@ retry:
        if ( rc == LDAP_SUCCESS ) {
                if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &res ) == -1 ) {
                        ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &rc );
-                       ldap_back_freeconn( op, lc, 0 );
-                       lc = NULL;
+                       rs->sr_err = rc;
 
                } else {
                        /* sigh. parse twice, because parse_passwd
@@ -182,6 +181,7 @@ retry:
                        ldap_msgfree( res );
                }
        }
+
        if ( rc != LDAP_SUCCESS ) {
                rs->sr_err = slap_map_api2result( rs );
                if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
@@ -200,6 +200,7 @@ retry:
                free( (char *)rs->sr_matched );
                rs->sr_matched = NULL;
        }
+
        if ( rs->sr_text ) {
                free( (char *)rs->sr_text );
                rs->sr_text = NULL;
@@ -239,8 +240,7 @@ retry:
        if ( rc == LDAP_SUCCESS ) {
                if ( ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, NULL, &res ) == -1 ) {
                        ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER, &rc );
-                       ldap_back_freeconn( op, lc, 0 );
-                       lc = NULL;
+                       rs->sr_err = rc;
 
                } else {
                        /* sigh. parse twice, because parse_passwd
@@ -275,6 +275,7 @@ retry:
                        ldap_msgfree( res );
                }
        }
+
        if ( rc != LDAP_SUCCESS ) {
                rs->sr_err = slap_map_api2result( rs );
                if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
@@ -293,6 +294,7 @@ retry:
                free( (char *)rs->sr_matched );
                rs->sr_matched = NULL;
        }
+
        if ( rs->sr_text ) {
                free( (char *)rs->sr_text );
                rs->sr_text = NULL;
index 3cc9c97d83f57c58e05d59eb60f2228ac1ddecff..69c013d834f8a7413c959ef780110328b63b1e8d 100644 (file)
@@ -224,14 +224,13 @@ retry:
                                        goto retry;
                                }
                        }
+
                        if ( lc == NULL ) {
                                /* reset by ldap_back_retry ... */
                                rs->sr_err = slap_map_api2result( rs );
 
                        } else {
                                rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_DONTSEND );
-                               ldap_back_freeconn( op, lc, 0 );
-                               lc = NULL;
                        }
                                
                        goto finish;