[389-commits] 2 commits - ldap/schema ldap/servers

Richard Allen Megginson rmeggins at fedoraproject.org
Tue Aug 28 01:58:07 UTC 2012


 ldap/schema/02common.ldif                                |    3 
 ldap/servers/plugins/replication/repl5.h                 |    4 
 ldap/servers/plugins/replication/repl5_agmt.c            |   26 ++
 ldap/servers/plugins/replication/repl5_inc_protocol.c    |    2 
 ldap/servers/plugins/replication/repl5_tot_protocol.c    |    2 
 ldap/servers/plugins/replication/repl_globals.c          |    1 
 ldap/servers/plugins/replication/windows_inc_protocol.c  |    7 
 ldap/servers/plugins/replication/windows_private.c       |  131 +++++++++++++++
 ldap/servers/plugins/replication/windows_protocol_util.c |  112 ++++++++++++
 ldap/servers/plugins/replication/windows_tot_protocol.c  |    7 
 ldap/servers/plugins/replication/windowsrepl.h           |   10 +
 11 files changed, 297 insertions(+), 8 deletions(-)

New commits:
commit 6cfc1c0ac84200535a512dd4ef28fc9dd82d6c18
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Fri Aug 24 13:30:43 2012 -0600

    Ticket #440 - periodic dirsync timed event causes server to loop repeatedly
    
    https://fedorahosted.org/389/ticket/440
    Resolves: Ticket #440
    Bug Description: periodic dirsync timed event causes server to loop repeatedly
    Reviewed by: nhosoi (Thanks!)
    Branch: master
    Fix Description: If we get the EVENT_RUN_DIRSYNC in state
    STATE_WAIT_WINDOW_OPEN, just go to sleep, and wait for some event that is able
    to bump from this state, such as schedule window open or agreement change.
    Platforms tested: RHEL6 x86_64
    Flag Day: no
    Doc impact: no
    (cherry picked from commit d6ca372b30ae0c4e9fcd65c22ac3a7ce870e3f67)

diff --git a/ldap/servers/plugins/replication/windows_inc_protocol.c b/ldap/servers/plugins/replication/windows_inc_protocol.c
index e9df9f6..b5fcadc 100644
--- a/ldap/servers/plugins/replication/windows_inc_protocol.c
+++ b/ldap/servers/plugins/replication/windows_inc_protocol.c
@@ -414,6 +414,11 @@ windows_inc_run(Private_Repl_Protocol *prp)
 						state2name(current_state));
 					protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT);
 				  }
