diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 3f3c933bca..b7a8079d5b 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -494,11 +494,6 @@ meta_clear_one_candidate( metaconn_t *mc, int candidate ); -extern int -meta_clear_candidates( - Operation *op, - metaconn_t *mc ); - /* * Dn cache stuff (experimental) */ diff --git a/servers/slapd/back-meta/bind.c b/servers/slapd/back-meta/bind.c index f96c60cadf..84bd5ec45b 100644 --- a/servers/slapd/back-meta/bind.c +++ b/servers/slapd/back-meta/bind.c @@ -253,6 +253,7 @@ retry_lock:; ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn ); if ( isroot ) { + LDAP_BACK_CONN_ISPRIV_SET( mc ); mc->mc_conn = LDAP_BACK_PCONN_SET( op ); } lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc, @@ -262,9 +263,8 @@ retry_lock:; #endif /* META_BACK_PRINT_CONNTREE */ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); if ( lerr == -1 ) { - meta_clear_candidates( op, mc ); - /* we can do this because mc_refcnt == 1 */ + assert( mc->mc_refcnt == 1 ); mc->mc_refcnt = 0; meta_back_conn_free( mc ); mc = NULL; @@ -396,10 +396,10 @@ retry:; ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); assert( LDAP_BACK_CONN_BINDING( msc ) ); -#if 0 +#ifdef DEBUG_205 Debug( LDAP_DEBUG_ANY, "### %s meta_back_bind_op_result ldap_unbind_ext[%d] ld=%p\n", op->o_log_prefix, candidate, (void *)msc->msc_ld ); -#endif +#endif /* DEBUG_205 */ ldap_unbind_ext( msc->msc_ld, NULL, NULL ); msc->msc_ld = NULL; @@ -575,7 +575,7 @@ meta_back_single_dobind( !op->o_do_not_cache && ( BER_BVISNULL( &msc->msc_bound_ndn ) || BER_BVISEMPTY( &msc->msc_bound_ndn ) || - ( LDAP_BACK_CONN_ISPRIV( msc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) || + ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) || ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) ) { (void)meta_back_proxy_authz_bind( mc, candidate, op, rs, sendok ); diff --git a/servers/slapd/back-meta/candidates.c b/servers/slapd/back-meta/candidates.c index 878e6aee58..4a7ba3b3e2 100644 --- a/servers/slapd/back-meta/candidates.c +++ b/servers/slapd/back-meta/candidates.c @@ -189,10 +189,14 @@ meta_clear_one_candidate( if ( msc->msc_ld ) { -#if 0 - Debug( LDAP_DEBUG_ANY, "### %s meta_clear_one_candidate ldap_unbind_ext[%d] mc=%p\n", - op ? op->o_log_prefix : "", candidate, (void *)mc ); -#endif +#ifdef DEBUG_205 + char buf[ BUFSIZ ]; + + snprintf( buf, sizeof( buf ), "meta_clear_one_candidate ldap_unbind_ext[%d] mc=%p ld=%p", + candidate, (void *)mc, (void *)msc->msc_ld ); + Debug( LDAP_DEBUG_ANY, "### %s %s\n", + op ? op->o_log_prefix : "", buf, 0 ); +#endif /* DEBUG_205 */ ldap_unbind_ext( msc->msc_ld, NULL, NULL ); msc->msc_ld = NULL; @@ -212,20 +216,3 @@ meta_clear_one_candidate( return 0; } -/* - * meta_clear_candidates - * - * clears all candidates - */ -int -meta_clear_candidates( Operation *op, metaconn_t *mc ) -{ - metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; - int c; - - for ( c = 0; c < mi->mi_ntargets; c++ ) { - meta_clear_one_candidate( op, mc, c ); - } - - return 0; -} diff --git a/servers/slapd/back-meta/compare.c b/servers/slapd/back-meta/compare.c index be48b0a03a..408021de4f 100644 --- a/servers/slapd/back-meta/compare.c +++ b/servers/slapd/back-meta/compare.c @@ -34,319 +34,122 @@ int meta_back_compare( Operation *op, SlapReply *rs ) { - metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; - metaconn_t *mc = NULL; - char *match = NULL, - *err = NULL; - struct berval mmatch = BER_BVNULL; - int ncandidates = 0, - last = 0, - i, - count = 0, - rc, - cres = LDAP_SUCCESS, - rres = LDAP_SUCCESS, - *msgid; - dncookie dc; + metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private; + metatarget_t *mt; + metaconn_t *mc; + int rc = 0; + int candidate = -1; + struct berval mdn = BER_BVNULL; + dncookie dc; + struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname; + struct berval mapped_value = op->orc_ava->aa_value; + int msgid; + int do_retry = 1; + LDAPControl **ctrls = NULL; - SlapReply *candidates = meta_back_candidates_get( op ); - - mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_SENDERR ); + mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) { return rs->sr_err; } - - msgid = ch_calloc( sizeof( int ), mi->mi_ntargets ); - if ( msgid == NULL ) { - send_ldap_error( op, rs, LDAP_OTHER, NULL ); - rc = LDAP_OTHER; - goto done; - } + + assert( mc->mc_conns[ candidate ].msc_ld != NULL ); /* - * start an asynchronous compare for each candidate target + * Rewrite the modify dn, if needed */ + mt = mi->mi_targets[ candidate ]; + dc.target = mt; dc.conn = op->o_conn; dc.rs = rs; dc.ctx = "compareDN"; - for ( i = 0; i < mi->mi_ntargets; i++ ) { - struct berval mdn = BER_BVNULL; - struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname; - struct berval mapped_value = op->orc_ava->aa_value; - metatarget_t *mt = mi->mi_targets[ i ]; - LDAPControl **ctrls = NULL; + switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { + case LDAP_UNWILLING_TO_PERFORM: + rc = 1; + goto cleanup; - if ( ! META_IS_CANDIDATE( &candidates[ i ] ) ) { - msgid[ i ] = -1; - continue; - } - - /* - * Rewrite the compare dn, if needed - */ - dc.target = mt; - - switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { - case LDAP_UNWILLING_TO_PERFORM: - rc = 1; - goto finish; - - default: - break; - } - - /* - * if attr is objectClass, try to remap the value - */ - if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass ) { - ldap_back_map( &mt->mt_rwmap.rwm_oc, - &op->orc_ava->aa_value, - &mapped_value, BACKLDAP_MAP ); - - if ( BER_BVISNULL( &mapped_value ) || mapped_value.bv_val[0] == '\0' ) { - continue; - } - /* - * else try to remap the attribute - */ - } else { - ldap_back_map( &mt->mt_rwmap.rwm_at, - &op->orc_ava->aa_desc->ad_cname, - &mapped_attr, BACKLDAP_MAP ); - if ( BER_BVISNULL( &mapped_attr ) || mapped_attr.bv_val[0] == '\0' ) { - continue; - } - - if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) - { - dc.ctx = "compareAttrDN"; - - switch ( ldap_back_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ) ) - { - case LDAP_UNWILLING_TO_PERFORM: - rc = 1; - goto finish; - - default: - break; - } - } - } - - ctrls = op->o_ctrls; - if ( ldap_back_proxy_authz_ctrl( &mc->mc_conns[ i ].msc_bound_ndn, - mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS ) - { - continue; - } - - /* - * the compare op is spawned across the targets and the first - * that returns determines the result; a constraint on unicity - * of the result ought to be enforced - */ - rc = ldap_compare_ext( mc->mc_conns[ i ].msc_ld, mdn.bv_val, - mapped_attr.bv_val, &mapped_value, - ctrls, NULL, &msgid[ i ] ); - - (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); - - if ( mdn.bv_val != op->o_req_dn.bv_val ) { - free( mdn.bv_val ); - BER_BVZERO( &mdn ); - } - - if ( mapped_attr.bv_val != op->orc_ava->aa_desc->ad_cname.bv_val ) { - free( mapped_attr.bv_val ); - BER_BVZERO( &mapped_attr ); - } - - if ( mapped_value.bv_val != op->orc_ava->aa_value.bv_val ) { - free( mapped_value.bv_val ); - BER_BVZERO( &mapped_value ); - } - - if ( rc != LDAP_SUCCESS ) { - /* FIXME: what should we do with the error? */ - continue; - } - - ++ncandidates; + default: + break; } /* - * wait for replies + * if attr is objectClass, try to remap the value */ - for ( rc = 0, count = 0; ncandidates > 0; ) { + if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass ) { + ldap_back_map( &mt->mt_rwmap.rwm_oc, + &op->orc_ava->aa_value, + &mapped_value, BACKLDAP_MAP ); - /* - * FIXME: should we check for abandon? - */ - for ( i = 0; i < mi->mi_ntargets; i++ ) { - metasingleconn_t *msc = &mc->mc_conns[ i ]; - int lrc; - LDAPMessage *res = NULL; - struct timeval tv; + if ( BER_BVISNULL( &mapped_value ) || BER_BVISEMPTY( &mapped_value ) ) { + goto cleanup; + } - LDAP_BACK_TV_SET( &tv ); + /* + * else try to remap the attribute + */ + } else { + ldap_back_map( &mt->mt_rwmap.rwm_at, + &op->orc_ava->aa_desc->ad_cname, + &mapped_attr, BACKLDAP_MAP ); + if ( BER_BVISNULL( &mapped_attr ) || BER_BVISEMPTY( &mapped_attr ) ) { + goto cleanup; + } - if ( msgid[ i ] == -1 ) { - continue; - } + if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) + { + dc.ctx = "compareAttrDN"; - lrc = ldap_result( msc->msc_ld, msgid[ i ], - LDAP_MSG_ALL, &tv, &res ); - - switch ( lrc ) { - case 0: - assert( res == NULL ); - continue; - - case -1: - /* we do not retry in this case; - * only for unique operations... */ - ldap_get_option( msc->msc_ld, - LDAP_OPT_RESULT_CODE, &rs->sr_err ); - rres = slap_map_api2result( rs ); - rres = rc; - rc = -1; - goto finish; + switch ( ldap_back_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ) ) + { + case LDAP_UNWILLING_TO_PERFORM: + rc = 1; + goto cleanup; default: - /* only touch when activity actually took place... */ - /* NOTE: no mutex because there's only a loose requirement - * to bump it up... */ - if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) { - msc->msc_time = op->o_time; - } - break; - } - - if ( lrc == LDAP_RES_COMPARE ) { - if ( count > 0 ) { - rres = LDAP_OTHER; - rc = -1; - goto finish; - } - - /* FIXME: matched? referrals? response controls? */ - rc = ldap_parse_result( msc->msc_ld, res, - &rs->sr_err, - NULL, NULL, NULL, NULL, 1 ); - if ( rc != LDAP_SUCCESS ) { - rres = rc; - rc = -1; - goto finish; - } - - switch ( rs->sr_err ) { - case LDAP_COMPARE_TRUE: - case LDAP_COMPARE_FALSE: - - /* - * true or false, got it; - * sending to cache ... - */ - if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) { - ( void )meta_dncache_update_entry( &mi->mi_cache, &op->o_req_ndn, i ); - } - - count++; - rc = 0; - break; - - default: - rres = slap_map_api2result( rs ); - - if ( err != NULL ) { - free( err ); - } - ldap_get_option( msc->msc_ld, - LDAP_OPT_DIAGNOSTIC_MESSAGE, &err ); - - if ( match != NULL ) { - free( match ); - } - ldap_get_option( msc->msc_ld, - LDAP_OPT_MATCHED_DN, &match ); - - last = i; - break; - } - msgid[ i ] = -1; - --ncandidates; - - } else { - msgid[ i ] = -1; - --ncandidates; - if ( res ) { - ldap_msgfree( res ); - } break; } } } -finish:; +retry:; + ctrls = op->o_ctrls; + rc = ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn, + mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ); + if ( rc != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + goto cleanup; + } - /* - * Rewrite the matched portion of the search base, if required - * - * FIXME: only the last one gets caught! - */ - if ( count == 1 ) { - if ( match != NULL ) { - free( match ); - match = NULL; - } - - /* - * the result of the compare is assigned to the res code - * that will be returned - */ - rres = cres; - - /* - * At least one compare failed with matched portion, - * and none was successful - */ - } else if ( match != NULL && match[ 0 ] != '\0' ) { - struct berval matched, pmatched; + rs->sr_err = ldap_compare_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val, + mapped_attr.bv_val, &mapped_value, + ctrls, NULL, &msgid ); - ber_str2bv( match, 0, 0, &matched ); - - dc.ctx = "matchedDN"; - ldap_back_dn_massage( &dc, &matched, &mmatch ); - if ( dnPretty( NULL, &mmatch, &pmatched, NULL ) == LDAP_SUCCESS ) { - if ( mmatch.bv_val != match ) { - free( mmatch.bv_val ); - } - mmatch = pmatched; + rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid, + mt->mt_timeout[ SLAP_OP_COMPARE ], LDAP_BACK_SENDRESULT ); + if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) { + do_retry = 0; + if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { + /* if the identity changed, there might be need to re-authz */ + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + goto retry; } } - if ( rres != LDAP_SUCCESS ) { - rs->sr_err = rres; - } - rs->sr_matched = mmatch.bv_val; - send_ldap_result( op, rs ); - rs->sr_matched = NULL; +cleanup:; + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); - if ( match != NULL ) { - if ( mmatch.bv_val != match ) { - free( mmatch.bv_val ); - } - free( match ); + if ( mdn.bv_val != op->o_req_dn.bv_val ) { + free( mdn.bv_val ); } - if ( msgid ) { - free( msgid ); + if ( op->orc_ava->aa_value.bv_val != mapped_value.bv_val ) { + free( mapped_value.bv_val ); } -done:; - meta_back_release_conn( op, mc ); + if ( mc ) { + meta_back_release_conn( op, mc ); + } - return rc; + return rs->sr_err; } diff --git a/servers/slapd/back-meta/conn.c b/servers/slapd/back-meta/conn.c index 8d226df8ad..4d2ddc4544 100644 --- a/servers/slapd/back-meta/conn.c +++ b/servers/slapd/back-meta/conn.c @@ -156,11 +156,12 @@ ravl_print( Avlnode *root, int depth ) } mc = (metaconn_t *)root->avl_data; - fprintf( stderr, "mc=%p local=\"%s\" conn=%p %s refcnt=%d\n", + fprintf( stderr, "mc=%p local=\"%s\" conn=%p %s refcnt=%d%s\n", (void *)mc, mc->mc_local_ndn.bv_val ? mc->mc_local_ndn.bv_val : "", (void *)mc->mc_conn, - avl_bf2str( root->avl_bf ), mc->mc_refcnt ); + avl_bf2str( root->avl_bf ), mc->mc_refcnt, + LDAP_BACK_CONN_TAINTED( mc ) ? " tainted" : "" ); ravl_print( root->avl_left, depth + 1 ); } @@ -424,10 +425,10 @@ retry:; || ( rs->sr_err != LDAP_SUCCESS && LDAP_BACK_TLS_CRITICAL( mi ) ) ) { -#if 0 +#ifdef DEBUG_205 Debug( LDAP_DEBUG_ANY, "### %s meta_back_init_one_conn(TLS) ldap_unbind_ext[%d] ld=%p\n", op->o_log_prefix, candidate, (void *)msc->msc_ld ); -#endif +#endif /* DEBUG_205 */ ldap_unbind_ext( msc->msc_ld, NULL, NULL ); msc->msc_ld = NULL; @@ -464,8 +465,6 @@ retry:; ber_bvreplace( &msc->msc_bound_ndn, &slap_empty_bv ); } - LDAP_BACK_CONN_ISPRIV_SET( msc ); - } else { if ( !BER_BVISNULL( &msc->msc_cred ) ) { memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len ); @@ -492,10 +491,10 @@ retry:; &msc->msc_bound_ndn ) ) { -#if 0 +#ifdef DEBUG_205 Debug( LDAP_DEBUG_ANY, "### %s meta_back_init_one_conn(rewrite) ldap_unbind_ext[%d] ld=%p\n", op->o_log_prefix, candidate, (void *)msc->msc_ld ); -#endif +#endif /* DEBUG_205 */ ldap_unbind_ext( msc->msc_ld, NULL, NULL ); msc->msc_ld = NULL; @@ -872,7 +871,7 @@ meta_back_getconn( META_DNTYPE_ENTRY, META_DNTYPE_PARENT, META_DNTYPE_NEWPARENT - } dn_type = META_DNTYPE_ENTRY; + } dn_type = META_DNTYPE_ENTRY; struct berval ndn = op->o_req_ndn, pndn; @@ -923,7 +922,8 @@ retry_lock:; op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc ) ); } - /* Don't reuse connections while they're still binding */ + /* 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(); @@ -959,12 +959,12 @@ retry_lock:; } break; + case LDAP_REQ_COMPARE: case LDAP_REQ_DELETE: case LDAP_REQ_MODIFY: /* just a unique candidate */ break; - case LDAP_REQ_COMPARE: case LDAP_REQ_SEARCH: /* allow multiple candidates for the searchBase */ op_type = META_OP_ALLOW_MULTIPLE; @@ -990,6 +990,13 @@ retry_lock:; if ( sendok & LDAP_BACK_BINDING ) { LDAP_BACK_CONN_BINDING_SET( mc ); } + if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { + LDAP_BACK_CONN_ISPRIV_SET( mc ); + } + + } else if ( 0 ) { + /* TODO: if any of the connections is binding, + * release mc and create a new one */ } for ( i = 0; i < mi->mi_ntargets; i++ ) { @@ -1121,12 +1128,11 @@ retry_lock2:; (caddr_t)&mc_curr, meta_back_conndn_cmp ); if ( mc != NULL ) { /* Don't reuse connections while they're still binding */ - if ( LDAP_BACK_CONN_BINDING( mc ) ) { + 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; } - mc->mc_refcnt++; } ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); @@ -1142,6 +1148,9 @@ retry_lock2:; if ( sendok & LDAP_BACK_BINDING ) { LDAP_BACK_CONN_BINDING_SET( mc ); } + if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { + LDAP_BACK_CONN_ISPRIV_SET( mc ); + } } } @@ -1197,8 +1206,8 @@ retry_lock2:; mc->mc_conn = mc_curr.mc_conn; ber_dupbv( &mc->mc_local_ndn, &mc_curr.mc_local_ndn ); new_conn = 1; - if ( sendok & LDAP_BACK_BINDING ) { - LDAP_BACK_CONN_BINDING_SET( mc ); + if ( LDAP_BACK_CONN_ISPRIV( &mc_curr ) ) { + LDAP_BACK_CONN_ISPRIV_SET( mc ); } } @@ -1404,7 +1413,6 @@ meta_back_release_conn_lock( } assert( mc->mc_refcnt > 0 ); mc->mc_refcnt--; - LDAP_BACK_CONN_BINDING_CLEAR( mc ); /* NOTE: the connection is removed if either it is tainted * or if it is shared and no one else is using it. This needs * to occur because for intrinsic reasons cached connections @@ -1428,8 +1436,14 @@ meta_back_release_conn_lock( #endif /* META_BACK_PRINT_CONNTREE */ if ( mc->mc_refcnt == 0 ) { meta_back_conn_free( mc ); + mc = NULL; } } + + if ( mc != NULL ) { + LDAP_BACK_CONN_BINDING_CLEAR( mc ); + } + if ( dolock ) { ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); } diff --git a/servers/slapd/back-meta/init.c b/servers/slapd/back-meta/init.c index 8bec4e3fe2..46f18cb200 100644 --- a/servers/slapd/back-meta/init.c +++ b/servers/slapd/back-meta/init.c @@ -170,7 +170,6 @@ meta_back_conn_free( { metaconn_t *mc = v_mc; int ntargets; - Operation op; assert( mc != NULL ); assert( mc->mc_refcnt == 0 ); diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index 3c34c3aa65..04aa880f04 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -85,7 +85,8 @@ meta_search_dobind_init( meta_search_candidate_t retcode; - Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n", op->o_log_prefix, candidate, 0 ); + Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n", + op->o_log_prefix, candidate, 0 ); /* * all the targets are already bound as pseudoroot @@ -98,17 +99,55 @@ meta_search_dobind_init( ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex ); if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) { /* already bound (or anonymous) */ + +#ifdef DEBUG_205 + char buf[ SLAP_TEXT_BUFLEN ] = { '\0' }; + int bound = 0; + + if ( LDAP_BACK_CONN_ISBOUND( msc ) ) { + bound = 1; + } + + snprintf( buf, sizeof( buf ), " mc=%p lc=%p%s DN=\"%s\"", + (void *)mc, (void *)msc->msc_ld, + bound ? " bound" : " anonymous", + bound == 0 ? "" : msc->msc_bound_ndn.bv_val ); + Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n", + op->o_log_prefix, candidate, buf ); +#endif /* DEBUG_205 */ + retcode = META_SEARCH_CANDIDATE; } else if ( 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", + (void *)mc, (void *)msc->msc_ld ); + Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n", + op->o_log_prefix, candidate, buf ); +#endif /* DEBUG_205 */ + candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND; retcode = META_SEARCH_NEED_BIND; } else { /* we'll need to bind the target for this conn */ + +#ifdef DEBUG_205 + char buf[ SLAP_TEXT_BUFLEN ]; + + snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding", + (void *)mc, (void *)msc->msc_ld ); + Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n", + op->o_log_prefix, candidate, buf ); +#endif /* DEBUG_205 */ + LDAP_BACK_CONN_BINDING_SET( msc ); } + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); if ( retcode != META_SEARCH_BINDING ) { @@ -120,8 +159,8 @@ meta_search_dobind_init( * state, with eventual connection expiration or invalidation) * it was not initialized as expected */ - Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] ld=NULL\n", - op->o_log_prefix, candidate, 0 ); + 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 ); @@ -185,6 +224,18 @@ meta_search_dobind_init( rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &candidates[ candidate ].sr_msgid ); + +#ifdef DEBUG_205 + { + char buf[ SLAP_TEXT_BUFLEN ]; + + snprintf( buf, sizeof( buf ), "meta_search_dobind_init[%d] mc=%p ld=%p rc=%d", + candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc ); + Debug( LDAP_DEBUG_ANY, "### %s %s\n", + op->o_log_prefix, buf, 0 ); + } +#endif /* DEBUG_205 */ + switch ( rc ) { case LDAP_SUCCESS: assert( candidates[ candidate ].sr_msgid >= 0 ); @@ -222,9 +273,9 @@ other:; retcode = META_SEARCH_ERR; } else { - candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; retcode = META_SEARCH_NOT_CANDIDATE; } + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); break; } @@ -271,17 +322,22 @@ meta_search_dobind_result( } else { /* FIXME: check if bound as idassert authcDN! */ - if ( be_isroot( op ) ) { - LDAP_BACK_CONN_ISBOUND_SET( msc ); - } else { + if ( BER_BVISNULL( &msc->msc_bound_ndn ) + || BER_BVISEMPTY( &msc->msc_bound_ndn ) ) + { LDAP_BACK_CONN_ISANON_SET( msc ); + + } else { + LDAP_BACK_CONN_ISBOUND_SET( msc ); } retcode = META_SEARCH_CANDIDATE; } - ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; META_BINDING_CLEAR( &candidates[ candidate ] ); + ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + return retcode; } @@ -317,6 +373,7 @@ meta_back_search_start( if ( META_BACK_ONERR_STOP( mi ) ) { return META_SEARCH_ERR; } + candidates[ candidate ].sr_msgid = META_MSGID_IGNORE; return META_SEARCH_NOT_CANDIDATE; } @@ -567,8 +624,17 @@ getconn:; * Inits searches */ for ( i = 0; i < mi->mi_ntargets; i++ ) { + /* reset sr_msgid; it is used in most loops + * to check if that target is still to be considered */ candidates[ i ].sr_msgid = META_MSGID_IGNORE; + /* a target is marked as candidate by meta_back_getconn(); + * if for any reason (an error, it's over or so) it is + * no longer active, sr_msgid is set to META_MSGID_IGNORE + * but it remains candidate, which means it has been active + * at some point during the operation. This allows to + * use its response code and more to compute the final + * response */ if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) { continue; } @@ -589,6 +655,7 @@ getconn:; switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) ) { case META_SEARCH_NOT_CANDIDATE: + candidates[ i ].sr_msgid = META_MSGID_IGNORE; break; case META_SEARCH_NEED_BIND: @@ -612,15 +679,31 @@ getconn:; } if ( ncandidates > 0 && needbind == ncandidates ) { - assert( ( sendok & LDAP_BACK_BINDING ) == 0 ); + /* + * give up the second time... + * + * NOTE: this should not occur the second time, since a fresh + * connection has ben created; however, targets may also + * need bind because the bind timed out or so. + */ + if ( sendok & LDAP_BACK_BINDING ) { + Debug( LDAP_DEBUG_ANY, + "%s meta_back_search: unable to initialize conn\n", + op->o_log_prefix, 0, 0 ); + rs->sr_err = LDAP_UNAVAILABLE; + rs->sr_text = "unable to initialize connection to remote targets"; + send_ldap_result( op, rs ); + rc = -1; + goto finish; + } /* FIXME: better create a separate connection? */ sendok |= LDAP_BACK_BINDING; -#if 0 - Debug( LDAP_DEBUG_TRACE, "*** %s drop mc=%p create new connection\n", - op->o_log_prefix, mc, 0 ); -#endif +#ifdef DEBUG_205 + Debug( LDAP_DEBUG_ANY, "*** %s drop mc=%p create new connection\n", + op->o_log_prefix, (void *)mc, 0 ); +#endif /* DEBUG_205 */ meta_back_release_conn( op, mc ); mc = NULL; @@ -634,7 +717,7 @@ getconn:; initial_candidates = ncandidates; if ( LogTest( LDAP_DEBUG_TRACE ) ) { - char cnd[ BUFSIZ ]; + char cnd[ SLAP_TEXT_BUFLEN ]; int c; for ( c = 0; c < mi->mi_ntargets; c++ ) { @@ -719,10 +802,12 @@ getconn:; metasingleconn_t *msc = &mc->mc_conns[ i ]; LDAPMessage *res = NULL, *msg; + /* if msgid is invalid, don't ldap_result() */ if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) { continue; } + /* if target still needs bind, retry */ if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND ) { meta_search_candidate_t retcode; @@ -805,6 +890,23 @@ getconn:; if ( op->o_abandon ) { break; } + +#ifdef DEBUG_205 + if ( msc->msc_ld == NULL ) { + char buf[ SLAP_TEXT_BUFLEN ]; + + 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", + 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_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex ); + + Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 ); + } +#endif /* DEBUG_205 */ /* * FIXME: handle time limit as well? @@ -833,7 +935,8 @@ really_bad:; switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) ) { case META_SEARCH_CANDIDATE: - break; + /* get back into business... */ + continue; /* means that failed but onerr == continue */ case META_SEARCH_NOT_CANDIDATE: @@ -855,6 +958,7 @@ really_bad:; default: /* unrecoverable error */ + candidates[ i ].sr_msgid = META_MSGID_IGNORE; rc = rs->sr_err = LDAP_OTHER; goto finish; } @@ -1225,11 +1329,16 @@ really_bad:; if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ) { /* if still binding, destroy */ -#if 0 - Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(abandon) " - "ldap_unbind_ext[%ld] ld=%p\n", - op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld ); -#endif +#ifdef DEBUG_205 + char buf[ SLAP_TEXT_BUFLEN ]; + + snprintf( buf, sizeof( buf), "%s meta_back_search(abandon) " + "ldap_unbind_ext[%ld] mc=%p ld=%p", + op->o_log_prefix, i, (void *)mc, + (void *)mc->mc_conns[i].msc_ld ); + + 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; @@ -1273,7 +1382,7 @@ really_bad:; #if 0 if ( LogTest( LDAP_DEBUG_TRACE ) ) { - char buf[ BUFSIZ ]; + char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), "%s %ld.%06ld %d/%d mc=%p", op->o_log_prefix, save_tv.tv_sec, save_tv.tv_usec, @@ -1390,8 +1499,8 @@ really_bad:; #if 0 { - char buf[BUFSIZ]; - char cnd[BUFSIZ]; + char buf[ SLAP_TEXT_BUFLEN ]; + char cnd[ SLAP_TEXT_BUFLEN ]; int i; for ( i = 0; i < mi->mi_ntargets; i++ ) { @@ -1449,11 +1558,11 @@ finish:; assert( candidates[ i ].sr_msgid >= 0 ); assert( mc->mc_conns[ i ].msc_ld != NULL ); -#if 0 +#ifdef DEBUG_205 Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) " "ldap_unbind_ext[%ld] ld=%p\n", op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld ); -#endif +#endif /* DEBUG_205 */ /* if still binding, destroy */ ldap_unbind_ext( mc->mc_conns[ i ].msc_ld, NULL, NULL );