From e8e0799e94b06a5f328ed4d230770f7a8afe63d7 Mon Sep 17 00:00:00 2001
From: Ludwig Krispenz <lkrispen@redhat.com>
Date: Tue, 3 Dec 2013 09:16:23 +0100
Subject: [PATCH] Ticket 47526 - Allow memberof suffixes to be configurable

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

Fix Description:  The fix adds a configuration parameters to the
	memberof plugin:
	nsslapd-memberofScope: <dn>

	The logic implemented is:
		If a member is added top group only if member and group
		are in the defined memberof scope the memberof attribute
		is updated.
		If an entry is deleted and it is inside the scope, its
		member references will be purged (like befoer, only apply scope)
		If an entry is renamed and moved out of scope it will be handled
		like a deletie and in addition its memberof attribute is removed.

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

Reviewed by:  ?
---
 ldap/servers/plugins/memberof/memberof.c        | 29 ++++++++++++++++++++++++-
 ldap/servers/plugins/memberof/memberof.h        |  3 +++
 ldap/servers/plugins/memberof/memberof_config.c | 28 ++++++++++++++++++++++++
 3 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
index 67ef860..4796644 100644
--- a/ldap/servers/plugins/memberof/memberof.c
+++ b/ldap/servers/plugins/memberof/memberof.c
@@ -666,6 +666,7 @@ int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
 	char *filter_str = NULL;
 	char *cookie = NULL;
 	int all_backends = memberof_config_get_all_backends();
+	Slapi_DN *entry_scope = memberof_config_get_entry_scope();
 	int types_name_len = 0;
 	int num_types = 0;
 	int dn_len = slapi_sdn_get_ndn_len(sdn);
@@ -673,6 +674,10 @@ int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
 	int rc = 0;
 	int i = 0;
 
+	if (entry_scope && !slapi_sdn_issuffix(sdn, entry_scope)) {
+		return (rc);
+	}
+
 	/* Count the number of types. */
 	for (num_types = 0; types && types[num_types]; num_types++)
 	{
@@ -741,6 +746,21 @@ int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
 				continue;
 			}
 		}
+		if (entry_scope) {
+			if (slapi_sdn_issuffix(base_sdn, entry_scope)) {
+				/* do nothing, entry scope is spanning 
+				 * multiple suffixes, start at suffix */
+			} else if (slapi_sdn_issuffix(entry_scope, base_sdn)) {
+				/* scope is below suffix, set search base */
+				base_sdn = entry_scope;
+			} else if(!all_backends){
+				break;
+			} else {
+				/* its ok, goto the next backend */
+				be = slapi_get_next_backend(cookie);
+				continue;
+			}
+		}
 
 		slapi_search_internal_set_pb(search_pb, slapi_sdn_get_dn(base_sdn),
 			LDAP_SCOPE_SUBTREE, filter_str, 0, 0, 0, 0, memberof_get_plugin_id(), 0);
@@ -770,6 +790,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
 {
 	int ret = SLAPI_PLUGIN_SUCCESS;
 	void *caller_id = NULL;
+	Slapi_DN *entry_scope = memberof_config_get_entry_scope();
 
 	slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
 		     "--> memberof_postop_modrdn\n" );
@@ -833,7 +854,13 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
 		 * of other group entries.  We need to update any member
 		 * attributes to refer to the new name. */
 		if (pre_sdn && post_sdn) {
-			memberof_replace_dn_from_groups(pb, &configCopy, pre_sdn, post_sdn);
+			if (entry_scope && !slapi_sdn_issuffix(post_sdn, entry_scope)) {
+				memberof_del_dn_data del_data = {0, configCopy.memberof_attr};
+				memberof_del_dn_from_groups(pb, &configCopy, pre_sdn);
+				memberof_del_dn_type_callback(post_e, &del_data);
+			} else {
+				memberof_replace_dn_from_groups(pb, &configCopy, pre_sdn, post_sdn);
+			}
 		}
 
 		memberof_unlock();
