From cc79c9e86c3294a405a45b8bf61340015c2e137e Mon Sep 17 00:00:00 2001
From: Howard Chu <hyc@openldap.org>
Date: Fri, 8 May 2020 16:22:44 +0100
Subject: [PATCH] ITS#9227 syncrepl: don't delete non-replicated attrs

---
 servers/slapd/syncrepl.c | 43 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 40 insertions(+), 3 deletions(-)

diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c
index e968e7b09a..c659a32752 100644
--- a/servers/slapd/syncrepl.c
+++ b/servers/slapd/syncrepl.c
@@ -2788,6 +2788,7 @@ static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
  * operational attributes from the entry, and do a regular ModDN.
  */
 typedef struct dninfo {
+	syncinfo_t *si;
 	Entry *new_entry;
 	struct berval dn;
 	struct berval ndn;
@@ -3010,6 +3011,7 @@ syncrepl_entry(
 	op->o_callback = &cb;
 	cb.sc_response = dn_callback;
 	cb.sc_private = &dni;
+	dni.si = si;
 	dni.new_entry = entry;
 	dni.modlist = modlist;
 
@@ -4292,6 +4294,37 @@ void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new,
 	*ml = NULL;
 }
 
+/* shallow copy attrs, excluding non-replicated attrs */
+static Attribute *
+attrs_exdup( Operation *op, dninfo *dni, Attribute *attrs )
+{
+	int i;
+	Attribute *tmp, *anew;
+
+	if ( attrs == NULL ) return NULL;
+
+	/* count attrs */
+	for ( tmp = attrs,i=0; tmp; tmp=tmp->a_next ) i++;
+
+	anew = op->o_tmpalloc( i * sizeof(Attribute), op->o_tmpmemctx );
+	for ( tmp = anew; attrs; attrs=attrs->a_next ) {
+		if ( dni->si->si_anlist && !ad_inlist( attrs->a_desc, dni->si->si_anlist ))
+			continue;
+		if ( dni->si->si_exanlist && ad_inlist( attrs->a_desc, dni->si->si_exanlist ))
+			continue;
+		*tmp = *attrs;
+		tmp->a_next = tmp+1;
+		tmp++;
+	}
+	if ( tmp == anew ) {
+		/* excluded everything */
+		op->o_tmpfree( anew, op->o_tmpmemctx );
+		return NULL;
+	}
+	tmp[-1].a_next = NULL;
+	return anew;
+}
+
 static int
 dn_callback(
 	Operation*	op,
@@ -4414,9 +4447,13 @@ dn_callback(
 					 */
 				}
 
-				syncrepl_diff_entry( op, rs->sr_entry->e_attrs,
-					dni->new_entry->e_attrs, &dni->mods, dni->modlist,
-					is_ctx );
+				{
+					Attribute *old = attrs_exdup( op, dni, rs->sr_entry->e_attrs );
+					syncrepl_diff_entry( op, old,
+						dni->new_entry->e_attrs, &dni->mods, dni->modlist,
+						is_ctx );
+					op->o_tmpfree( old, op->o_tmpmemctx );
+				}
 			}
 		}
 	} else if ( rs->sr_type == REP_RESULT ) {
-- 
GitLab