From 340aa4d138d421bcd92b24d0114c89aeebc49600 Mon Sep 17 00:00:00 2001
From: Ludwig Krispenz <lkrispen@redhat.com>
Date: Fri, 22 Nov 2013 12:58:46 +0100
Subject: [PATCH] Ticket 47527 - Allow referential integrity suffixes to be
 configurable

Bug Description:  Request to apply referential integrity operations
			to specific subtrees only

Fix Description:  The fix adds two configuration parameters to the
	referential integrity plugins:
	nsslapd-pluginContainerScope: <dn>
	nsslapd-pluginEntryScope: <dn>

	The logic implemented is:
		Only entries in the nsslapd-pluginContainerScope will
		be searched for references to be handled
		Only for entries for which nsslapd-pluginEntryScope is
		a suffix will be considered for referential integrity
		processing. This results in a different bahaviour for
		modrdn operations in some scenarios:
		if an entry is renamed and the new superior is not
		below nsslapd-pluginEntryScope then the reference to the
		original dn is removed, like a delete.
		For consistency also a modrdn, which moves an entry
		into scope will be considered: if the old rdn is already
		referenced in an entry inside the containerscope its reference
		will be updated to the newdn

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

Reviewed by: ?
---
 ldap/servers/plugins/referint/referint.c | 72 +++++++++++++++++++++++++++-----
 1 file changed, 62 insertions(+), 10 deletions(-)

diff --git a/ldap/servers/plugins/referint/referint.c b/ldap/servers/plugins/referint/referint.c
index 3d5bba8..dda1175 100644
--- a/ldap/servers/plugins/referint/referint.c
+++ b/ldap/servers/plugins/referint/referint.c
@@ -91,6 +91,8 @@ static int refint_started = 0;
 
 static Slapi_PluginDesc pdesc = { "referint", VENDOR, DS_PACKAGE_VERSION, "referential integrity plugin" };
 static int allow_repl = 0;
+static Slapi_DN *plugin_EntryScope = NULL;
+static Slapi_DN *plugin_ContainerScope = NULL;
 static void* referint_plugin_identity = NULL;
 
 static int use_txn = 0;
