Selaa lähdekoodia

Ticket 47525 - Allow memberOf to use an alternate config area

Description:  Added support for nsslapd-pluginConfigArea.  If this attribute is set
              the config settings in the plugin entry are ignored, and only the
              shared config entry will apply.

              Registered a preop plugin function to perform config validation on
              the shared config entry.  Then in the modify postop function we
              apply the changes.

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

Reviewed by: richm(Thanks!)
Mark Reynolds 12 vuotta sitten
vanhempi
sitoutus
f81ac81a47

+ 169 - 22
ldap/servers/plugins/memberof/memberof.c

@@ -75,10 +75,13 @@ static Slapi_PluginDesc pdesc = { "memberof", VENDOR,
 	DS_PACKAGE_VERSION, "memberof plugin" };
 
 static void* _PluginID = NULL;
+static Slapi_DN* _ConfigAreaDN = NULL;
+static Slapi_DN* _pluginDN = NULL;
 static PRMonitor *memberof_operation_lock = 0;
 MemberOfConfig *qsortConfig = 0;
 static int g_plugin_started = 0;
 static int usetxn = 0;
+static int premodfn = 0;
 
 typedef struct _memberofstringll
 {
@@ -99,6 +102,7 @@ typedef struct _memberof_get_groups_data
 /* exported functions */
 int memberof_postop_init(Slapi_PBlock *pb );
 static int memberof_internal_postop_init(Slapi_PBlock *pb);
+static int memberof_preop_init(Slapi_PBlock *pb);
 
 /* plugin callbacks */ 
 static int memberof_postop_del(Slapi_PBlock *pb ); 
@@ -140,7 +144,6 @@ static int memberof_moddn_attr_list(Slapi_PBlock *pb, MemberOfConfig *config,
 static int memberof_replace_list(Slapi_PBlock *pb, MemberOfConfig *config,
 	Slapi_DN *group_sdn);
 static void memberof_set_plugin_id(void * plugin_id);
-static void *memberof_get_plugin_id();
 static int memberof_compare(MemberOfConfig *config, const void *a, const void *b);
 static int memberof_qsort_compare(const void *a, const void *b);
 static void memberof_load_array(Slapi_Value **array, Slapi_Attr *attr);
@@ -193,6 +196,7 @@ memberof_postop_init(Slapi_PBlock *pb)
 	char *memberof_plugin_identity = 0;
 	Slapi_Entry *plugin_entry = NULL;
 	char *plugin_type = NULL;
+	char *preop_plugin_type = NULL;
 	int delfn = SLAPI_PLUGIN_POST_DELETE_FN;
 	int mdnfn = SLAPI_PLUGIN_POST_MODRDN_FN;
 	int modfn = SLAPI_PLUGIN_POST_MODIFY_FN;
@@ -214,6 +218,18 @@ memberof_postop_init(Slapi_PBlock *pb)
 	}
 	slapi_ch_free_string(&plugin_type);
 
+	if(usetxn){
+		preop_plugin_type = "betxnpreoperation";
+		premodfn = SLAPI_PLUGIN_BE_TXN_PRE_MODIFY_FN;
+	} else {
+		preop_plugin_type = "preoperation";
+		premodfn = SLAPI_PLUGIN_PRE_MODIFY_FN;
+	}
+
+	if(plugin_entry){
+		memberof_set_plugin_area(slapi_entry_get_sdn(plugin_entry));
+	}
+
 	/*
 	 * Get plugin identity and stored it for later use
 	 * Used for internal operations
@@ -223,21 +239,17 @@ memberof_postop_init(Slapi_PBlock *pb)
 	PR_ASSERT (memberof_plugin_identity);
 	memberof_set_plugin_id(memberof_plugin_identity);
 
-	ret = ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
-				SLAPI_PLUGIN_VERSION_01 ) != 0 ||
-		slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
-	                     (void *)&pdesc ) != 0 ||
-		slapi_pblock_set( pb, delfn, (void *) memberof_postop_del ) != 0 ||
-		slapi_pblock_set( pb, mdnfn, (void *) memberof_postop_modrdn ) != 0 ||
-		slapi_pblock_set( pb, modfn, (void *) memberof_postop_modify ) != 0 ||
-		slapi_pblock_set( pb, addfn, (void *) memberof_postop_add ) != 0 ||
-		slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
-			(void *) memberof_postop_start ) != 0 ||
-		slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
-			(void *) memberof_postop_close ) != 0 );
+	ret = ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+			slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&pdesc ) != 0 ||
+			slapi_pblock_set( pb, delfn, (void *) memberof_postop_del ) != 0 ||
+			slapi_pblock_set( pb, mdnfn, (void *) memberof_postop_modrdn ) != 0 ||
+			slapi_pblock_set( pb, modfn, (void *) memberof_postop_modify ) != 0 ||
+			slapi_pblock_set( pb, addfn, (void *) memberof_postop_add ) != 0 ||
+			slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) memberof_postop_start ) != 0 ||
+			slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) memberof_postop_close ) != 0 );
 
 	if (!ret && !usetxn &&
-		slapi_register_plugin("internalpostoperation",  /* op type */
+			slapi_register_plugin("internalpostoperation",  /* op type */
 			1,        /* Enabled */
 			"memberof_postop_init",   /* this function desc */
 			memberof_internal_postop_init,  /* init func */
@@ -255,12 +267,52 @@ memberof_postop_init(Slapi_PBlock *pb)
 			"memberof_postop_init failed\n" );
 		ret = -1;
 	}
