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)
#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)
#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;
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 )
{
&& !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:;
}
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 );
}
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;
}
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 );
}
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 );
(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;
}
(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 );
}
{
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 );
}
/* 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 );
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
"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 },
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 );
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 );
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 "
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
ldap_msgfree( res );
}
}
+
if ( rc != LDAP_SUCCESS ) {
rs->sr_err = slap_map_api2result( rs );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
free( (char *)rs->sr_matched );
rs->sr_matched = NULL;
}
+
if ( rs->sr_text ) {
free( (char *)rs->sr_text );
rs->sr_text = NULL;
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
ldap_msgfree( res );
}
}
+
if ( rc != LDAP_SUCCESS ) {
rs->sr_err = slap_map_api2result( rs );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
free( (char *)rs->sr_matched );
rs->sr_matched = NULL;
}
+
if ( rs->sr_text ) {
free( (char *)rs->sr_text );
rs->sr_text = NULL;
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;