@@ -155,13 +157,21 @@ referint_postop_init( Slapi_PBlock *pb )
         use_txn = 1;
     }
     if(plugin_entry){
-        char *allow_repl_updates;
+        char *plugin_attr_value;
 
-        allow_repl_updates = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginAllowReplUpdates");
-        if(allow_repl_updates && strcasecmp(allow_repl_updates,"on")==0){
+        plugin_attr_value = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginAllowReplUpdates");
+        if(plugin_attr_value && strcasecmp(plugin_attr_value,"on")==0){
             allow_repl = 1;
         }
-        slapi_ch_free_string(&allow_repl_updates);
+        slapi_ch_free_string(&plugin_attr_value);
+        plugin_attr_value = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginEntryScope");
+        if(plugin_attr_value) {
+		plugin_EntryScope = slapi_sdn_new_dn_byref(plugin_attr_value);
+	}
+        plugin_attr_value = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-pluginContainerScope");
+        if(plugin_attr_value) {
+		plugin_ContainerScope = slapi_sdn_new_dn_byref(plugin_attr_value);
+	}
     }
     slapi_ch_free_string(&plugin_type);
 
@@ -242,7 +252,9 @@ referint_postop_del( Slapi_PBlock *pb )
             rc = SLAPI_PLUGIN_SUCCESS;
         } else if(delay == 0){ /* no delay */
             /* call function to update references to entry */
-            rc = update_integrity(argv, sdn, NULL, NULL, logChanges);
+	    if (plugin_EntryScope && slapi_sdn_issuffix(sdn, plugin_EntryScope)) {
+        	rc = update_integrity(argv, sdn, NULL, NULL, logChanges);
+	    }
         } else {
             /* write the entry to integrity log */
             writeintegritylog(pb, argv[1], sdn, NULL, NULL, NULL /* slapi_get_requestor_sdn(pb) */);
@@ -322,7 +334,22 @@ referint_postop_modrdn( Slapi_PBlock *pb )
         rc = SLAPI_PLUGIN_SUCCESS;
     } else if(delay == 0){ /* no delay */
         /* call function to update references to entry */
-        rc = update_integrity(argv, sdn, newrdn, newsuperior, logChanges);
+	if (!plugin_EntryScope) {
+	    /* no scope definde, default always process refint */
+            rc = update_integrity(argv, sdn, newrdn, newsuperior, logChanges);
+	} else {
+	    const char *newsuperiordn = slapi_sdn_get_dn(newsuperior);
+	    if ( (newsuperiordn == NULL && slapi_sdn_issuffix(sdn, plugin_EntryScope)) || 
+		    ( newsuperiordn && slapi_sdn_issuffix(newsuperior, plugin_EntryScope))) {
+	        /* it is a modrdn inside the scope or into the scope, 
+                 * process normal modrdn
+                 */
+                rc = update_integrity(argv, sdn, newrdn, newsuperior, logChanges);
+       	    } else if (slapi_sdn_issuffix(sdn, plugin_EntryScope)) {
+	        /* the entry is moved out of scope, treat as delete */
+                rc = update_integrity(argv, sdn, NULL, NULL, logChanges);
+	    }
+	}
     } else {
         /* write the entry to integrity log */
         writeintegritylog(pb, argv[1], sdn, newrdn, newsuperior, NULL /* slapi_get_requestor_sdn(pb) */);
@@ -734,9 +761,15 @@ update_integrity(char **argv, Slapi_DN *origSDN,
      */
     search_result_pb = slapi_pblock_new();
 
-    /* Search each namingContext in turn */
-    for ( sdn = slapi_get_first_suffix( &node, 0 ); sdn != NULL;
-          sdn = slapi_get_next_suffix( &node, 0 ))
+    /* Search each namingContext in turn
+     * or use the defined scope(s)
+     */
+    if (plugin_ContainerScope) {
+	sdn = plugin_ContainerScope;
+    } else {
+    	sdn = slapi_get_first_suffix( &node, 0 );
+    }
+    while (sdn)
     {
         Slapi_Backend *be = slapi_be_select(sdn);
         search_base = slapi_sdn_get_dn( sdn );
@@ -831,6 +864,14 @@ update_integrity(char **argv, Slapi_DN *origSDN,
             }
             slapi_free_search_results_internal(search_result_pb);
         }
+	if (plugin_ContainerScope) {
+		/* at the moment only a single scope is supported
+		 * so the loop ends after the first iteration
+		 */
+		sdn = NULL;
+	} else {
+        	sdn = slapi_get_next_suffix( &node, 0 );
+	}
     }
     /* if got here, then everything good rc = 0 */
     rc = SLAPI_PLUGIN_SUCCESS;
@@ -1128,6 +1169,11 @@ writeintegritylog(Slapi_PBlock *pb, char *logfilename, Slapi_DN *sdn,
     const char *newsuperiordn = NULL;
     size_t reqdn_len = 0;
     
+	if (plugin_EntryScope && 
+		!(slapi_sdn_issuffix(sdn, plugin_EntryScope) ||
+		(newsuperior && slapi_sdn_issuffix(newsuperior, plugin_EntryScope)))) {
+		return;
+	}
     /*
      * Use this lock to protect file data when update integrity is occuring.
      * If betxn is enabled, this mutex is ignored; transaction itself takes
@@ -1152,6 +1198,13 @@ writeintegritylog(Slapi_PBlock *pb, char *logfilename, Slapi_DN *sdn,
      */
     len_to_write = slapi_sdn_get_ndn_len(sdn) + 5;
 
+    newsuperiordn = slapi_sdn_get_dn(newsuperior);
+    if (plugin_EntryScope && newsuperiordn && 
+		!slapi_sdn_issuffix(newsuperior, plugin_EntryScope)) {
+	/* this is a modrdn which moves teh entry out of scope, handle liek a delete */
+	newsuperiordn = NULL;
+	newrdn = NULL;
+    } 
     if(newrdn == NULL){
         /* add the length of "NULL" */
         len_to_write += 4;
@@ -1159,7 +1212,6 @@ writeintegritylog(Slapi_PBlock *pb, char *logfilename, Slapi_DN *sdn,
         /* add the length of the newrdn */
         len_to_write += strlen(newrdn);
     }
-    newsuperiordn = slapi_sdn_get_dn(newsuperior);
     if(NULL == newsuperiordn)
     {
         /* add the length of "NULL" */
-- 
1.7.11.7

