andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From cb913517504be482dabf168957582ea030f8fc38 Mon Sep 17 00:00:00 2001
dc8c34
From: Noriko Hosoi <nhosoi@redhat.com>
dc8c34
Date: Thu, 20 Feb 2014 14:32:41 -0800
dc8c34
Subject: [PATCH 166/225] Ticket #415 - winsync doesn't sync DN valued
dc8c34
 attributes if DS DN value doesn't exist
dc8c34
dc8c34
Bug description:
dc8c34
2 case were fixed.
dc8c34
1) A group on AD has a member which is not a target of windows
dc8c34
   sync and exists only on AD.  The member value in the group is
dc8c34
   synchronized to DS.  If an operation is executed on AD so that
dc8c34
   the member is replaced with other members which are the target
dc8c34
   of the windows sync, the new member values are not synchronized.
dc8c34
2) If a group on AD and DS have members which are local and are
dc8c34
   not synchronized and the members are removed in the group on
dc8c34
   the other side, the delete operation is synchronized and
dc8c34
   deletes all the members including the local members.
dc8c34
dc8c34
Fix description:
dc8c34
1) In windows_generate_update_mods, even if a sync'ed member value
dc8c34
   in a DS entry is not the target of windows sync and it is does
dc8c34
   not exist on DS, a following modify operation including the member
dc8c34
   value is proceeded by confirming the existence on AD.
dc8c34
2) AD->DS: in windows_map_mods_for_replay
dc8c34
   DS->AD: in windwos_generate_update_mods
dc8c34
   added the code to check if an attribute is completely deleted on
dc8c34
   one side, then the each value on the other side is in the sync
dc8c34
   scope or not.  Put the value to the mod for the delete only if
dc8c34
   the value is in the sync scope.
dc8c34
dc8c34
Reviewed by Rich (Thank you!!)
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/415
dc8c34
(cherry picked from commit 03814dd74df7f1f0d2842c5096c6425609da6f2c)
dc8c34
(cherry picked from commit 8772ea1ac524f1f011d51d0a42c0055f5641e2e6)
dc8c34
(cherry picked from commit 737169e0afd0547b6de0a61081508314d076cc6a)
dc8c34
---
dc8c34
 .../plugins/posix-winsync/posix-group-func.c       |   2 +-
dc8c34
 .../plugins/replication/windows_protocol_util.c    | 442 ++++++++++++++-------
dc8c34
 ldap/servers/slapd/slapi-plugin.h                  |  10 +
dc8c34
 ldap/servers/slapd/valueset.c                      |  23 +-
dc8c34
 4 files changed, 337 insertions(+), 140 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/plugins/posix-winsync/posix-group-func.c b/ldap/servers/plugins/posix-winsync/posix-group-func.c
dc8c34
index 60528f5..6a7aa84 100644
dc8c34
--- a/ldap/servers/plugins/posix-winsync/posix-group-func.c
dc8c34
+++ b/ldap/servers/plugins/posix-winsync/posix-group-func.c
dc8c34
@@ -100,7 +100,7 @@ getEntry(const char *udn, char **attrs)
dc8c34
     }
dc8c34
     else {
dc8c34
         slapi_log_error(SLAPI_LOG_FATAL, POSIX_WINSYNC_PLUGIN_NAME,
dc8c34
-                        "getEntry: error searching for uid: %d", rc);
dc8c34
+                        "getEntry: error searching for uid: %d\n", rc);
dc8c34
     }
dc8c34
 
dc8c34
     return NULL;
dc8c34
diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c b/ldap/servers/plugins/replication/windows_protocol_util.c
dc8c34
index bac6573..811d2fd 100644
dc8c34
--- a/ldap/servers/plugins/replication/windows_protocol_util.c
dc8c34
+++ b/ldap/servers/plugins/replication/windows_protocol_util.c
dc8c34
@@ -409,12 +409,19 @@ map_dn_values(Private_Repl_Protocol *prp,Slapi_ValueSet *original_values, Slapi_
dc8c34
 	int retval = 0;
dc8c34
 	int i = 0;
dc8c34
 
dc8c34
+	if (NULL == mapped_values) {
dc8c34
+		slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
+		                "%s: map_dn_values: arg mapped_values is NULL.\n",
dc8c34
+		                agmt_get_long_name(prp->agmt));
dc8c34
+		return;
dc8c34
+	}
dc8c34
+
dc8c34
 	/* Set the keep raw entry flag to avoid overwriting the existing raw entry. */
dc8c34
 	windows_private_set_keep_raw_entry(prp->agmt, 1);
dc8c34
 
dc8c34
 	/* For each value: */