+	/*
+	 * Setup the preop plugin for shared config updates
+	 */
+	if (!ret && !usetxn &&
+		slapi_register_plugin(preop_plugin_type,  /* op type */
+			1,        /* Enabled */
+			"memberof_preop_init",   /* this function desc */
+			memberof_preop_init,  /* init func */
+			MEMBEROF_PREOP_DESC,      /* plugin desc */
+			NULL,     /* ? */
+			memberof_plugin_identity   /* access control */))
+	{
+		slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+			"memberof_preop_init failed\n" );
+		ret = -1;
+	}
+	else if (ret)
+	{
+		slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+			"memberof_preop_init failed\n");
+		ret = -1;
+	}
 
 	slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
 		"<-- memberof_postop_init\n" );
+
 	return ret;
 }
 
+static int
+memberof_preop_init(Slapi_PBlock *pb)
+{
+	int status = 0;
+
+	if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01) != 0 ||
+		slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,	(void *) &pdesc) != 0 ||
+		slapi_pblock_set(pb, premodfn, (void *)memberof_shared_config_validate) != 0)
+	{
+		slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+			"memberof_internal_postop_init: failed to register plugin\n");
+		status = -1;
+	}
+
+	return status;
+}
+
 static int
 memberof_internal_postop_init(Slapi_PBlock *pb)
 {
@@ -294,8 +346,12 @@ memberof_internal_postop_init(Slapi_PBlock *pb)
  */
 int memberof_postop_start(Slapi_PBlock *pb)
 {
-	int rc = 0;
+	Slapi_PBlock *search_pb = NULL;
+	Slapi_Entry **entries = NULL;
 	Slapi_Entry *config_e = NULL; /* entry containing plugin config */
+	char *config_area = NULL;
+	int result = 0;
+	int rc = 0;
 
 	slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
 		"--> memberof_postop_start\n" );
@@ -311,18 +367,53 @@ int memberof_postop_start(Slapi_PBlock *pb)
 		rc = -1;
 		goto bail;
 	}
-
-	if ( slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &config_e ) != 0 ) {
-		slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
-				"missing config entry\n" );
-		rc = -1;
-		goto bail;
+	/* Set the alternate config area if one is defined. */
+	slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_AREA, &config_area);
+	if (config_area)
+	{
+		search_pb = slapi_pblock_new();
+		slapi_search_internal_set_pb(search_pb, config_area, LDAP_SCOPE_BASE, "objectclass=*",
+									 NULL, 0, NULL, NULL, memberof_get_plugin_id(), 0);
+		slapi_search_internal_pb(search_pb);
+		slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+		if (LDAP_SUCCESS != result) {
+			if (result == LDAP_NO_SUCH_OBJECT) {
+				/* log an error and use the plugin entry for the config */
+				slapi_log_error(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM,
+								"memberof_postop_start: Config entry \"%s\" does "
+								"not exist.\n", config_area);
+				rc = -1;
+				goto bail;
+			}
+		} else {
+			slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+			if(entries && entries[0]){
+				config_e = entries[0];
+			} else {
+				slapi_log_error(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM,
+								"memberof_postop_start: Config entry \"%s\" was "
+								"not located.\n", config_area);
+				rc = -1;
+				goto bail;
+			}
+		}
+	} else {
+		/* The plugin entry itself contains the config */
+		if ( slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &config_e ) != 0 ) {
+			slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+							"missing config entry\n" );
+			rc = -1;
+			goto bail;
+		}
 	}
 