+				else if (event_occurred(prp, EVENT_RUN_DIRSYNC)) /* periodic_dirsync */
+				  {
+					/* just ignore it and go to sleep */
+					protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT);
+				  }
 				else
 				  {
 					/* wait until window opens or an event occurs */


commit 94f9ceffbc0dba95763b9a27b71955323c58384f
Author: Rich Megginson <rmeggins at redhat.com>
Date:   Wed Aug 22 20:52:24 2012 -0600

    Ticket #355 - winsync should not delete entry that appears to be out of scope
    
    https://fedorahosted.org/389/ticket/355
    Resolves: Ticket #355
    Bug Description: winsync should not delete entry that appears to be out of scope
    Reviewed by: nhosoi (Thanks!)
    Branch: master
    Fix Description: There is a new winsync config attribute - winSyncMoveAction -
    this is the action to take on the DS side when the winsync finds an AD entry
    that has the same name/uid as a DS entry but the AD entry is out of the scope
    of the sync agreement (winsync has to search out of scope/subtree on AD to
    support deleted and moved entries).  In earlier versions of DS, these entries
    were ignored.  When DS was changed to support entry move/subtree rename, the
    winsync code was changed to delete entries moved out of scope.  The new
    winSyncMoveAction has 3 values:
    none - ignore moved entries (like older versions of DS)
    delete - delete DS entries when the AD entry moves out of scope - like current
             versions of DS
    unsync - new behavior - if the DS entry is currently synced with the AD entry
             this will cause the DS entry to be "unlinked" from the AD entry so
             that they will no longer be in sync
    The default value is "none" because we should not unexpectedly delete DS
    entries (principle of least astonishment).
    Another problem with winsync is that it allowed you to change the subtree and
    domain in the middle of a sync update - this can lead to a great deal of
    confusion if suddenly many entries are out of scope.  The fix is to "save"
    the changes in the entry, and apply those changes when the update is
    complete.
    Platforms tested: RHEL6 x86_64
    Flag Day: yes - new attribute, schema
    Doc impact: yes - new attribute, schema
    (cherry picked from commit 3206571b8ac8308482c20c3866f407079479b8e6)

diff --git a/ldap/schema/02common.ldif b/ldap/schema/02common.ldif
index db8ea19..c209615 100644
--- a/ldap/schema/02common.ldif
+++ b/ldap/schema/02common.ldif
@@ -144,6 +144,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.1004 NAME 'nsds7WindowsDomain' DESC 'Net
 attributeTypes: ( 2.16.840.1.113730.3.1.1005 NAME 'nsds7DirsyncCookie' DESC 'Netscape defined attribute type'  SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.1099 NAME 'winSyncInterval' DESC 'Netscape defined attribute type'  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.1100 NAME 'oneWaySync' DESC 'Netscape defined attribute type'  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2139 NAME 'winSyncMoveAction' DESC 'Netscape defined attribute type'  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 1.3.6.1.1.4 NAME 'vendorName' EQUALITY 1.3.6.1.4.1.1466.109.114.1 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation X-ORIGIN 'RFC 3045' )
 attributeTypes: ( 1.3.6.1.1.5 NAME 'vendorVersion' EQUALITY 1.3.6.1.4.1.1466.109.114.1 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation X-ORIGIN 'RFC 3045' )
 attributeTypes: ( 2.16.840.1.113730.3.1.3023 NAME 'nsViewFilter' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )
@@ -178,7 +179,7 @@ objectClasses: ( 2.16.840.1.113730.3.2.99 NAME 'cosSuperDefinition' DESC 'Netsca
 objectClasses: ( 2.16.840.1.113730.3.2.100 NAME 'cosClassicDefinition' DESC 'Netscape defined objectclass' SUP cosSuperDefinition MAY ( cosTemplateDn $ cosspecifier ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.101 NAME 'cosPointerDefinition' DESC 'Netscape defined objectclass' SUP cosSuperDefinition MAY ( cosTemplateDn ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.102 NAME 'cosIndirectDefinition' DESC 'Netscape defined objectclass' SUP cosSuperDefinition MAY ( cosIndirectSpecifier ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.503 NAME 'nsDSWindowsReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5replicaSessionPauseTime $ nsds7WindowsReplicaSubtree $ nsds7DirectoryReplicaSubtree $ nsds7NewWinUserSyncEnabled $ nsds7NewWinGroupSyncEnabled $ nsds7WindowsDomain $ nsds7DirsyncCookie $ winSyncInterval $ oneWaySync) X-ORIGIN 
 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.503 NAME 'nsDSWindowsReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5replicaSessionPauseTime $ nsds7WindowsReplicaSubtree $ nsds7DirectoryReplicaSubtree $ nsds7NewWinUserSyncEnabled $ nsds7NewWinGroupSyncEnabled $ nsds7WindowsDomain $ nsds7DirsyncCookie $ winSyncInterval $ oneWaySync $ winSyncM
 oveAction) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.128 NAME 'costemplate' DESC 'Netscape defined objectclass' SUP top MAY ( cn $ cospriority ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.304 NAME 'nsView' DESC 'Netscape defined objectclass' SUP top AUXILIARY MAY ( nsViewFilter $ description ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.316 NAME 'nsAttributeEncryption' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsEncryptionAlgorithm ) X-ORIGIN 'Netscape Directory Server' )
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index 26d0298..7b6cb8c 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -169,6 +169,7 @@ extern const char *type_nsds7DirsyncCookie;
 extern const char *type_nsds7WindowsDomain;
 extern const char *type_winSyncInterval;
 extern const char *type_oneWaySync;
+extern const char *type_winsyncMoveAction;
 
 /* To Allow Consumer Initialisation when adding an agreement - */
 extern const char *type_nsds5BeginReplicaRefresh;
@@ -342,6 +343,7 @@ void agmt_set_last_update_start (Repl_Agmt *ra, time_t start_time);
 void agmt_set_last_update_end (Repl_Agmt *ra, time_t end_time);
 void agmt_set_last_update_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *msg);
 void agmt_set_update_in_progress (Repl_Agmt *ra, PRBool in_progress);
+PRBool agmt_get_update_in_progress (const Repl_Agmt *ra);
 void agmt_set_last_init_start (Repl_Agmt *ra, time_t start_time);
 void agmt_set_last_init_end (Repl_Agmt *ra, time_t end_time);
 void agmt_set_last_init_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *msg);
@@ -367,6 +369,7 @@ void agmt_set_cleanruv_notified_from_entry(Repl_Agmt *ra, Slapi_Entry *e);
 int agmt_set_cleanruv_data(Repl_Agmt *ra, ReplicaId rid, int op);
 int agmt_is_cleanruv_notified(Repl_Agmt *ra, ReplicaId rid);
 int agmt_set_timeout(Repl_Agmt *ra, long timeout);
+void agmt_update_done(Repl_Agmt *ra, int is_total);
 
 typedef struct replica Replica;
 
@@ -679,6 +682,7 @@ int windows_handle_modify_agreement(Repl_Agmt *ra, const char *type, Slapi_Entry
 void windows_agreement_delete(Repl_Agmt *ra);
 Repl_Connection *windows_conn_new(Repl_Agmt *agmt);
 void windows_conn_delete(Repl_Connection *conn);
+void windows_update_done(Repl_Agmt *ra, int is_total);
 
 /* repl_session_plugin.c */
 void repl_session_plugin_init();
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
index 9002ff3..d25f54b 100644
--- a/ldap/servers/plugins/replication/repl5_agmt.c
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -2265,6 +2265,17 @@ agmt_set_update_in_progress (Repl_Agmt *ra, PRBool in_progress)
 	}
 }
 
+PRBool
+agmt_get_update_in_progress (const Repl_Agmt *ra)
+{
+	PR_ASSERT(NULL != ra);
+	if (NULL != ra)
+	{
+		return ra->update_in_progress;
+	}
+	return PR_FALSE;
+}
+
 void
 agmt_inc_last_update_changecount (Repl_Agmt *ra, ReplicaId rid, int skipped)
 {
@@ -2694,3 +2705,18 @@ agmt_set_cleanruv_notified_from_entry(Repl_Agmt *ra, Slapi_Entry *e){
     }
     PR_Unlock(ra->lock);
 }
+
+/* this is called whenever an update (total/incremental)
+   is completed */
+void 
+agmt_update_done(Repl_Agmt *agmt, int is_total)
+{
+    /* we could do a lot of stuff here - consolidate all of the other stuff that gets
+       done at the end of an update - setting status, times, etc.
+       but for now, all we want to do is "flush" any pending changes made
+       during the update into the proper structures so they are in place for the
+       next run
+    */
+    windows_update_done(agmt, is_total);
+}
+
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
index 025c23f..743be57 100644
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
@@ -962,6 +962,7 @@ repl5_inc_run(Private_Repl_Protocol *prp)
               /* richm: We at least need to let monitors know that the protocol has been
                * shutdown - maybe they can figure out why */
               agmt_set_last_update_status(prp->agmt, 0, 0, "Protocol stopped");
+              agmt_update_done(prp->agmt, 0);
               break;
           }
 
@@ -1076,6 +1077,7 @@ repl5_inc_run(Private_Repl_Protocol *prp)
           }
           agmt_set_last_update_end(prp->agmt, current_time());
           agmt_set_update_in_progress(prp->agmt, PR_FALSE);