dc8c34
-    i= slapi_valueset_first_value(original_values,&original_value);
dc8c34
-    while ( i != -1 ) {
dc8c34
+	i= slapi_valueset_first_value(original_values,&original_value);
dc8c34
+	while ( i != -1 ) {
dc8c34
 
dc8c34
 		int is_ours = 0;
dc8c34
 		char *new_dn_string = NULL;
dc8c34
@@ -480,7 +487,7 @@ map_dn_values(Private_Repl_Protocol *prp,Slapi_ValueSet *original_values, Slapi_
dc8c34
 				local_entry = NULL;
dc8c34
 			}
dc8c34
 		} else
dc8c34
-		{
dc8c34
+		{   /* from windows */
dc8c34
 			Slapi_Entry *remote_entry = NULL;
dc8c34
 			Slapi_DN *local_dn = NULL;
dc8c34
 			/* Try to get the remote entry */
dc8c34
@@ -1584,89 +1591,111 @@ windows_replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op
dc8c34
 					slapi_entry_free(ad_entry); /* getting sets windows_private_get_raw_entry */
dc8c34
 				}
dc8c34
 
dc8c34
+			/*
dc8c34
+			 * If the magic objectclass and attributes have been added to the entry
dc8c34
+			 * to make the entry sync-able, add the entry first, then apply the other
dc8c34
+			 * mods
dc8c34
+			 */
dc8c34
+			if (sync_attrs_added(op->p.p_modify.modify_mods, local_entry)) {
dc8c34
+				Slapi_Entry *ad_entry = NULL;
dc8c34
 
dc8c34
-				windows_map_mods_for_replay(prp,op->p.p_modify.modify_mods, &mapped_mods, is_user, &password);
dc8c34
-				if (is_user) {
dc8c34
-					winsync_plugin_call_pre_ad_mod_user_mods_cb(prp->agmt,
dc8c34
-																windows_private_get_raw_entry(prp->agmt),
dc8c34
-																local_dn,
dc8c34
-																local_entry,
dc8c34
-																op->p.p_modify.modify_mods,
dc8c34
-																remote_dn,
dc8c34
-																&mapped_mods);
dc8c34
-				} else if (is_group) {
dc8c34
-					winsync_plugin_call_pre_ad_mod_group_mods_cb(prp->agmt,
dc8c34
-																 windows_private_get_raw_entry(prp->agmt),
dc8c34
-																 local_dn,
dc8c34
-																 local_entry,
dc8c34
-																 op->p.p_modify.modify_mods,
dc8c34
-																 remote_dn,
dc8c34
-																 &mapped_mods);
dc8c34
+				return_value = process_replay_add(prp,local_entry,local_entry,local_dn,remote_dn,is_user,missing_entry,&password);
dc8c34
+				slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
+				                "%s: windows_replay_update: "
dc8c34
+				                "The modify operation added the sync objectclass and attribute, so "
dc8c34
+				                "the entry was added to windows - result [%d]\n",
dc8c34
+				                agmt_get_long_name(prp->agmt), return_value);
dc8c34
+				if (return_value) {
dc8c34
+					break; /* error adding entry - cannot continue */
dc8c34
 				}
dc8c34
+				/* the modify op needs the new remote entry, so retrieve it */
dc8c34
+				windows_get_remote_entry(prp, remote_dn, &ad_entry);
dc8c34
+				slapi_entry_free(ad_entry); /* getting sets windows_private_get_raw_entry */
dc8c34
+			}
dc8c34
 
dc8c34
-				/* Check if a naming attribute is being modified. */
dc8c34
-				if (windows_check_mods_for_rdn_change(prp, op->p.p_modify.modify_mods, local_entry, remote_dn, &newrdn)) {
dc8c34
-					/* Issue MODRDN */
dc8c34
-					slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s: renaming remote entry \"%s\" with new RDN of \"%s\"\n",
dc8c34
-							agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn), newrdn);
dc8c34
-					return_value = windows_conn_send_rename(prp->conn, slapi_sdn_get_dn(remote_dn),
dc8c34
-						newrdn, NULL, 1 /* delete old RDN */,
dc8c34
-						NULL, NULL /* returned controls */);
dc8c34
-					slapi_ch_free_string(&newrdn);
dc8c34
-				}
dc8c34
+			windows_map_mods_for_replay(prp,op->p.p_modify.modify_mods, &mapped_mods, is_user, &password);
dc8c34
+			if (is_user) {
dc8c34
+				winsync_plugin_call_pre_ad_mod_user_mods_cb(prp->agmt,
dc8c34
+				                                            windows_private_get_raw_entry(prp->agmt),
dc8c34
+				                                            local_dn,
dc8c34
+				                                            local_entry,
dc8c34
+				                                            op->p.p_modify.modify_mods,
dc8c34
+				                                            remote_dn,
dc8c34
+				                                            &mapped_mods);
dc8c34
+			} else if (is_group) {
dc8c34
+				winsync_plugin_call_pre_ad_mod_group_mods_cb(prp->agmt,
dc8c34
+				                                            windows_private_get_raw_entry(prp->agmt),
dc8c34
+				                                            local_dn,
dc8c34
+				                                            local_entry,
dc8c34
+				                                            op->p.p_modify.modify_mods,
dc8c34
+				                                            remote_dn,
dc8c34
+				                                            &mapped_mods);
dc8c34
+			}
dc8c34
 