+	memberof_set_plugin_area(slapi_entry_get_sdn(config_e));
+	memberof_set_config_area(slapi_entry_get_sdn(config_e));
 	if (( rc = memberof_config( config_e )) != LDAP_SUCCESS ) {
 		slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
 				"configuration failed (%s)\n", ldap_err2string( rc ));
-		return( -1 );
+		rc = -1;
+		goto bail;
 	}
 
 	rc = slapi_task_register_handler("memberof task", memberof_task_add);
@@ -344,6 +435,9 @@ int memberof_postop_start(Slapi_PBlock *pb)
 	 */
 
 bail:
+	slapi_free_search_results_internal(search_pb);
+	slapi_pblock_destroy(search_pb);
+
 	slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
 		"<-- memberof_postop_start\n" );
 
@@ -368,6 +462,32 @@ int memberof_postop_close(Slapi_PBlock *pb)
 	return 0;
 }
 
+void
+memberof_set_config_area(Slapi_DN *dn)
+{
+	slapi_sdn_free(&_ConfigAreaDN);
+	_ConfigAreaDN = slapi_sdn_dup(dn);
+}
+
+Slapi_DN *
+memberof_get_config_area()
+{
+	return _ConfigAreaDN;
+}
+
+void
+memberof_set_plugin_area(Slapi_DN *sdn)
+{
+	slapi_sdn_free(&_pluginDN);
+	_pluginDN = slapi_sdn_dup(sdn);
+}
+
+Slapi_DN *
+memberof_get_plugin_area()
+{
+	return _pluginDN;
+}
+
 /*
  * memberof_postop_del()
  *
@@ -821,6 +941,32 @@ int memberof_postop_modify(Slapi_PBlock *pb)
 		return SLAPI_PLUGIN_SUCCESS;
 	}
 
+	/* check if we are updating the shared config entry */
+	slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
+	if (slapi_sdn_issuffix(sdn, memberof_get_config_area()) &&
+		slapi_sdn_compare(sdn, memberof_get_config_area()) == 0)
+	{
+		Slapi_Entry *entry = NULL;
+		char returntext[SLAPI_DSE_RETURNTEXT_SIZE];
+		int result = 0;
+
+		slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &entry);
+		if(entry){
+			if( SLAPI_DSE_CALLBACK_ERROR == memberof_apply_config (pb, NULL, entry, &result, returntext, NULL)){
+				slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "%s", returntext);
+				ret = SLAPI_PLUGIN_FAILURE;
+				goto done;
+			}
+		} else {
+			/* this should not happen since this was validated in preop */
+			ret = SLAPI_PLUGIN_FAILURE;
+			goto done;
+		}
+		/* we're done, no need to do the other processing */
+		goto done;
+	}
+
+
 	if(memberof_oktodo(pb) && (sdn = memberof_getsdn(pb)))
 	{
 		int config_copied = 0;
@@ -932,6 +1078,7 @@ int memberof_postop_modify(Slapi_PBlock *pb)
 		slapi_mods_free(&smods);
 	}
 
+done:
 	slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
 		     "<-- memberof_postop_modify\n" );
 	return ret;

+ 9 - 0
ldap/servers/plugins/memberof/memberof.h

@@ -63,6 +63,7 @@
  */
 #define MEMBEROF_PLUGIN_SUBSYSTEM   "memberof-plugin"   /* used for logging */
 #define MEMBEROF_INT_PREOP_DESC "memberOf internal postop plugin"
+#define MEMBEROF_PREOP_DESC "memberof preop plugin"
 #define MEMBEROF_GROUP_ATTR "memberOfGroupAttr"
 #define MEMBEROF_ATTR "memberOfAttr"
 #define MEMBEROF_BACKEND_ATTR "memberOfAllBackends"
@@ -95,5 +96,13 @@ void memberof_rlock_config();
 void memberof_wlock_config();
 void memberof_unlock_config();
 int memberof_config_get_all_backends();
+void memberof_set_config_area(Slapi_DN *sdn);
+Slapi_DN * memberof_get_config_area();
+void memberof_set_plugin_area(Slapi_DN *sdn);
+Slapi_DN * memberof_get_plugin_area();
+int memberof_shared_config_validate(Slapi_PBlock *pb);
+int memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+	int *returncode, char *returntext, void *arg);
+void *memberof_get_plugin_id();
 
 #endif	/* _MEMBEROF_H_ */

+ 156 - 11
ldap/servers/plugins/memberof/memberof_config.c

@@ -65,8 +65,6 @@
  */ 
 static int memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, 
 										 int *returncode, char *returntext, void *arg);
