From d040348237186cbee006816eae6442639c91d2df Mon Sep 17 00:00:00 2001
From: Ludwig Krispenz <lkrispen@redhat.com>
Date: Mon, 2 Jun 2014 14:10:54 +0200
Subject: [PATCH] Ticket 47803 - syncrepl crash if attribute list is non-empty

Bug Description:  if the list of requested attributes in a persistent
			sync repl request was set, the server could
			crash after a modify operation which should
			send an entry

Fix Description:   the reason for the crash was that the list of requested
			attributes was freed when the original search
			operation was completed. In the persit phase this
			list was still accessed.
			To fix it, a copy of the orignal op had to be used
                        and the list of requested attr duplicated and set
			in the copy of the op.
			unfortunately a reference to the original op is
			still needed as the disconnet code sets the abandonned
                        flag to the original op
			To be able to duplicate an operation, some methods to get
			and set operation attributes had to be provided

https://fedorahosted.org/389/ticket/47803

Reviewed by: ?
---
 ldap/servers/plugins/sync/sync.h         |  1 +
 ldap/servers/plugins/sync/sync_persist.c |  8 +++----
 ldap/servers/plugins/sync/sync_util.c    | 16 +++++++++++---
 ldap/servers/slapd/operation.c           | 38 ++++++++++++++++++++++++++++++++
 ldap/servers/slapd/pblock.c              | 12 ++++++++++
 ldap/servers/slapd/slapi-plugin.h        |  7 ++++++
 6 files changed, 74 insertions(+), 8 deletions(-)