+          agmt_update_done(prp->agmt, 0);
           /* If timed out, close the connection after released the replica */
           release_replica(prp);
           if (rc == UPDATE_TIMEOUT) {
diff --git a/ldap/servers/plugins/replication/repl5_tot_protocol.c b/ldap/servers/plugins/replication/repl5_tot_protocol.c
index 5eeef5d..b10d2d0 100644
--- a/ldap/servers/plugins/replication/repl5_tot_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_tot_protocol.c
@@ -475,6 +475,8 @@ repl5_tot_run(Private_Repl_Protocol *prp)
 	slapi_pblock_destroy (pb);
 	agmt_set_last_init_end(prp->agmt, current_time());
 	rc = cb_data.rc;
+	agmt_set_update_in_progress(prp->agmt, PR_FALSE);
+	agmt_update_done(prp->agmt, 1);
 	release_replica(prp);
 	
     if (rc != LDAP_SUCCESS)
diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c
index 383d562..f31a476 100644
--- a/ldap/servers/plugins/replication/repl_globals.c
+++ b/ldap/servers/plugins/replication/repl_globals.c
@@ -141,6 +141,7 @@ const char *type_nsds7WindowsDomain = "nsds7WindowsDomain";
 const char *type_nsds7DirsyncCookie = "nsds7DirsyncCookie";
 const char *type_winSyncInterval = "winSyncInterval";
 const char *type_oneWaySync = "oneWaySync";
+const char *type_winsyncMoveAction = "winSyncMoveAction";
 
 /* To Allow Consumer Initialization when adding an agreement - */
 const char *type_nsds5BeginReplicaRefresh = "nsds5BeginReplicaRefresh";
diff --git a/ldap/servers/plugins/replication/windows_inc_protocol.c b/ldap/servers/plugins/replication/windows_inc_protocol.c
index 3bba77d..e9df9f6 100644
--- a/ldap/servers/plugins/replication/windows_inc_protocol.c
+++ b/ldap/servers/plugins/replication/windows_inc_protocol.c
@@ -769,6 +769,7 @@ windows_inc_run(Private_Repl_Protocol *prp)
 	    /* richm: We at least need to let monitors know that the protocol has been
 	       shutdown - maybe they can figure out why */
 	    agmt_set_last_update_status(prp->agmt, 0, 0, "Protocol stopped");
+	    agmt_update_done(prp->agmt, 0);
 	    break;
 	  } 
 