-static int memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, 
-										 int *returncode, char *returntext, void *arg);
 static int memberof_search (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, 
 								int *returncode, char *returntext, void *arg)
 {
@@ -117,14 +115,17 @@ memberof_config(Slapi_Entry *config_e)
 
 	/* initialize fields */
 	if (SLAPI_DSE_CALLBACK_OK == memberof_validate_config(NULL, NULL, config_e,
-							&returncode, returntext, NULL)) {
-		memberof_apply_config(NULL, NULL, config_e,
-					&returncode, returntext, NULL);
+							&returncode, returntext, NULL))
+	{
+		memberof_apply_config(NULL, NULL, config_e, &returncode, returntext, NULL);
 	}
 
-	/* config DSE must be initialized before we get here */
+	/*
+	 * config DSE must be initialized before we get here we only need the dse callbacks
+	 * for the plugin entry, but not the shared config entry.
+	 */
 	if (returncode == LDAP_SUCCESS) {
-		const char *config_dn = slapi_entry_get_dn_const(config_e);
+		const char *config_dn = slapi_sdn_get_dn(memberof_get_plugin_area());
 		slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP,
 			config_dn, LDAP_SCOPE_BASE, MEMBEROF_CONFIG_FILTER,
 			memberof_validate_config,NULL);
@@ -164,7 +165,9 @@ memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
 {
 	Slapi_Attr *memberof_attr = NULL;
 	Slapi_Attr *group_attr = NULL;
+	Slapi_DN *config_sdn = NULL;
 	char *syntaxoid = NULL;
+	char *config_dn = NULL;
 	int not_dn_syntax = 0;
 
 	*returncode = LDAP_UNWILLING_TO_PERFORM; /* be pessimistic */
@@ -230,20 +233,54 @@ memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
 					"an attribute defined to use the Distinguished "
 					"Name syntax.  (illegal value: %s)",
 					slapi_value_get_string(value), MEMBEROF_ATTR);
+				goto done;
 			}
 			else
 			{
 				*returncode = LDAP_SUCCESS;
 			}
 		}
-	}
-	else
-	{
+	} else {
 		PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
 			"The %s and %s configuration attributes must be provided",
 			MEMBEROF_GROUP_ATTR, MEMBEROF_ATTR); 
+		goto done;
 	}
 
+	if ((config_dn = slapi_entry_attr_get_charptr(e, SLAPI_PLUGIN_SHARED_CONFIG_AREA))){
+		/* Now check the shared config attribute, validate it now */
+
+		Slapi_Entry *e = NULL;
+		int rc = 0;
+
+		rc = slapi_dn_syntax_check(pb, config_dn, 1);
+		if (rc) { /* syntax check failed */
+			slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_validate_config: "
+					"%s does not contain a valid DN (%s)\n",
+					SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_dn);
+			*returncode = LDAP_INVALID_DN_SYNTAX;
+			goto done;
+		}
+		config_sdn = slapi_sdn_new_dn_byval(config_dn);
+
+		slapi_search_internal_get_entry(config_sdn, NULL, &e, memberof_get_plugin_id());
+		if(e){
+			slapi_entry_free(e);
+			*returncode = LDAP_SUCCESS;
+		} else {
+			/* config area does not exist! */
+			PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+								"The %s configuration attribute points to an entry that  "
+								"can not be found.  (%s)",
+								SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_dn);
+			*returncode = LDAP_UNWILLING_TO_PERFORM;
+		}
+	}
+
+done:
+	slapi_sdn_free(&config_sdn);
+	slapi_ch_free_string(&config_dn);
+
 	if (*returncode != LDAP_SUCCESS)
 	{
 		return SLAPI_DSE_CALLBACK_ERROR;
@@ -261,19 +298,65 @@ memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
  * Apply the pending changes in the e entry to our config struct.
  * memberof_validate_config()  must have already been called.
  */
-static int 
+int
 memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, 
 	int *returncode, char *returntext, void *arg)
 {
+	Slapi_Entry *config_entry = NULL;
+	Slapi_DN *config_sdn = NULL;
 	char **groupattrs = NULL;
 	char *memberof_attr = NULL;
 	char *filter_str = NULL;
 	int num_groupattrs = 0;
 	int groupattr_name_len = 0;
 	char *allBackends = NULL;
+	char *sharedcfg = NULL;
 
 	*returncode = LDAP_SUCCESS;
 
+	/*
+	 * Apply the config settings from the shared config entry
+	 */
+	sharedcfg = slapi_entry_attr_get_charptr(e, SLAPI_PLUGIN_SHARED_CONFIG_AREA);
+	if(sharedcfg){
+		int rc = 0;
+
+		rc = slapi_dn_syntax_check(pb, sharedcfg, 1);
+		if (rc) { /* syntax check failed */
+			slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,"memberof_apply_config: "
+					"%s does not contain a valid DN (%s)\n",
+					SLAPI_PLUGIN_SHARED_CONFIG_AREA, sharedcfg);
+			*returncode = LDAP_INVALID_DN_SYNTAX;
+			goto done;
+		}
+		if((config_sdn = slapi_sdn_new_dn_byval(sharedcfg))){
+			slapi_search_internal_get_entry(config_sdn, NULL, &config_entry, memberof_get_plugin_id());
+			if(config_entry){
+				char errtext[SLAPI_DSE_RETURNTEXT_SIZE];
+				int err = 0;
+				/*
+				 * If we got here, we are updating the shared config area, so we need to
+				 * validate and apply the settings from that config area.
+				 */
+				if ( SLAPI_DSE_CALLBACK_ERROR == memberof_validate_config (pb, NULL, config_entry, &err, errtext,0))
+				{
+					slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+									"%s", errtext);
+					*returncode = LDAP_UNWILLING_TO_PERFORM;
+					goto done;
+
+				}
+				e = config_entry;
+			} else {
+				/* this should of been checked in preop validation */
+				slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_apply_config: "
+						"Failed to locate shared config entry (%s)\n",sharedcfg);
+				*returncode = LDAP_UNWILLING_TO_PERFORM;
+				goto done;
+			}
+		}
+	}
+
 	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);
