From e25cba04af8567b7720287b57f70a7591411475e Mon Sep 17 00:00:00 2001
From: Howard Chu <hyc@openldap.org>
Date: Fri, 21 Mar 2008 02:01:07 +0000
Subject: [PATCH] ITS#5419 OpExtra

---
 servers/slapd/add.c             | 20 ++++++--
 servers/slapd/backend.c         | 90 +++++++++++++++++++++++++++------
 servers/slapd/slap.h            | 17 +++++++
 servers/slapd/slapi/slapi_ops.c | 16 ++++--
 4 files changed, 117 insertions(+), 26 deletions(-)

diff --git a/servers/slapd/add.c b/servers/slapd/add.c
index aed74d39a2..2561152d0b 100644
--- a/servers/slapd/add.c
+++ b/servers/slapd/add.c
@@ -48,6 +48,7 @@ do_add( Operation *op, SlapReply *rs )
 	size_t		textlen = sizeof( textbuf );
 	int		rc = 0;
 	int		freevals = 1;
+	OpExtraDB oex;
 
 	Debug( LDAP_DEBUG_TRACE, "%s do_add\n",
 		op->o_log_prefix, 0, 0 );
@@ -185,8 +186,13 @@ do_add( Operation *op, SlapReply *rs )
 
 	freevals = 0;
 
+	oex.oe.oe_key = (void *)do_add;
+	oex.oe_db = NULL;
+	LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next);
+
 	op->o_bd = frontendDB;
 	rc = frontendDB->be_add( op, rs );
+	LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next);
 
 #ifdef LDAP_X_TXN
 	if ( rc == LDAP_X_TXN_SPECIFY_OKAY ) {
@@ -195,17 +201,15 @@ do_add( Operation *op, SlapReply *rs )
 	} else
 #endif
 	if ( rc == 0 ) {
-		if ( op->ora_e != NULL && op->o_private != NULL ) {
+		if ( op->ora_e != NULL && oex.oe_db != NULL ) {
 			BackendDB	*bd = op->o_bd;
 
-			op->o_bd = (BackendDB *)op->o_private;
-			op->o_private = NULL;
+			op->o_bd = oex.oe_db;
 
 			be_entry_release_w( op, op->ora_e );
 
 			op->ora_e = NULL;
 			op->o_bd = bd;
-			op->o_private = NULL;
 		}
 	}
 
@@ -329,11 +333,17 @@ fe_op_add( Operation *op, SlapReply *rs )
 
 			rc = op->o_bd->be_add( op, rs );
 			if ( rc == LDAP_SUCCESS ) {
+				OpExtra *oex;
 				/* NOTE: be_entry_release_w() is
 				 * called by do_add(), so that global
 				 * overlays on the way back can
 				 * at least read the entry */
-				op->o_private = op->o_bd;
+				LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) {
+					if ( oex->oe_key == (void *)do_add ) {
+						((OpExtraDB *)oex)->oe_db = op->o_bd;
+						break;
+					}
+				}
 			}
 
 		} else {
diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c
index b36b65c3d1..fb92cf6f7f 100644
--- a/servers/slapd/backend.c
+++ b/servers/slapd/backend.c
@@ -585,6 +585,7 @@ backend_db_init(
 	}
 
 	be->bd_info = bi;
+	be->bd_orig = be;
 
 	be->be_def_limit = frontendDB->be_def_limit;
 	be->be_dfltaccess = frontendDB->be_dfltaccess;
@@ -1349,8 +1350,17 @@ fe_acl_group(
 	int rc;
 	GroupAssertion *g;
 	Backend *be = op->o_bd;
+	OpExtra		*oex;
 
-	op->o_bd = select_backend( gr_ndn, 0 );
+	LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) {
+		if ( oex->oe_key == (void *)backend_group )
+			break;
+	}
+
+	if ( oex && ((OpExtraDB *)oex)->oe_db )
+		op->o_bd = ((OpExtraDB *)oex)->oe_db;
+	else
+		op->o_bd = select_backend( gr_ndn, 0 );
 
 	for ( g = op->o_groups; g; g = g->ga_next ) {
 		if ( g->ga_be != op->o_bd || g->ga_oc != group_oc ||
@@ -1556,17 +1566,26 @@ backend_group(
 	AttributeDescription *group_at )
 {
 	int			rc;
-	BackendDB		*be_orig;
+	BackendDB *be_orig;
+	OpExtraDB	oex;
 
 	if ( op->o_abandon ) {
 		return SLAPD_ABANDON;
 	}
 
+	if ( op->o_bd && SLAP_ISOVERLAY( op->o_bd ))
+		oex.oe_db = op->o_bd->bd_orig;
+	else
+		oex.oe_db = op->o_bd;
+	oex.oe.oe_key = (void *)backend_group;
+	LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next);
+
 	be_orig = op->o_bd;
 	op->o_bd = frontendDB;
 	rc = frontendDB->be_group( op, target, gr_ndn,
 		op_ndn, group_oc, group_at );
 	op->o_bd = be_orig;
+	LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next);
 
 	return rc;
 }
@@ -1586,8 +1605,17 @@ fe_acl_attribute(
 	int			freeattr = 0, i, j, rc = LDAP_SUCCESS;
 	AccessControlState	acl_state = ACL_STATE_INIT;
 	Backend			*be = op->o_bd;
+	OpExtra		*oex;
+
+	LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) {
+		if ( oex->oe_key == (void *)backend_attribute )
+			break;
+	}
 
-	op->o_bd = select_backend( edn, 0 );
+	if ( oex && ((OpExtraDB *)oex)->oe_db )
+		op->o_bd = ((OpExtraDB *)oex)->oe_db;
+	else
+		op->o_bd = select_backend( edn, 0 );
 
 	if ( target && dn_match( &target->e_nname, edn ) ) {
 		e = target;
@@ -1706,13 +1734,22 @@ backend_attribute(
 	slap_access_t access )
 {
 	int			rc;
-	BackendDB		*be_orig;
+	BackendDB *be_orig;
+	OpExtraDB	oex;
+
+	if ( op->o_bd && SLAP_ISOVERLAY( op->o_bd ))
+		oex.oe_db = op->o_bd->bd_orig;
+	else
+		oex.oe_db = op->o_bd;
+	oex.oe.oe_key = (void *)backend_attribute;
+	LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next);
 
 	be_orig = op->o_bd;
 	op->o_bd = frontendDB;
 	rc = frontendDB->be_attribute( op, target, edn,
 		entry_at, vals, access );
 	op->o_bd = be_orig;
+	LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next);
 
 	return rc;
 }