@@ -903,6 +904,7 @@ windows_inc_run(Private_Repl_Protocol *prp)
 
 	agmt_set_last_update_end(prp->agmt, current_time());
 	agmt_set_update_in_progress(prp->agmt, PR_FALSE);
+	agmt_update_done(prp->agmt, 0);
 	/* If timed out, close the connection after released the replica */
 	windows_release_replica(prp);
 	if (rc == UPDATE_TIMEOUT) {
diff --git a/ldap/servers/plugins/replication/windows_private.c b/ldap/servers/plugins/replication/windows_private.c
index 1f0318f..26d03c2 100644
--- a/ldap/servers/plugins/replication/windows_private.c
+++ b/ldap/servers/plugins/replication/windows_private.c
@@ -76,6 +76,7 @@ struct windowsprivate {
   void *api_cookie; /* private data used by api callbacks */
   time_t sync_interval; /* how often to run the dirsync search, in seconds */
   int one_way; /* Indicates if this is a one-way agreement and which direction it is */
+  int move_action; /* Indicates what to do with DS entry if AD entry is moved out of scope */
 };
 
 static void windows_private_set_windows_domain(const Repl_Agmt *ra, char *domain);
@@ -93,11 +94,62 @@ true_value_from_string(char *val)
 	}
 }
 