diff --git a/ldap/servers/plugins/sync/sync.h b/ldap/servers/plugins/sync/sync.h
index 9168039..9c2d8be 100644
--- a/ldap/servers/plugins/sync/sync.h
+++ b/ldap/servers/plugins/sync/sync.h
@@ -158,6 +158,7 @@ typedef struct sync_queue_node {
  */
 typedef struct sync_request {
 	Slapi_PBlock	*req_pblock;
+	Slapi_Operation	*req_orig_op;
 	PRLock		*req_lock;
 	PRThread	*req_tid;
 	char 		*req_orig_base;
diff --git a/ldap/servers/plugins/sync/sync_persist.c b/ldap/servers/plugins/sync/sync_persist.c
index 4216a87..00f7aef 100644
--- a/ldap/servers/plugins/sync/sync_persist.c
+++ b/ldap/servers/plugins/sync/sync_persist.c
@@ -286,6 +286,7 @@ sync_persist_add (Slapi_PBlock *pb)
 	if ( SYNC_IS_INITIALIZED() && NULL != pb ) {
 		/* Create the new node */
 		req = sync_request_alloc();
+		slapi_pblock_get(pb, SLAPI_OPERATION, &req->req_orig_op); /* neede to access original op */
 		req->req_pblock = sync_pblock_copy(pb);
 		slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET_DN, &base);
 		req->req_orig_base = slapi_ch_strdup(base);
@@ -560,7 +561,7 @@ sync_send_results( void *arg )
 	SyncQueueNode *qnode, *qnodenext;
 	int conn_acq_flag = 0;
 	Slapi_Connection *conn = NULL;
-	Slapi_Operation *op = NULL;
+	Slapi_Operation *op = req->req_orig_op;
 	int rc;
 	PRUint64 connid;
 	int opid;
@@ -568,7 +569,6 @@ sync_send_results( void *arg )
 	slapi_pblock_get(req->req_pblock, SLAPI_CONN_ID, &connid);
 	slapi_pblock_get(req->req_pblock, SLAPI_OPERATION_ID, &opid);
 	slapi_pblock_get(req->req_pblock, SLAPI_CONNECTION, &conn);
-	slapi_pblock_get(req->req_pblock, SLAPI_OPERATION, &op);
 
 	conn_acq_flag = sync_acquire_connection (conn);
 	if (conn_acq_flag) {
@@ -581,9 +581,7 @@ sync_send_results( void *arg )
 
 	while ( (conn_acq_flag == 0) && !req->req_complete && !plugin_closing) {
 		/* Check for an abandoned operation */
-		Slapi_Operation *op;
-		slapi_pblock_get(req->req_pblock, SLAPI_OPERATION, &op);
-		if ( op == NULL || slapi_op_abandoned( req->req_pblock ) ) {
+		if ( op == NULL || slapi_is_operation_abandoned( op ) ) {
 			slapi_log_error(SLAPI_LOG_PLUGIN, "Content Synchronization Search",
 						"conn=%" NSPRIu64 " op=%d Operation no longer active - terminating\n",
 						(long long unsigned int)connid, opid);
diff --git a/ldap/servers/plugins/sync/sync_util.c b/ldap/servers/plugins/sync/sync_util.c
index 5ec5e5d..ef4a3f7 100644
--- a/ldap/servers/plugins/sync/sync_util.c
+++ b/ldap/servers/plugins/sync/sync_util.c
@@ -644,18 +644,21 @@ Slapi_PBlock *
 sync_pblock_copy(Slapi_PBlock *src)
 {
 	Slapi_Operation *operation;
+	Slapi_Operation *operation_new;
 	Slapi_Connection *connection;
 	int *scope;
 	int *deref;
 	int *filter_normalized;
 	char *fstr;
 	char **attrs, **attrs_dup;
+	char **reqattrs, **reqattrs_dup;
 	int *attrsonly;
 	int *isroot;
 	int *sizelimit;
 	int *timelimit;
 	struct slapdplugin *pi;
-
+	ber_int_t msgid;
+        ber_tag_t tag;
 
 	slapi_pblock_get( src, SLAPI_OPERATION, &operation );
 	slapi_pblock_get( src, SLAPI_CONNECTION, &connection );
@@ -664,6 +667,7 @@ sync_pblock_copy(Slapi_PBlock *src)
 	slapi_pblock_get( src, SLAPI_PLUGIN_SYNTAX_FILTER_NORMALIZED, &filter_normalized );
 	slapi_pblock_get( src, SLAPI_SEARCH_STRFILTER, &fstr );
 	slapi_pblock_get( src, SLAPI_SEARCH_ATTRS, &attrs );
+	slapi_pblock_get( src, SLAPI_SEARCH_REQATTRS, &reqattrs );
 	slapi_pblock_get( src, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
 	slapi_pblock_get( src, SLAPI_REQUESTOR_ISROOT, &isroot );
 	slapi_pblock_get( src, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
@@ -671,15 +675,21 @@ sync_pblock_copy(Slapi_PBlock *src)
 	slapi_pblock_get( src, SLAPI_PLUGIN, &pi);
 
 	Slapi_PBlock *dest = slapi_pblock_new();
-
-	slapi_pblock_set( dest, SLAPI_OPERATION, operation );
+	operation_new = slapi_operation_new(0);
+	msgid = slapi_operation_get_msgid(operation);
+	slapi_operation_set_msgid(operation_new, msgid);
+	tag = slapi_operation_get_tag(operation);
+	slapi_operation_set_tag(operation_new, tag);
+	slapi_pblock_set( dest, SLAPI_OPERATION, operation_new );
 	slapi_pblock_set( dest, SLAPI_CONNECTION, connection );
 	slapi_pblock_set( dest, SLAPI_SEARCH_SCOPE, &scope );
 	slapi_pblock_set( dest, SLAPI_SEARCH_DEREF, &deref );
 	slapi_pblock_set( dest, SLAPI_PLUGIN_SYNTAX_FILTER_NORMALIZED, &filter_normalized );
 	slapi_pblock_set( dest, SLAPI_SEARCH_STRFILTER, slapi_ch_strdup(fstr) );
 	attrs_dup = slapi_ch_array_dup(attrs);
+	reqattrs_dup = slapi_ch_array_dup(reqattrs);
 	slapi_pblock_set( dest, SLAPI_SEARCH_ATTRS, attrs_dup );
+	slapi_pblock_set( dest, SLAPI_SEARCH_REQATTRS, reqattrs_dup );
 	slapi_pblock_set( dest, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
 	slapi_pblock_set( dest, SLAPI_REQUESTOR_ISROOT, &isroot );
 	slapi_pblock_set( dest, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
diff --git a/ldap/servers/slapd/operation.c b/ldap/servers/slapd/operation.c
index c82e6be..1b45c3f 100644
--- a/ldap/servers/slapd/operation.c
+++ b/ldap/servers/slapd/operation.c
@@ -52,6 +52,15 @@
 #include "fe.h"
 
 int
+slapi_is_operation_abandoned( Slapi_Operation *op )
+{
+	if (op) {
+		return( op->o_status == SLAPI_OP_STATUS_ABANDONED );
+	}
+	return 0;
+}
+
+int
 slapi_op_abandoned( Slapi_PBlock *pb )
 {
 	int	op_status;
@@ -192,6 +201,11 @@ operation_init(Slapi_Operation *o, int flags)
 
 }
 
+Slapi_Operation *
+slapi_operation_new(int flags)
+{
+	return (operation_new(flags));
+}
 /*
  * Allocate a new Slapi_Operation.
  * The flag parameter indicates whether the the operation is
@@ -427,6 +441,30 @@ struct slapi_operation_parameters *operation_parameters_new()
 	return (slapi_operation_parameters *)slapi_ch_calloc (1, sizeof (slapi_operation_parameters));
 }
 
+ber_tag_t
+slapi_operation_get_tag(Slapi_Operation *op)
+{
+	return op->o_tag;
+}
+
+ber_int_t
+slapi_operation_get_msgid(Slapi_Operation *op)
+{
+	return op->o_msgid;
+}
+
+void
+slapi_operation_set_tag(Slapi_Operation *op, ber_tag_t tag)
+{
+	op->o_tag = tag;
+}
+
+void
+slapi_operation_set_msgid(Slapi_Operation *op, ber_int_t msgid)
+{
+	op->o_msgid = msgid;
+}
+
 LDAPMod **
 copy_mods(LDAPMod **orig_mods)
 {
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
index d3cc55c..ff991ab 100644
--- a/ldap/servers/slapd/pblock.c
+++ b/ldap/servers/slapd/pblock.c
@@ -1463,6 +1463,12 @@ slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
 			(*(char ***)value) = pblock->pb_op->o_params.p.p_search.search_gerattrs;
 		}
 		break;
+	case SLAPI_SEARCH_REQATTRS:
+		if(pblock->pb_op!=NULL)
+		{
+			(*(char ***)value) = pblock->pb_op->o_searchattrs;
+		}
+		break;
 	case SLAPI_SEARCH_ATTRSONLY:
 		if(pblock->pb_op!=NULL)
 		{
@@ -3104,6 +3110,12 @@ slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value )
 			pblock->pb_op->o_params.p.p_search.search_gerattrs = (char **) value;
 		}
 		break;
+	case SLAPI_SEARCH_REQATTRS:
+		if(pblock->pb_op!=NULL)
+		{
+			pblock->pb_op->o_searchattrs = (char **) value;
+		}
+		break;
 	case SLAPI_SEARCH_ATTRSONLY:
 		if(pblock->pb_op!=NULL)
 		{
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index c39d3b3..b83b08a 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -5145,16 +5145,22 @@ Slapi_Value *slapi_valueset_find(const Slapi_Attr *a, const Slapi_ValueSet *vs,
  * operation routines
  */
 int slapi_op_abandoned( Slapi_PBlock *pb );
+int slapi_is_operation_abandoned( Slapi_Operation *op );
 unsigned long slapi_op_get_type(Slapi_Operation * op);
 void slapi_operation_set_flag(Slapi_Operation *op, unsigned long flag);
 void slapi_operation_clear_flag(Slapi_Operation *op, unsigned long flag);
 int slapi_operation_is_flag_set(Slapi_Operation *op, unsigned long flag);
+ber_tag_t slapi_operation_get_tag(Slapi_Operation *op);
+ber_int_t slapi_operation_get_msgid(Slapi_Operation *op);
+void slapi_operation_set_tag(Slapi_Operation *op, ber_tag_t tag);
+void slapi_operation_set_msgid(Slapi_Operation *op, ber_int_t msgid);
 int slapi_op_reserved(Slapi_PBlock *pb);
 void slapi_operation_set_csngen_handler ( Slapi_Operation *op, void *callback );
 void slapi_operation_set_replica_attr_handler ( Slapi_Operation *op, void *callback );
 int slapi_operation_get_replica_attr ( Slapi_PBlock *pb, Slapi_Operation *op, const char *type, void *value );
 char *slapi_op_type_to_string(unsigned long type);
 int slapi_op_internal( Slapi_PBlock *pb );
+Slapi_Operation *slapi_operation_new(int flags);
 
 /*
  * connection routines
@@ -7157,6 +7163,7 @@ typedef struct slapi_plugindesc {
 #define SLAPI_SEARCH_STRFILTER      115
 #define SLAPI_SEARCH_ATTRS          116
 #define SLAPI_SEARCH_GERATTRS       1160
+#define SLAPI_SEARCH_REQATTRS       1161
 #define SLAPI_SEARCH_ATTRSONLY      117
 #define SLAPI_SEARCH_IS_AND         118
 
-- 
1.7.11.7

