1*cf1d77f7Schristos /*	$NetBSD: add.c,v 1.2 2021/08/14 16:14:59 christos Exp $	*/
292cfeba6Schristos 
392cfeba6Schristos /* add.c - add request handler for back-asyncmeta */
492cfeba6Schristos /* $OpenLDAP$ */
592cfeba6Schristos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
692cfeba6Schristos  *
792cfeba6Schristos  * Copyright 2016-2021 The OpenLDAP Foundation.
892cfeba6Schristos  * Portions Copyright 2016 Symas Corporation.
992cfeba6Schristos  * All rights reserved.
1092cfeba6Schristos  *
1192cfeba6Schristos  * Redistribution and use in source and binary forms, with or without
1292cfeba6Schristos  * modification, are permitted only as authorized by the OpenLDAP
1392cfeba6Schristos  * Public License.
1492cfeba6Schristos  *
1592cfeba6Schristos  * A copy of this license is available in the file LICENSE in the
1692cfeba6Schristos  * top-level directory of the distribution or, alternatively, at
1792cfeba6Schristos  * <http://www.OpenLDAP.org/license.html>.
1892cfeba6Schristos  */
1992cfeba6Schristos 
2092cfeba6Schristos /* ACKNOWLEDGEMENTS:
2192cfeba6Schristos  * This work was developed by Symas Corporation
2292cfeba6Schristos  * based on back-meta module for inclusion in OpenLDAP Software.
2392cfeba6Schristos  * This work was sponsored by Ericsson. */
2492cfeba6Schristos 
2592cfeba6Schristos 
2692cfeba6Schristos #include <sys/cdefs.h>
27*cf1d77f7Schristos __RCSID("$NetBSD: add.c,v 1.2 2021/08/14 16:14:59 christos Exp $");
2892cfeba6Schristos 
2992cfeba6Schristos #include "portable.h"
3092cfeba6Schristos 
3192cfeba6Schristos #include <stdio.h>
3292cfeba6Schristos 
3392cfeba6Schristos #include <ac/string.h>
3492cfeba6Schristos #include <ac/socket.h>
3592cfeba6Schristos #include "slap.h"
3692cfeba6Schristos #include "../../../libraries/liblber/lber-int.h"
3792cfeba6Schristos #include "../../../libraries/libldap/ldap-int.h"
3892cfeba6Schristos #include "../back-ldap/back-ldap.h"
3992cfeba6Schristos #include "back-asyncmeta.h"
4092cfeba6Schristos #include "ldap_rq.h"
4192cfeba6Schristos 
4292cfeba6Schristos 
4392cfeba6Schristos int
asyncmeta_error_cleanup(Operation * op,SlapReply * rs,bm_context_t * bc,a_metaconn_t * mc,int candidate)4492cfeba6Schristos asyncmeta_error_cleanup(Operation *op,
4592cfeba6Schristos 			SlapReply *rs,
4692cfeba6Schristos 			bm_context_t *bc,
4792cfeba6Schristos 			a_metaconn_t *mc,
4892cfeba6Schristos 			int candidate)
4992cfeba6Schristos {
5092cfeba6Schristos 	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
5192cfeba6Schristos 	mc->mc_conns[candidate].msc_active--;
5292cfeba6Schristos 	if (asyncmeta_bc_in_queue(mc,bc) == NULL || bc->bc_active > 1) {
5392cfeba6Schristos 		bc->bc_active--;
5492cfeba6Schristos 		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
5592cfeba6Schristos 		return LDAP_SUCCESS;
5692cfeba6Schristos 	}
5792cfeba6Schristos 	asyncmeta_drop_bc(mc, bc);
5892cfeba6Schristos 	slap_sl_mem_setctx(op->o_threadctx, op->o_tmpmemctx);
5992cfeba6Schristos 	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
6092cfeba6Schristos 	send_ldap_result(op, rs);
6192cfeba6Schristos 	return LDAP_SUCCESS;
6292cfeba6Schristos }
6392cfeba6Schristos 
6492cfeba6Schristos meta_search_candidate_t
asyncmeta_back_add_start(Operation * op,SlapReply * rs,a_metaconn_t * mc,bm_context_t * bc,int candidate,int do_lock)6592cfeba6Schristos asyncmeta_back_add_start(Operation *op,
6692cfeba6Schristos 			 SlapReply *rs,
6792cfeba6Schristos 			 a_metaconn_t *mc,
6892cfeba6Schristos 			 bm_context_t *bc,
6992cfeba6Schristos 			 int candidate,
7092cfeba6Schristos 			 int do_lock)
7192cfeba6Schristos {
7292cfeba6Schristos 	int		isupdate;
7392cfeba6Schristos 	Attribute	*a;
7492cfeba6Schristos 	int i;
7592cfeba6Schristos 	LDAPMod		**attrs;
7692cfeba6Schristos 	a_dncookie	dc;
7792cfeba6Schristos 	a_metainfo_t	*mi = mc->mc_info;
7892cfeba6Schristos 	a_metatarget_t	*mt = mi->mi_targets[ candidate ];
7992cfeba6Schristos 	struct berval   mdn = {0, NULL};
8092cfeba6Schristos 	meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
8192cfeba6Schristos 	BerElement *ber = NULL;
8292cfeba6Schristos 	a_metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
8392cfeba6Schristos 	SlapReply		*candidates = bc->candidates;
8492cfeba6Schristos 	ber_int_t	msgid;
8592cfeba6Schristos 	LDAPControl		**ctrls = NULL;
8692cfeba6Schristos 	int rc;
8792cfeba6Schristos 
8892cfeba6Schristos 	dc.op = op;
8992cfeba6Schristos 	dc.target = mt;
9092cfeba6Schristos 	dc.memctx = op->o_tmpmemctx;
9192cfeba6Schristos 	dc.to_from = MASSAGE_REQ;
9292cfeba6Schristos 	asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
9392cfeba6Schristos 
9492cfeba6Schristos 	/* Count number of attributes in entry ( +1 ) */
9592cfeba6Schristos 	for ( i = 1, a = op->ora_e->e_attrs; a; i++, a = a->a_next );
9692cfeba6Schristos 
9792cfeba6Schristos 	/* Create array of LDAPMods for ldap_add() */
9892cfeba6Schristos 	attrs = op->o_tmpalloc(sizeof( LDAPMod * )*i, op->o_tmpmemctx);
9992cfeba6Schristos 
10092cfeba6Schristos 	isupdate = be_shadow_update( op );
10192cfeba6Schristos 	for ( i = 0, a = op->ora_e->e_attrs; a; a = a->a_next ) {
10292cfeba6Schristos 		int j;
10392cfeba6Schristos 
10492cfeba6Schristos 		if ( !isupdate && !get_relax( op ) && a->a_desc->ad_type->sat_no_user_mod  )
10592cfeba6Schristos 		{
10692cfeba6Schristos 			continue;
10792cfeba6Schristos 		}
10892cfeba6Schristos 
10992cfeba6Schristos 		attrs[ i ] = op->o_tmpalloc( sizeof( LDAPMod ), op->o_tmpmemctx );
11092cfeba6Schristos 		if ( attrs[ i ] == NULL ) {
11192cfeba6Schristos 			continue;
11292cfeba6Schristos 		}
11392cfeba6Schristos 		attrs[ i ]->mod_op = LDAP_MOD_BVALUES;
11492cfeba6Schristos 		attrs[ i ]->mod_type = a->a_desc->ad_cname.bv_val;
11592cfeba6Schristos 		j = a->a_numvals;
11692cfeba6Schristos 		attrs[ i ]->mod_bvalues = op->o_tmpalloc( ( j + 1 ) * sizeof( struct berval * ), op->o_tmpmemctx );
11792cfeba6Schristos 		for (j=0; j<a->a_numvals; j++) {
11892cfeba6Schristos 			attrs[ i ]->mod_bvalues[ j ] = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
11992cfeba6Schristos 			if ( a->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
12092cfeba6Schristos 				asyncmeta_dn_massage( &dc, &a->a_vals[ j ], attrs[ i ]->mod_bvalues[ j ] );
12192cfeba6Schristos 			else
12292cfeba6Schristos 				*attrs[ i ]->mod_bvalues[ j ] = a->a_vals[ j ];
12392cfeba6Schristos 		}
12492cfeba6Schristos 
12592cfeba6Schristos 		attrs[ i ]->mod_bvalues[ j ] = NULL;
12692cfeba6Schristos 		i++;
12792cfeba6Schristos 	}
12892cfeba6Schristos 	attrs[ i ] = NULL;
12992cfeba6Schristos 
13092cfeba6Schristos 	asyncmeta_set_msc_time(msc);
13192cfeba6Schristos 
13292cfeba6Schristos 	ctrls = op->o_ctrls;
13392cfeba6Schristos 	if ( asyncmeta_controls_add( op, rs, mc, candidate, bc->is_root, &ctrls ) != LDAP_SUCCESS )
13492cfeba6Schristos 	{
13592cfeba6Schristos 		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
13692cfeba6Schristos 		retcode = META_SEARCH_ERR;
13792cfeba6Schristos 		goto done;
13892cfeba6Schristos 	}
13992cfeba6Schristos 	/* someone might have reset the connection */
14092cfeba6Schristos 	if (!( LDAP_BACK_CONN_ISBOUND( msc )
14192cfeba6Schristos 	       || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
14292cfeba6Schristos 		Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
14392cfeba6Schristos 		goto error_unavailable;
14492cfeba6Schristos 	}
14592cfeba6Schristos 
14692cfeba6Schristos 	ber = ldap_build_add_req( msc->msc_ld, mdn.bv_val, attrs, ctrls, NULL, &msgid);
14792cfeba6Schristos 	if (!ber) {
14892cfeba6Schristos 		Debug( asyncmeta_debug, "%s asyncmeta_back_add_start: Operation encoding failed with errno %d\n",
14992cfeba6Schristos 		       op->o_log_prefix, msc->msc_ld->ld_errno );
15092cfeba6Schristos 		rs->sr_err = LDAP_OPERATIONS_ERROR;
15192cfeba6Schristos 		rs->sr_text = "Failed to encode proxied request";
15292cfeba6Schristos 		retcode = META_SEARCH_ERR;
15392cfeba6Schristos 		goto done;
15492cfeba6Schristos 	}
15592cfeba6Schristos 
15692cfeba6Schristos 	if (ber) {
15792cfeba6Schristos 		struct timeval tv = {0, mt->mt_network_timeout*1000};
15892cfeba6Schristos 		ber_socket_t s;
15992cfeba6Schristos 		if (!( LDAP_BACK_CONN_ISBOUND( msc )
16092cfeba6Schristos 		       || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
16192cfeba6Schristos 			Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
16292cfeba6Schristos 			goto error_unavailable;
16392cfeba6Schristos 		}
16492cfeba6Schristos 		ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
16592cfeba6Schristos 		if (s < 0) {
16692cfeba6Schristos 			Debug( asyncmeta_debug, "msc %p not initialized at %s:%d\n", msc, __FILE__, __LINE__ );
16792cfeba6Schristos 			goto error_unavailable;
16892cfeba6Schristos 		}
16992cfeba6Schristos 
17092cfeba6Schristos 		rc = ldap_int_poll( msc->msc_ld, s, &tv, 1);
17192cfeba6Schristos 		if (rc < 0) {
17292cfeba6Schristos 			Debug( asyncmeta_debug, "msc %p not writable within network timeout %s:%d\n", msc, __FILE__, __LINE__ );
17392cfeba6Schristos 			if ((msc->msc_result_time + META_BACK_RESULT_INTERVAL) < slap_get_time()) {
17492cfeba6Schristos 				rc = LDAP_SERVER_DOWN;
17592cfeba6Schristos 			} else {
17692cfeba6Schristos 				goto error_unavailable;
17792cfeba6Schristos 			}
17892cfeba6Schristos 		} else {
17992cfeba6Schristos 			candidates[ candidate ].sr_msgid = msgid;
18092cfeba6Schristos 			rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_ADD,
18192cfeba6Schristos 							mdn.bv_val, ber, msgid );
18292cfeba6Schristos 			if (rc == msgid)
18392cfeba6Schristos 				rc = LDAP_SUCCESS;
18492cfeba6Schristos 			else
18592cfeba6Schristos 				rc = LDAP_SERVER_DOWN;
18692cfeba6Schristos 			ber = NULL;
18792cfeba6Schristos 		}
18892cfeba6Schristos 
18992cfeba6Schristos 		switch ( rc ) {
19092cfeba6Schristos 		case LDAP_SUCCESS:
19192cfeba6Schristos 			retcode = META_SEARCH_CANDIDATE;
19292cfeba6Schristos 			asyncmeta_set_msc_time(msc);
19392cfeba6Schristos 			goto done;
19492cfeba6Schristos 
19592cfeba6Schristos 		case LDAP_SERVER_DOWN:
19692cfeba6Schristos 			/* do not lock if called from asyncmeta_handle_bind_result. Also do not reset the connection */
19792cfeba6Schristos 			if (do_lock > 0) {
19892cfeba6Schristos 				ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
19992cfeba6Schristos 				asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
20092cfeba6Schristos 				ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
20192cfeba6Schristos 			}
20292cfeba6Schristos 			/* fall though*/
20392cfeba6Schristos 		default:
20492cfeba6Schristos 			Debug( asyncmeta_debug, "msc %p ldap_send_initial_request failed. %s:%d\n", msc, __FILE__, __LINE__ );
20592cfeba6Schristos 			goto error_unavailable;
20692cfeba6Schristos 		}
20792cfeba6Schristos 	}
20892cfeba6Schristos 
20992cfeba6Schristos error_unavailable:
21092cfeba6Schristos 	if (ber)
21192cfeba6Schristos 		ber_free(ber, 1);
21292cfeba6Schristos 	switch (bc->nretries[candidate]) {
21392cfeba6Schristos 	case -1: /* nretries = forever */
21492cfeba6Schristos 		ldap_pvt_thread_yield();
21592cfeba6Schristos 		retcode = META_SEARCH_NEED_BIND;
21692cfeba6Schristos 		break;
21792cfeba6Schristos 	case 0: /* no retries left */
21892cfeba6Schristos 		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
21992cfeba6Schristos 		rs->sr_err = LDAP_UNAVAILABLE;
22092cfeba6Schristos 		rs->sr_text = "Unable to send add request to target";
22192cfeba6Schristos 		retcode = META_SEARCH_ERR;
22292cfeba6Schristos 		break;
22392cfeba6Schristos 	default: /* more retries left - try to rebind and go again */
22492cfeba6Schristos 		retcode = META_SEARCH_NEED_BIND;
22592cfeba6Schristos 		bc->nretries[candidate]--;
22692cfeba6Schristos 		ldap_pvt_thread_yield();
22792cfeba6Schristos 		break;
22892cfeba6Schristos 	}
22992cfeba6Schristos 
23092cfeba6Schristos done:
23192cfeba6Schristos 	(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
23292cfeba6Schristos 
23392cfeba6Schristos 	if ( mdn.bv_val != op->o_req_dn.bv_val ) {
23492cfeba6Schristos 		op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
23592cfeba6Schristos 	}
23692cfeba6Schristos 
23792cfeba6Schristos 	Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_add_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
23892cfeba6Schristos 	return retcode;
23992cfeba6Schristos }
24092cfeba6Schristos 
24192cfeba6Schristos 
24292cfeba6Schristos int
asyncmeta_back_add(Operation * op,SlapReply * rs)24392cfeba6Schristos asyncmeta_back_add( Operation *op, SlapReply *rs )
24492cfeba6Schristos {
24592cfeba6Schristos 	a_metainfo_t	*mi = ( a_metainfo_t * )op->o_bd->be_private;
24692cfeba6Schristos 	a_metatarget_t	*mt;
24792cfeba6Schristos 	a_metaconn_t	*mc;
24892cfeba6Schristos 	int		rc, candidate = -1;
24992cfeba6Schristos 	void *thrctx = op->o_threadctx;
25092cfeba6Schristos 	bm_context_t *bc;
25192cfeba6Schristos 	SlapReply *candidates;
25292cfeba6Schristos 	time_t current_time = slap_get_time();
25392cfeba6Schristos 	int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops;
25492cfeba6Schristos 
25592cfeba6Schristos 	Debug(LDAP_DEBUG_TRACE, "==> asyncmeta_back_add: %s\n",
25692cfeba6Schristos 	      op->o_req_dn.bv_val );
25792cfeba6Schristos 
25892cfeba6Schristos 	if (current_time > op->o_time) {
25992cfeba6Schristos 		Debug(asyncmeta_debug, "==> asyncmeta_back_add[%s]: o_time:[%ld], current time: [%ld]\n",
26092cfeba6Schristos 		      op->o_log_prefix, op->o_time, current_time );
26192cfeba6Schristos 	}
26292cfeba6Schristos 
26392cfeba6Schristos 	asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets, mi );
26492cfeba6Schristos 	if (bc == NULL) {
26592cfeba6Schristos 		rs->sr_err = LDAP_OTHER;
26692cfeba6Schristos 		send_ldap_result(op, rs);
26792cfeba6Schristos 		return rs->sr_err;
26892cfeba6Schristos 	}
26992cfeba6Schristos 
27092cfeba6Schristos 	candidates = bc->candidates;
27192cfeba6Schristos 	mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
27292cfeba6Schristos 	if ( !mc || rs->sr_err != LDAP_SUCCESS) {
27392cfeba6Schristos 		send_ldap_result(op, rs);
27492cfeba6Schristos 		return rs->sr_err;
27592cfeba6Schristos 	}
27692cfeba6Schristos 
27792cfeba6Schristos 	mt = mi->mi_targets[ candidate ];
27892cfeba6Schristos 	bc->timeout = mt->mt_timeout[ SLAP_OP_ADD ];
27992cfeba6Schristos 	bc->retrying = LDAP_BACK_RETRYING;
28092cfeba6Schristos 	bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
28192cfeba6Schristos 	bc->stoptime = op->o_time + bc->timeout;
28292cfeba6Schristos 	bc->bc_active = 1;
28392cfeba6Schristos 
28492cfeba6Schristos 	if (mc->pending_ops >= max_pending_ops) {
28592cfeba6Schristos 		rs->sr_err = LDAP_BUSY;
28692cfeba6Schristos 		rs->sr_text = "Maximum pending ops limit exceeded";
28792cfeba6Schristos 		send_ldap_result(op, rs);
28892cfeba6Schristos 		return rs->sr_err;
28992cfeba6Schristos 	}
29092cfeba6Schristos 
29192cfeba6Schristos 	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
29292cfeba6Schristos 	rc = asyncmeta_add_message_queue(mc, bc);
29392cfeba6Schristos 	mc->mc_conns[candidate].msc_active++;
29492cfeba6Schristos 	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
29592cfeba6Schristos 
29692cfeba6Schristos 	if (rc != LDAP_SUCCESS) {
29792cfeba6Schristos 		rs->sr_err = LDAP_BUSY;
29892cfeba6Schristos 		rs->sr_text = "Maximum pending ops limit exceeded";
29992cfeba6Schristos 		send_ldap_result(op, rs);
30092cfeba6Schristos 		ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
30192cfeba6Schristos 		mc->mc_conns[candidate].msc_active--;
30292cfeba6Schristos 		ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
30392cfeba6Schristos 		goto finish;
30492cfeba6Schristos 	}
30592cfeba6Schristos 
30692cfeba6Schristos retry:
30792cfeba6Schristos 	current_time = slap_get_time();
30892cfeba6Schristos 	if (bc->timeout && bc->stoptime < current_time) {
30992cfeba6Schristos 		int		timeout_err;
31092cfeba6Schristos 		timeout_err = op->o_protocol >= LDAP_VERSION3 ?
31192cfeba6Schristos 			LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
31292cfeba6Schristos 		rs->sr_err = timeout_err;
31392cfeba6Schristos 		rs->sr_text = "Operation timed out before it was sent to target";
31492cfeba6Schristos 		asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
31592cfeba6Schristos 		goto finish;
31692cfeba6Schristos 	}
31792cfeba6Schristos 
31892cfeba6Schristos 	rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate);
31992cfeba6Schristos 	switch (rc)
32092cfeba6Schristos 	{
32192cfeba6Schristos 	case META_SEARCH_CANDIDATE:
32292cfeba6Schristos 		/* target is already bound, just send the request */
32392cfeba6Schristos 		Debug(LDAP_DEBUG_TRACE , "%s asyncmeta_back_add:  "
32492cfeba6Schristos 		       "cnd=\"%d\"\n", op->o_log_prefix, candidate );
32592cfeba6Schristos 
32692cfeba6Schristos 		rc = asyncmeta_back_add_start( op, rs, mc, bc, candidate, 1);
32792cfeba6Schristos 		if (rc == META_SEARCH_ERR) {
32892cfeba6Schristos 			asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
32992cfeba6Schristos 			goto finish;
33092cfeba6Schristos 
33192cfeba6Schristos 		} else if (rc == META_SEARCH_NEED_BIND) {
33292cfeba6Schristos 			goto retry;
33392cfeba6Schristos 		}
33492cfeba6Schristos 		break;
33592cfeba6Schristos 	case META_SEARCH_NOT_CANDIDATE:
33692cfeba6Schristos 		Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: NOT_CANDIDATE "
33792cfeba6Schristos 		       "cnd=\"%d\"\n", op->o_log_prefix, candidate );
33892cfeba6Schristos 		asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
33992cfeba6Schristos 		goto finish;
34092cfeba6Schristos 
34192cfeba6Schristos 	case META_SEARCH_NEED_BIND:
34292cfeba6Schristos 	case META_SEARCH_BINDING:
34392cfeba6Schristos 		Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: BINDING "
34492cfeba6Schristos 		       "cnd=\"%d\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
34592cfeba6Schristos 		/* add the context to the message queue but do not send the request
34692cfeba6Schristos 		   the receiver must send this when we are done binding */
34792cfeba6Schristos 		break;
34892cfeba6Schristos 
34992cfeba6Schristos 	case META_SEARCH_ERR:
35092cfeba6Schristos 		Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_add: ERR "
35192cfeba6Schristos 		       "cnd=\"%d\"\n", op->o_log_prefix, candidate );
35292cfeba6Schristos 		asyncmeta_error_cleanup(op, rs, bc, mc, candidate);
35392cfeba6Schristos 		goto finish;
35492cfeba6Schristos 	default:
35592cfeba6Schristos 		assert( 0 );
35692cfeba6Schristos 		break;
35792cfeba6Schristos 	}
35892cfeba6Schristos 
35992cfeba6Schristos 	ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
36092cfeba6Schristos 	mc->mc_conns[candidate].msc_active--;
36192cfeba6Schristos 	asyncmeta_start_one_listener(mc, candidates, bc, candidate);
36292cfeba6Schristos 	bc->bc_active--;
36392cfeba6Schristos 	ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
36492cfeba6Schristos 	rs->sr_err = SLAPD_ASYNCOP;
36592cfeba6Schristos finish:
36692cfeba6Schristos 	return rs->sr_err;
36792cfeba6Schristos }
368