+/* yech - can't declare a constant string array because type_nsds7XX variables
+   are not constant strings - so have to build a lookup table */
+static int
+get_next_disallow_attr_type(int *ii, const char **type)
+{
+	switch (*ii) {
+	case 0: *type = type_nsds7WindowsReplicaArea; break;
+	case 1: *type = type_nsds7DirectoryReplicaArea; break;
+	case 2: *type = type_nsds7WindowsDomain; break;
+	default: *type = NULL; break;
+	}
+
+	if (*type) {
+		(*ii)++;
+		return 1;
+	}
+	return 0;
+}
+
+static int
+check_update_allowed(Repl_Agmt *ra, const char *type, Slapi_Entry *e, int *retval)
+{
+	int rc = 1;
+
+	/* note - it is not an error to defer setting the value in the ra */
+	*retval = 1;
+	if (agmt_get_update_in_progress(ra)) {
+		const char *distype = NULL;
+		int ii = 0;
+		while (get_next_disallow_attr_type(&ii, &distype)) {
+			if (slapi_attr_types_equivalent(type, distype)) {
+				char *tmpstr = slapi_entry_attr_get_charptr(e, type);
+				slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+								"windows_parse_config_entry: setting %s to %s will be "
+								"deferred until current update is completed\n",
+								type, tmpstr);
+				slapi_ch_free_string(&tmpstr);
+				rc = 0;
+				break;
+			}
+		}
+	}
+
+	return rc;
+}
+
 static int
 windows_parse_config_entry(Repl_Agmt *ra, const char *type, Slapi_Entry *e)
 {
 	char *tmpstr = NULL;
 	int retval = 0;
+
+	if (!check_update_allowed(ra, type, e, &retval))
+	{
+		return retval;
+	}
 	
 	if (type == NULL || slapi_attr_types_equivalent(type,type_nsds7WindowsReplicaArea))
 	{
@@ -190,6 +242,32 @@ windows_parse_config_entry(Repl_Agmt *ra, const char *type, Slapi_Entry *e)
 		slapi_ch_free((void**)&tmpstr);
 		retval = 1;
 	}
+	if (type == NULL || slapi_attr_types_equivalent(type,type_winsyncMoveAction))
+	{
+		tmpstr = slapi_entry_attr_get_charptr(e, type_winsyncMoveAction);
+		if (NULL != tmpstr)
+		{
+			if (strcasecmp(tmpstr, "delete") == 0) {
+				windows_private_set_move_action(ra, MOVE_DOES_DELETE);
+			} else if (strcasecmp(tmpstr, "unsync") == 0) {
+				windows_private_set_move_action(ra, MOVE_DOES_UNSYNC);
+			} else if (strcasecmp(tmpstr, "none") == 0) {
+				windows_private_set_move_action(ra, MOVE_DOES_NOTHING);
+			} else {
+				slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+					"Ignoring illegal setting for %s attribute in replication "
+					"agreement \"%s\".  Valid values are \"delete\" or "
+					"\"unsync\".\n", type_winsyncMoveAction, slapi_entry_get_dn(e));
+				windows_private_set_move_action(ra, MOVE_DOES_NOTHING);
+			}
+		}
+		else
+		{
+			windows_private_set_move_action(ra, MOVE_DOES_NOTHING);
+		}
+		slapi_ch_free((void**)&tmpstr);
+		retval = 1;
+	}
 	return retval;
 }
 
@@ -207,6 +285,26 @@ windows_handle_modify_agreement(Repl_Agmt *ra, const char *type, Slapi_Entry *e)
 	}
 }
 