diff --git a/ldap/servers/plugins/memberof/memberof.h b/ldap/servers/plugins/memberof/memberof.h
index d308022..46da1c3 100644
--- a/ldap/servers/plugins/memberof/memberof.h
+++ b/ldap/servers/plugins/memberof/memberof.h
@@ -67,6 +67,7 @@
 #define MEMBEROF_GROUP_ATTR "memberOfGroupAttr"
 #define MEMBEROF_ATTR "memberOfAttr"
 #define MEMBEROF_BACKEND_ATTR "memberOfAllBackends"
+#define MEMBEROF_ENTRY_SCOPE_ATTR "memberOfEntryScope"
 #define DN_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.12"
 #define NAME_OPT_UID_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.34"
 
@@ -78,6 +79,7 @@ typedef struct memberofconfig {
 	char **groupattrs;
 	char *memberof_attr;
 	int allBackends;
+	Slapi_DN *entryScope;
 	Slapi_Filter *group_filter;
 	Slapi_Attr **group_slapiattrs;
 } MemberOfConfig;
@@ -96,6 +98,7 @@ void memberof_rlock_config();
 void memberof_wlock_config();
 void memberof_unlock_config();
 int memberof_config_get_all_backends();
+Slapi_DN * memberof_config_get_entry_scope();
 void memberof_set_config_area(Slapi_DN *sdn);
 Slapi_DN * memberof_get_config_area();
 void memberof_set_plugin_area(Slapi_DN *sdn);
diff --git a/ldap/servers/plugins/memberof/memberof_config.c b/ldap/servers/plugins/memberof/memberof_config.c
index e7e807b..4eb3ac6 100644
--- a/ldap/servers/plugins/memberof/memberof_config.c
+++ b/ldap/servers/plugins/memberof/memberof_config.c
@@ -310,6 +310,7 @@ memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 	int num_groupattrs = 0;
 	int groupattr_name_len = 0;
 	char *allBackends = NULL;
+	char *entryScope = NULL;
 	char *sharedcfg = NULL;
 
 	*returncode = LDAP_SUCCESS;
@@ -360,6 +361,7 @@ memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 	groupattrs = slapi_entry_attr_get_charray(e, MEMBEROF_GROUP_ATTR);
 	memberof_attr = slapi_entry_attr_get_charptr(e, MEMBEROF_ATTR);
 	allBackends = slapi_entry_attr_get_charptr(e, MEMBEROF_BACKEND_ATTR);
+	entryScope = slapi_entry_attr_get_charptr(e, MEMBEROF_ENTRY_SCOPE_ATTR);
 
 	/* We want to be sure we don't change the config in the middle of
 	 * a memberOf operation, so we obtain an exclusive lock here */
@@ -468,6 +470,20 @@ memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 	} else {
 		theConfig.allBackends = 0;
 	}
+	if (entryScope)
+	{
+        	if (slapi_dn_syntax_check(NULL, entryScope, 1) == 1) {
+            		slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+                		"Error: Ignoring invalid DN used as plugin entry scope: [%s]\n",
+                		entryScope);
+			theConfig.entryScope = NULL;
+			slapi_ch_free_string(&entryScope);
+		} else {
+			theConfig.entryScope = slapi_sdn_new_dn_byref(entryScope);
+		}
+	} else {
+		theConfig.entryScope = NULL;
+	}
 
 	/* release the lock */
 	memberof_unlock_config();
@@ -648,6 +664,18 @@ memberof_config_get_all_backends()
 	return all_backends;
 }
 
+Slapi_DN *
+memberof_config_get_entry_scope()
+{
+	Slapi_DN *entry_scope;
+
+	slapi_rwlock_rdlock(memberof_config_lock);
+	entry_scope = theConfig.entryScope;
+	slapi_rwlock_unlock(memberof_config_lock);
+
+	return entry_scope;
+}
+
 /*
  * Check if we are modifying the config, or changing the shared config entry
  */
-- 
1.7.11.7