dc8c34
-				/* It's possible that the mapping process results in an empty mod list, in which case we don't bother with the replay */
dc8c34
-				if ( mapped_mods == NULL || *(mapped_mods)== NULL )
dc8c34
-				{
dc8c34
-					return_value = CONN_OPERATION_SUCCESS;
dc8c34
-				} else 
dc8c34
+			/* Check if a naming attribute is being modified. */
dc8c34
+			if (windows_check_mods_for_rdn_change(prp, op->p.p_modify.modify_mods, local_entry, remote_dn, &newrdn)) {
dc8c34
+				/* Issue MODRDN */
dc8c34
+				slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name, "%s: renaming remote entry \"%s\" with new RDN of \"%s\"\n",
dc8c34
+				                agmt_get_long_name(prp->agmt), slapi_sdn_get_dn(remote_dn), newrdn);
dc8c34
+				return_value = windows_conn_send_rename(prp->conn, slapi_sdn_get_dn(remote_dn),
dc8c34
+				                                        newrdn, NULL, 1 /* delete old RDN */,
dc8c34
+				                                        NULL, NULL /* returned controls */);
dc8c34
+				slapi_ch_free_string(&newrdn);
dc8c34
+			}
dc8c34
+
dc8c34
+			/* It's possible that the mapping process results in an empty mod list, in which case we don't bother with the replay */
dc8c34
+			if ((mapped_mods == NULL) || (*mapped_mods == NULL))
dc8c34
+			{
dc8c34
+				return_value = CONN_OPERATION_SUCCESS;
dc8c34
+			} else 
dc8c34
+			{
dc8c34
+				int ldap_op = 0;
dc8c34
+				int ldap_result_code = 0;
dc8c34
+				if (slapi_is_loglevel_set(SLAPI_LOG_REPL))
dc8c34
 				{
dc8c34
-					int ldap_op = 0;
dc8c34
-					int ldap_result_code = 0;
dc8c34
-					if (slapi_is_loglevel_set(SLAPI_LOG_REPL))
dc8c34
+					int i = 0;
dc8c34
+					slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
+					                "dump mods for replay update:\n");
dc8c34
+					for(i=0;mapped_mods[i];i++)
dc8c34
 					{
dc8c34
-						int i = 0;
dc8c34
-						slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,"dump mods for replay update:");
dc8c34
-						for(i=0;mapped_mods[i];i++)
dc8c34
-						{
dc8c34
-							slapi_mod_dump(mapped_mods[i],i);
dc8c34
-						}
dc8c34
-					}
dc8c34
-					return_value = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(remote_dn), mapped_mods, NULL, NULL /* returned controls */);
dc8c34
-					windows_conn_get_error(prp->conn, &ldap_op, &ldap_result_code);
dc8c34
-					if ((return_value != CONN_OPERATION_SUCCESS) && !ldap_result_code) {
dc8c34
-						/* op failed but no ldap error code ??? */
dc8c34
-						ldap_result_code = LDAP_OPERATIONS_ERROR;
dc8c34
-					}
dc8c34
-					if (is_user) {
dc8c34
-						winsync_plugin_call_post_ad_mod_user_mods_cb(prp->agmt,
dc8c34
-																windows_private_get_raw_entry(prp->agmt),
dc8c34
-																local_dn, local_entry,
dc8c34
-																op->p.p_modify.modify_mods,
dc8c34
-																remote_dn, mapped_mods, &ldap_result_code);
dc8c34
-					} else if (is_group) {
dc8c34
-						winsync_plugin_call_post_ad_mod_group_mods_cb(prp->agmt,
dc8c34
-																 windows_private_get_raw_entry(prp->agmt),
dc8c34
-																 local_dn, local_entry,
dc8c34
-																 op->p.p_modify.modify_mods,
dc8c34
-																 remote_dn, mapped_mods, &ldap_result_code);
dc8c34
-					}
dc8c34
-					/* see if plugin reset success/error condition */
dc8c34
-					if ((return_value != CONN_OPERATION_SUCCESS) && !ldap_result_code) {
dc8c34
-						return_value = CONN_OPERATION_SUCCESS;
dc8c34
-						windows_conn_set_error(prp->conn, ldap_result_code);
dc8c34
-					} else if ((return_value == CONN_OPERATION_SUCCESS) && ldap_result_code) {
dc8c34
-						return_value = CONN_OPERATION_FAILED;
dc8c34
-						windows_conn_set_error(prp->conn, ldap_result_code);
dc8c34
+						slapi_mod_dump(mapped_mods[i],i);
dc8c34
 					}
dc8c34
 				}
dc8c34
-				if (mapped_mods)
dc8c34
-				{
dc8c34
-					ldap_mods_free(mapped_mods,1);
dc8c34
-					mapped_mods = NULL;
dc8c34
+				return_value = windows_conn_send_modify(prp->conn, slapi_sdn_get_dn(remote_dn), mapped_mods, NULL, NULL /* returned controls */);
dc8c34
+				windows_conn_get_error(prp->conn, &ldap_op, &ldap_result_code);
dc8c34
+				if ((return_value != CONN_OPERATION_SUCCESS) && !ldap_result_code) {
dc8c34
+					/* op failed but no ldap error code ??? */
dc8c34
+					ldap_result_code = LDAP_OPERATIONS_ERROR;
dc8c34
+				}
dc8c34
+				if (is_user) {
dc8c34
+					winsync_plugin_call_post_ad_mod_user_mods_cb(prp->agmt,
dc8c34
+					                                             windows_private_get_raw_entry(prp->agmt),
dc8c34
+					                                             local_dn, local_entry,
dc8c34
+					                                             op->p.p_modify.modify_mods,
dc8c34
+					                                             remote_dn, mapped_mods, &ldap_result_code);
dc8c34
+				} else if (is_group) {
dc8c34
+					winsync_plugin_call_post_ad_mod_group_mods_cb(prp->agmt,
dc8c34
+					                                             windows_private_get_raw_entry(prp->agmt),
dc8c34
+					                                             local_dn, local_entry,
dc8c34
+					                                             op->p.p_modify.modify_mods,
dc8c34
+					                                             remote_dn, mapped_mods, &ldap_result_code);
dc8c34
 				}
dc8c34
+				/* see if plugin reset success/error condition */
dc8c34
+				if ((return_value != CONN_OPERATION_SUCCESS) && !ldap_result_code) {
dc8c34
+					return_value = CONN_OPERATION_SUCCESS;
dc8c34
+					windows_conn_set_error(prp->conn, ldap_result_code);
dc8c34
+				} else if ((return_value == CONN_OPERATION_SUCCESS) && ldap_result_code) {
dc8c34
+					return_value = CONN_OPERATION_FAILED;
dc8c34
+					windows_conn_set_error(prp->conn, ldap_result_code);
dc8c34
+				}
dc8c34
+			}
dc8c34
+			if (mapped_mods)
dc8c34
+			{
dc8c34
+				ldap_mods_free(mapped_mods,1);
dc8c34
+				mapped_mods = NULL;
dc8c34
 			}