+void 
+windows_update_done(Repl_Agmt *agmt, int is_total)
+{
+	/* "flush" the changes made during the update to the agmt */
+	/* get the agmt entry */
+	Slapi_DN *agmtdn = slapi_sdn_dup(agmt_get_dn_byref(agmt));
+	Slapi_Entry *agmte = NULL;
+	int rc = slapi_search_internal_get_entry(agmtdn, NULL, &agmte,
+											 repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION));
+	if ((rc == 0) && agmte) {
+		int ii = 0;
+		const char *distype = NULL;
+		while (get_next_disallow_attr_type(&ii, &distype)) {
+			windows_handle_modify_agreement(agmt, distype, agmte);
+		}
+	}
+	slapi_entry_free(agmte);
+	slapi_sdn_free(&agmtdn);
+}
+
 void
 windows_init_agreement_from_entry(Repl_Agmt *ra, Slapi_Entry *e)
 {
@@ -1024,6 +1122,39 @@ windows_private_set_sync_interval(Repl_Agmt *ra, char *str)
 	LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= windows_private_set_sync_interval\n" );
 }
 
+int
+windows_private_get_move_action(const Repl_Agmt *ra)
+{
+	Dirsync_Private *dp;
+
+	LDAPDebug0Args( LDAP_DEBUG_TRACE, "=> windows_private_get_move_action\n" );
+
+	PR_ASSERT(ra);
+
+	dp = (Dirsync_Private *) agmt_get_priv(ra);
+	PR_ASSERT (dp);
+
+	LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= windows_private_get_move_action\n" );
+
+	return dp->move_action;	
+}
+
+void
+windows_private_set_move_action(const Repl_Agmt *ra, int value)
+{
+	Dirsync_Private *dp;
+
+	LDAPDebug0Args( LDAP_DEBUG_TRACE, "=> windows_private_set_move_action\n" );
+
+	PR_ASSERT(ra);
+
+	dp = (Dirsync_Private *) agmt_get_priv(ra);
+	PR_ASSERT (dp);
+	dp->move_action = value;
+
+	LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= windows_private_set_move_action\n" );
+}
+
 static PRCallOnceType winsync_callOnce = {0,0};
 
 struct winsync_plugin {
diff --git a/ldap/servers/plugins/replication/windows_protocol_util.c b/ldap/servers/plugins/replication/windows_protocol_util.c
index af3cfa1..84382e5 100644
--- a/ldap/servers/plugins/replication/windows_protocol_util.c
+++ b/ldap/servers/plugins/replication/windows_protocol_util.c
@@ -5049,6 +5049,85 @@ windows_get_local_entry(const Slapi_DN* local_dn,Slapi_Entry **local_entry)
 	return retval;
 }
 