@@ -389,6 +472,13 @@ memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
 	/* release the lock */
 	memberof_unlock_config();
 
+done:
+	slapi_ch_free_string(&sharedcfg);
+	slapi_sdn_free(&config_sdn);
+	if(config_entry){
+		/* we switched the entry pointer to the shared config entry - which needs to be freed */
+		slapi_entry_free(e);
+	}
 	slapi_ch_array_free(groupattrs);
 	slapi_ch_free_string(&memberof_attr);
 	slapi_ch_free_string(&allBackends);
@@ -557,3 +647,58 @@ memberof_config_get_all_backends()
 
 	return all_backends;
 }
+
+/*
+ * Check if we are modifying the config, or changing the shared config entry
+ */
+int
+memberof_shared_config_validate(Slapi_PBlock *pb)
+{
+	Slapi_Entry *e = 0;
+	Slapi_DN *sdn = 0;
+	Slapi_Mods *smods = 0;
+	LDAPMod **mods = NULL;
+	char returntext[SLAPI_DSE_RETURNTEXT_SIZE];
+	int ret = SLAPI_PLUGIN_SUCCESS;
+
+	slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
+
+   	if (slapi_sdn_issuffix(sdn, memberof_get_config_area()) &&
+   	    slapi_sdn_compare(sdn, memberof_get_config_area()) == 0)
+   	{
+   		/*
+   		 * This is the shared config entry.  Apply the mods and set/validate
+   		 * the config
+   		 */
+		int result = 0;
+
+		slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
+		if(e){
+			slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+			smods = slapi_mods_new();
+			slapi_mods_init_byref(smods, mods);
+
+			/* Apply the mods to create the resulting entry. */
+			if (mods && (slapi_entry_apply_mods(e, mods) != LDAP_SUCCESS)) {
+				/* we don't care about this, the update is invalid and will be caught later */
+				goto bail;
+			}
+
+			if ( SLAPI_DSE_CALLBACK_ERROR == memberof_validate_config (pb, NULL, e, &ret, returntext,0)) {
+				slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+								"%s", returntext);
+				ret = LDAP_UNWILLING_TO_PERFORM;
+			}
+		} else {
+			slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_shared_config_validate: "
+											"Unable to locate shared config entry (%s) error %d\n",
+											slapi_sdn_get_dn(memberof_get_config_area()), result);
+			ret = LDAP_UNWILLING_TO_PERFORM;
+		}
+   	}
+
+bail:
+	slapi_entry_free(e);
+
+	return ret;
+}

+ 3 - 0
ldap/servers/slapd/slapi-plugin.h

@@ -479,6 +479,9 @@ NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...)
 #define SLAPI_ATTR_ENTRYUSN 			"entryusn"
 #define SLAPI_ATTR_ENTRYDN 				"entrydn"
 
+/* plugin shared config area */
+#define SLAPI_PLUGIN_SHARED_CONFIG_AREA "nsslapd-pluginConfigArea"
+
 
 /* opaque structures */
 /**