dc8c34
 			break;
dc8c34
+		}
dc8c34
 		case SLAPI_OPERATION_DELETE:
dc8c34
 			if (delete_remote_entry_allowed(local_entry))
dc8c34
 			{
dc8c34
@@ -2569,17 +2598,34 @@ done:
dc8c34
 
dc8c34
 
dc8c34
 static void 
dc8c34
-windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods, LDAPMod ***returned_mods, int is_user, char** password) 
dc8c34
+windows_map_mods_for_replay(Private_Repl_Protocol *prp,
dc8c34
+                            LDAPMod **original_mods,
dc8c34
+                            LDAPMod ***returned_mods,
dc8c34
+                            int is_user,
dc8c34
+                            char** password) 
dc8c34
 {
dc8c34
 	Slapi_Mods smods = {0};
dc8c34
 	Slapi_Mods mapped_smods = {0};
dc8c34
 	LDAPMod *mod = NULL;
dc8c34
-	int is_nt4 = windows_private_get_isnt4(prp->agmt);
dc8c34
+	int is_nt4 = 0;
dc8c34
 	Slapi_Mod *mysmod = NULL;
dc8c34
 	const Slapi_Entry *ad_entry = NULL;
dc8c34
 	Slapi_Entry *ad_entry_copy = NULL;
dc8c34
+	const Slapi_DN *windows_subtree = NULL;
dc8c34
 
dc8c34
 	LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_map_mods_for_replay\n", 0, 0, 0 );
dc8c34
+	if (NULL == prp) {
dc8c34
+		LDAPDebug(LDAP_DEBUG_TRACE,
dc8c34
+		          "<= windows_map_mods_for_replay; NULL protocol; NOOP\n", 0, 0, 0);
dc8c34
+		return;
dc8c34
+	}
dc8c34
+	windows_subtree = windows_private_get_windows_subtree(prp->agmt);
dc8c34
+	if (NULL == windows_subtree) {
dc8c34
+		LDAPDebug(LDAP_DEBUG_TRACE,
dc8c34
+		          "<= windows_map_mods_for_replay; NULL agreement subtree; NOOP\n", 0, 0, 0);
dc8c34
+		return;
dc8c34
+	}
dc8c34
+	is_nt4 = windows_private_get_isnt4(prp->agmt);
dc8c34
 
dc8c34
 	/* Iterate through the original mods, looking each attribute type up in the maps for either user or group */
dc8c34
 
dc8c34
@@ -2667,13 +2713,66 @@ windows_map_mods_for_replay(Private_Repl_Protocol *prp,LDAPMod **original_mods,
dc8c34
 						mapped_values = NULL;
dc8c34
 					} else 
dc8c34
 					{
dc8c34
-						/* this might be a del: mod, in which case there are no values */
dc8c34
-						if (mod->mod_op & LDAP_MOD_DELETE)
dc8c34
+						if (slapi_valueset_isempty(vs) && (mod->mod_op & LDAP_MOD_DELETE))
dc8c34
 						{
dc8c34
-							mysmod = slapi_mod_new();
dc8c34
-							slapi_mod_init(mysmod, 0);
dc8c34
-							slapi_mod_set_operation(mysmod, LDAP_MOD_DELETE|LDAP_MOD_BVALUES);
dc8c34
-							slapi_mod_set_type(mysmod, mapped_type);
dc8c34
+							/* modify - del all, in which case there are no values */
dc8c34
+							Slapi_Attr *attr = NULL;
dc8c34
+
dc8c34
+							/* 
dc8c34
+							 * ad_entry:
dc8c34
+							 * get mapped_type values
dc8c34
+							 * get in-scope values from the values
dc8c34
+							 */
dc8c34
+							slapi_entry_attr_find(ad_entry, mapped_type, &attr);
dc8c34
+							if (attr) {
dc8c34
+								Slapi_ValueSet *thisvs = NULL;
dc8c34
+								Slapi_Value *valp = NULL;
dc8c34
+								Slapi_DN *sdn = slapi_sdn_new();
dc8c34
+								int i;
dc8c34
+								int is_in_subtree = 0;
dc8c34
+								Slapi_Value **myva = NULL;
dc8c34
+
dc8c34
+								slapi_attr_get_valueset(attr, &thisvs); /* thisvs is dup'ed */
dc8c34
+								for (i = slapi_valueset_first_value(thisvs, &valp);
dc8c34
+									(i != -1) && (valp != NULL);
dc8c34
+									i = slapi_valueset_next_value(thisvs, i, &valp)) {
dc8c34
+									/* valp is a pointer to va in thisvs */
dc8c34
+									const char *strval = slapi_value_get_string(valp); /* no dup */
dc8c34
+									if (strval) {
dc8c34
+										slapi_sdn_set_dn_byref(sdn, strval);
dc8c34
+										is_in_subtree = slapi_sdn_scope_test(sdn, windows_subtree,
dc8c34
+										                                     LDAP_SCOPE_SUBTREE);
dc8c34
+										if (is_in_subtree) {
dc8c34
+											/* 
dc8c34
+											 * If delete all on DS, 
dc8c34
+											 * we could delete the values on AD in the scope.
dc8c34
+											 */
dc8c34
+											/* myva is (re)allocated and valp is copied */
dc8c34
+											valuearray_add_value(&myva, valp);
dc8c34
+										}
dc8c34
+									}
dc8c34
+								}
dc8c34
+								if (myva) {
dc8c34
+									Slapi_ValueSet *myvs = NULL;
dc8c34
+									
dc8c34
+									myvs = slapi_valueset_new();
dc8c34
+									valueset_set_valuearray_passin(myvs, myva);
dc8c34
+									mysmod = slapi_mod_new();
dc8c34
+									slapi_mod_init_valueset_byval(mysmod,
dc8c34
+									                LDAP_MOD_DELETE|LDAP_MOD_BVALUES,
dc8c34
+									                mapped_type,
dc8c34
+									                myvs);
dc8c34
+									slapi_valueset_free(myvs);
dc8c34
+								}
dc8c34
+								slapi_sdn_free(&sdn;;
dc8c34
+								slapi_valueset_free(thisvs);
dc8c34
+							} else {
dc8c34
+								/* 
dc8c34
+								 * No corresponsing attribute in AD.  
dc8c34
+								 * There's no need to do anything on AD.
dc8c34
+								 * slapi_mod_set_type(mysmod, mapped_type);
dc8c34
+								 */
dc8c34
+							}
dc8c34
 						}
dc8c34
 					}
dc8c34
 					slapi_mod_done(&smod);
dc8c34
@@ -4236,19 +4335,20 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr
dc8c34
 	int is_group = 0;
dc8c34
 	int rc = 0;
dc8c34
 	int is_nt4 = windows_private_get_isnt4(prp->agmt);
dc8c34
+	const Slapi_DN *local_subtree = NULL;
dc8c34
 	/* Iterate over the attributes on the remote entry, updating the local entry where appropriate */
dc8c34
 	LDAPDebug( LDAP_DEBUG_TRACE, "=> windows_generate_update_mods\n", 0, 0, 0 );
dc8c34
 
dc8c34
 	*do_modify = 0;
dc8c34
 
dc8c34
-        if (!remote_entry || !local_entry) {
dc8c34
-            slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
-                            "%s: windows_generate_update_mods: remote_entry is [%s] local_entry is [%s] "
dc8c34
-                            "cannot generate update mods\n", agmt_get_long_name(prp->agmt),
dc8c34
-                            remote_entry ? slapi_entry_get_dn_const(remote_entry) : "NULL",
dc8c34
-                            local_entry ? slapi_entry_get_dn_const(local_entry) : "NULL");
dc8c34
-            goto bail;
dc8c34
-        }
dc8c34
+	if (!remote_entry || !local_entry) {
dc8c34
+		slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
+		                "%s: windows_generate_update_mods: remote_entry is [%s] local_entry is [%s] "
dc8c34
+		                "cannot generate update mods\n", agmt_get_long_name(prp->agmt),
dc8c34
+		                remote_entry ? slapi_entry_get_dn_const(remote_entry) : "NULL",
dc8c34
+		                local_entry ? slapi_entry_get_dn_const(local_entry) : "NULL");
dc8c34
+		goto bail;
dc8c34
+	}
dc8c34
 
