andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 4 months ago
Clone
dc8c34
From 8436befeeb9f1d62cf1a48329e9933387d89e394 Mon Sep 17 00:00:00 2001
dc8c34
From: Noriko Hosoi <nhosoi@redhat.com>
dc8c34
Date: Thu, 20 Feb 2014 14:29:16 -0800
dc8c34
Subject: [PATCH 165/225] Ticket #47642 - Windows Sync group issues
dc8c34
dc8c34
Bug Description: When an entry is moved on AD, and the entry is
dc8c34
a member of a group, the value of the member in the group is
dc8c34
automatically updated.  But Windows Sync Control request only
dc8c34
returns the renamed entry; it does not return the group having
dc8c34
the member in it even though the value is updated.  This is
dc8c34
because an AD group stores DNT (Distinguish Name Tag -- ID in
dc8c34
integer) instead of the dn itself.  Since the rename operation
dc8c34
does not change DNT, the group entry on AD has no change, either.
dc8c34
dc8c34
On the DS side, the group entry stores the full DN which needs
dc8c34
to be adjusted to the renamed DN to complete the synchronization
dc8c34
with AD.
dc8c34
dc8c34
Fix Description: Once rename operation is received from AD,
dc8c34
windows_update_local_entry searches groups having a member value
dc8c34
matches the pre-renamed dn on DS, and replaces the old dn with the
dc8c34
renamed one.
dc8c34
dc8c34
Thanks to tbordaz@redhat.com for pointing out the possibility of
dc8c34
NULL dereference.  The problem is fixed, as well.
dc8c34
dc8c34
Thanks to rmeggins@redhat.com for suggesting to escape the search
dc8c34
filter value.  It was added.
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/47642
dc8c34
(cherry picked from commit 98ddd817e26f236adebd80270ec71d7ec372c20e)
dc8c34
(cherry picked from commit 86515d1b18a96b9d7e6143f870b343030a7af5a7)
dc8c34
(cherry picked from commit ab4893cb851533d89e1b02c91972255a48776ce4)
dc8c34
(cherry picked from commit 5324aeca04c8fd0dd3787565815e92bfad1eb3d4)
dc8c34
---
dc8c34
 .../plugins/replication/windows_protocol_util.c    | 117 +++++++++++++++++++--
dc8c34
 1 file changed, 111 insertions(+), 6 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c b/ldap/servers/plugins/replication/windows_protocol_util.c
dc8c34
index 93246ec..bac6573 100644
dc8c34
--- a/ldap/servers/plugins/replication/windows_protocol_util.c
dc8c34
+++ b/ldap/servers/plugins/replication/windows_protocol_util.c
dc8c34
@@ -3871,6 +3871,7 @@ map_entry_dn_inbound_ext(Slapi_Entry *e, Slapi_DN **dn, const Repl_Agmt *ra, int
dc8c34
 		} else 
dc8c34
 		{
dc8c34
 			/* Error, no username */
dc8c34
+			retval = ENTRY_NOTFOUND;
dc8c34
 		}
dc8c34
 	}
dc8c34
 	if (new_dn) 
dc8c34
@@ -4689,7 +4690,7 @@ windows_update_remote_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry
dc8c34
 static int
dc8c34
 windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,Slapi_Entry *local_entry)