+static int
+windows_unsync_entry(Private_Repl_Protocol *prp, Slapi_Entry *e)
+{
+	/* remote the ntuser/ntgroup objectclass and all attributes whose
+	   name begins with "nt" - this will effectively cause the entry
+	   to become "unsynced" with the corresponding windows entry */
+	Slapi_Mods *smods = NULL;
+	Slapi_Value *ntu = NULL, *ntg = NULL;
+	Slapi_Value *va[2] = {NULL, NULL};
+	char **syncattrs = NULL;
+	PRUint32 ocflags = SLAPI_OC_FLAG_REQUIRED|SLAPI_OC_FLAG_ALLOWED;
+	Slapi_PBlock *pb = NULL;
+	int ii;
+	int rc = -1;
+
+	smods = slapi_mods_new();
+	ntu = slapi_value_new_string("ntuser");
+	ntg = slapi_value_new_string("ntgroup");
+
+	if (slapi_entry_attr_has_syntax_value(e, "objectclass", ntu)) {
+		syncattrs = slapi_schema_list_objectclass_attributes(slapi_value_get_string(ntu), ocflags);
+		va[0] = ntu;
+	} else if (slapi_entry_attr_has_syntax_value(e, "objectclass", ntg)) {
+		syncattrs = slapi_schema_list_objectclass_attributes(slapi_value_get_string(ntg), ocflags);
+		va[0] = ntg;
+	} else {
+		rc = 0; /* not an error */
+		goto done; /* nothing to see here, move along */
+	}
+	slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, "objectclass", va);
+	slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+					"%s: windows_unsync_entry: removing objectclass %s from %s\n",
+					agmt_get_long_name(prp->agmt), slapi_value_get_string(va[0]),
+					slapi_entry_get_dn_const(e));
+
+	for (ii = 0; syncattrs && syncattrs[ii]; ++ii) {
+		const char *type = syncattrs[ii];
+		Slapi_Attr *attr = NULL;
+
+		if (!slapi_entry_attr_find(e, type, &attr) && attr) {
+			if (!PL_strncasecmp(type, "nt", 2)) { /* begins with "nt" */
+				slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, type, NULL);
+				slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+								"%s: windows_unsync_entry: removing attribute %s from %s\n",
+								agmt_get_long_name(prp->agmt), type,
+								slapi_entry_get_dn_const(e));
+			}
+		}
+	}
+
+	pb = slapi_pblock_new();
+	if (!pb) {
+		goto done;
+	}
+	slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+					"%s: windows_unsync_entry: modifying entry %s\n",
+					agmt_get_long_name(prp->agmt), slapi_entry_get_dn_const(e));
+	slapi_modify_internal_set_pb_ext(pb, slapi_entry_get_sdn(e),
+									 slapi_mods_get_ldapmods_byref(smods), NULL, NULL,
+									 repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+	slapi_modify_internal_pb(pb);
+	slapi_pblock_get (pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+	if (rc) {
+		slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name,
+						"%s: windows_unsync_entry: failed to modify entry %s - error %d:%s\n",
+						agmt_get_long_name(prp->agmt), slapi_entry_get_dn_const(e),
+						rc, ldap_err2string(rc));
+	}
+	slapi_pblock_destroy(pb);
+
+done:
+	slapi_ch_array_free(syncattrs);
+	slapi_mods_free(&smods);
+	slapi_value_free(&ntu);
+	slapi_value_free(&ntg);
+
+	return rc;
+}
+
 static int 
 windows_process_dirsync_entry(Private_Repl_Protocol *prp,Slapi_Entry *e, int is_total)
 {
@@ -5183,13 +5262,34 @@ retry:
 				rc = windows_get_local_entry(local_sdn, &local_entry);
 				if ((0 == rc) && local_entry) 
 				{
-					/* Need to delete the local entry since the remote counter
-					 * part is now moved out of scope of the agreement. */
-					/* Since map_Entry_dn_oubound returned local_sdn,
-					 * the entry is either user or group. */
-					rc = windows_delete_local_entry(local_sdn);
-					slapi_entry_free(local_entry);
+					if (windows_private_get_move_action(prp->agmt) == MOVE_DOES_DELETE) {
+						/* Need to delete the local entry since the remote counter
+						 * part is now moved out of scope of the agreement. */
+						/* Since map_Entry_dn_oubound returned local_sdn,
+						 * the entry is either user or group. */
+						slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+										"%s: windows_process_dirsync_entry: deleting out of "
+										"scope entry %s\n", agmt_get_long_name(prp->agmt),
+										slapi_sdn_get_dn(local_sdn));
+						rc = windows_delete_local_entry(local_sdn);
+					} else if (windows_private_get_move_action(prp->agmt) == MOVE_DOES_UNSYNC) {
+						rc = windows_unsync_entry(prp, local_entry);
+					} else {
+						slapi_log_error(SLAPI_LOG_REPL, windows_repl_plugin_name,
+										"%s: windows_process_dirsync_entry: windows "
+										"inbound entry %s has the same name as local "
+										"entry %s but the windows entry is out of the "
+										"scope of the sync subtree [%s] - if you want "
+										"these entries to be in sync, add the ntUser/ntGroup "
+										"objectclass and required attributes to the local "
+										"entry, and move the windows entry into scope\n",
+										agmt_get_long_name(prp->agmt),
+										slapi_entry_get_dn_const(e),
+										slapi_sdn_get_dn(local_sdn),
+										slapi_sdn_get_dn(windows_private_get_windows_subtree(prp->agmt)));
+					}
 				}