dc8c34
 	if (to_windows)
dc8c34
 	{
dc8c34
@@ -4258,8 +4358,8 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr
dc8c34
 		windows_is_remote_entry_user_or_group(remote_entry,&is_user,&is_group);
dc8c34
 	}
dc8c34
 
dc8c34
-    for (rc = slapi_entry_first_attr(remote_entry, &attr); rc == 0;
dc8c34
-             rc = slapi_entry_next_attr(remote_entry, attr, &attr)) 
dc8c34
+	for (rc = slapi_entry_first_attr(remote_entry, &attr); rc == 0;
dc8c34
+	     rc = slapi_entry_next_attr(remote_entry, attr, &attr)) 
dc8c34
 	{
dc8c34
 		int is_present_local = 0;
dc8c34
 		char *type = NULL;
dc8c34
@@ -4403,15 +4503,17 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr
dc8c34
 			} else {
dc8c34
 				/* A dn-valued attribute : need to take special steps */
dc8c34
 				Slapi_ValueSet *mapped_remote_values = NULL;
dc8c34
+				Slapi_ValueSet *local_values = NULL;
dc8c34
+
dc8c34
+				/* We ignore any DNs that are outside the scope of the agreement (on both sides) */
dc8c34
+				slapi_attr_get_valueset(local_attr,&local_values);
dc8c34
+
dc8c34
 				/* First map all the DNs to that they're in a consistent domain */
dc8c34
 				map_dn_values(prp,vs,&mapped_remote_values, to_windows,0);
dc8c34
 				if (mapped_remote_values) 
dc8c34
 				{
dc8c34
-					Slapi_ValueSet *local_values = NULL;
dc8c34
 					Slapi_ValueSet *restricted_local_values = NULL;
dc8c34
 					/* Now do a compare on the values, generating mods to bring them into consistency (if any) */
dc8c34
-					/* We ignore any DNs that are outside the scope of the agreement (on both sides) */
dc8c34
-					slapi_attr_get_valueset(local_attr,&local_values);
dc8c34
 					if (local_values) 
dc8c34
 					{
dc8c34
 						map_dn_values(prp,local_values,&restricted_local_values,!to_windows,1);
dc8c34
@@ -4423,6 +4525,9 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr
dc8c34
 						}
dc8c34
 						else
dc8c34
 						{
dc8c34
+							windows_generate_dn_value_mods(local_type, local_attr, smods,
dc8c34
+							                               mapped_remote_values,
dc8c34
+							                               local_values,do_modify);
dc8c34
 							slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
 											"windows_generate_update_mods: no restricted local values found for "
dc8c34
 											"local attribute %s in local entry %s for remote attribute "
dc8c34
@@ -4432,9 +4537,9 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr
dc8c34
 											type ? type : "NULL",
dc8c34
 											slapi_entry_get_dn(remote_entry));
dc8c34
 						}
dc8c34
-						slapi_valueset_free(local_values);
dc8c34
-						local_values = NULL;
dc8c34
 					} else {
dc8c34
+						windows_generate_dn_value_mods(local_type, local_attr, smods,
dc8c34
+						                               mapped_remote_values, NULL, do_modify);
dc8c34
 						slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
 										"windows_generate_update_mods: no local values found for "
dc8c34
 										"local attribute %s in local entry %s for remote attribute "
dc8c34
@@ -4447,18 +4552,25 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr
dc8c34
 					slapi_valueset_free(mapped_remote_values);
dc8c34
 					mapped_remote_values = NULL;
dc8c34
 				} else {
dc8c34
-					slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
-									"windows_generate_update_mods: could not map the values in "
dc8c34
-									"local attribute %s in local entry %s for remote attribute "
dc8c34
-									"%s in remote entry %s\n",
dc8c34
-									local_type,
dc8c34
-									slapi_entry_get_dn(local_entry),
dc8c34
-									type ? type : "NULL",
dc8c34
-									slapi_entry_get_dn(remote_entry));
dc8c34
+					if (local_values) {
dc8c34
+						windows_generate_dn_value_mods(local_type, local_attr, smods,
dc8c34
+						                               NULL, local_values, do_modify);
dc8c34
+					} else {
dc8c34
+						slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
+						                "windows_generate_update_mods: could not map the values in "
dc8c34
+						                "local attribute %s in local entry %s for remote attribute "
dc8c34
+						                "%s in remote entry %s\n",
dc8c34
+						                local_type,
dc8c34
+						                slapi_entry_get_dn(local_entry),
dc8c34
+						                type ? type : "NULL",
dc8c34
+						                slapi_entry_get_dn(remote_entry));
dc8c34
+					}
dc8c34
 				}
