From 4e11af075fb8c6a375b6cf7604208008b0e943c1 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Sun, 17 Dec 2006 23:52:23 +0000 Subject: [PATCH] - add support for "use-temporary-conn" much like back-ldap - fix various connection creation/setup concurrency issues - use shared connection when always idasserting (similar to ITS#4781) - reduce the impact of schema mapping when not used (tnx to gprof) - fix temporary/tainted connection leak in abnormal conditions --- doc/man/man5/slapd-meta.5 | 7 + servers/slapd/back-meta/back-meta.h | 40 ++++- servers/slapd/back-meta/bind.c | 10 +- servers/slapd/back-meta/candidates.c | 4 +- servers/slapd/back-meta/config.c | 46 +++++- servers/slapd/back-meta/conn.c | 225 ++++++++++++++++++++------- servers/slapd/back-meta/init.c | 17 +- servers/slapd/back-meta/map.c | 20 ++- servers/slapd/back-meta/search.c | 84 +++++----- 9 files changed, 335 insertions(+), 118 deletions(-) diff --git a/doc/man/man5/slapd-meta.5 b/doc/man/man5/slapd-meta.5 index fd15479b0c..7fc1ac3b28 100644 --- a/doc/man/man5/slapd-meta.5 +++ b/doc/man/man5/slapd-meta.5 @@ -176,6 +176,13 @@ is set to .B single\-conn {NO|yes} Discards current cached connection when the client rebinds. +.TP +.B use-temporary-conn {NO|yes} +when set to +.BR yes , +create a temporary connection whenever competing with other threads +for a shared one; otherwise, wait until the shared connection is available. + .SH TARGET SPECIFICATION Target specification starts with a "uri" directive: diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 4d367674fc..945d54623f 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -160,6 +160,35 @@ ldap_dnattr_result_rewrite( /* (end of) from back-ldap.h before rwm removal */ +/* + * A metasingleconn_t can be in the following, mutually exclusive states: + * + * - none (0x0U) + * - creating META_BACK_FCONN_CREATING + * - initialized META_BACK_FCONN_INITED + * - binding LDAP_BACK_FCONN_BINDING + * - bound/anonymous LDAP_BACK_FCONN_ISBOUND/LDAP_BACK_FCONN_ISANON + * + * possible modifiers are: + * + * - privileged LDAP_BACK_FCONN_ISPRIV + * - privileged, TLS LDAP_BACK_FCONN_ISTLS + * - subjected to idassert LDAP_BACK_FCONN_ISIDASR + * - tainted LDAP_BACK_FCONN_TAINTED + */ + +#define META_BACK_FCONN_INITED (0x00100000U) +#define META_BACK_FCONN_CREATING (0x00200000U) + +#define META_BACK_CONN_INITED(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_INITED) +#define META_BACK_CONN_INITED_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_INITED) +#define META_BACK_CONN_INITED_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_INITED) +#define META_BACK_CONN_INITED_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), META_BACK_FCONN_INITED, (mlc)) +#define META_BACK_CONN_CREATING(lc) LDAP_BACK_CONN_ISSET((lc), META_BACK_FCONN_CREATING) +#define META_BACK_CONN_CREATING_SET(lc) LDAP_BACK_CONN_SET((lc), META_BACK_FCONN_CREATING) +#define META_BACK_CONN_CREATING_CLEAR(lc) LDAP_BACK_CONN_CLEAR((lc), META_BACK_FCONN_CREATING) +#define META_BACK_CONN_CREATING_CPY(lc, mlc) LDAP_BACK_CONN_CPY((lc), META_BACK_FCONN_CREATING, (mlc)) + struct metainfo_t; #define META_NOT_CANDIDATE ((ber_tag_t)0x0) @@ -329,16 +358,18 @@ typedef struct metainfo_t { unsigned mi_flags; #define li_flags mi_flags /* uses flags as defined in */ -#define META_BACK_F_ONERR_STOP (0x00010000U) -#define META_BACK_F_ONERR_REPORT (0x00020000U) +#define META_BACK_F_ONERR_STOP (0x00100000U) +#define META_BACK_F_ONERR_REPORT (0x00200000U) #define META_BACK_F_ONERR_MASK (META_BACK_F_ONERR_STOP|META_BACK_F_ONERR_REPORT) -#define META_BACK_F_DEFER_ROOTDN_BIND (0x00040000U) +#define META_BACK_F_DEFER_ROOTDN_BIND (0x00400000U) +#define META_BACK_F_PROXYAUTHZ_ALWAYS (0x00800000U) #define META_BACK_ONERR_STOP(mi) ( (mi)->mi_flags & META_BACK_F_ONERR_STOP ) #define META_BACK_ONERR_REPORT(mi) ( (mi)->mi_flags & META_BACK_F_ONERR_REPORT ) #define META_BACK_ONERR_CONTINUE(mi) ( !( (mi)->mi_flags & META_BACK_F_ONERR_MASK ) ) #define META_BACK_DEFER_ROOTDN_BIND(mi) ( (mi)->mi_flags & META_BACK_F_DEFER_ROOTDN_BIND ) +#define META_BACK_PROXYAUTHZ_ALWAYS(mi) ( (mi)->mi_flags & META_BACK_F_PROXYAUTHZ_ALWAYS ) int mi_version; time_t mi_network_timeout; @@ -397,7 +428,8 @@ meta_back_init_one_conn( metaconn_t *mc, int candidate, int ispriv, - ldap_back_send_t sendok ); + ldap_back_send_t sendok, + int dolock ); extern void meta_back_quarantine( diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index e648dee098..3880e06e54 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -399,9 +399,7 @@ retry:; op->o_log_prefix, candidate, (void *)msc->msc_ld ); #endif /* DEBUG_205 */ - ldap_unbind_ext( msc->msc_ld, NULL, NULL ); - msc->msc_ld = NULL; - LDAP_BACK_CONN_BINDING_CLEAR( msc ); + meta_clear_one_candidate( op, mc, candidate ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); rs->sr_err = timeout_err; @@ -683,7 +681,8 @@ retry_binding:; ++bound; continue; - } else if ( LDAP_BACK_CONN_BINDING( msc ) ) { + } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) + { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); ldap_pvt_thread_yield(); goto retry_binding; @@ -710,7 +709,7 @@ retry_binding:; if ( rc == LDAP_UNAVAILABLE ) { - /* FIXME: meta_back_retry() already calls + /* FIXME: meta_back_retry() already re-calls * meta_back_single_dobind() */ if ( meta_back_retry( op, rs, &mc, i, sendok ) ) { goto retry_ok; @@ -720,6 +719,7 @@ retry_binding:; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); LDAP_BACK_CONN_BINDING_CLEAR( msc ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + meta_back_release_conn( op, mc ); } return 0; diff --git a/servers/slapd/back-meta/candidates.c b/servers/slapd/back-meta/candidates.c index 4a7ba3b3e2..e0c0116af6 100644 --- a/servers/slapd/back-meta/candidates.c +++ b/servers/slapd/back-meta/candidates.c @@ -187,7 +187,7 @@ meta_clear_one_candidate( { metasingleconn_t *msc = &mc->mc_conns[ candidate ]; - if ( msc->msc_ld ) { + if ( msc->msc_ld != NULL ) { #ifdef DEBUG_205 char buf[ BUFSIZ ]; @@ -213,6 +213,8 @@ meta_clear_one_candidate( BER_BVZERO( &msc->msc_cred ); } + msc->msc_mscflags = 0; + return 0; } diff --git a/servers/slapd/back-meta/config.c b/servers/slapd/back-meta/config.c index 6ae4b3ba5f..6bdc63e90e 100644 --- a/servers/slapd/back-meta/config.c +++ b/servers/slapd/back-meta/config.c @@ -38,7 +38,6 @@ static int meta_back_new_target( metatarget_t **mtp ) { - struct ldapmapping *mapping; char *rargv[ 3 ]; metatarget_t *mt; @@ -52,7 +51,6 @@ meta_back_new_target( return -1; } - /* * the filter rewrite as a string must be disabled * by default; it can be re-enabled by adding rules; @@ -68,8 +66,6 @@ meta_back_new_target( rargv[ 2 ] = NULL; rewrite_parse( mt->mt_rwmap.rwm_rw, "", 1, 2, rargv ); - ldap_back_map_init( &mt->mt_rwmap.rwm_at, &mapping ); - ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex ); mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY; @@ -849,6 +845,38 @@ meta_back_db_config( return 1; } + /* use-temporaries? */ + } else if ( strcasecmp( argv[ 0 ], "use-temporary-conn" ) == 0 ) { + if ( argc != 2 ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: \"use-temporary-conn {FALSE|true}\" takes 1 argument\n", + fname, lineno, 0 ); + return( 1 ); + } + + if ( mi->mi_ntargets > 0 ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: \"use-temporary-conn\" must appear before target definitions\n", + fname, lineno, 0 ); + return( 1 ); + } + + switch ( check_true_false( argv[ 1 ] ) ) { + case 0: + mi->mi_flags &= ~LDAP_BACK_F_USE_TEMPORARIES; + break; + + case 1: + mi->mi_flags |= LDAP_BACK_F_USE_TEMPORARIES; + break; + + default: + Debug( LDAP_DEBUG_ANY, + "%s: line %d: \"use-temporary-conn {FALSE|true}\": invalid arg \"%s\".\n", + fname, lineno, argv[ 1 ] ); + return 1; + } + } else if ( strcasecmp( argv[ 0 ], "cancel" ) == 0 ) { unsigned flag = 0; unsigned *flagsp = mi->mi_ntargets ? @@ -1402,7 +1430,7 @@ ldap_back_map_config( if ( strcmp( argv[ 2 ], "*" ) == 0 ) { if ( argc < 4 || strcmp( argv[ 3 ], "*" ) == 0 ) { map->drop_missing = ( argc < 4 ); - return 0; + goto success_return; } src = dst = argv[ 3 ]; @@ -1416,7 +1444,7 @@ ldap_back_map_config( } if ( ( map == at_map ) - && ( strcasecmp( src, "objectclass" ) == 0 + && ( strcasecmp( src, "objectclass" ) == 0 || strcasecmp( dst, "objectclass" ) == 0 ) ) { Debug( LDAP_DEBUG_ANY, @@ -1544,6 +1572,12 @@ ldap_back_map_config( avl_insert( &map->remap, (caddr_t)&mapping[ 1 ], mapping_cmp, mapping_dup ); +success_return:; + if ( !is_oc && map->map == NULL ) { + /* only init if required */ + ldap_back_map_init( map, &mapping ); + } + return 0; error_return:; diff --git a/servers/slapd/back-meta/conn.c b/servers/slapd/back-meta/conn.c index b1c4cc5724..9758cf1cd0 100644 --- a/servers/slapd/back-meta/conn.c +++ b/servers/slapd/back-meta/conn.c @@ -202,7 +202,7 @@ metaconn_alloc( /* malloc all in one */ mc = ( metaconn_t * )ch_calloc( 1, sizeof( metaconn_t ) - + sizeof( metasingleconn_t ) * ntargets ); + + sizeof( metasingleconn_t ) * ( ntargets - 1 ) ); if ( mc == NULL ) { return NULL; } @@ -227,7 +227,8 @@ meta_back_init_one_conn( metaconn_t *mc, int candidate, int ispriv, - ldap_back_send_t sendok ) + ldap_back_send_t sendok, + int dolock ) { metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; metatarget_t *mt = mi->mi_targets[ candidate ]; @@ -235,6 +236,7 @@ meta_back_init_one_conn( int version; dncookie dc; int isauthz = ( candidate == mc->mc_authz_target ); + int do_return = 0; #ifdef HAVE_TLS int is_ldaps = 0; #endif /* HAVE_TLS */ @@ -275,14 +277,62 @@ meta_back_init_one_conn( } } +retry_lock:; + if ( dolock ) { + ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + } + /* * Already init'ed */ - if ( msc->msc_ld != NULL ) { - return rs->sr_err = LDAP_SUCCESS; + if ( LDAP_BACK_CONN_ISBOUND( msc ) + || LDAP_BACK_CONN_ISANON( msc ) ) + { + assert( msc->msc_ld != NULL ); + rs->sr_err = LDAP_SUCCESS; + do_return = 1; + + } else if ( META_BACK_CONN_CREATING( msc ) + || LDAP_BACK_CONN_BINDING( msc ) ) + { + if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { + if ( dolock ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + } + + ldap_pvt_thread_yield(); + goto retry_lock; + } + + /* sounds more appropriate */ + rs->sr_err = LDAP_BUSY; + do_return = 1; + + } else if ( META_BACK_CONN_INITED( msc ) ) { + assert( msc->msc_ld != NULL ); + rs->sr_err = LDAP_SUCCESS; + do_return = 1; + + } else { + /* + * creating... + */ + META_BACK_CONN_CREATING_SET( msc ); + } + + if ( dolock ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + } + + if ( do_return ) { + if ( rs->sr_err != LDAP_SUCCESS && op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) { + send_ldap_result( op, rs ); + } + + return rs->sr_err; } - msc->msc_mscflags = 0; + assert( msc->msc_ld == NULL ); /* * Attempts to initialize the connection to the target ds @@ -430,8 +480,8 @@ retry:; op->o_log_prefix, candidate, (void *)msc->msc_ld ); #endif /* DEBUG_205 */ - ldap_unbind_ext( msc->msc_ld, NULL, NULL ); - msc->msc_ld = NULL; + /* need to trash a failed Start TLS */ + meta_clear_one_candidate( op, mc, candidate ); goto error_return; } } @@ -500,8 +550,8 @@ retry:; op->o_log_prefix, candidate, (void *)msc->msc_ld ); #endif /* DEBUG_205 */ - ldap_unbind_ext( msc->msc_ld, NULL, NULL ); - msc->msc_ld = NULL; + /* need to trash a connection not fully established */ + meta_clear_one_candidate( op, mc, candidate ); goto error_return; } @@ -510,6 +560,8 @@ retry:; ber_dupbv( &msc->msc_bound_ndn, &op->o_conn->c_dn ); } + assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); + } else { ber_dupbv( &msc->msc_bound_ndn, (struct berval *)&slap_empty_bv ); } @@ -518,13 +570,22 @@ retry:; assert( !BER_BVISNULL( &msc->msc_bound_ndn ) ); error_return:; + if ( dolock ) { + ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + } + META_BACK_CONN_CREATING_CLEAR( msc ); if ( rs->sr_err == LDAP_SUCCESS ) { /* * Sets a cookie for the rewrite session */ ( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn ); + META_BACK_CONN_INITED_SET( msc ); + } + if ( dolock ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + } - } else { + if ( rs->sr_err != LDAP_SUCCESS ) { rs->sr_err = slap_map_api2result( rs ); if ( sendok & LDAP_BACK_SENDERR ) { send_ldap_result( op, rs ); @@ -556,13 +617,18 @@ meta_back_retry( binding; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); + + assert( !META_BACK_CONN_CREATING( msc ) ); binding = LDAP_BACK_CONN_BINDING( msc ); + LDAP_BACK_CONN_BINDING_CLEAR( msc ); assert( mc->mc_refcnt > 0 ); if ( mc->mc_refcnt == 1 ) { if ( LogTest( LDAP_DEBUG_ANY ) ) { char buf[ SLAP_TEXT_BUFLEN ]; + /* this lock is required; however, + * it's invoked only when logging is on */ ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex ); snprintf( buf, sizeof( buf ), "retrying URI=\"%s\" DN=\"%s\"", @@ -583,7 +649,7 @@ meta_back_retry( /* mc here must be the regular mc, reset and ready for init */ rc = meta_back_init_one_conn( op, rs, mc, candidate, - LDAP_BACK_CONN_ISPRIV( mc ), sendok ); + LDAP_BACK_CONN_ISPRIV( mc ), sendok, 0 ); /* restore the "binding" flag, in case */ if ( binding ) { @@ -614,6 +680,9 @@ meta_back_retry( } } } + + /* don't send twice */ + sendok &= ~LDAP_BACK_SENDERR; } if ( rc != LDAP_SUCCESS ) { @@ -622,9 +691,13 @@ meta_back_retry( candidates[ candidate ].sr_err = rc; if ( *mcp != NULL ) { - if ( binding ) { - LDAP_BACK_CONN_BINDING_CLEAR( msc ); + if ( mc->mc_refcnt == 1 ) { + if ( binding ) { + LDAP_BACK_CONN_BINDING_CLEAR( msc ); + } + (void)meta_clear_one_candidate( op, mc, candidate ); } + LDAP_BACK_CONN_TAINTED_SET( mc ); /* only release if mandatory; otherwise * let the caller do what's best before @@ -632,10 +705,21 @@ meta_back_retry( if ( META_BACK_ONERR_STOP( mi ) ) { meta_back_release_conn_lock( op, mc, 0 ); *mcp = NULL; + + } else { +#if META_BACK_PRINT_CONNTREE > 0 + meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_retry" ); +#endif /* META_BACK_PRINT_CONNTREE */ + /* FIXME: could be done better, reworking meta_back_release_conn_lock() */ + (void)avl_delete( &mi->mi_conninfo.lai_tree, + ( caddr_t )mc, meta_back_conndnmc_cmp ); +#if META_BACK_PRINT_CONNTREE > 0 + meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_retry" ); +#endif /* META_BACK_PRINT_CONNTREE */ } } - if ( sendok ) { + if ( sendok & LDAP_BACK_SENDERR ) { rs->sr_err = rc; rs->sr_text = NULL; send_ldap_result( op, rs ); @@ -882,8 +966,8 @@ meta_back_getconn( SlapReply *candidates = meta_back_candidates_get( op ); /* Internal searches are privileged and shared. So is root. */ - /* FIXME: there seem to be concurrency issues */ - if ( op->o_do_not_cache || be_isroot( op ) ) { + /* FIXME: there seems to be concurrency issues */ + if ( META_BACK_PROXYAUTHZ_ALWAYS( mi ) || op->o_do_not_cache || be_isroot( op ) ) { mc_curr.mc_local_ndn = op->o_bd->be_rootndn; LDAP_BACK_CONN_ISPRIV_SET( &mc_curr ); mc_curr.mc_conn = LDAP_BACK_PCONN_SET( op ); @@ -908,33 +992,45 @@ retry_lock:; mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, (caddr_t)&mc_curr, meta_back_conndn_cmp ); if ( mc ) { - if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl ) - || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) ) - { + /* catch taint errors */ + assert( !LDAP_BACK_CONN_TAINTED( mc ) ); + + /* Don't reuse connections while they're still binding + * NOTE: only makes sense for binds */ + if ( LDAP_BACK_CONN_BINDING( mc ) ) { + if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + + ldap_pvt_thread_yield(); + goto retry_lock; + } + + /* release conn, and create a temporary */ + mc = NULL; + + } else { + if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl ) + || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) ) + { #if META_BACK_PRINT_CONNTREE > 0 - meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_getconn" ); + meta_back_print_conntree( mi->mi_conninfo.lai_tree, + ">>> meta_back_getconn(expired)" ); #endif /* META_BACK_PRINT_CONNTREE */ - /* don't let anyone else use this expired connection */ - (void)avl_delete( &mi->mi_conninfo.lai_tree, - (caddr_t)mc, meta_back_conndnmc_cmp ); + /* don't let anyone else use this expired connection */ + (void)avl_delete( &mi->mi_conninfo.lai_tree, + (caddr_t)mc, meta_back_conndnmc_cmp ); #if META_BACK_PRINT_CONNTREE > 0 - meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_getconn" ); + meta_back_print_conntree( mi->mi_conninfo.lai_tree, + "<<< meta_back_getconn(expired)" ); #endif /* META_BACK_PRINT_CONNTREE */ - LDAP_BACK_CONN_TAINTED_SET( mc ); + LDAP_BACK_CONN_TAINTED_SET( mc ); - Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired.\n", - op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) ); - } + Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired (tainted).\n", + op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) ); + } - /* Don't reuse connections while they're still binding - * NOTE: only makes sense for binds */ - if ( LDAP_BACK_CONN_BINDING( mc ) ) { - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - ldap_pvt_thread_yield(); - goto retry_lock; + mc->mc_refcnt++; } - - mc->mc_refcnt++; } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } @@ -1010,7 +1106,7 @@ retry_lock:; */ candidates[ i ].sr_err = meta_back_init_one_conn( op, rs, mc, i, LDAP_BACK_CONN_ISPRIV( &mc_curr ), - sendok ); + LDAP_BACK_DONTSEND, !new_conn ); if ( candidates[ i ].sr_err == LDAP_SUCCESS ) { META_CANDIDATE_SET( &candidates[ i ] ); ncandidates++; @@ -1131,13 +1227,24 @@ retry_lock2:; mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree, (caddr_t)&mc_curr, meta_back_conndn_cmp ); if ( mc != NULL ) { + /* catch taint errors */ + assert( !LDAP_BACK_CONN_TAINTED( mc ) ); + /* Don't reuse connections while they're still binding */ - if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) { - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); - ldap_pvt_thread_yield(); - goto retry_lock2; + if ( META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) + || LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) + { + if ( !LDAP_BACK_USE_TEMPORARIES( mi ) ) { + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + ldap_pvt_thread_yield(); + goto retry_lock2; + } + + mc = NULL; + + } else { + mc->mc_refcnt++; } - mc->mc_refcnt++; } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } @@ -1172,7 +1279,7 @@ retry_lock2:; * sends the appropriate result. */ err = meta_back_init_one_conn( op, rs, mc, i, - LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok ); + LDAP_BACK_CONN_ISPRIV( &mc_curr ), sendok, !new_conn ); if ( err != LDAP_SUCCESS ) { /* * FIXME: in case one target cannot @@ -1230,7 +1337,8 @@ retry_lock2:; * also init'd */ int lerr = meta_back_init_one_conn( op, rs, mc, i, - LDAP_BACK_CONN_ISPRIV( &mc_curr ), LDAP_BACK_DONTSEND ); + LDAP_BACK_CONN_ISPRIV( &mc_curr ), + LDAP_BACK_DONTSEND, !new_conn ); if ( lerr == LDAP_SUCCESS ) { META_CANDIDATE_SET( &candidates[ i ] ); candidates[ i ].sr_err = LDAP_SUCCESS; @@ -1262,11 +1370,11 @@ retry_lock2:; err = lerr; if ( lerr == LDAP_UNAVAILABLE && mt->mt_isquarantined != LDAP_BACK_FQ_NO ) { - Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] quarantined: %d\n", + Debug( LDAP_DEBUG_TRACE, "%s: meta_back_getconn[%d] quarantined err=%d\n", op->o_log_prefix, i, lerr ); } else { - Debug( LDAP_DEBUG_ANY, "%s: meta_back_getconn[%d] failed: %d\n", + Debug( LDAP_DEBUG_ANY, "%s: meta_back_getconn[%d] failed err=%d\n", op->o_log_prefix, i, lerr ); } @@ -1362,10 +1470,14 @@ done:; case -1: /* duplicate: free and try to get the newly created one */ - if ( !( sendok & LDAP_BACK_BINDING ) ) { + if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( mi ) ) { + mc->mc_refcnt = 0; + meta_back_conn_free( mc ); + new_conn = 0; goto retry_lock; } + LDAP_BACK_CONN_TAINTED_SET( mc ); break; @@ -1398,7 +1510,7 @@ done:; op->o_log_prefix, ncandidates, LDAP_BACK_PCONN_ID( mc ) ); } - + return mc; } @@ -1424,27 +1536,34 @@ meta_back_release_conn_lock( * the connection space (and eat up resources). Maybe this * should be configurable... */ if ( LDAP_BACK_CONN_TAINTED( mc ) || - ( !LDAP_BACK_CONN_ISPRIV( mc ) && - LDAP_BACK_PCONN_ISPRIV( mc ) && - mc->mc_refcnt == 0 ) ) + ( !LDAP_BACK_CONN_ISPRIV( mc ) && LDAP_BACK_PCONN_ISPRIV( mc ) && mc->mc_refcnt == 0 ) ) { + metaconn_t *tmpmc; + Debug( LDAP_DEBUG_TRACE, "%s meta_back_release_conn: mc=%p conn=%ld tainted.\n", op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) ); #if META_BACK_PRINT_CONNTREE > 0 meta_back_print_conntree( mi->mi_conninfo.lai_tree, ">>> meta_back_release_conn" ); #endif /* META_BACK_PRINT_CONNTREE */ - (void)avl_delete( &mi->mi_conninfo.lai_tree, + tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )mc, meta_back_conndnmc_cmp ); #if META_BACK_PRINT_CONNTREE > 0 meta_back_print_conntree( mi->mi_conninfo.lai_tree, "<<< meta_back_release_conn" ); #endif /* META_BACK_PRINT_CONNTREE */ + if ( tmpmc == NULL ) { + Debug( LDAP_DEBUG_TRACE, "%s: meta_back_release_conn: unable to find mc=%p\n", + op->o_log_prefix, (void *)mc, 0 ); + } else { + assert( tmpmc == mc ); + } + if ( mc->mc_refcnt == 0 ) { meta_back_conn_free( mc ); mc = NULL; } } - if ( mc != NULL ) { + if ( mc != NULL && LDAP_BACK_CONN_BINDING( mc ) ) { LDAP_BACK_CONN_BINDING_CLEAR( mc ); } diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c index 46f18cb200..2b0c41835c 100644 --- a/servers/slapd/back-meta/init.c +++ b/servers/slapd/back-meta/init.c @@ -125,7 +125,9 @@ meta_back_db_open( { metainfo_t *mi = (metainfo_t *)be->be_private; - int i, rc; + int i, + not_always = 0, + rc; for ( i = 0; i < mi->mi_ntargets; i++ ) { slap_bindconf sb = { 0 }; @@ -153,6 +155,18 @@ meta_back_db_open( mt->mt_flags |= LDAP_BACK_F_CANCEL_EXOP; } } + + if ( not_always == 0 ) { + if ( !( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) + || !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) ) + { + not_always = 1; + } + } + } + + if ( not_always == 0 ) { + mi->mi_flags |= META_BACK_F_PROXYAUTHZ_ALWAYS; } return 0; @@ -175,7 +189,6 @@ meta_back_conn_free( assert( mc->mc_refcnt == 0 ); /* at least one must be present... */ - assert( mc->mc_conns != NULL ); ntargets = mc->mc_info->mi_ntargets; assert( ntargets > 0 ); diff --git a/servers/slapd/back-meta/map.c b/servers/slapd/back-meta/map.c index 0f01e6bfc5..379094350a 100644 --- a/servers/slapd/back-meta/map.c +++ b/servers/slapd/back-meta/map.c @@ -90,19 +90,19 @@ ldap_back_map_init ( struct ldapmap *lm, struct ldapmapping **m ) assert( m != NULL ); *m = NULL; - + mapping = (struct ldapmapping *)ch_calloc( 2, sizeof( struct ldapmapping ) ); if ( mapping == NULL ) { return; } - ber_str2bv( "objectclass", sizeof("objectclass")-1, 1, &mapping->src); - ber_dupbv( &mapping->dst, &mapping->src ); - mapping[1].src = mapping->src; - mapping[1].dst = mapping->dst; + ber_str2bv( "objectclass", STRLENOF("objectclass"), 1, &mapping[0].src); + ber_dupbv( &mapping[0].dst, &mapping[0].src ); + mapping[1].src = mapping[0].src; + mapping[1].dst = mapping[0].dst; - avl_insert( &lm->map, (caddr_t)mapping, + avl_insert( &lm->map, (caddr_t)&mapping[0], mapping_cmp, mapping_dup ); avl_insert( &lm->remap, (caddr_t)&mapping[1], mapping_cmp, mapping_dup ); @@ -120,6 +120,7 @@ ldap_back_mapping ( struct ldapmap *map, struct berval *s, struct ldapmapping ** if ( remap == BACKLDAP_REMAP ) { tree = map->remap; + } else { tree = map->map; } @@ -139,6 +140,13 @@ ldap_back_map ( struct ldapmap *map, struct berval *s, struct berval *bv, { struct ldapmapping *mapping; + /* map->map may be NULL when mapping is configured, + * but map->remap can't */ + if ( map->remap == NULL ) { + *bv = *s; + return; + } + BER_BVZERO( bv ); ( void )ldap_back_mapping( map, s, &mapping, remap ); if ( mapping != NULL ) { diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index c5627d56d1..149a6c3837 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -108,7 +108,7 @@ meta_search_dobind_init( bound = 1; } - snprintf( buf, sizeof( buf ), " mc=%p lc=%p%s DN=\"%s\"", + snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"", (void *)mc, (void *)msc->msc_ld, bound ? " bound" : " anonymous", bound == 0 ? "" : msc->msc_bound_ndn.bv_val ); @@ -118,13 +118,13 @@ meta_search_dobind_init( retcode = META_SEARCH_CANDIDATE; - } else if ( LDAP_BACK_CONN_BINDING( msc ) ) { + } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) { /* another thread is binding the target for this conn; wait */ #ifdef DEBUG_205 char buf[ SLAP_TEXT_BUFLEN ] = { '\0' }; - snprintf( buf, sizeof( buf ), " mc=%p lc=%p needbind", + snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind", (void *)mc, (void *)msc->msc_ld ); Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n", op->o_log_prefix, candidate, buf ); @@ -145,6 +145,32 @@ meta_search_dobind_init( op->o_log_prefix, candidate, buf ); #endif /* DEBUG_205 */ + if ( msc->msc_ld == NULL ) { + /* for some reason (e.g. because formerly in "binding" + * state, with eventual connection expiration or invalidation) + * it was not initialized as expected */ + + Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n", + op->o_log_prefix, candidate, (void *)mc ); + + rc = meta_back_init_one_conn( op, rs, *mcp, candidate, + LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND, 0 ); + switch ( rc ) { + case LDAP_SUCCESS: + assert( msc->msc_ld != NULL ); + break; + + case LDAP_SERVER_DOWN: + case LDAP_UNAVAILABLE: + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + goto down; + + default: + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + goto other; + } + } + LDAP_BACK_CONN_BINDING_SET( msc ); } @@ -154,29 +180,6 @@ meta_search_dobind_init( return retcode; } - if ( msc->msc_ld == NULL ) { - /* for some reason (e.g. because formerly in "binding" - * state, with eventual connection expiration or invalidation) - * it was not initialized as expected */ - - Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n", - op->o_log_prefix, candidate, (void *)mc ); - - rc = meta_back_init_one_conn( op, rs, *mcp, candidate, - LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND ); - switch ( rc ) { - case LDAP_SUCCESS: - assert( msc->msc_ld != NULL ); - break; - - case LDAP_SERVER_DOWN: - goto down; - - default: - goto other; - } - } - /* NOTE: this obsoletes pseudorootdn */ if ( op->o_conn != NULL && !op->o_do_not_cache && @@ -268,7 +271,7 @@ other:; rc = slap_map_api2result( rs ); ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); - LDAP_BACK_CONN_BINDING_CLEAR( msc ); + meta_clear_one_candidate( op, mc, candidate ); if ( META_BACK_ONERR_STOP( mi ) ) { LDAP_BACK_CONN_TAINTED_SET( mc ); meta_back_release_conn_lock( op, mc, 0 ); @@ -315,14 +318,17 @@ meta_search_dobind_result( NULL, NULL, NULL, NULL, 0 ); if ( rc != LDAP_SUCCESS ) { candidates[ candidate ].sr_err = rc; + + } else { + rc = slap_map_api2result( &candidates[ candidate ] ); } - rc = slap_map_api2result( &candidates[ candidate ] ); ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); LDAP_BACK_CONN_BINDING_CLEAR( msc ); if ( rc != LDAP_SUCCESS ) { if ( META_BACK_ONERR_STOP( mi ) ) { LDAP_BACK_CONN_TAINTED_SET( mc ); + meta_clear_one_candidate( op, mc, candidate ); meta_back_release_conn_lock( op, mc, 0 ); *mcp = NULL; retcode = META_SEARCH_ERR; @@ -796,9 +802,8 @@ getconn:; */ for ( rc = 0; ncandidates > 0; ) { int gotit = 0, - doabandon = 0; - - needbind = ncandidates; + doabandon = 0, + alreadybound = ncandidates; /* check time limit */ if ( op->ors_tlimit != SLAP_NO_LIMIT @@ -834,7 +839,7 @@ getconn:; switch ( retcode ) { case META_SEARCH_NEED_BIND: - needbind--; + alreadybound--; /* fallthru */ case META_SEARCH_BINDING: @@ -918,11 +923,12 @@ getconn:; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); snprintf( buf, sizeof( buf ), - "%s meta_back_search[%ld] mc=%p msgid=%d%s%s\n", + "%s meta_back_search[%ld] mc=%p msgid=%d%s%s%s\n", op->o_log_prefix, (long)i, (void *)mc, candidates[ i ].sr_msgid, META_IS_BINDING( &candidates[ i ] ) ? " binding" : "", - LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "" ); + LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "", + META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) ? " conncreating" : "" ); ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 ); @@ -1376,9 +1382,7 @@ really_bad:; Debug( LDAP_DEBUG_ANY, "### %s\n", buf, 0, 0 ); #endif /* DEBUG_205 */ - ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL ); - mc->mc_conns[ i ].msc_ld = NULL; - LDAP_BACK_CONN_BINDING_CLEAR( &mc->mc_conns[ i ] ); + meta_clear_one_candidate( op, mc, i ); } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); META_BINDING_CLEAR( &candidates[ i ] ); @@ -1439,7 +1443,7 @@ really_bad:; } #endif - if ( needbind == 0 ) { + if ( alreadybound == 0 ) { #if 0 Debug( LDAP_DEBUG_TRACE, "### %s select(%ld.%06ld)\n", op->o_log_prefix, save_tv.tv_sec, save_tv.tv_usec ); @@ -1622,9 +1626,7 @@ finish:; #endif /* DEBUG_205 */ /* if still binding, destroy */ - ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL ); - mc->mc_conns[ i ].msc_ld = NULL; - LDAP_BACK_CONN_BINDING_CLEAR( &mc->mc_conns[ i ] ); + meta_clear_one_candidate( op, mc, i ); } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); META_BINDING_CLEAR( &candidates[ i ] ); -- 2.39.5