From 92e217e180fec8ecd71114a990a21568c90c7ef3 Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Sat, 6 Sep 2008 21:23:42 +0000
Subject: [PATCH] ITS#5687

---
 CHANGES                      |   2 +-
 servers/slapd/backglue.c     |  24 +++---
 servers/slapd/overlays/rwm.c | 151 ++++++++++++++++++++---------------
 3 files changed, 101 insertions(+), 76 deletions(-)

diff --git a/CHANGES b/CHANGES
index 32b0fb0879..319a37fa44 100644
--- a/CHANGES
+++ b/CHANGES
@@ -30,7 +30,7 @@ OpenLDAP 2.4.12 Engineering
 	Fixed slapo-memberof internal operations DN (ITS#5622)
 	Fixed slapo-pcache attrset crash (ITS#5665)
 	Fixed slapo-pcache caching with invalid schema (ITS#5680)
-	Fixed slapo-rwm callback cleanup (ITS#5601)
+	Fixed slapo-rwm callback cleanup (ITS#5601,ITS#5687)
 	Fixed slapo-rwm attr mapping and merging (ITS#5624)
 	Fixed slapo-rwm objectClass filtering (ITS#5647)
 	Fixed slapo-unique filter validation (ITS#5581)
diff --git a/servers/slapd/backglue.c b/servers/slapd/backglue.c
index 15ef0380ed..7cd176adcf 100644
--- a/servers/slapd/backglue.c
+++ b/servers/slapd/backglue.c
@@ -435,16 +435,19 @@ glue_op_search ( Operation *op, SlapReply *rs )
 			if (scope0 == LDAP_SCOPE_ONELEVEL && 
 				dn_match(pdn, &ndn))
 			{
+				struct berval mdn, mndn;
 				op->ors_scope = LDAP_SCOPE_BASE;
-				op->o_req_dn = op->o_bd->be_suffix[0];
-				op->o_req_ndn = op->o_bd->be_nsuffix[0];
+				mdn = op->o_req_dn = op->o_bd->be_suffix[0];
+				mndn = op->o_req_ndn = op->o_bd->be_nsuffix[0];
 				rs->sr_err = op->o_bd->be_search(op, rs);
 				if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
 					gs.err = LDAP_SUCCESS;
 				}
 				op->ors_scope = LDAP_SCOPE_ONELEVEL;
-				op->o_req_dn = dn;
-				op->o_req_ndn = ndn;
+				if ( op->o_req_dn.bv_val == mdn.bv_val )
+					op->o_req_dn = dn;
+				if ( op->o_req_ndn.bv_val == mndn.bv_val )
+					op->o_req_ndn = ndn;
 
 			} else if (scope0 == LDAP_SCOPE_SUBTREE &&
 				dn_match(&op->o_bd->be_nsuffix[0], &ndn))
@@ -454,14 +457,17 @@ glue_op_search ( Operation *op, SlapReply *rs )
 			} else if (scope0 == LDAP_SCOPE_SUBTREE &&
 				dnIsSuffix(&op->o_bd->be_nsuffix[0], &ndn))
 			{
-				op->o_req_dn = op->o_bd->be_suffix[0];
-				op->o_req_ndn = op->o_bd->be_nsuffix[0];
+				struct berval mdn, mndn;
+				mdn = op->o_req_dn = op->o_bd->be_suffix[0];
+				mndn = op->o_req_ndn = op->o_bd->be_nsuffix[0];
 				rs->sr_err = glue_sub_search( op, rs, b0, on );
 				if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
 					gs.err = LDAP_SUCCESS;
 				}
-				op->o_req_dn = dn;
-				op->o_req_ndn = ndn;
+				if ( op->o_req_dn.bv_val == mdn.bv_val )
+					op->o_req_dn = dn;
+				if ( op->o_req_ndn.bv_val == mndn.bv_val )
+					op->o_req_ndn = ndn;
 
 			} else if (dnIsSuffix(&ndn, &op->o_bd->be_nsuffix[0])) {
 				rs->sr_err = glue_sub_search( op, rs, b0, on );
@@ -524,8 +530,6 @@ end_of_loop:;
 		op->ors_scope = scope0;
 		op->ors_tlimit = tlimit0;
 		op->o_time = starttime;
-		op->o_req_dn = dn;
-		op->o_req_ndn = ndn;
 
 		break;
 	}
diff --git a/servers/slapd/overlays/rwm.c b/servers/slapd/overlays/rwm.c
index 3e515481ee..300476dac0 100644
--- a/servers/slapd/overlays/rwm.c
+++ b/servers/slapd/overlays/rwm.c
@@ -46,80 +46,97 @@ typedef struct rwm_op_cb {
 	rwm_op_state ros;
 } rwm_op_cb;
 
-static int
-rwm_op_cleanup( Operation *op, SlapReply *rs )
+static void
+rwm_op_rollback( Operation *op, SlapReply *rs, rwm_op_state *ros )
 {
-	slap_callback	*cb = op->o_callback;
-	rwm_op_state *ros = cb->sc_private;
-
-	if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
-		op->o_abandon || rs->sr_err == SLAPD_ABANDON ) {
-
+	if ( !BER_BVISNULL( &ros->ro_dn ) ) {
 		op->o_req_dn = ros->ro_dn;
+	}
+	if ( !BER_BVISNULL( &ros->ro_ndn ) ) {
 		op->o_req_ndn = ros->ro_ndn;
+	}
 
-		if ( !BER_BVISNULL( &ros->r_dn )
-			&& ros->r_dn.bv_val != ros->r_ndn.bv_val )
-		{
-			ch_free( ros->r_dn.bv_val );
-			BER_BVZERO( &ros->r_dn );
-		}
+	if ( !BER_BVISNULL( &ros->r_dn )
+		&& ros->r_dn.bv_val != ros->ro_dn.bv_val )
+	{
+		assert( ros->r_dn.bv_val != ros->r_ndn.bv_val );
+		ch_free( ros->r_dn.bv_val );
+		BER_BVZERO( &ros->r_dn );
+	}
 
-		if ( !BER_BVISNULL( &ros->r_ndn ) ) {
-			ch_free( ros->r_ndn.bv_val );
-			BER_BVZERO( &ros->r_ndn );
-		}
+	if ( !BER_BVISNULL( &ros->r_ndn )
+		&& ros->r_ndn.bv_val != ros->ro_ndn.bv_val )
+	{
+		ch_free( ros->r_ndn.bv_val );
+		BER_BVZERO( &ros->r_ndn );
+	}
 
-		switch( ros->r_tag ) {
-		case LDAP_REQ_COMPARE:
-			if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
-				op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
-			op->orc_ava = ros->orc_ava;
-			break;
-		case LDAP_REQ_MODIFY:
-			slap_mods_free( op->orm_modlist, 1 );
-			op->orm_modlist = ros->orm_modlist;
-			break;
-		case LDAP_REQ_MODRDN:
-			if ( op->orr_newSup != ros->orr_newSup ) {
-				ch_free( op->orr_newSup->bv_val );
-				ch_free( op->orr_nnewSup->bv_val );
-				op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
-				op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
-				op->orr_newSup = ros->orr_newSup;
-				op->orr_nnewSup = ros->orr_nnewSup;
-			}
-			break;
-		case LDAP_REQ_SEARCH:
-			ch_free( ros->mapped_attrs );
-			filter_free_x( op, op->ors_filter );
-			ch_free( op->ors_filterstr.bv_val );
-			op->ors_attrs = ros->ors_attrs;
-			op->ors_filter = ros->ors_filter;
-			op->ors_filterstr = ros->ors_filterstr;
-			break;
-		case LDAP_REQ_EXTENDED:
-			if ( op->ore_reqdata != ros->ore_reqdata ) {
-				ber_bvfree( op->ore_reqdata );
-				op->ore_reqdata = ros->ore_reqdata;
-			}
-			break;
-		case LDAP_REQ_BIND:
-			if ( rs->sr_err == LDAP_SUCCESS ) {
+	BER_BVZERO( &ros->ro_dn );
+	BER_BVZERO( &ros->ro_ndn );
+
+	switch( ros->r_tag ) {
+	case LDAP_REQ_COMPARE:
+		if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
+			op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
+		op->orc_ava = ros->orc_ava;
+		break;
+	case LDAP_REQ_MODIFY:
+		slap_mods_free( op->orm_modlist, 1 );
+		op->orm_modlist = ros->orm_modlist;
+		break;
+	case LDAP_REQ_MODRDN:
+		if ( op->orr_newSup != ros->orr_newSup ) {
+			ch_free( op->orr_newSup->bv_val );
+			ch_free( op->orr_nnewSup->bv_val );
+			op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
+			op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
+			op->orr_newSup = ros->orr_newSup;
+			op->orr_nnewSup = ros->orr_nnewSup;
+		}
+		break;
+	case LDAP_REQ_SEARCH:
+		ch_free( ros->mapped_attrs );
+		filter_free_x( op, op->ors_filter );
+		ch_free( op->ors_filterstr.bv_val );
+		op->ors_attrs = ros->ors_attrs;
+		op->ors_filter = ros->ors_filter;
+		op->ors_filterstr = ros->ors_filterstr;
+		break;
+	case LDAP_REQ_EXTENDED:
+		if ( op->ore_reqdata != ros->ore_reqdata ) {
+			ber_bvfree( op->ore_reqdata );
+			op->ore_reqdata = ros->ore_reqdata;
+		}
+		break;
+	case LDAP_REQ_BIND:
+		if ( rs->sr_err == LDAP_SUCCESS ) {
 #if 0
-				ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
-				/* too late, c_mutex released */
-				fprintf( stderr, "*** DN: \"%s\" => \"%s\"\n",
-					op->o_conn->c_ndn.bv_val,
-					op->o_req_ndn.bv_val );
-				ber_bvreplace( &op->o_conn->c_ndn,
-					&op->o_req_ndn );
-				ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
+			ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
+			/* too late, c_mutex released */
+			fprintf( stderr, "*** DN: \"%s\" => \"%s\"\n",
+				op->o_conn->c_ndn.bv_val,
+				op->o_req_ndn.bv_val );
+			ber_bvreplace( &op->o_conn->c_ndn,
+				&op->o_req_ndn );
+			ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
 #endif
-			}
-			break;
-		default:	break;
 		}
+		break;
+	default:	break;
+	}
+}
+
+static int
+rwm_op_cleanup( Operation *op, SlapReply *rs )
+{
+	slap_callback	*cb = op->o_callback;
+	rwm_op_state *ros = cb->sc_private;
+
+	if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
+		op->o_abandon || rs->sr_err == SLAPD_ABANDON )
+	{
+		rwm_op_rollback( op, rs, ros );
+
 		op->o_callback = op->o_callback->sc_next;
 		op->o_tmpfree( cb, op->o_tmpmemctx );
 	}
@@ -193,11 +210,13 @@ rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
 
 	if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
 		op->o_req_dn = dn;
+		assert( BER_BVISNULL( &ros->r_dn ) );
 		ros->r_dn = dn;
 	} else {
 		op->o_req_dn = ndn;
 	}
 	op->o_req_ndn = ndn;
+	assert( BER_BVISNULL( &ros->r_ndn ) );
 	ros->r_ndn = ndn;
 
 	return LDAP_SUCCESS;
@@ -821,7 +840,9 @@ error_return:;
 		ch_free( fstr.bv_val );
 	}
 
+	rwm_op_rollback( op, rs, &roc->ros );
 	op->oq_search = roc->ros.oq_search;
+	op->o_tmpfree( roc, op->o_tmpmemctx );
 
 	op->o_bd->bd_info = (BackendInfo *)on->on_info;
 	send_ldap_error( op, rs, rc, text );
-- 
GitLab