dc8c34
+				slapi_valueset_free(local_values);
dc8c34
+				local_values = NULL;
dc8c34
 			}
dc8c34
 		} else
dc8c34
-		{
dc8c34
+		{    /* !is_present_local || is_guid */
dc8c34
 			if (!is_present_local)
dc8c34
 			{
dc8c34
 				slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
@@ -4555,37 +4667,91 @@ windows_generate_update_mods(Private_Repl_Protocol *prp,Slapi_Entry *remote_entr
dc8c34
 		slapi_ch_free_string(&local_type);
dc8c34
 	}
dc8c34
 
dc8c34
-        /* Check if any attributes were deleted from the remote entry */
dc8c34
-        entry_first_deleted_attribute(remote_entry, &del_attr);
dc8c34
-        while (del_attr != NULL) {
dc8c34
-                Slapi_Attr *local_attr = NULL;
dc8c34
-                char *type = NULL;
dc8c34
-                char *local_type = NULL;
dc8c34
-                int mapdn = 0;
dc8c34
+	/* Check if any attributes were deleted from the remote entry */
dc8c34
+	entry_first_deleted_attribute(remote_entry, &del_attr);
dc8c34
+	local_subtree = windows_private_get_directory_subtree(prp->agmt);
dc8c34
+	while (del_attr != NULL) {
dc8c34
+		Slapi_Attr *local_attr = NULL;
dc8c34
+		char *type = NULL;
dc8c34
+		char *local_type = NULL;
dc8c34
+		int mapdn = 0;
dc8c34
 
dc8c34
-                /* Map remote type to local type */
dc8c34
+		/* Map remote type to local type */
dc8c34
 		slapi_attr_get_type(del_attr, &type);
dc8c34
-                if ( is_straight_mapped_attr(type,is_user,is_nt4) ) {
dc8c34
-                        local_type = slapi_ch_strdup(type);
dc8c34
-                } else {
dc8c34
-                        windows_map_attr_name(type , to_windows, is_user, 0 /* not create */, &local_type, &mapdn);
dc8c34
-                }
dc8c34
-
dc8c34
-                /* Check if this attr exists in the local entry */
dc8c34
-                if (local_type) {
dc8c34
-                        slapi_entry_attr_find(local_entry, local_type, &local_attr);
dc8c34
-                        if (local_attr) {
dc8c34
-                                slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
-                                        "windows_generate_update_mods: deleting %s attribute from local entry\n", local_type);
dc8c34
-                                /* Delete this attr from the local entry */
dc8c34
-                                slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, local_type, NULL);
dc8c34
+		if ( is_straight_mapped_attr(type,is_user,is_nt4) ) {
dc8c34
+			local_type = slapi_ch_strdup(type);
dc8c34
+		} else {
dc8c34
+			windows_map_attr_name(type , to_windows, is_user, 0 /* not create */, &local_type, &mapdn);
dc8c34
+		}
dc8c34
+
dc8c34
+		/* Check if this attr exists in the local entry */
dc8c34
+		if (local_type) {
dc8c34
+			slapi_entry_attr_find(local_entry, local_type, &local_attr);
dc8c34
+			if (local_attr) {
dc8c34
+				Slapi_Mod *mysmod = NULL;
dc8c34
+				slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
dc8c34
+					"windows_generate_update_mods: deleting %s attribute from local entry\n", local_type);
dc8c34
+				/* Delete this attr from the local entry */
dc8c34
+				/* if type is dn and the dn is out of winsync scope, keep them.
dc8c34
+				 * othewise delete all attr. */
dc8c34
+				if (mapdn) {
dc8c34
+					Slapi_ValueSet *vs = NULL;
dc8c34
+					Slapi_Value *valp = NULL;
dc8c34
+					Slapi_DN *sdn = slapi_sdn_new();
dc8c34
+					int i = 0;
dc8c34
+					int is_in_subtree = 0;
dc8c34
+					Slapi_Value **myva = NULL;
dc8c34
+
dc8c34
+					slapi_attr_get_valueset(local_attr, &vs); /* thisvs is dup'ed */
dc8c34
+					for (i = slapi_valueset_first_value(vs, &valp);
dc8c34
+					     (i != -1) && (valp != NULL);
dc8c34
+					     i = slapi_valueset_next_value(vs, i, &valp)) {
dc8c34
+						/* valp is a pointer to va in vs */
dc8c34
+						const char *strval = slapi_value_get_string(valp); /* no dup */
dc8c34
+						if (strval) {
dc8c34
+							slapi_sdn_set_dn_byref(sdn, strval);
dc8c34
+							is_in_subtree = slapi_sdn_scope_test(sdn, local_subtree,
dc8c34
+							                                     LDAP_SCOPE_SUBTREE);
dc8c34
+							if (is_in_subtree) {
dc8c34
+								/* 
dc8c34
+								 * If delete all on AD, 
dc8c34
+								 * we could delete the values on DS in the scope.
dc8c34
+								 */
dc8c34
+								/* myva is (re)allocated and valp is copied */
dc8c34
+								valuearray_add_value(&myva, valp);
dc8c34
+							}
dc8c34
+						}
dc8c34
+					}
dc8c34
+					if (myva) {
dc8c34
+						Slapi_ValueSet *myvs = NULL;
dc8c34
+
dc8c34
+						myvs = slapi_valueset_new();
dc8c34
+						valueset_set_valuearray_passin(myvs, myva);
dc8c34
+						mysmod = slapi_mod_new();
dc8c34
+						slapi_mod_init_valueset_byval(mysmod,
dc8c34
+						                              LDAP_MOD_DELETE|LDAP_MOD_BVALUES,
dc8c34
+						                              local_type,
dc8c34
+						                              myvs);
dc8c34
+						slapi_valueset_free(myvs);
dc8c34
+					}
dc8c34
+					slapi_sdn_free(&sdn;;
dc8c34
+					slapi_valueset_free(vs);
dc8c34
+					if (mysmod) {
dc8c34
+						slapi_mods_add_ldapmod(smods, slapi_mod_get_ldapmod_passout(mysmod));
dc8c34
+					}
dc8c34
+					if (mysmod) {
dc8c34
+						slapi_mod_free(&mysmod);
dc8c34
+					}
dc8c34
+				} else {
dc8c34
+					slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, local_type, NULL);
dc8c34
+				}
dc8c34
 				*do_modify = 1;
dc8c34
-                        }
dc8c34
-                }
dc8c34
+			}
dc8c34
+		}
dc8c34
 
dc8c34
-                entry_next_deleted_attribute(remote_entry, &del_attr);
dc8c34
+		entry_next_deleted_attribute(remote_entry, &del_attr);
dc8c34
 		slapi_ch_free_string(&local_type);
dc8c34
-        }
dc8c34
+	}
dc8c34
 