@@ -1738,7 +1775,12 @@ backend_access(
 	assert( edn != NULL );
 	assert( access > ACL_NONE );
 
-	op->o_bd = select_backend( edn, 0 );
+	if ( op->o_bd ) {
+		if ( SLAP_ISOVERLAY( op->o_bd ))
+			op->o_bd = op->o_bd->bd_orig;
+	} else {
+		op->o_bd = select_backend( edn, 0 );
+	}
 
 	if ( target && dn_match( &target->e_nname, edn ) ) {
 		e = target;
@@ -1831,6 +1873,13 @@ fe_aux_operational(
 {
 	Attribute		**ap;
 	int			rc = LDAP_SUCCESS;
+	BackendDB		*be_orig = op->o_bd;
+	OpExtra		*oex;
+
+	LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) {
+		if ( oex->oe_key == (void *)backend_operational )
+			break;
+	}
 
 	for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next )
 		/* just count them */ ;
@@ -1856,19 +1905,19 @@ fe_aux_operational(
 		ap = &(*ap)->a_next;
 	}
 
-	if ( op->o_bd != NULL ) {
-		BackendDB		*be_orig = op->o_bd;
-
-		/* Let the overlays have a chance at this */
+	/* Let the overlays have a chance at this */
+	if ( oex && ((OpExtraDB *)oex)->oe_db ) {
+		op->o_bd = ((OpExtraDB *)oex)->oe_db;
+	} else {
 		op->o_bd = select_backend( &op->o_req_ndn, 0 );
-		if ( op->o_bd != NULL && !be_match( op->o_bd, frontendDB ) &&
-			( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) &&
-			op->o_bd->be_operational != NULL )
-		{
-			rc = op->o_bd->be_operational( op, rs );
-		}
-		op->o_bd = be_orig;
 	}
+	if ( op->o_bd != NULL && !be_match( op->o_bd, frontendDB ) &&
+		( SLAP_OPATTRS( rs->sr_attr_flags ) || rs->sr_attrs ) &&
+		op->o_bd->be_operational != NULL )
+	{
+		rc = op->o_bd->be_operational( op, rs );
+	}
+	op->o_bd = be_orig;
 
 	return rc;
 }
@@ -1877,6 +1926,14 @@ int backend_operational( Operation *op, SlapReply *rs )
 {
 	int rc;
 	BackendDB *be_orig;
+	OpExtraDB	oex;
+
+	if ( op->o_bd && SLAP_ISOVERLAY( op->o_bd ))
+		oex.oe_db = op->o_bd->bd_orig;
+	else
+		oex.oe_db = op->o_bd;
+	oex.oe.oe_key = (void *)backend_operational;
+	LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next);
 
 	/* Moved this into the frontend so global overlays are called */
 
@@ -1884,6 +1941,7 @@ int backend_operational( Operation *op, SlapReply *rs )
 	op->o_bd = frontendDB;
 	rc = frontendDB->be_operational( op, rs );
 	op->o_bd = be_orig;
+	LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next);
 
 	return rc;
 }
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index 2a086aa560..7aa16a3b44 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -1707,6 +1707,7 @@ struct ConfigOCs;	/* config.h */
 
 struct BackendDB {
 	BackendInfo	*bd_info;	/* pointer to shared backend info */
+	BackendDB *bd_orig;		/* pointer to original backend, for overlays */
 
 	/* fields in this structure (and routines acting on this structure)
 	   should be renamed from be_ to bd_ */
@@ -2466,6 +2467,20 @@ typedef union OpRequest {
 	req_pwdexop_s oq_pwdexop;
 } OpRequest;
 
+/* This is only a header. Actual users should define their own
+ * structs with the oe_next / oe_key fields at the top and
+ * whatever else they need following.
+ */
+typedef struct OpExtra {
+	LDAP_SLIST_ENTRY(OpExtra) oe_next;
+	void *oe_key;
+} OpExtra;
+
+typedef struct OpExtraDB {
+	OpExtra oe;
+	BackendDB *oe_db;
+} OpExtraDB;
+
 struct Operation {
 	Opheader *o_hdr;
 
@@ -2657,7 +2672,9 @@ struct Operation {
 	LDAPControl	**o_ctrls;	 /* controls */
 	struct berval o_csn;
 
+	/* DEPRECATE o_private - use o_extra instead */
 	void	*o_private;	/* anything the backend needs */
+	LDAP_SLIST_HEAD(o_e, OpExtra) o_extra;	/* anything the backend needs */
 
 	LDAP_STAILQ_ENTRY(Operation)	o_next;	/* next operation in list */
 };
diff --git a/servers/slapd/slapi/slapi_ops.c b/servers/slapd/slapi/slapi_ops.c
index 9080f174e5..e7aab5d8d3 100644
--- a/servers/slapd/slapi/slapi_ops.c
+++ b/servers/slapd/slapi/slapi_ops.c
@@ -419,6 +419,8 @@ slapi_add_internal_pb( Slapi_PBlock *pb )
 {
 	SlapReply		*rs;
 	Slapi_Entry		*entry_orig = NULL;
+	OpExtraDB oex;
+	int rc;
 
 	if ( pb == NULL ) {
 		return -1;
@@ -478,16 +480,20 @@ slapi_add_internal_pb( Slapi_PBlock *pb )
 		goto cleanup;
 	}
 
-	if ( slapi_int_func_internal_pb( pb, op_add ) == 0 ) {
-		if ( pb->pb_op->ora_e != NULL && pb->pb_op->o_private != NULL ) {
+	oex.oe.oe_key = (void *)do_add;
+	oex.oe_db = NULL;
+	LDAP_SLIST_INSERT_HEAD(&pb->pb_op->o_extra, &oex.oe, oe_next);
+	rc = slapi_int_func_internal_pb( pb, op_add );
+	LDAP_SLIST_REMOVE(&pb->pb_op->o_extra, &oex.oe, OpExtra, oe_next);
+
+	if ( !rc ) {
+		if ( pb->pb_op->ora_e != NULL && oex.oe_db != NULL ) {
 			BackendDB	*bd = pb->pb_op->o_bd;
 
-			pb->pb_op->o_bd = (BackendDB *)pb->pb_op->o_private;
-			pb->pb_op->o_private = NULL;
+			pb->pb_op->o_bd = oex.oe_db;
 			be_entry_release_w( pb->pb_op, pb->pb_op->ora_e );
 			pb->pb_op->ora_e = NULL;
 			pb->pb_op->o_bd = bd;
-			pb->pb_op->o_private = NULL;
 		}
 	}
 
-- 
GitLab