+				slapi_entry_free(local_entry);
 				slapi_sdn_free(&local_sdn);
 			}
 		}
diff --git a/ldap/servers/plugins/replication/windows_tot_protocol.c b/ldap/servers/plugins/replication/windows_tot_protocol.c
index 6c54004..0791941 100644
--- a/ldap/servers/plugins/replication/windows_tot_protocol.c
+++ b/ldap/servers/plugins/replication/windows_tot_protocol.c
@@ -151,6 +151,8 @@ windows_tot_run(Private_Repl_Protocol *prp)
 
 	agmt_set_last_init_status(prp->agmt, 0, 0, "Total update in progress");
 
+	agmt_set_update_in_progress(prp->agmt, PR_TRUE);
+
 	slapi_log_error(SLAPI_LOG_FATAL, windows_repl_plugin_name, "Beginning total update of replica "
 		"\"%s\".\n", agmt_get_long_name(prp->agmt));
     
@@ -216,7 +218,6 @@ windows_tot_run(Private_Repl_Protocol *prp)
     server_controls = NULL;
 
     slapi_pblock_destroy (pb);
-	agmt_set_last_init_end(prp->agmt, current_time());
 	rc = cb_data.rc;
 	windows_release_replica(prp);
 		
@@ -249,6 +250,10 @@ windows_tot_run(Private_Repl_Protocol *prp)
 	/* Save the dirsync cookie. */
 	windows_private_save_dirsync_cookie(prp->agmt);
 
+	agmt_set_last_init_end(prp->agmt, current_time());
+	agmt_set_update_in_progress(prp->agmt, PR_FALSE);
+	agmt_update_done(prp->agmt, 1);
+
 	/* call end total update callback */
 	winsync_plugin_call_end_update_cb(prp->agmt,
 									  windows_private_get_directory_subtree(prp->agmt),
diff --git a/ldap/servers/plugins/replication/windowsrepl.h b/ldap/servers/plugins/replication/windowsrepl.h
index 5780e74..6047fef 100644
--- a/ldap/servers/plugins/replication/windowsrepl.h
+++ b/ldap/servers/plugins/replication/windowsrepl.h
@@ -86,6 +86,8 @@ time_t windows_private_get_sync_interval(const Repl_Agmt *ra);
 void windows_private_set_sync_interval(Repl_Agmt *ra, char *str);
 PRBool windows_private_get_one_way(const Repl_Agmt *ra);
 void windows_private_set_one_way(const Repl_Agmt *ra, PRBool value);
+int windows_private_get_move_action(const Repl_Agmt *ra);
+void windows_private_set_move_action(const Repl_Agmt *ra, int value);
 
 /* in windows_connection.c */
 ConnResult windows_conn_connect(Repl_Connection *conn);
@@ -141,6 +143,14 @@ int windows_check_user_password(Repl_Connection *conn, Slapi_DN *sdn, char *pass
 #define ONE_WAY_SYNC_FROM_AD 1
 #define ONE_WAY_SYNC_TO_AD 2
 
+/*
+ * Specifies what action for sync to take if it detects an AD entry has
+ * moved out of scope
+ */
+#define MOVE_DOES_NOTHING 0
+#define MOVE_DOES_UNSYNC 1
+#define MOVE_DOES_DELETE 2
+
 /* called for each replication agreement - so the winsync
    plugin can be agreement specific and store agreement
    specific data




More information about the 389-commits mailing list