dc8c34
 	if (to_windows) {
dc8c34
 	    if (is_user) {
dc8c34
@@ -4690,7 +4856,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;
dc8c34
+	Slapi_Mods smods = {0};
dc8c34
 	int retval = 0;
dc8c34
 	Slapi_PBlock *pb = NULL;
dc8c34
 	int do_modify = 0;
dc8c34
@@ -4736,9 +4902,9 @@ windows_update_local_entry(Private_Repl_Protocol *prp,Slapi_Entry *remote_entry,
dc8c34
 
dc8c34
 	/* compare the parents */
dc8c34
 	retval = windows_get_superior_change(prp,
dc8c34
-										 slapi_entry_get_sdn(local_entry),
dc8c34
-										 mapped_sdn,
dc8c34
-										 &newsuperior, 0 /* to_windows */);
dc8c34
+	                                     slapi_entry_get_sdn(local_entry),
dc8c34
+	                                     mapped_sdn,
dc8c34
+	                                     &newsuperior, 0 /* to_windows */);
dc8c34
 
dc8c34
 	if (newsuperior || newrdn) {
dc8c34
 		char *escaped_filter_val;
dc8c34
@@ -5439,7 +5605,7 @@ retry:
dc8c34
 
dc8c34
 void 
dc8c34
 windows_dirsync_inc_run(Private_Repl_Protocol *prp)
dc8c34
-	{ 
dc8c34
+{ 
dc8c34
 	
dc8c34
 	int rc = 0;
dc8c34
 	int done = 0;
dc8c34
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
dc8c34
index a23b641..e5fe904 100644
dc8c34
--- a/ldap/servers/slapd/slapi-plugin.h
dc8c34
+++ b/ldap/servers/slapd/slapi-plugin.h
dc8c34
@@ -7001,6 +7001,16 @@ int slapi_set_plugin_default_config(const char *type, Slapi_Value *value);
dc8c34
  */
dc8c34
 int slapi_get_plugin_default_config(char *type, Slapi_ValueSet **valueset);
dc8c34
 
dc8c34
+/**
dc8c34
+ * Checks if  a \c Slapi_ValueSet structure has values
dc8c34
+ *
dc8c34
+ * \param vs Pointer to the \c Slapi_ValueSet structure of which
dc8c34
+ * you wish to get the count.
dc8c34
+ * \return 1 if there are no values contained in the \c Slapi_ValueSet structure.
dc8c34
+ * \return 0 if there are values contained in the \c Slapi_ValueSet structure.
dc8c34
+ */
dc8c34
+int slapi_valueset_isempty(const Slapi_ValueSet *vs);
dc8c34
+
dc8c34
 int slapi_check_account_lock( Slapi_PBlock *pb, Slapi_Entry *bind_target_entry, int pwresponse_req, int check_password_policy, int send_result);
dc8c34
 
dc8c34
 /* backend get/set info */
dc8c34
diff --git a/ldap/servers/slapd/valueset.c b/ldap/servers/slapd/valueset.c
dc8c34
index de6914f..732b411 100644
dc8c34
--- a/ldap/servers/slapd/valueset.c
dc8c34
+++ b/ldap/servers/slapd/valueset.c
dc8c34
@@ -890,12 +890,24 @@ slapi_valueset_set_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2)
dc8c34
 int
dc8c34
 slapi_valueset_first_value( Slapi_ValueSet *vs, Slapi_Value **v )
dc8c34
 {
dc8c34
+	if (NULL == vs) {
dc8c34
+		if (v) {
dc8c34
+			*v = NULL;
dc8c34
+		}
dc8c34
+		return 0;
dc8c34
+	}
dc8c34
 	return valuearray_first_value(vs->va,v);
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
 slapi_valueset_next_value( Slapi_ValueSet *vs, int index, Slapi_Value **v)
dc8c34
 {
dc8c34
+	if (NULL == vs) {
dc8c34
+		if (v) {
dc8c34
+			*v = NULL;
dc8c34
+		}
dc8c34
+		return index;
dc8c34
+	}
dc8c34
 	return valuearray_next_value(vs->va,index,v);
dc8c34
 }
dc8c34
 
dc8c34
@@ -914,8 +926,17 @@ slapi_valueset_count( const Slapi_ValueSet *vs)
dc8c34
 }
dc8c34
 
dc8c34
 int
dc8c34
+slapi_valueset_isempty(const Slapi_ValueSet *vs)
dc8c34
+{
dc8c34
+	return valueset_isempty(vs);
dc8c34
+}
dc8c34
+
dc8c34
+int
dc8c34
 valueset_isempty( const Slapi_ValueSet *vs)
dc8c34
 {
dc8c34
+	if (NULL == vs) {
dc8c34
+		return 1; /* true */
dc8c34
+	}
dc8c34
 	return valuearray_isempty(vs->va);
dc8c34
 }
dc8c34
 
dc8c34
@@ -924,7 +945,7 @@ Slapi_Value *
dc8c34
 slapi_valueset_find(const Slapi_Attr *a, const Slapi_ValueSet *vs, const Slapi_Value *v)
dc8c34
 {
dc8c34
 	Slapi_Value *r= NULL;
dc8c34
-	if(!valuearray_isempty(vs->va))
dc8c34
+	if(vs && !valuearray_isempty(vs->va))
dc8c34
 	{
dc8c34
 		int i= valuearray_find(a,vs->va,v);
dc8c34
 		if(i!=-1)
dc8c34
-- 
dc8c34
1.8.1.4
dc8c34