dc8c34
 {
dc8c34
-    Slapi_Mods smods = {0};
dc8c34
+	Slapi_Mods smods;
dc8c34
 	int retval = 0;
dc8c34
 	Slapi_PBlock *pb = NULL;
dc8c34
 	int do_modify = 0;
dc8c34
@@ -4701,14 +4702,24 @@ windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,
dc8c34
 	Slapi_DN *mapped_sdn = NULL;
dc8c34
 	Slapi_RDN rdn = {0};
dc8c34
 	Slapi_Entry *orig_local_entry = NULL;
dc8c34
+	const Slapi_DN *orig_local_sdn = NULL;
dc8c34
+
dc8c34
+	/* Variables for updating local groups */
dc8c34
+	Slapi_Entry **entries = NULL;
dc8c34
+	char *filter_string = NULL;
dc8c34
+	const Slapi_DN *local_subtree = NULL;
dc8c34
+	const Slapi_DN *local_subtree_sdn = NULL;
dc8c34
+	char *attrs[3];
dc8c34
+	/* Variables for updating local groups */
dc8c34
 
dc8c34
+	slapi_mods_init(&smods, 0);
dc8c34
 	windows_is_local_entry_user_or_group(local_entry, &is_user, &is_group);
dc8c34
 
dc8c34
 	/* Get the mapped DN.  We don't want to locate the existing entry by
dc8c34
 	 * guid or username.  We want to get the mapped DN just as we would 
dc8c34
 	 * if we were creating a new entry. */
dc8c34
 	retval = map_entry_dn_inbound_ext(remote_entry, &mapped_sdn, prp->agmt, 0 /* use_guid */, 0 /* use_username */);
dc8c34
-	if (retval != 0) {
dc8c34
+	if (retval || (NULL == mapped_sdn)) {
dc8c34
 		slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
 				"unable to map remote entry to local DN\n");
dc8c34
 		return retval;
dc8c34
@@ -4730,8 +4741,10 @@ windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,
dc8c34
 										 &newsuperior, 0 /* to_windows */);
dc8c34
 
dc8c34
 	if (newsuperior || newrdn) {
dc8c34
+		char *escaped_filter_val;
dc8c34
+		const char *ptr;
dc8c34
 		/* remote parent is different from the local parent */
dc8c34
-		Slapi_PBlock *pb = slapi_pblock_new ();
dc8c34
+		pb = slapi_pblock_new ();
dc8c34
 
dc8c34
 		if (NULL == newrdn) {
dc8c34
 			newdn = slapi_entry_get_dn_const(local_entry);
dc8c34
@@ -4778,10 +4791,102 @@ windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,
dc8c34
 			orig_local_entry = NULL;
dc8c34
 			goto bail;
dc8c34
 		}
dc8c34
-	}
dc8c34
-
dc8c34
 
dc8c34
-	slapi_mods_init (&smods, 0);
dc8c34
+		/* WinSync control req does not return the member updates 
dc8c34
+		 * in the groups caused by moving member entries.
dc8c34
+		 * We need to update the local groups manually... */
dc8c34
+		local_subtree = agmt_get_replarea(prp->agmt); 
dc8c34
+		local_subtree_sdn = local_subtree;
dc8c34
+		orig_local_sdn = slapi_entry_get_sdn_const(orig_local_entry);
dc8c34
+		escaped_filter_val = slapi_ch_malloc(slapi_sdn_get_ndn_len(orig_local_sdn) * 3 + 1);
dc8c34
+		ptr = escape_filter_value((char *)slapi_sdn_get_ndn(orig_local_sdn),
dc8c34
+		                          slapi_sdn_get_ndn_len(orig_local_sdn), escaped_filter_val);
dc8c34
+		/* Search entries which have pre-renamed members */
dc8c34
+		filter_string = PR_smprintf("(&(objectclass=ntGroup)(|(member=%s)(uniquemember=%s)))", 
dc8c34
+		                            ptr, ptr);
dc8c34
+		slapi_ch_free_string(&escaped_filter_val);
dc8c34
+		attrs[0] = "member";
dc8c34
+		attrs[1] = "uniquemember";
dc8c34
+		attrs[2] = NULL;
dc8c34
+		pb = slapi_pblock_new ();
dc8c34
+		slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(local_subtree_sdn), 
dc8c34
+		                             LDAP_SCOPE_SUBTREE, filter_string, attrs, 0, NULL, NULL,
dc8c34
+		                             repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
dc8c34
+		slapi_search_internal_pb(pb);
dc8c34
+		slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &retval);
dc8c34
+		if (LDAP_SUCCESS == retval) {
dc8c34
+			Slapi_Entry **ep;
dc8c34
+			const char *prev_member = slapi_sdn_get_ndn(orig_local_sdn);
dc8c34
+			const char *new_member = slapi_sdn_get_ndn(mapped_sdn);
dc8c34
+			size_t prev_member_len = slapi_sdn_get_ndn_len(orig_local_sdn);
dc8c34
+			size_t new_member_len = strlen(new_member);
dc8c34
+			slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
dc8c34
+			for (ep = entries; ep && *ep; ep++) {
dc8c34
+				/* there are group entries whose member matches the renamed entry. */
dc8c34
+				Slapi_PBlock *mod_pb = NULL;
dc8c34
+				Slapi_Attr *mattr = NULL;
dc8c34
+				Slapi_Attr *umattr = NULL;
dc8c34
+				char *type = NULL;
dc8c34
+				slapi_entry_attr_find(*ep, "member", &mattr);
dc8c34
+				slapi_entry_attr_find(*ep, "uniquemember", &umattr);
dc8c34
+				if (mattr) {
dc8c34
+					if (umattr) {
dc8c34
+						/* This entry has both member and uniquemember ... */
dc8c34
+						Slapi_Value *v = NULL;
dc8c34
+						int i = 0;
dc8c34
+						for (i = slapi_attr_first_value(mattr, &v);
dc8c34
+					 		 v && (i != -1);
dc8c34
+					 		i = slapi_attr_next_value(mattr, i, &v)) {
dc8c34
+							const char *s = slapi_value_get_string(v);
dc8c34
+							if (NULL == s) {
dc8c34
+								continue;
dc8c34
+							}
dc8c34
+							if (0 == strcasecmp(s, prev_member)) {
dc8c34
+								type = "member";
dc8c34
+								break;
dc8c34
+							}
dc8c34
+						}
dc8c34
+						if (!type) {
dc8c34
+							type = "uniquemember";
dc8c34
+						}
dc8c34
+					} else {
dc8c34
+						type = "member";
dc8c34
+					}
dc8c34
+				} else {
dc8c34
+					if (umattr) {
dc8c34
+						type = "uniquemember";
dc8c34
+					}
dc8c34
+				}
dc8c34
+				if (type) {
dc8c34
+					mod_pb = slapi_pblock_new();
dc8c34
+					slapi_mods_add(&smods, LDAP_MOD_DELETE, type, prev_member_len, prev_member);
dc8c34
+					slapi_mods_add(&smods, LDAP_MOD_ADD, type, new_member_len, new_member);
dc8c34
+					slapi_modify_internal_set_pb_ext(mod_pb, slapi_entry_get_sdn(*ep),
dc8c34
+					                                 slapi_mods_get_ldapmods_byref(&smods), NULL, NULL,
dc8c34
+					                                 repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
dc8c34
+					                                 0);
dc8c34
+					slapi_modify_internal_pb(mod_pb);
dc8c34
+					slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &retval);
dc8c34
+					if (retval) {
dc8c34
+						slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
dc8c34
+						                "windows_update_local_entry: "
dc8c34
+						                "failed to modify entry %s replacing %s with %s "
dc8c34
+						                "- error %d:%s\n",
dc8c34
+						                slapi_entry_get_dn(*ep), prev_member, new_member,
dc8c34
+						                retval, ldap_err2string(retval));
dc8c34
+					}
dc8c34
+					slapi_pblock_destroy(mod_pb);
dc8c34
+					slapi_mods_done(&smods);
dc8c34
+				} /* if (type) */
dc8c34
+			} /* for (ep = entries; ep && *ep; ep++) */
dc8c34
+		} /* if (LDAP_SUCCESS == retval) - searching with "(|(member=..)(uniquemember=..)) */
dc8c34
+		slapi_free_search_results_internal(pb);
dc8c34
+		slapi_pblock_destroy(pb);
dc8c34
+		if (filter_string) {
dc8c34
+			PR_smprintf_free(filter_string);
dc8c34
+		}
dc8c34
+		slapi_sdn_free((Slapi_DN **)&local_subtree);
dc8c34
+	} /* if (newsuperior || newrdn) */
dc8c34
 
dc8c34
 	retval = windows_generate_update_mods(prp,remote_entry,local_entry,0,&smods,&do_modify);
dc8c34
 	/* Now perform the modify if we need to */
dc8c34
-- 
dc8c34
1.8.1.4
dc8c34