From 671db96e082ffe0b13a10772387a78949ef2c893 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Tue, 11 Apr 2006 23:26:27 +0000 Subject: [PATCH] import fix to ITS#4474 --- CHANGES | 1 + servers/slapd/back-ldap/back-ldap.h | 4 ++ servers/slapd/back-ldap/bind.c | 86 +++++++++++++++++++++++------ servers/slapd/back-ldap/config.c | 39 +++++++++++++ servers/slapd/back-ldap/extended.c | 10 ++-- servers/slapd/back-ldap/search.c | 3 +- 6 files changed, 121 insertions(+), 22 deletions(-) diff --git a/CHANGES b/CHANGES index eb29721fc8..3a987ec8f9 100644 --- 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) diff --git a/servers/slapd/back-ldap/back-ldap.h b/servers/slapd/back-ldap/back-ldap.h index f6c25b2496..8a19a72c05 100644 --- a/servers/slapd/back-ldap/back-ldap.h +++ b/servers/slapd/back-ldap/back-ldap.h @@ -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; diff --git a/servers/slapd/back-ldap/bind.c b/servers/slapd/back-ldap/bind.c index 647e9cf5da..4c6d731b55 100644 --- a/servers/slapd/back-ldap/bind.c +++ b/servers/slapd/back-ldap/bind.c @@ -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 ); diff --git a/servers/slapd/back-ldap/config.c b/servers/slapd/back-ldap/config.c index 38c9a95296..7214eeaf1f 100644 --- a/servers/slapd/back-ldap/config.c +++ b/servers/slapd/back-ldap/config.c @@ -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]> 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 " diff --git a/servers/slapd/back-ldap/extended.c b/servers/slapd/back-ldap/extended.c index de7a1c7ad1..225eee430d 100644 --- a/servers/slapd/back-ldap/extended.c +++ b/servers/slapd/back-ldap/extended.c @@ -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; diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 3cc9c97d83..69c013d834 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -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; -- 2.39.5