Branch '389-ds-base-1.3.3' - ldap/servers
by Mark Reynolds
ldap/servers/plugins/memberof/memberof.c | 217 +++++++++++++-------
ldap/servers/plugins/memberof/memberof.h | 8
ldap/servers/plugins/memberof/memberof_config.c | 249 +++++++++++++++++-------
ldap/servers/plugins/retrocl/retrocl.c | 183 +++++++++++++++--
ldap/servers/plugins/retrocl/retrocl.h | 4
ldap/servers/plugins/retrocl/retrocl_po.c | 41 +++
6 files changed, 516 insertions(+), 186 deletions(-)
New commits:
commit f86dab3bc94482df4f6850ea6a9a90371c1cfc03
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Tue Aug 4 12:19:31 2015 -0400
Ticket 47931 - memberOf & retrocl deadlocks
Bug Description: When concurrently updating multiple backends the
memberOf and retrocl plugins can deadlock on each
other. This is caused by the required retrocl lock,
and the db lock on the changenumber index in the
retrocl db.
Fix Description: Added scoping to the retrocl that allows subtrees/suffixes
to be included or excluded. Also moved the existing
memberOf scoping outside of its global lock.
Also improved the memberOf config copying to be consistent
and more efficient. Improved the memberOf scoping attributes
to be multivalued. And, properly valdiated new config
settings in the preop valdiation function, instead of the
"apply config" function.
https://fedorahosted.org/389/ticket/47931
Valgrind: passed
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit fd959ac864d6d86d24928bc2c6f097d1a6031ecd)
(cherry picked from commit d8108476d3bedbcc03f6c61bfb3d50e921faaf42)
diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
index 32af605..723f291 100644
--- a/ldap/servers/plugins/memberof/memberof.c
+++ b/ldap/servers/plugins/memberof/memberof.c
@@ -148,7 +148,7 @@ 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);
static int memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_DN *sdn);
-static int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
+static int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn, MemberOfConfig *config,
char **types, plugin_search_entry_callback callback, void *callback_data);
static int memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn,
Slapi_Value *memberdn);
@@ -176,7 +176,7 @@ static const char *fetch_attr(Slapi_Entry *e, const char *attrname,
static void memberof_fixup_task_thread(void *arg);
static int memberof_fix_memberof(MemberOfConfig *config, char *dn, char *filter_str);
static int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data);
-
+static int memberof_entry_in_scope(MemberOfConfig *config, Slapi_DN *sdn);
/*** implementation ***/
@@ -521,7 +521,8 @@ memberof_get_plugin_area()
int memberof_postop_del(Slapi_PBlock *pb)
{
int ret = SLAPI_PLUGIN_SUCCESS;
- MemberOfConfig configCopy = {0, 0, 0, 0};
+ MemberOfConfig *mainConfig = NULL;
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Slapi_DN *sdn;
void *caller_id = NULL;
@@ -541,12 +542,13 @@ int memberof_postop_del(Slapi_PBlock *pb)
struct slapi_entry *e = NULL;
slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &e );
-
- /* We need to get the config lock first. Trying to get the
- * config lock after we already hold the op lock can cause
- * a deadlock. */
memberof_rlock_config();
- /* copy config so it doesn't change out from under us */
+ mainConfig = memberof_get_config();
+ if(!memberof_entry_in_scope(mainConfig, slapi_entry_get_sdn(e))){
+ /* The entry is not in scope, bail...*/
+ memberof_unlock_config();
+ goto bail;
+ }
memberof_copy_config(&configCopy, memberof_get_config());
memberof_unlock_config();
@@ -561,7 +563,6 @@ int memberof_postop_del(Slapi_PBlock *pb)
"memberof_postop_del: error deleting dn (%s) from group. Error (%d)\n",
slapi_sdn_get_dn(sdn),ret);
memberof_unlock();
- memberof_free_config(&configCopy);
goto bail;
}
@@ -586,10 +587,10 @@ int memberof_postop_del(Slapi_PBlock *pb)
}
}
memberof_unlock();
+bail:
memberof_free_config(&configCopy);
}
-bail:
if(ret){
slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
ret = SLAPI_PLUGIN_FAILURE;
@@ -623,7 +624,7 @@ memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_DN *
groupattrs[0] = config->groupattrs[i];
- rc = memberof_call_foreach_dn(pb, sdn, groupattrs,
+ rc = memberof_call_foreach_dn(pb, sdn, config, groupattrs,
memberof_del_dn_type_callback, &data);
}
@@ -673,6 +674,20 @@ memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data)
return rc;
}
+/* Check if the the entry include scope is a child of the sdn */
+static Slapi_DN*
+memberof_scope_is_child_of_dn(MemberOfConfig *config, Slapi_DN *sdn)
+{
+ int i = 0;
+
+ while(config->entryScopes && config->entryScopes[i]){
+ if(slapi_sdn_issuffix(config->entryScopes[i], sdn)){
+ return config->entryScopes[i];
+ }
+ i++;
+ }
+ return NULL;
+}
/*
* Does a callback search of "type=dn" under the db suffix that "dn" is in,
* unless all_backends is set, then we look at all the backends. If "dn"
@@ -681,7 +696,7 @@ memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data)
*/
int
memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
- char **types, plugin_search_entry_callback callback, void *callback_data)
+ MemberOfConfig *config, char **types, plugin_search_entry_callback callback, void *callback_data)
{
Slapi_PBlock *search_pb = NULL;
Slapi_DN *base_sdn = NULL;
@@ -689,9 +704,7 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
char *escaped_filter_val;
char *filter_str = NULL;
char *cookie = NULL;
- int all_backends = memberof_config_get_all_backends();
- Slapi_DN *entry_scope = memberof_config_get_entry_scope();
- Slapi_DN *entry_scope_exclude_subtree = memberof_config_get_entry_scope_exclude_subtree();
+ int all_backends = config->allBackends;
int types_name_len = 0;
int num_types = 0;
int dn_len = slapi_sdn_get_ndn_len(sdn);
@@ -699,11 +712,7 @@ 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);
- }
-
- if (entry_scope_exclude_subtree && slapi_sdn_issuffix(sdn, entry_scope_exclude_subtree)) {
+ if (!memberof_entry_in_scope(config, sdn)) {
return (rc);
}
@@ -760,6 +769,8 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
search_pb = slapi_pblock_new();
be = slapi_get_first_backend(&cookie);
while(be){
+ Slapi_DN *scope_sdn = NULL;
+
if(!all_backends){
be = slapi_be_select(sdn);
if(be == NULL){
@@ -775,13 +786,14 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
continue;
}
}
- if (entry_scope) {
- if (slapi_sdn_issuffix(base_sdn, entry_scope)) {
+
+ if (config->entryScopes || config->entryScopeExcludeSubtrees) {
+ if (memberof_entry_in_scope(config, base_sdn)) {
/* do nothing, entry scope is spanning
* multiple suffixes, start at suffix */
- } else if (slapi_sdn_issuffix(entry_scope, base_sdn)) {
+ } else if ((scope_sdn = memberof_scope_is_child_of_dn(config, base_sdn))) {
/* scope is below suffix, set search base */
- base_sdn = entry_scope;
+ base_sdn = scope_sdn;
} else if(!all_backends){
break;
} else {
@@ -799,7 +811,6 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
break;
}
-
if(!all_backends){
break;
}
@@ -824,10 +835,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
{
int ret = SLAPI_PLUGIN_SUCCESS;
void *caller_id = NULL;
- Slapi_DN *entry_scope = NULL;
- Slapi_DN *entry_scope_exclude_subtree = memberof_config_get_entry_scope_exclude_subtree();
- entry_scope = memberof_config_get_entry_scope();
slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
"--> memberof_postop_modrdn\n" );
@@ -842,7 +850,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
if(memberof_oktodo(pb))
{
MemberOfConfig *mainConfig = 0;
- MemberOfConfig configCopy = {0, 0, 0, 0};
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
struct slapi_entry *pre_e = NULL;
struct slapi_entry *post_e = NULL;
Slapi_DN *pre_sdn = 0;
@@ -850,7 +858,6 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &pre_e );
slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &post_e );
-
if(pre_e && post_e)
{
pre_sdn = slapi_entry_get_sdn(pre_e);
@@ -863,11 +870,19 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
memberof_copy_config(&configCopy, mainConfig);
memberof_unlock_config();
+ /* Need to check both the pre/post entries */
+ if((pre_sdn && !memberof_entry_in_scope(&configCopy, pre_sdn)) &&
+ (post_sdn && !memberof_entry_in_scope(&configCopy, post_sdn)))
+ {
+ /* The entry is not in scope */
+ goto bail;
+ }
+
memberof_lock();
/* update any downstream members */
if(pre_sdn && post_sdn && configCopy.group_filter &&
- 0 == slapi_filter_test_simple(post_e, configCopy.group_filter))
+ 0 == slapi_filter_test_simple(post_e, configCopy.group_filter))
{
int i = 0;
Slapi_Attr *attr = 0;
@@ -879,7 +894,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
if(0 == slapi_entry_attr_find(post_e, configCopy.groupattrs[i], &attr))
{
if((ret = memberof_moddn_attr_list(pb, &configCopy, pre_sdn,
- post_sdn, attr) != 0))
+ post_sdn, attr) != 0))
{
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
"memberof_postop_modrdn - update failed for (%s), error (%d)\n",
@@ -894,49 +909,49 @@ 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 (ret == LDAP_SUCCESS && pre_sdn && post_sdn) {
- if ((entry_scope && !slapi_sdn_issuffix(post_sdn, entry_scope)) ||
- (entry_scope_exclude_subtree && slapi_sdn_issuffix(post_sdn, entry_scope_exclude_subtree))) {
+ if (!memberof_entry_in_scope(&configCopy, post_sdn)){
if((ret = memberof_del_dn_from_groups(pb, &configCopy, pre_sdn))){
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
"memberof_postop_modrdn - delete dn failed for (%s), error (%d)\n",
slapi_sdn_get_dn(pre_sdn), ret);
}
if(ret == LDAP_SUCCESS && pre_e && configCopy.group_filter &&
- 0 == slapi_filter_test_simple(pre_e, configCopy.group_filter)) {
+ 0 == slapi_filter_test_simple(pre_e, configCopy.group_filter))
+ {
/* is the entry of interest as a group? */
- int i = 0;
- Slapi_Attr *attr = 0;
-
- /* Loop through to find each grouping attribute separately. */
- for (i = 0; configCopy.groupattrs[i] && ret == LDAP_SUCCESS; i++) {
- if (0 == slapi_entry_attr_find(pre_e, configCopy.groupattrs[i], &attr)) {
- if((ret = memberof_del_attr_list(pb, &configCopy, pre_sdn, attr))){
- slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "memberof_postop_modrdn: error deleting attr list - dn (%s). Error (%d)\n",
- slapi_sdn_get_dn(pre_sdn),ret);
- }
+ int i = 0;
+ Slapi_Attr *attr = 0;
+ /* Loop through to find each grouping attribute separately. */
+ for (i = 0; configCopy.groupattrs[i] && ret == LDAP_SUCCESS; i++) {
+ if (0 == slapi_entry_attr_find(pre_e, configCopy.groupattrs[i], &attr)) {
+ if((ret = memberof_del_attr_list(pb, &configCopy, pre_sdn, attr))){
+ slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+ "memberof_postop_modrdn: error deleting attr list - dn (%s). Error (%d)\n",
+ slapi_sdn_get_dn(pre_sdn),ret);
}
+
}
- }
+ }
+ }
if(ret == LDAP_SUCCESS) {
- memberof_del_dn_data del_data = {0, configCopy.memberof_attr};
- if((ret = memberof_del_dn_type_callback(post_e, &del_data))){
- slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "memberof_postop_modrdn - delete dn callback failed for (%s), error (%d)\n",
- slapi_entry_get_dn(post_e), ret);
- }
+ memberof_del_dn_data del_data = {0, configCopy.memberof_attr};
+ if((ret = memberof_del_dn_type_callback(post_e, &del_data))){
+ slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+ "memberof_postop_modrdn - delete dn callback failed for (%s), error (%d)\n",
+ slapi_entry_get_dn(post_e), ret);
}
+ }
} else {
if((ret = memberof_replace_dn_from_groups(pb, &configCopy, pre_sdn, post_sdn))){
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "memberof_postop_modrdn - replace dne failed for (%s), error (%d)\n",
+ "memberof_postop_modrdn - replace dn failed for (%s), error (%d)\n",
slapi_sdn_get_dn(pre_sdn), ret);
}
}
}
-
memberof_unlock();
+bail:
memberof_free_config(&configCopy);
}
@@ -978,7 +993,7 @@ memberof_replace_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config,
groupattrs[0] = config->groupattrs[i];
- if((ret = memberof_call_foreach_dn(pb, pre_sdn, groupattrs,
+ if((ret = memberof_call_foreach_dn(pb, pre_sdn, config, groupattrs,
memberof_replace_dn_type_callback,
&data)))
{
@@ -1096,12 +1111,11 @@ int memberof_postop_modify(Slapi_PBlock *pb)
goto done;
}
-
- if(memberof_oktodo(pb) && (sdn = memberof_getsdn(pb)))
+ if(memberof_oktodo(pb))
{
int config_copied = 0;
MemberOfConfig *mainConfig = 0;
- MemberOfConfig configCopy = {0, 0, 0, 0};
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* get the mod set */
slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
@@ -1120,19 +1134,22 @@ int memberof_postop_modify(Slapi_PBlock *pb)
* only copy the config the first time it's needed so
* it remains the same for all mods in the operation,
* despite any config changes that may be made. */
- if (!config_copied)
- {
+ if (!config_copied){
memberof_rlock_config();
mainConfig = memberof_get_config();
if (memberof_is_grouping_attr(type, mainConfig))
{
interested = 1;
+ if (!memberof_entry_in_scope(mainConfig, sdn)){
+ /* Entry is not in scope */
+ memberof_unlock_config();
+ goto bail;
+ }
/* copy config so it doesn't change out from under us */
memberof_copy_config(&configCopy, mainConfig);
config_copied = 1;
}
-
memberof_unlock_config();
} else {
if (memberof_is_grouping_attr(type, &configCopy))
@@ -1229,8 +1246,7 @@ int memberof_postop_modify(Slapi_PBlock *pb)
}
bail:
- if (config_copied)
- {
+ if (config_copied){
memberof_free_config(&configCopy);
}
@@ -1276,22 +1292,25 @@ int memberof_postop_add(Slapi_PBlock *pb)
if(memberof_oktodo(pb) && (sdn = memberof_getsdn(pb)))
{
- MemberOfConfig *mainConfig = 0;
- MemberOfConfig configCopy = {0, 0, 0, 0};
struct slapi_entry *e = NULL;
-
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ MemberOfConfig *mainConfig;
slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &e );
-
/* is the entry of interest? */
memberof_rlock_config();
mainConfig = memberof_get_config();
if(e && mainConfig && mainConfig->group_filter &&
0 == slapi_filter_test_simple(e, mainConfig->group_filter))
+
{
interested = 1;
- /* copy config so it doesn't change out from under us */
- memberof_copy_config(&configCopy, mainConfig);
+ if(!memberof_entry_in_scope(mainConfig, slapi_entry_get_sdn(e))){
+ /* Entry is not in scope */
+ memberof_unlock_config();
+ goto bail;
+ }
+ memberof_copy_config(&configCopy, memberof_get_config());
}
memberof_unlock_config();
@@ -1316,11 +1335,11 @@ int memberof_postop_add(Slapi_PBlock *pb)
}
memberof_unlock();
-
memberof_free_config(&configCopy);
}
}
+bail:
if(ret){
slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
ret = SLAPI_PLUGIN_FAILURE;
@@ -1358,26 +1377,61 @@ int memberof_oktodo(Slapi_PBlock *pb)
}
if(slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
- {
+ {
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
"memberof_postop_oktodo: could not get parameters\n" );
ret = -1;
}
- /* this plugin should only execute if the operation succeeded
- */
- if(oprc != 0)
+ /* this plugin should only execute if the operation succeeded */
+ if(oprc != 0)
{
ret = 0;
}
-
+
+bail:
slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
"<-- memberof_postop_oktodo\n" );
-bail:
return ret;
}
+/*
+ * Return 1 if the entry is in the scope.
+ * For MODRDN the caller should check both the preop
+ * and postop entries. If we are moving out of, or
+ * into scope, we should process it.
+ */
+static int
+memberof_entry_in_scope(MemberOfConfig *config, Slapi_DN *sdn)
+{
+ if (config->entryScopeExcludeSubtrees){
+ int i = 0;
+
+ /* check the excludes */
+ while(config->entryScopeExcludeSubtrees[i]){
+ if (slapi_sdn_issuffix(sdn, config->entryScopeExcludeSubtrees[i])){
+ return 0;
+ }
+ i++;
+ }
+ }
+ if (config->entryScopes){
+ int i = 0;
+
+ /* check the excludes */
+ while(config->entryScopes[i]){
+ if (slapi_sdn_issuffix(sdn, config->entryScopes[i])){
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
static Slapi_DN *
memberof_getsdn(Slapi_PBlock *pb)
{
@@ -2045,7 +2099,7 @@ memberof_get_groups_r(MemberOfConfig *config, Slapi_DN *member_sdn,
{
/* Search for any grouping attributes that point to memberdn.
* For each match, add it to the list, recurse and do same search */
- return memberof_call_foreach_dn(NULL, member_sdn, config->groupattrs,
+ return memberof_call_foreach_dn(NULL, member_sdn, config, config->groupattrs,
memberof_get_groups_callback, data);
}
@@ -2062,7 +2116,6 @@ int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data)
Slapi_Value *group_dn_val = 0;
Slapi_ValueSet *groupvals = *((memberof_get_groups_data*)callback_data)->groupvals;
Slapi_ValueSet *group_norm_vals = *((memberof_get_groups_data*)callback_data)->group_norm_vals;
- Slapi_DN *entry_scope_exclude_subtree = memberof_config_get_entry_scope_exclude_subtree();
MemberOfConfig *config = ((memberof_get_groups_data*)callback_data)->config;
int rc = 0;
@@ -2118,7 +2171,7 @@ int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data)
}
/* if the group does not belong to an excluded subtree, adds it to the valueset */
- if (!(entry_scope_exclude_subtree && slapi_sdn_issuffix(group_sdn, entry_scope_exclude_subtree))) {
+ if (memberof_entry_in_scope(config, group_sdn)) {
/* Push group_dn_val into the valueset. This memory is now owned
* by the valueset. */
group_dn_val = slapi_value_new_string(group_dn);
@@ -2220,8 +2273,8 @@ memberof_test_membership(Slapi_PBlock *pb, MemberOfConfig *config,
{
char *attrs[2] = {config->memberof_attr, 0};
- return memberof_call_foreach_dn(pb, group_sdn, attrs,
- memberof_test_membership_callback , config);
+ return memberof_call_foreach_dn(pb, group_sdn, config, attrs,
+ memberof_test_membership_callback, config);
}
/*
diff --git a/ldap/servers/plugins/memberof/memberof.h b/ldap/servers/plugins/memberof/memberof.h
index a067e6d..d7849c9 100644
--- a/ldap/servers/plugins/memberof/memberof.h
+++ b/ldap/servers/plugins/memberof/memberof.h
@@ -81,8 +81,10 @@ typedef struct memberofconfig {
char **groupattrs;
char *memberof_attr;
int allBackends;
- Slapi_DN *entryScope;
- Slapi_DN *entryScopeExcludeSubtree;
+ Slapi_DN **entryScopes;
+ int entryScopeCount;
+ Slapi_DN **entryScopeExcludeSubtrees;
+ int entryExcludeScopeCount;
Slapi_Filter *group_filter;
Slapi_Attr **group_slapiattrs;
int skip_nested;
@@ -103,8 +105,6 @@ 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();
-Slapi_DN * memberof_config_get_entry_scope_exclude_subtree();
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 7fa5897..9db3b39 100644
--- a/ldap/servers/plugins/memberof/memberof_config.c
+++ b/ldap/servers/plugins/memberof/memberof_config.c
@@ -77,7 +77,7 @@ static int memberof_search (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_En
/* This is the main configuration which is updated from dse.ldif. The
* config will be copied when it is used by the plug-in to prevent it
* being changed out from under a running memberOf operation. */
-static MemberOfConfig theConfig = {NULL, NULL,0, NULL, NULL, NULL, NULL};
+static MemberOfConfig theConfig = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static Slapi_RWLock *memberof_config_lock = 0;
static int inited = 0;
@@ -89,6 +89,19 @@ static int dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Ent
return SLAPI_DSE_CALLBACK_ERROR;
}
+static void
+memberof_free_scope(Slapi_DN **scopes, int *count)
+{
+ int i = 0;
+
+ while(scopes && scopes[i]){
+ slapi_sdn_free(&scopes[i]);
+ i++;
+ }
+ slapi_ch_free((void**)&scopes);
+ *count = 0;
+}
+
/*
* memberof_config()
*
@@ -184,17 +197,22 @@ memberof_release_config()
*
* Validate the pending changes in the e entry.
*/
-static int
+int
memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
int *returncode, char *returntext, void *arg)
{
Slapi_Attr *memberof_attr = NULL;
Slapi_Attr *group_attr = NULL;
Slapi_DN *config_sdn = NULL;
+ Slapi_DN **include_dn = NULL;
+ Slapi_DN **exclude_dn = NULL;
char *syntaxoid = NULL;
char *config_dn = NULL;
char *skip_nested = NULL;
+ char **entry_scopes = NULL;
+ char **entry_exclude_scopes = NULL;
int not_dn_syntax = 0;
+ int num_vals = 0;
*returncode = LDAP_UNWILLING_TO_PERFORM; /* be pessimistic */
@@ -312,8 +330,112 @@ memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
*returncode = LDAP_UNWILLING_TO_PERFORM;
}
}
+ /*
+ * Check the entry scopes
+ */
+ entry_scopes = slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_ATTR, &num_vals);
+ if(entry_scopes){
+ int i = 0;
+
+ /* Validate the syntax before we create our DN array */
+ for (i = 0;i < num_vals; i++){
+ if(slapi_dn_syntax_check(pb, entry_scopes[i], 1)){
+ /* invalid dn syntax */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: Invalid DN (%s) for include suffix.",
+ MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]);
+ slapi_ch_array_free(entry_scopes);
+ theConfig.entryScopeCount = 0;
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ }
+ /* Now create our SDN array for conflict checking */
+ include_dn = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *), num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ include_dn[i] = slapi_sdn_new_dn_passin(entry_scopes[i]);
+ }
+ }
+ /*
+ * Check and process the entry exclude scopes
+ */
+ entry_exclude_scopes =
+ slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE, &num_vals);
+ if(entry_exclude_scopes){
+ int i = 0;
+
+ /* Validate the syntax before we create our DN array */
+ for (i = 0;i < num_vals; i++){
+ if(slapi_dn_syntax_check(pb, entry_exclude_scopes[i], 1)){
+ /* invalid dn syntax */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: Invalid DN (%s) for exclude suffix.",
+ MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]);
+ slapi_ch_array_free(entry_exclude_scopes);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ }
+ /* Now create our SDN array for conflict checking */
+ exclude_dn = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ exclude_dn[i] = slapi_sdn_new_dn_passin(entry_exclude_scopes[i]);
+ }
+ }
+ /*
+ * Need to do conflict checking
+ */
+ if(include_dn && exclude_dn){
+ /*
+ * Make sure we haven't mixed the same suffix, and there are no
+ * conflicts between the includes and excludes
+ */
+ int i = 0;
+
+ while(include_dn[i]){
+ int x = 0;
+ while(exclude_dn[x]){
+ if(slapi_sdn_compare(include_dn[i], exclude_dn[x] ) == 0)
+ {
+ /* we have a conflict */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: include suffix (%s) is also listed as an exclude suffix list",
+ MEMBEROF_PLUGIN_SUBSYSTEM, slapi_sdn_get_dn(include_dn[i]));
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ x++;
+ }
+ i++;
+ }
+
+ /* Check for parent/child conflicts */
+ i = 0;
+ while(include_dn[i]){
+ int x = 0;
+ while(exclude_dn[x]){
+ if(slapi_sdn_issuffix(include_dn[i], exclude_dn[x]))
+ {
+ /* we have a conflict */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: include suffix (%s) is a child of the exclude suffix(%s)",
+ MEMBEROF_PLUGIN_SUBSYSTEM,
+ slapi_sdn_get_dn(include_dn[i]),
+ slapi_sdn_get_dn(exclude_dn[i]));
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ x++;
+ }
+ i++;
+ }
+ }
done:
+ memberof_free_scope(exclude_dn, &num_vals);
+ memberof_free_scope(include_dn, &num_vals);
+ slapi_ch_free((void**)&entry_scopes);
+ slapi_ch_free((void**)&entry_exclude_scopes);
slapi_sdn_free(&config_sdn);
slapi_ch_free_string(&config_dn);
slapi_ch_free_string(&skip_nested);
@@ -328,7 +450,6 @@ done:
}
}
-
/*
* memberof_apply_config()
*
@@ -347,10 +468,11 @@ 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 *entryScopeExcludeSubtree = NULL;
+ char **entryScopes = NULL;
+ char **entryScopeExcludeSubtrees = NULL;
char *sharedcfg = NULL;
char *skip_nested = NULL;
+ int num_vals = 0;
*returncode = LDAP_SUCCESS;
@@ -382,8 +504,6 @@ 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);
- entryScopeExcludeSubtree = slapi_entry_attr_get_charptr(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE);
skip_nested = slapi_entry_attr_get_charptr(e, MEMBEROF_SKIP_NESTED_ATTR);
/*
@@ -509,49 +629,39 @@ memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
theConfig.allBackends = 0;
}
- slapi_sdn_free(&theConfig.entryScope);
- 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_passin(entryScope);
+ /*
+ * Check and process the entry scopes
+ */
+ memberof_free_scope(theConfig.entryScopes, &theConfig.entryScopeCount);
+ entryScopes = slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_ATTR, &num_vals);
+ if(entryScopes){
+ int i = 0;
+
+ /* Validation has already been performed in preop, just build the DN's */
+ theConfig.entryScopes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *), num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ theConfig.entryScopes[i] = slapi_sdn_new_dn_passin(entryScopes[i]);
}
- } else {
- theConfig.entryScope = NULL;
+ theConfig.entryScopeCount = num_vals; /* shortcut for config copy */
}
-
- slapi_sdn_free(&theConfig.entryScopeExcludeSubtree);
- if (entryScopeExcludeSubtree)
- {
- if (theConfig.entryScope == NULL) {
- slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "Error: Ignoring ExcludeSubtree (%s) because entryScope is not define\n",
- entryScopeExcludeSubtree);
- theConfig.entryScopeExcludeSubtree = NULL;
- slapi_ch_free_string(&entryScopeExcludeSubtree);
- } else if (slapi_dn_syntax_check(NULL, entryScopeExcludeSubtree, 1) == 1) {
- slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "Error: Ignoring invalid DN used as plugin entry exclude subtree: [%s]\n",
- entryScopeExcludeSubtree);
- theConfig.entryScopeExcludeSubtree = NULL;
- slapi_ch_free_string(&entryScopeExcludeSubtree);
- } else {
- theConfig.entryScopeExcludeSubtree = slapi_sdn_new_dn_passin(entryScopeExcludeSubtree);
+ /*
+ * Check and process the entry exclude scopes
+ */
+ memberof_free_scope(theConfig.entryScopeExcludeSubtrees,
+ &theConfig.entryExcludeScopeCount);
+ entryScopeExcludeSubtrees =
+ slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE, &num_vals);
+ if(entryScopeExcludeSubtrees){
+ int i = 0;
+
+ /* Validation has already been performed in preop, just build the DN's */
+ theConfig.entryScopeExcludeSubtrees =
+ (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ theConfig.entryScopeExcludeSubtrees[i] =
+ slapi_sdn_new_dn_passin(entryScopeExcludeSubtrees[i]);
}
- } else {
- theConfig.entryScopeExcludeSubtree = NULL;
- }
- if (theConfig.entryScopeExcludeSubtree && theConfig.entryScope && !slapi_sdn_issuffix(theConfig.entryScopeExcludeSubtree, theConfig.entryScope)) {
- slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "Error: Ignoring ExcludeSubtree (%s) that is out of the scope (%s)\n",
- slapi_sdn_get_dn(theConfig.entryScopeExcludeSubtree),
- slapi_sdn_get_dn(theConfig.entryScope));
- slapi_sdn_free(&theConfig.entryScopeExcludeSubtree);
+ theConfig.entryExcludeScopeCount = num_vals; /* shortcut for config copy */
}
/* release the lock */
@@ -565,6 +675,8 @@ done:
slapi_ch_free_string(&memberof_attr);
slapi_ch_free_string(&allBackends);
slapi_ch_free_string(&skip_nested);
+ slapi_ch_free((void **)&entryScopes);
+ slapi_ch_free((void **)&entryScopeExcludeSubtrees);
if (*returncode != LDAP_SUCCESS)
{
@@ -645,6 +757,23 @@ memberof_copy_config(MemberOfConfig *dest, MemberOfConfig *src)
{
dest->allBackends = src->allBackends;
}
+
+ if(src->entryScopes){
+ int num_vals = 0;
+
+ dest->entryScopes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),src->entryScopeCount+1);
+ for(num_vals = 0; src->entryScopes[num_vals]; num_vals++){
+ dest->entryScopes[num_vals] = slapi_sdn_dup(src->entryScopes[num_vals]);
+ }
+ }
+ if(src->entryScopeExcludeSubtrees){
+ int num_vals = 0;
+
+ dest->entryScopeExcludeSubtrees = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),src->entryExcludeScopeCount+1);
+ for(num_vals = 0; src->entryScopes[num_vals]; num_vals++){
+ dest->entryScopeExcludeSubtrees[num_vals] = slapi_sdn_dup(src->entryScopeExcludeSubtrees[num_vals]);
+ }
+ }
}
}
@@ -670,6 +799,8 @@ memberof_free_config(MemberOfConfig *config)
slapi_ch_free((void **)&config->group_slapiattrs);
slapi_ch_free_string(&config->memberof_attr);
+ memberof_free_scope(config->entryScopes, &config->entryScopeCount);
+ memberof_free_scope(config->entryScopeExcludeSubtrees, &config->entryExcludeScopeCount);
}
}
@@ -735,30 +866,6 @@ 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;
-}
-
-Slapi_DN *
-memberof_config_get_entry_scope_exclude_subtree()
-{
- Slapi_DN *entry_exclude_subtree;
-
- slapi_rwlock_rdlock(memberof_config_lock);
- entry_exclude_subtree = theConfig.entryScopeExcludeSubtree;
- slapi_rwlock_unlock(memberof_config_lock);
-
- return entry_exclude_subtree;
-}
-
/*
* Check if we are modifying the config, or changing the shared config entry
*/
diff --git a/ldap/servers/plugins/retrocl/retrocl.c b/ldap/servers/plugins/retrocl/retrocl.c
index 8a0f350..7679c29 100644
--- a/ldap/servers/plugins/retrocl/retrocl.c
+++ b/ldap/servers/plugins/retrocl/retrocl.c
@@ -82,6 +82,9 @@ char **retrocl_attributes = NULL;
char **retrocl_aliases = NULL;
int retrocl_log_deleted = 0;
+static Slapi_DN **retrocl_includes = NULL;
+static Slapi_DN **retrocl_excludes = NULL;
+
/* ----------------------------- Retrocl Plugin */
static Slapi_PluginDesc retrocldesc = {"retrocl", VENDOR, DS_PACKAGE_VERSION, "Retrocl Plugin"};
@@ -386,6 +389,8 @@ static int retrocl_start (Slapi_PBlock *pb)
int rc = 0;
Slapi_Entry *e = NULL;
char **values = NULL;
+ int num_vals = 0;
+ int i = 0;
retrocl_rootdse_init(pb);
@@ -406,6 +411,87 @@ static int retrocl_start (Slapi_PBlock *pb)
return -1;
}
+ /* Get the exclude suffixes */
+ values = slapi_entry_attr_get_charray_ext(e, CONFIG_CHANGELOG_EXCLUDE_SUFFIX, &num_vals);
+ if(values){
+ /* Validate the syntax before we create our DN array */
+ for (i = 0;i < num_vals; i++){
+ if(slapi_dn_syntax_check(pb, values[i], 1)){
+ /* invalid dn syntax */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "Invalid DN (%s) for exclude suffix.\n", values[i] );
+ slapi_ch_array_free(values);
+ return -1;
+ }
+ }
+ /* Now create our SDN array */
+ retrocl_excludes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ retrocl_excludes[i] = slapi_sdn_new_dn_byval(values[i]);
+ }
+ slapi_ch_array_free(values);
+ }
+ /* Get the include suffixes */
+ values = slapi_entry_attr_get_charray_ext(e, CONFIG_CHANGELOG_INCLUDE_SUFFIX, &num_vals);
+ if(values){
+ for (i = 0;i < num_vals; i++){
+ /* Validate the syntax before we create our DN array */
+ if(slapi_dn_syntax_check(pb, values[i], 1)){
+ /* invalid dn syntax */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "Invalid DN (%s) for include suffix.\n", values[i] );
+ slapi_ch_array_free(values);
+ return -1;
+ }
+ }
+ /* Now create our SDN array */
+ retrocl_includes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ retrocl_includes[i] = slapi_sdn_new_dn_byval(values[i]);
+ }
+ slapi_ch_array_free(values);
+ }
+ if(retrocl_includes && retrocl_excludes){
+ /*
+ * Make sure we haven't mixed the same suffix, and there are no
+ * conflicts between the includes and excludes
+ */
+ int i = 0;
+
+ while(retrocl_includes[i]){
+ int x = 0;
+ while(retrocl_excludes[x]){
+ if(slapi_sdn_compare(retrocl_includes[i], retrocl_excludes[x] ) == 0){
+ /* we have a conflict */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "include suffix (%s) is also listed in exclude suffix list\n",
+ slapi_sdn_get_dn(retrocl_includes[i]));
+ return -1;
+ }
+ x++;
+ }
+ i++;
+ }
+
+ /* Check for parent/child conflicts */
+ i = 0;
+ while(retrocl_includes[i]){
+ int x = 0;
+ while(retrocl_excludes[x]){
+ if(slapi_sdn_issuffix(retrocl_includes[i], retrocl_excludes[x])){
+ /* we have a conflict */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "include suffix (%s) is a child of the exclude suffix(%s)\n",
+ slapi_sdn_get_dn(retrocl_includes[i]),
+ slapi_sdn_get_dn(retrocl_excludes[i]));
+ return -1;
+ }
+ x++;
+ }
+ i++;
+ }
+ }
+
values = slapi_entry_attr_get_charray(e, "nsslapd-attribute");
if (values != NULL) {
int n = 0;
@@ -471,6 +557,49 @@ static int retrocl_start (Slapi_PBlock *pb)
}
/*
+ * Check if an entry is in the configured scope.
+ * Return 1 if entry is in the scope, or 0 otherwise.
+ * For MODRDN the caller should check both the preop
+ * and postop entries. If we are moving out of, or
+ * into scope, we should record it.
+ */
+int
+retrocl_entry_in_scope(Slapi_Entry *e)
+{
+ Slapi_DN *sdn = slapi_entry_get_sdn(e);
+
+ if (e == NULL){
+ return 1;
+ }
+
+ if (retrocl_excludes){
+ int i = 0;
+
+ /* check the excludes */
+ while(retrocl_excludes[i]){
+ if (slapi_sdn_issuffix(sdn, retrocl_excludes[i])){
+ return 0;
+ }
+ i++;
+ }
+ }
+ if (retrocl_includes){
+ int i = 0;
+
+ /* check the excludes */
+ while(retrocl_includes[i]){
+ if (slapi_sdn_issuffix(sdn, retrocl_includes[i])){
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
* Function: retrocl_stop
*
* Returns: 0
@@ -483,26 +612,40 @@ static int retrocl_start (Slapi_PBlock *pb)
static int retrocl_stop (Slapi_PBlock *pb)
{
- int rc = 0;
-
- slapi_ch_array_free(retrocl_attributes);
- retrocl_attributes = NULL;
- slapi_ch_array_free(retrocl_aliases);
- retrocl_aliases = NULL;
-
- retrocl_stop_trimming();
- retrocl_be_changelog = NULL;
- retrocl_forget_changenumbers();
- PR_DestroyLock(retrocl_internal_lock);
- retrocl_internal_lock = NULL;
- slapi_destroy_rwlock(retrocl_cn_lock);
- retrocl_cn_lock = NULL;
- legacy_initialised = 0;
-
- slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, "",
- LDAP_SCOPE_BASE,"(objectclass=*)", retrocl_rootdse_search);
-
- return rc;
+ int rc = 0;
+ int i = 0;
+
+ slapi_ch_array_free(retrocl_attributes);
+ retrocl_attributes = NULL;
+ slapi_ch_array_free(retrocl_aliases);
+ retrocl_aliases = NULL;
+
+ while(retrocl_excludes && retrocl_excludes[i]){
+ slapi_sdn_free(&retrocl_excludes[i]);
+ i++;
+ }
+ slapi_ch_free((void**)&retrocl_excludes);
+ i = 0;
+
+ while(retrocl_includes && retrocl_includes[i]){
+ slapi_sdn_free(&retrocl_includes[i]);
+ i++;
+ }
+ slapi_ch_free((void**)&retrocl_includes);
+
+ retrocl_stop_trimming();
+ retrocl_be_changelog = NULL;
+ retrocl_forget_changenumbers();
+ PR_DestroyLock(retrocl_internal_lock);
+ retrocl_internal_lock = NULL;
+ slapi_destroy_rwlock(retrocl_cn_lock);
+ retrocl_cn_lock = NULL;
+ legacy_initialised = 0;
+
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, "",
+ LDAP_SCOPE_BASE,"(objectclass=*)", retrocl_rootdse_search);
+
+ return rc;
}
/*
diff --git a/ldap/servers/plugins/retrocl/retrocl.h b/ldap/servers/plugins/retrocl/retrocl.h
index 27f55dc..fe8bf84 100644
--- a/ldap/servers/plugins/retrocl/retrocl.h
+++ b/ldap/servers/plugins/retrocl/retrocl.h
@@ -96,6 +96,8 @@ typedef struct _cnumRet {
/* was originally changelogmaximumage */
#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage"
#define CONFIG_CHANGELOG_DIRECTORY_ATTRIBUTE "nsslapd-changelogdir"
+#define CONFIG_CHANGELOG_INCLUDE_SUFFIX "nsslapd-include-suffix"
+#define CONFIG_CHANGELOG_EXCLUDE_SUFFIX "nsslapd-exclude-suffix"
#define RETROCL_CHANGELOG_DN "cn=changelog"
#define RETROCL_MAPPINGTREE_DN "cn=\"cn=changelog\",cn=mapping tree,cn=config"
@@ -169,4 +171,6 @@ extern void retrocl_init_trimming(void);
extern void retrocl_stop_trimming(void);
extern char *retrocl_get_config_str(const char *attrt);
+int retrocl_entry_in_scope(Slapi_Entry *e);
+
#endif /* _H_RETROCL */
diff --git a/ldap/servers/plugins/retrocl/retrocl_po.c b/ldap/servers/plugins/retrocl/retrocl_po.c
index 61f99cf..a60becc 100644
--- a/ldap/servers/plugins/retrocl/retrocl_po.c
+++ b/ldap/servers/plugins/retrocl/retrocl_po.c
@@ -169,6 +169,7 @@ write_replog_db(
int flag,
time_t curtime,
Slapi_Entry *log_e,
+ Slapi_Entry *post_entry,
const char *newrdn,
LDAPMod **modrdn_mods,
const char *newsuperior
@@ -185,11 +186,26 @@ write_replog_db(
int err = 0;
int ret = LDAP_SUCCESS;
int i;
+ int mark = 0;
if (!dn) {
slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "write_replog_db: NULL dn\n");
return ret;
}
+ mark = (post_entry && retrocl_entry_in_scope(post_entry));
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "post in scope (%d)\n",mark);
+
+ if (post_entry){
+ if(!retrocl_entry_in_scope(log_e) && !retrocl_entry_in_scope(post_entry)){
+ /* modrdn: entry not in scope, just return... */
+ return ret;
+ }
+ } else {
+ if(!retrocl_entry_in_scope(log_e)){
+ /* entry not in scope, just return... */
+ return ret;
+ }
+ }
PR_Lock(retrocl_internal_lock);
changenum = retrocl_assign_changenumber();
@@ -348,7 +364,7 @@ write_replog_db(
break;
case OP_DELETE:
- if (log_e) {
+ if (retrocl_log_deleted) {
/* we have to log the full entry */
if ( entry2reple( e, log_e, OP_DELETE ) != 0 ) {
err = SLAPI_PLUGIN_FAILURE;
@@ -588,7 +604,8 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
char *dn;
LDAPMod **log_m = NULL;
int flag = 0;
- Slapi_Entry *te = NULL;
+ Slapi_Entry *entry = NULL;
+ Slapi_Entry *post_entry = NULL;
Slapi_Operation *op = NULL;
LDAPMod **modrdn_mods = NULL;
char *newrdn = NULL;
@@ -653,7 +670,12 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
LDAPDebug0Args(LDAP_DEBUG_TRACE,"not applying change for nsTombstone entries\n");
return SLAPI_PLUGIN_SUCCESS;
}
-
+ /*
+ * Start by grabbing the preop entry, ADD will replace it as needed. Getting the entry
+ * allows up to perform scoping in write_replog_db() for all op types.
+ */
+ (void)slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &entry);
+
switch ( optype ) {
case OP_MODIFY:
(void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &log_m );
@@ -663,14 +685,14 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
* For adds, we want the unnormalized dn, so we can preserve
* spacing, case, when replicating it.
*/
- (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &te );
- if ( NULL != te ) {
- dn = slapi_entry_get_dn( te );
+ (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &entry );
+ if ( NULL != entry ) {
+ dn = slapi_entry_get_dn( entry );
}
break;
case OP_DELETE:
if (retrocl_log_deleted)
- (void)slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &te);
+ (void)slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &entry);
break;
case OP_MODRDN:
/* newrdn is used just for logging; no need to be normalized */
@@ -678,13 +700,14 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
(void)slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &flag );
(void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &modrdn_mods );
(void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperior );
+ (void)slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &post_entry);
break;
}
/* check if we should log change to retro changelog, and
* if so, do it here */
- if((rc = write_replog_db( pb, optype, dn, log_m, flag, curtime, te,
- newrdn, modrdn_mods, slapi_sdn_get_dn(newsuperior) )))
+ if((rc = write_replog_db( pb, optype, dn, log_m, flag, curtime, entry,
+ post_entry, newrdn, modrdn_mods, slapi_sdn_get_dn(newsuperior) )))
{
slapi_log_error(SLAPI_LOG_FATAL, "retrocl-plugin",
"retrocl_postob: operation failure [%d]\n", rc);
8 years, 8 months
Branch '389-ds-base-1.3.4' - ldap/servers
by Mark Reynolds
ldap/servers/slapd/dse.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
New commits:
commit 29c669e43e16611a290e1c82dfdcf5b51903319e
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Aug 10 12:19:00 2015 -0400
Ticket 47686 - removing chaining database links trigger valgrind read errors
Bug Description: Plugins that remove their dse callback from the dse callback
function lead to invalid reads in dse_call_callback().
Fix Description: In dse_call_callback(), save the pointers to the next callback,
and its plugin, before we call the callback function. So in
case the callback function removes itself, we are not accessing
the freed callback pointer later on.
https://fedorahosted.org/389/ticket/47686
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit a799c4670f2e6f6be1fc9a2828dc4a0f738d3021)
diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c
index 61e2629..e8e393b 100644
--- a/ldap/servers/slapd/dse.c
+++ b/ldap/servers/slapd/dse.c
@@ -2607,18 +2607,21 @@ dse_call_callback(struct dse* pdse, Slapi_PBlock *pb, int operation, int flags,
if (pdse->dse_callback != NULL) {
struct dse_callback *p = pdse->dse_callback;
+ struct dse_callback *next = NULL;
int result = SLAPI_DSE_CALLBACK_OK;
while (p != NULL) {
+ next = p->next;
if ((p->operation & operation) && (p->flags & flags)) {
if(slapi_sdn_scope_test(slapi_entry_get_sdn_const(entryBefore), p->base, p->scope)){
if(NULL == p->slapifilter || slapi_vattr_filter_test(pb, entryBefore, p->slapifilter, 0) == 0){
+ struct slapdplugin *plugin = p->plugin;
int plugin_started = 1;
- if(p->plugin){
+ if(plugin){
/* this is a plugin callback, update the operation counter */
- slapi_plugin_op_started(p->plugin);
- if(!p->plugin->plg_started){
+ slapi_plugin_op_started(plugin);
+ if(!plugin->plg_started){
/* must be a task function being called */
result = SLAPI_DSE_CALLBACK_ERROR;
PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
@@ -2633,11 +2636,11 @@ dse_call_callback(struct dse* pdse, Slapi_PBlock *pb, int operation, int flags,
if(result < rc){
rc = result;
}
- slapi_plugin_op_finished(p->plugin);
+ slapi_plugin_op_finished(plugin);
}
}
}
- p = p->next;
+ p = next;
}
}
return rc;
8 years, 8 months
ldap/servers
by Mark Reynolds
ldap/servers/slapd/dse.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
New commits:
commit a799c4670f2e6f6be1fc9a2828dc4a0f738d3021
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Aug 10 12:19:00 2015 -0400
Ticket 47686 - removing chaining database links trigger valgrind read errors
Bug Description: Plugins that remove their dse callback from the dse callback
function lead to invalid reads in dse_call_callback().
Fix Description: In dse_call_callback(), save the pointers to the next callback,
and its plugin, before we call the callback function. So in
case the callback function removes itself, we are not accessing
the freed callback pointer later on.
https://fedorahosted.org/389/ticket/47686
Reviewed by: nhosoi(Thanks!)
diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c
index 61e2629..e8e393b 100644
--- a/ldap/servers/slapd/dse.c
+++ b/ldap/servers/slapd/dse.c
@@ -2607,18 +2607,21 @@ dse_call_callback(struct dse* pdse, Slapi_PBlock *pb, int operation, int flags,
if (pdse->dse_callback != NULL) {
struct dse_callback *p = pdse->dse_callback;
+ struct dse_callback *next = NULL;
int result = SLAPI_DSE_CALLBACK_OK;
while (p != NULL) {
+ next = p->next;
if ((p->operation & operation) && (p->flags & flags)) {
if(slapi_sdn_scope_test(slapi_entry_get_sdn_const(entryBefore), p->base, p->scope)){
if(NULL == p->slapifilter || slapi_vattr_filter_test(pb, entryBefore, p->slapifilter, 0) == 0){
+ struct slapdplugin *plugin = p->plugin;
int plugin_started = 1;
- if(p->plugin){
+ if(plugin){
/* this is a plugin callback, update the operation counter */
- slapi_plugin_op_started(p->plugin);
- if(!p->plugin->plg_started){
+ slapi_plugin_op_started(plugin);
+ if(!plugin->plg_started){
/* must be a task function being called */
result = SLAPI_DSE_CALLBACK_ERROR;
PR_snprintf (returntext, SLAPI_DSE_RETURNTEXT_SIZE,
@@ -2633,11 +2636,11 @@ dse_call_callback(struct dse* pdse, Slapi_PBlock *pb, int operation, int flags,
if(result < rc){
rc = result;
}
- slapi_plugin_op_finished(p->plugin);
+ slapi_plugin_op_finished(plugin);
}
}
}
- p = p->next;
+ p = next;
}
}
return rc;
8 years, 8 months
Branch '389-ds-base-1.3.4' - ldap/servers
by Mark Reynolds
ldap/servers/plugins/memberof/memberof_config.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
New commits:
commit 9a0047ef75f6dbeb1980ac77fab5d62865c77e6a
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Aug 10 10:42:40 2015 -0400
Ticket 47931 - Fix coverity issues
Description: Fix coverity issues in memberof_config.c
13316 - double free
13315 - Dereference after null check
13314 - Dereference after null check
13313 - copy/paste error
https://fedorahosted.org/389/ticket/47931
Reviewed by: rmeggins(Thanks!)
(cherry picked from commit 5daea973e4526584ee41d7b9f4b1b4993b4de6f1)
diff --git a/ldap/servers/plugins/memberof/memberof_config.c b/ldap/servers/plugins/memberof/memberof_config.c
index b4cc941..10cbd7a 100644
--- a/ldap/servers/plugins/memberof/memberof_config.c
+++ b/ldap/servers/plugins/memberof/memberof_config.c
@@ -316,6 +316,7 @@ memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
"%s: Invalid DN (%s) for include suffix.",
MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]);
slapi_ch_array_free(entry_scopes);
+ entry_scopes = NULL;
theConfig.entryScopeCount = 0;
*returncode = LDAP_UNWILLING_TO_PERFORM;
goto done;
@@ -341,8 +342,9 @@ memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
/* invalid dn syntax */
PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
"%s: Invalid DN (%s) for exclude suffix.",
- MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]);
+ MEMBEROF_PLUGIN_SUBSYSTEM, entry_exclude_scopes[i]);
slapi_ch_array_free(entry_exclude_scopes);
+ entry_exclude_scopes = NULL;
*returncode = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
@@ -741,7 +743,7 @@ memberof_copy_config(MemberOfConfig *dest, MemberOfConfig *src)
int num_vals = 0;
dest->entryScopeExcludeSubtrees = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),src->entryExcludeScopeCount+1);
- for(num_vals = 0; src->entryScopes[num_vals]; num_vals++){
+ for(num_vals = 0; src->entryScopeExcludeSubtrees[num_vals]; num_vals++){
dest->entryScopeExcludeSubtrees[num_vals] = slapi_sdn_dup(src->entryScopeExcludeSubtrees[num_vals]);
}
}
8 years, 8 months
ldap/servers
by Mark Reynolds
ldap/servers/plugins/memberof/memberof_config.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
New commits:
commit 5daea973e4526584ee41d7b9f4b1b4993b4de6f1
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Aug 10 10:42:40 2015 -0400
Ticket 47931 - Fix coverity issues
Description: Fix coverity issues in memberof_config.c
13316 - double free
13315 - Dereference after null check
13314 - Dereference after null check
13313 - copy/paste error
https://fedorahosted.org/389/ticket/47931
Reviewed by: rmeggins(Thanks!)
diff --git a/ldap/servers/plugins/memberof/memberof_config.c b/ldap/servers/plugins/memberof/memberof_config.c
index b4cc941..10cbd7a 100644
--- a/ldap/servers/plugins/memberof/memberof_config.c
+++ b/ldap/servers/plugins/memberof/memberof_config.c
@@ -316,6 +316,7 @@ memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
"%s: Invalid DN (%s) for include suffix.",
MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]);
slapi_ch_array_free(entry_scopes);
+ entry_scopes = NULL;
theConfig.entryScopeCount = 0;
*returncode = LDAP_UNWILLING_TO_PERFORM;
goto done;
@@ -341,8 +342,9 @@ memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
/* invalid dn syntax */
PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
"%s: Invalid DN (%s) for exclude suffix.",
- MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]);
+ MEMBEROF_PLUGIN_SUBSYSTEM, entry_exclude_scopes[i]);
slapi_ch_array_free(entry_exclude_scopes);
+ entry_exclude_scopes = NULL;
*returncode = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
@@ -741,7 +743,7 @@ memberof_copy_config(MemberOfConfig *dest, MemberOfConfig *src)
int num_vals = 0;
dest->entryScopeExcludeSubtrees = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),src->entryExcludeScopeCount+1);
- for(num_vals = 0; src->entryScopes[num_vals]; num_vals++){
+ for(num_vals = 0; src->entryScopeExcludeSubtrees[num_vals]; num_vals++){
dest->entryScopeExcludeSubtrees[num_vals] = slapi_sdn_dup(src->entryScopeExcludeSubtrees[num_vals]);
}
}
8 years, 8 months
Branch '389-ds-base-1.2.11' - ldap/servers
by Noriko Hosoi
ldap/servers/plugins/replication/cl5_api.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
New commits:
commit 439ed95bfc4e892b256a71448838954d15decf9c
Author: Ludwig Krispenz <lkrispen(a)redhat.com>
Date: Wed Mar 13 10:53:44 2013 +0100
Ticket #621 - modify operations without values do not get replicated
Description: This was introduced by the fix for ticket 561 where in the
_cl5WriteMod the mods were checked if the values need to be encrypted
and only mods with values were written to the changelog
reviewed by Mark, Thanks
(cherry picked from commit 5a5ff2640d6e66c925550498211743a8f78a8477)
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index 0618d9b..dd3168a 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -2537,11 +2537,15 @@ _cl5WriteMod (LDAPMod *mod, char **buff)
memcpy (pos, &count, sizeof (count));
pos += sizeof (PRInt32);
+ /* if the mod has no values, eg delete attr or replace attr without values
+ * do not reset buffer
+ */
+ rc = 0;
+
bv = slapi_mod_get_first_value (&smod);
while (bv)
{
encbv = NULL;
- rc = 0;
rc = clcrypt_encrypt_value(s_cl5Desc.clcrypt_handle,
bv, &encbv);
if (rc > 0) {
8 years, 8 months
Branch '389-ds-base-1.2.11' - ldap/servers
by Noriko Hosoi
ldap/servers/slapd/pw.c | 192 ++++++++++++++++++++++++++++--------------------
1 file changed, 114 insertions(+), 78 deletions(-)
New commits:
commit fd1c326539c5645d5c17df35bdec07c261a828db
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Mon Aug 3 18:49:58 2015 -0700
Ticket #48228 - wrong password check if passwordInHistory is decreased.
Bug Description: When N passwords to be remembered (passwordInHistroy)
and N passwords are remembered, decreasing the passwordInHistory value
to M (< N) does not allow to use the oldest password which should have
been discarded from the history and should be allowed.
Fix Description: Before checking if the password is in the history or
not, adding a check the passwordInHistory value (M) is less than the
count of passwords remembered (N). If M < N, discard the (N-M) oldest
passwords.
https://fedorahosted.org/389/ticket/48228
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
(cherry picked from commit 1a119125856006543aae0520b5800a8b52c3b049)
(cherry picked from commit dd85ee9c9ac24f1b141dd806943de236d2e44c90)
(cherry picked from commit 67c816451dc331aed50808c61d00b5c9d4d20890)
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index a1e3dd6..bd3a47c 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -609,7 +609,7 @@ update_pw_info ( Slapi_PBlock *pb , char *old_pw) {
/* update passwordHistory */
if ( old_pw != NULL && pwpolicy->pw_history == 1 ) {
- update_pw_history(pb, sdn, old_pw);
+ (void)update_pw_history(pb, sdn, old_pw);
slapi_ch_free ( (void**)&old_pw );
}
@@ -648,7 +648,7 @@ update_pw_info ( Slapi_PBlock *pb , char *old_pw) {
* for this special case to ensure we reset the expiration date properly. */
if ((internal_op && pwpolicy->pw_must_change && (!pb->pb_conn || slapi_dn_isroot(pb->pb_conn->c_dn))) ||
(!internal_op && pwpolicy->pw_must_change &&
- ((target_dn && bind_dn && strcasecmp(target_dn, bind_dn)) && pw_is_pwp_admin(pb, pwpolicy)))){
+ ((target_dn && bind_dn && strcasecmp(target_dn, bind_dn)) && pw_is_pwp_admin(pb, pwpolicy)))) {
pw_exp_date = NO_TIME;
} else if ( pwpolicy->pw_exp == 1 ) {
Slapi_Entry *pse = NULL;
@@ -994,6 +994,7 @@ check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
/* get the entry and check for the password history if this is called by a modify operation */
if ( mod_op ) {
+retry:
/* retrieve the entry */
e = get_entry ( pb, dn );
if ( e == NULL ) {
@@ -1003,19 +1004,21 @@ check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
/* check for password history */
if ( pwpolicy->pw_history == 1 ) {
+ Slapi_Value **va = NULL;
attr = attrlist_find(e->e_attrs, "passwordHistory");
- if (attr &&
- !valueset_isempty(&attr->a_present_values))
- {
- Slapi_Value **va= attr_get_present_values(attr);
+ if (attr && !valueset_isempty(&attr->a_present_values)) {
+ /* Resetting password history array if necessary. */
+ if (0 == update_pw_history(pb, sdn, NULL)) {
+ /* There was an update in the password history. Retry... */
+ slapi_entry_free(e);
+ goto retry;
+ }
+ va = attr_get_present_values(attr);
if ( pw_in_history( va, vals[0] ) == 0 ) {
if ( pwresponse_req == 1 ) {
- slapi_pwpolicy_make_response_control ( pb, -1, -1,
- LDAP_PWPOLICY_PWDINHISTORY );
+ slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_PWDINHISTORY);
}
- pw_send_ldap_result ( pb,
- LDAP_CONSTRAINT_VIOLATION, NULL,
- "password in history", 0, NULL );
+ pw_send_ldap_result(pb, LDAP_CONSTRAINT_VIOLATION, NULL, "password in history", 0, NULL);
slapi_entry_free( e );
delete_passwdPolicy(&pwpolicy);
return ( 1 );
@@ -1024,27 +1027,18 @@ check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
/* get current password. check it and remember it */
attr = attrlist_find(e->e_attrs, "userpassword");
- if (attr && !valueset_isempty(&attr->a_present_values))
- {
- Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
- if (slapi_is_encoded((char*)slapi_value_get_string(vals[0])))
- {
- if (slapi_attr_value_find(attr, (struct berval *)slapi_value_get_berval(vals[0])) == 0 )
- {
- pw_send_ldap_result ( pb,
- LDAP_CONSTRAINT_VIOLATION ,NULL,
- "password in history", 0, NULL);
+ if (attr && !valueset_isempty(&attr->a_present_values)) {
+ va = valueset_get_valuearray(&attr->a_present_values);
+ if (slapi_is_encoded((char*)slapi_value_get_string(vals[0]))) {
+ if (slapi_attr_value_find(attr, (struct berval *)slapi_value_get_berval(vals[0])) == 0 ) {
+ pw_send_ldap_result(pb, LDAP_CONSTRAINT_VIOLATION, NULL, "password in history", 0, NULL);
slapi_entry_free( e );
delete_passwdPolicy(&pwpolicy);
return ( 1 );
}
- } else
- {
- if ( slapi_pw_find_sv ( va, vals[0] ) == 0 )
- {
- pw_send_ldap_result ( pb,
- LDAP_CONSTRAINT_VIOLATION ,NULL,
- "password in history", 0, NULL);
+ } else {
+ if ( slapi_pw_find_sv ( va, vals[0] ) == 0 ) {
+ pw_send_ldap_result(pb, LDAP_CONSTRAINT_VIOLATION, NULL, "password in history", 0, NULL);
slapi_entry_free( e );
delete_passwdPolicy(&pwpolicy);
return ( 1 );
@@ -1090,22 +1084,56 @@ check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
}
+/*
+ * Basically, h0 and h1 must be longer than GENERALIZED_TIME_LENGTH.
+ */
+static int
+pw_history_cmp(const void *h0, const void *h1)
+{
+ size_t h0sz = 0;
+ size_t h1sz = 0;
+ if (!h0) {
+ if (!h1) {
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ if (!h1) {
+ return 1;
+ } else {
+ size_t delta;
+ h0sz = strlen(h0);
+ h1sz = strlen(h1);
+ delta = h0sz - h1sz;
+ if (!delta) {
+ return delta;
+ }
+ if (h0sz < GENERALIZED_TIME_LENGTH) {
+ /* too short for the history str. */
+ return 0;
+ }
+ }
+ }
+ return PL_strncmp(h0, h1, GENERALIZED_TIME_LENGTH);
+}
+
+
static int
update_pw_history( Slapi_PBlock *pb, const Slapi_DN *sdn, char *old_pw )
{
- time_t t, old_t, cur_time;
- int i = 0, oldest = 0;
- int res;
- Slapi_Entry *e;
- Slapi_Attr *attr;
+ time_t cur_time;
+ int res = 1; /* no update, by default */
+ Slapi_Entry *e = NULL;
LDAPMod attribute;
- char *values_replace[25]; /* 2-24 passwords in history */
LDAPMod *list_of_mods[2];
Slapi_PBlock mod_pb;
- char *history_str;
- char *str;
+ char *str = NULL;
passwdPolicy *pwpolicy = NULL;
const char *dn = slapi_sdn_get_dn(sdn);
+ char **values_replace = NULL;
+ int vacnt = 0;
+ int vacnt_todelete = 0;
pwpolicy = new_passwdPolicy(pb, dn);
@@ -1113,46 +1141,56 @@ update_pw_history( Slapi_PBlock *pb, const Slapi_DN *sdn, char *old_pw )
e = get_entry ( pb, dn );
if ( e == NULL ) {
delete_passwdPolicy(&pwpolicy);
- return ( 1 );
+ return res;
}
- history_str = (char *)slapi_ch_malloc(GENERALIZED_TIME_LENGTH + strlen(old_pw) + 1);
- /* get password history, and find the oldest password in history */
- cur_time = current_time ();
- old_t = cur_time;
- str = format_genTime ( cur_time );
- attr = attrlist_find(e->e_attrs, "passwordHistory");
- if (attr && !valueset_isempty(&attr->a_present_values))
- {
- Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
- for ( i = oldest = 0 ;
- (va[i] != NULL) && (slapi_value_get_length(va[i]) > 0) ;
- i++ ) {
-
- values_replace[i] = (char*)slapi_value_get_string(va[i]);
- strncpy( history_str, values_replace[i], GENERALIZED_TIME_LENGTH);
- history_str[GENERALIZED_TIME_LENGTH] = '\0';
- if (history_str[GENERALIZED_TIME_LENGTH - 1] != 'Z'){
- /* The time is not a generalized Time. Probably a password history from 4.x */
- history_str[GENERALIZED_TIME_LENGTH - 1] = '\0';
- }
- t = parse_genTime ( history_str );
- if ( difftime ( t, old_t ) < 0 ) {
- oldest = i;
- old_t = t;
- }
+ /* get password history */
+ values_replace = slapi_entry_attr_get_charray_ext(e, "passwordHistory", &vacnt);
+ if (old_pw) {
+ /* we have a password to replace with the oldest one in the history. */
+ if (!values_replace || !vacnt) { /* This is the first one to store */
+ values_replace = (char **)slapi_ch_calloc(2, sizeof(char *));
+ }
+ } else {
+ /* we are checking the history size if it stores more than the current inhistory count. */
+ if (!values_replace || !vacnt) { /* nothing to revise */
+ res = 1;
+ goto bail;
+ }
+ /*
+ * If revising the passwords in the passwordHistory values
+ * and the password count in the value array is less than the inhistory,
+ * we have nothing to do.
+ */
+ if (vacnt <= pwpolicy->pw_inhistory) {
+ res = 1;
+ goto bail;
}
+ vacnt_todelete = vacnt - pwpolicy->pw_inhistory;
}
- strcpy ( history_str, str );
- strcat ( history_str, old_pw );
- if ( i >= pwpolicy->pw_inhistory ) {
- /* replace the oldest password in history */
- values_replace[oldest] = history_str;
- values_replace[pwpolicy->pw_inhistory] = NULL;
+
+ cur_time = current_time();
+ str = format_genTime(cur_time);
+ /* values_replace is sorted. */
+ if (old_pw) {
+ if ( vacnt >= pwpolicy->pw_inhistory ) {
+ slapi_ch_free_string(&values_replace[0]);
+ values_replace[0] = slapi_ch_smprintf("%s%s", str, old_pw);
+ } else {
+ /* add old_pw at the end of password history */
+ values_replace = (char **)slapi_ch_realloc((char *)values_replace, sizeof(char *) * (vacnt + 2));
+ values_replace[vacnt] = slapi_ch_smprintf("%s%s", str, old_pw);
+ values_replace[vacnt+1] = NULL;
+ }
+ qsort((void *)values_replace, vacnt, (size_t)sizeof(char *), pw_history_cmp);
} else {
- /* add old_pw at the end of password history */
- values_replace[i] = history_str;
- values_replace[++i]=NULL;
+ int i;
+ /* vacnt > pwpolicy->pw_inhistory */
+ for (i = 0; i < vacnt_todelete; i++) {
+ slapi_ch_free_string(&values_replace[i]);
+ }
+ memmove(values_replace, values_replace + vacnt_todelete, sizeof(char *) * pwpolicy->pw_inhistory);
+ values_replace[pwpolicy->pw_inhistory] = NULL;
}
/* modify the attribute */
@@ -1164,22 +1202,20 @@ update_pw_history( Slapi_PBlock *pb, const Slapi_DN *sdn, char *old_pw )
list_of_mods[1] = NULL;
pblock_init(&mod_pb);
- slapi_modify_internal_set_pb_ext(&mod_pb, sdn, list_of_mods, NULL, NULL,
- pw_get_componentID(), 0);
+ slapi_modify_internal_set_pb_ext(&mod_pb, sdn, list_of_mods, NULL, NULL, pw_get_componentID(), 0);
slapi_modify_internal_pb(&mod_pb);
slapi_pblock_get(&mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
if (res != LDAP_SUCCESS){
LDAPDebug2Args(LDAP_DEBUG_ANY,
"WARNING: passwordPolicy modify error %d on entry '%s'\n", res, dn);
}
-
pblock_done(&mod_pb);
-
- slapi_ch_free((void **) &str );
- slapi_ch_free((void **) &history_str );
+ slapi_ch_free_string(&str);
+bail:
+ slapi_ch_array_free(values_replace);
slapi_entry_free( e );
delete_passwdPolicy(&pwpolicy);
- return 0;
+ return res;
}
static
8 years, 8 months
Branch '389-ds-base-1.3.3' - 2 commits - dirsrvtests/tickets ldap/servers
by Noriko Hosoi
dirsrvtests/tickets/ticket48228_test.py | 327 ++++++++++++++++++++++++++++++++
ldap/servers/slapd/pw.c | 193 +++++++++++-------
2 files changed, 441 insertions(+), 79 deletions(-)
New commits:
commit 08eabd5de9ebe6745c7bb4da4daef1179a271084
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Wed Aug 5 14:40:12 2015 -0700
Ticket #48228 - CI test: added test cases for ticket 48228
Description: wrong password check if passwordInHistory is decreased.
(cherry picked from commit 6b138a2091bf7d78f3bc60a13f226a39296e0f4c)
(cherry picked from commit e62b4815f0682845992dc9a4375e1d7c5597bfba)
diff --git a/dirsrvtests/tickets/ticket48228_test.py b/dirsrvtests/tickets/ticket48228_test.py
new file mode 100644
index 0000000..e0595bb
--- /dev/null
+++ b/dirsrvtests/tickets/ticket48228_test.py
@@ -0,0 +1,327 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2015 Red Hat, Inc.
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details.
+# --- END COPYRIGHT BLOCK ---
+#
+import os
+import sys
+import time
+import ldap
+import logging
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+# Assuming DEFAULT_SUFFIX is "dc=example,dc=com", otherwise it does not work... :(
+SUBTREE_CONTAINER = 'cn=nsPwPolicyContainer,' + DEFAULT_SUFFIX
+SUBTREE_PWPDN = 'cn=nsPwPolicyEntry,' + DEFAULT_SUFFIX
+SUBTREE_PWP = 'cn=cn\3DnsPwPolicyEntry\2Cdc\3Dexample\2Cdc\3Dcom,' + SUBTREE_CONTAINER
+SUBTREE_COS_TMPLDN = 'cn=nsPwTemplateEntry,' + DEFAULT_SUFFIX
+SUBTREE_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2Cdc\3Dexample\2Cdc\3Dcom,' + SUBTREE_CONTAINER
+SUBTREE_COS_DEF = 'cn=nsPwPolicy_CoS,' + DEFAULT_SUFFIX
+
+USER1_DN = 'uid=user1,' + DEFAULT_SUFFIX
+USER2_DN = 'uid=user2,' + DEFAULT_SUFFIX
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ # Here we have standalone instance up and running
+ return TopologyStandalone(standalone)
+
+def set_global_pwpolicy(topology, inhistory):
+ log.info(" +++++ Enable global password policy +++++\n")
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ # Enable password policy
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
+ except ldap.LDAPError, e:
+ log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
+ assert False
+
+ log.info(" Set global password history on\n")
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordHistory', 'on')])
+ except ldap.LDAPError, e:
+ log.error('Failed to set passwordHistory: error ' + e.message['desc'])
+ assert False
+
+ log.info(" Set global passwords in history\n")
+ try:
+ count = "%d" % inhistory
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordInHistory', count)])
+ except ldap.LDAPError, e:
+ log.error('Failed to set passwordInHistory: error ' + e.message['desc'])
+ assert False
+
+def set_subtree_pwpolicy(topology):
+ log.info(" +++++ Enable subtree level password policy +++++\n")
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ log.info(" Add the container")
+ try:
+ topology.standalone.add_s(Entry((SUBTREE_CONTAINER, {'objectclass': 'top nsContainer'.split(),
+ 'cn': 'nsPwPolicyContainer'})))
+ except ldap.LDAPError, e:
+ log.error('Failed to add subtree container: error ' + e.message['desc'])
+ assert False
+
+ log.info(" Add the password policy subentry {passwordHistory: on, passwordInHistory: 6}")
+ try:
+ topology.standalone.add_s(Entry((SUBTREE_PWP, {'objectclass': 'top ldapsubentry passwordpolicy'.split(),
+ 'cn': SUBTREE_PWPDN,
+ 'passwordMustChange': 'off',
+ 'passwordExp': 'off',
+ 'passwordHistory': 'on',
+ 'passwordInHistory': '6',
+ 'passwordMinAge': '0',
+ 'passwordChange': 'on',
+ 'passwordStorageScheme': 'clear'})))
+ except ldap.LDAPError, e:
+ log.error('Failed to add passwordpolicy: error ' + e.message['desc'])
+ assert False
+
+ log.info(" Add the COS template")
+ try:
+ topology.standalone.add_s(Entry((SUBTREE_COS_TMPL, {'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
+ 'cn': SUBTREE_PWPDN,
+ 'cosPriority': '1',
+ 'cn': SUBTREE_COS_TMPLDN,
+ 'pwdpolicysubentry': SUBTREE_PWP})))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS template: error ' + e.message['desc'])
+ assert False
+
+ log.info(" Add the COS definition")
+ try:
+ topology.standalone.add_s(Entry((SUBTREE_COS_DEF, {'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
+ 'cn': SUBTREE_PWPDN,
+ 'costemplatedn': SUBTREE_COS_TMPL,
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'})))
+ except ldap.LDAPError, e:
+ log.error('Failed to add COS def: error ' + e.message['desc'])
+ assert False
+
+def check_passwd_inhistory(topology, user, cpw, passwd):
+ inhistory = 0
+ log.info(" Bind as {%s,%s}" % (user, cpw))
+ topology.standalone.simple_bind_s(user, cpw)
+ try:
+ topology.standalone.modify_s(user, [(ldap.MOD_REPLACE, 'userpassword', passwd)])
+ except ldap.LDAPError, e:
+ log.info(' The password ' + passwd + ' of user' + USER1_DN + ' in history: error ' + e.message['desc'])
+ inhistory = 1
+ return inhistory
+
+def update_passwd(topology, user, passwd, times):
+ cpw = passwd
+ loop = 0
+ while loop < times:
+ log.info(" Bind as {%s,%s}" % (user, cpw))
+ topology.standalone.simple_bind_s(user, cpw)
+ cpw = 'password%d' % loop
+ try:
+ topology.standalone.modify_s(user, [(ldap.MOD_REPLACE, 'userpassword', cpw)])
+ except ldap.LDAPError, e:
+ log.fatal('test_ticket48228: Failed to update the password ' + cpw + ' of user ' + user + ': error ' + e.message['desc'])
+ assert False
+ loop += 1
+
+ # checking the first password, which is supposed to be in history
+ inhistory = check_passwd_inhistory(topology, user, cpw, passwd)
+ assert inhistory == 1
+
+def test_ticket48228_test_global_policy(topology):
+ """
+ Check global password policy
+ """
+
+ log.info(' Set inhistory = 6')
+ set_global_pwpolicy(topology, 6)
+
+ log.info(' Bind as directory manager')
+ log.info("Bind as %s" % DN_DM)
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+
+ log.info(' Add an entry' + USER1_DN)
+ try:
+ topology.standalone.add_s(Entry((USER1_DN, {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
+ 'sn': '1',
+ 'cn': 'user 1',
+ 'uid': 'user1',
+ 'givenname': 'user',
+ 'mail': 'user1(a)example.com',
+ 'userpassword': 'password'})))
+ except ldap.LDAPError, e:
+ log.fatal('test_ticket48228: Failed to add user' + USER1_DN + ': error ' + e.message['desc'])
+ assert False
+
+ log.info(' Update the password of ' + USER1_DN + ' 6 times')
+ update_passwd(topology, USER1_DN, 'password', 6)
+
+ log.info(' Set inhistory = 4')
+ set_global_pwpolicy(topology, 4)
+
+ log.info(' checking the first password, which is supposed NOT to be in history any more')
+ cpw = 'password%d' % 5
+ tpw = 'password'
+ inhistory = check_passwd_inhistory(topology, USER1_DN, cpw, tpw)
+ assert inhistory == 0
+
+ log.info(' checking the second password, which is supposed NOT to be in history any more')
+ cpw = tpw
+ tpw = 'password%d' % 0
+ inhistory = check_passwd_inhistory(topology, USER1_DN, cpw, tpw)
+ assert inhistory == 0
+
+ log.info(' checking the second password, which is supposed NOT to be in history any more')
+ cpw = tpw
+ tpw = 'password%d' % 1
+ inhistory = check_passwd_inhistory(topology, USER1_DN, cpw, tpw)
+ assert inhistory == 0
+
+ log.info(' checking the third password, which is supposed to be in history')
+ cpw = tpw
+ tpw = 'password%d' % 2
+ inhistory = check_passwd_inhistory(topology, USER1_DN, cpw, tpw)
+ assert inhistory == 1
+
+ log.info("Global policy was successfully verified.")
+
+def test_ticket48228_test_subtree_policy(topology):
+ """
+ Check subtree level password policy
+ """
+
+ log.info(' Set inhistory = 6')
+ set_subtree_pwpolicy(topology)
+
+ log.info(' Bind as directory manager')
+ log.info("Bind as %s" % DN_DM)
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+
+ log.info(' Add an entry' + USER2_DN)
+ try:
+ topology.standalone.add_s(Entry((USER2_DN, {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
+ 'sn': '2',
+ 'cn': 'user 2',
+ 'uid': 'user2',
+ 'givenname': 'user',
+ 'mail': 'user2(a)example.com',
+ 'userpassword': 'password'})))
+ except ldap.LDAPError, e:
+ log.fatal('test_ticket48228: Failed to add user' + USER2_DN + ': error ' + e.message['desc'])
+ assert False
+
+ log.info(' Update the password of ' + USER2_DN + ' 6 times')
+ update_passwd(topology, USER2_DN, 'password', 6)
+
+ log.info(' Set inhistory = 4')
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ try:
+ topology.standalone.modify_s(SUBTREE_PWP, [(ldap.MOD_REPLACE, 'passwordInHistory', '4')])
+ except ldap.LDAPError, e:
+ log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
+ assert False
+
+ log.info(' checking the first password, which is supposed NOT to be in history any more')
+ cpw = 'password%d' % 5
+ tpw = 'password'
+ inhistory = check_passwd_inhistory(topology, USER2_DN, cpw, tpw)
+ assert inhistory == 0
+
+ log.info(' checking the second password, which is supposed NOT to be in history any more')
+ cpw = tpw
+ tpw = 'password%d' % 0
+ inhistory = check_passwd_inhistory(topology, USER2_DN, cpw, tpw)
+ assert inhistory == 0
+
+ log.info(' checking the second password, which is supposed NOT to be in history any more')
+ cpw = tpw
+ tpw = 'password%d' % 1
+ inhistory = check_passwd_inhistory(topology, USER2_DN, cpw, tpw)
+ assert inhistory == 0
+
+ log.info(' checking the third password, which is supposed to be in history')
+ cpw = tpw
+ tpw = 'password%d' % 2
+ inhistory = check_passwd_inhistory(topology, USER2_DN, cpw, tpw)
+ assert inhistory == 1
+
+ log.info("Subtree level policy was successfully verified.")
+
+def test_ticket48228_final(topology):
+ topology.standalone.delete()
+ log.info('Testcase PASSED')
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ log.info('Testing Ticket 48228 - wrong password check if passwordInHistory is decreased')
+
+ test_ticket48228_test_global_policy(topo)
+
+ test_ticket48228_test_subtree_policy(topo)
+
+ test_ticket48228_final(topo)
+
+
+if __name__ == '__main__':
+ run_isolated()
+
commit 67c816451dc331aed50808c61d00b5c9d4d20890
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Mon Aug 3 18:49:58 2015 -0700
Ticket #48228 - wrong password check if passwordInHistory is decreased.
Bug Description: When N passwords to be remembered (passwordInHistroy)
and N passwords are remembered, decreasing the passwordInHistory value
to M (< N) does not allow to use the oldest password which should have
been discarded from the history and should be allowed.
Fix Description: Before checking if the password is in the history or
not, adding a check the passwordInHistory value (M) is less than the
count of passwords remembered (N). If M < N, discard the (N-M) oldest
passwords.
https://fedorahosted.org/389/ticket/48228
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
(cherry picked from commit 1a119125856006543aae0520b5800a8b52c3b049)
(cherry picked from commit dd85ee9c9ac24f1b141dd806943de236d2e44c90)
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index 3e2dd90..192584a 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -649,7 +649,7 @@ update_pw_info ( Slapi_PBlock *pb , char *old_pw)
/* update passwordHistory */
if ( old_pw != NULL && pwpolicy->pw_history == 1 ) {
- update_pw_history(pb, sdn, old_pw);
+ (void)update_pw_history(pb, sdn, old_pw);
slapi_ch_free ( (void**)&old_pw );
}
@@ -690,8 +690,7 @@ update_pw_info ( Slapi_PBlock *pb , char *old_pw)
*/
if ((internal_op && pwpolicy->pw_must_change && (!pb->pb_conn || strcasecmp(target_dn, pb->pb_conn->c_dn))) ||
(!internal_op && pwpolicy->pw_must_change &&
- ((target_dn && bind_dn && strcasecmp(target_dn, bind_dn)) && pw_is_pwp_admin(pb, pwpolicy))))
- {
+ ((target_dn && bind_dn && strcasecmp(target_dn, bind_dn)) && pw_is_pwp_admin(pb, pwpolicy)))) {
pw_exp_date = NO_TIME;
} else if ( pwpolicy->pw_exp == 1 ) {
Slapi_Entry *pse = NULL;
@@ -1032,6 +1031,7 @@ check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
/* get the entry and check for the password history if this is called by a modify operation */
if ( mod_op ) {
+retry:
/* retrieve the entry */
e = get_entry ( pb, dn );
if ( e == NULL ) {
@@ -1040,19 +1040,21 @@ check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
/* check for password history */
if ( pwpolicy->pw_history == 1 ) {
+ Slapi_Value **va = NULL;
attr = attrlist_find(e->e_attrs, "passwordHistory");
- if (attr &&
- !valueset_isempty(&attr->a_present_values))
- {
- Slapi_Value **va= attr_get_present_values(attr);
+ if (attr && !valueset_isempty(&attr->a_present_values)) {
+ /* Resetting password history array if necessary. */
+ if (0 == update_pw_history(pb, sdn, NULL)) {
+ /* There was an update in the password history. Retry... */
+ slapi_entry_free(e);
+ goto retry;
+ }
+ va = attr_get_present_values(attr);
if ( pw_in_history( va, vals[0] ) == 0 ) {
if ( pwresponse_req == 1 ) {
- slapi_pwpolicy_make_response_control ( pb, -1, -1,
- LDAP_PWPOLICY_PWDINHISTORY );
+ slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_PWDINHISTORY);
}
- pw_send_ldap_result ( pb,
- LDAP_CONSTRAINT_VIOLATION, NULL,
- "password in history", 0, NULL );
+ pw_send_ldap_result(pb, LDAP_CONSTRAINT_VIOLATION, NULL, "password in history", 0, NULL);
slapi_entry_free( e );
return ( 1 );
}
@@ -1060,26 +1062,17 @@ check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
/* get current password. check it and remember it */
attr = attrlist_find(e->e_attrs, "userpassword");
- if (attr && !valueset_isempty(&attr->a_present_values))
- {
- Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
- if (slapi_is_encoded((char*)slapi_value_get_string(vals[0])))
- {
- if (slapi_attr_value_find(attr, (struct berval *)slapi_value_get_berval(vals[0])) == 0 )
- {
- pw_send_ldap_result ( pb,
- LDAP_CONSTRAINT_VIOLATION ,NULL,
- "password in history", 0, NULL);
+ if (attr && !valueset_isempty(&attr->a_present_values)) {
+ va = valueset_get_valuearray(&attr->a_present_values);
+ if (slapi_is_encoded((char*)slapi_value_get_string(vals[0]))) {
+ if (slapi_attr_value_find(attr, (struct berval *)slapi_value_get_berval(vals[0])) == 0 ) {
+ pw_send_ldap_result(pb, LDAP_CONSTRAINT_VIOLATION, NULL, "password in history", 0, NULL);
slapi_entry_free( e );
return ( 1 );
}
- } else
- {
- if ( slapi_pw_find_sv ( va, vals[0] ) == 0 )
- {
- pw_send_ldap_result ( pb,
- LDAP_CONSTRAINT_VIOLATION ,NULL,
- "password in history", 0, NULL);
+ } else {
+ if ( slapi_pw_find_sv ( va, vals[0] ) == 0 ) {
+ pw_send_ldap_result(pb, LDAP_CONSTRAINT_VIOLATION, NULL, "password in history", 0, NULL);
slapi_entry_free( e );
return ( 1 );
}
@@ -1122,68 +1115,112 @@ check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
}
+/*
+ * Basically, h0 and h1 must be longer than GENERALIZED_TIME_LENGTH.
+ */
+static int
+pw_history_cmp(const void *h0, const void *h1)
+{
+ size_t h0sz = 0;
+ size_t h1sz = 0;
+ if (!h0) {
+ if (!h1) {
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ if (!h1) {
+ return 1;
+ } else {
+ size_t delta;
+ h0sz = strlen(h0);
+ h1sz = strlen(h1);
+ delta = h0sz - h1sz;
+ if (!delta) {
+ return delta;
+ }
+ if (h0sz < GENERALIZED_TIME_LENGTH) {
+ /* too short for the history str. */
+ return 0;
+ }
+ }
+ }
+ return PL_strncmp(h0, h1, GENERALIZED_TIME_LENGTH);
+}
+
+
static int
update_pw_history( Slapi_PBlock *pb, const Slapi_DN *sdn, char *old_pw )
{
- time_t t, old_t, cur_time;
- int i = 0, oldest = 0;
- int res;
- Slapi_Entry *e;
- Slapi_Attr *attr;
+ time_t cur_time;
+ int res = 1; /* no update, by default */
+ Slapi_Entry *e = NULL;
LDAPMod attribute;
- char *values_replace[25]; /* 2-24 passwords in history */
LDAPMod *list_of_mods[2];
Slapi_PBlock mod_pb;
- char *history_str;
- char *str;
+ char *str = NULL;
passwdPolicy *pwpolicy = NULL;
const char *dn = slapi_sdn_get_dn(sdn);
+ char **values_replace = NULL;
+ int vacnt = 0;
+ int vacnt_todelete = 0;
pwpolicy = new_passwdPolicy(pb, dn);
/* retrieve the entry */
e = get_entry ( pb, dn );
if ( e == NULL ) {
- return ( 1 );
+ return res;
}
- history_str = (char *)slapi_ch_malloc(GENERALIZED_TIME_LENGTH + strlen(old_pw) + 1);
- /* get password history, and find the oldest password in history */
- cur_time = current_time ();
- old_t = cur_time;
- str = format_genTime ( cur_time );
- attr = attrlist_find(e->e_attrs, "passwordHistory");
- if (attr && !valueset_isempty(&attr->a_present_values))
- {
- Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
- for ( i = oldest = 0 ;
- (va[i] != NULL) && (slapi_value_get_length(va[i]) > 0) ;
- i++ ) {
-
- values_replace[i] = (char*)slapi_value_get_string(va[i]);
- strncpy( history_str, values_replace[i], GENERALIZED_TIME_LENGTH);
- history_str[GENERALIZED_TIME_LENGTH] = '\0';
- if (history_str[GENERALIZED_TIME_LENGTH - 1] != 'Z'){
- /* The time is not a generalized Time. Probably a password history from 4.x */
- history_str[GENERALIZED_TIME_LENGTH - 1] = '\0';
- }
- t = parse_genTime ( history_str );
- if ( difftime ( t, old_t ) < 0 ) {
- oldest = i;
- old_t = t;
- }
+ /* get password history */
+ values_replace = slapi_entry_attr_get_charray_ext(e, "passwordHistory", &vacnt);
+ if (old_pw) {
+ /* we have a password to replace with the oldest one in the history. */
+ if (!values_replace || !vacnt) { /* This is the first one to store */
+ values_replace = (char **)slapi_ch_calloc(2, sizeof(char *));
}
+ } else {
+ /* we are checking the history size if it stores more than the current inhistory count. */
+ if (!values_replace || !vacnt) { /* nothing to revise */
+ res = 1;
+ goto bail;
+ }
+ /*
+ * If revising the passwords in the passwordHistory values
+ * and the password count in the value array is less than the inhistory,
+ * we have nothing to do.
+ */
+ if (vacnt <= pwpolicy->pw_inhistory) {
+ res = 1;
+ goto bail;
+ }
+ vacnt_todelete = vacnt - pwpolicy->pw_inhistory;
}
- strcpy ( history_str, str );
- strcat ( history_str, old_pw );
- if ( i >= pwpolicy->pw_inhistory ) {
- /* replace the oldest password in history */
- values_replace[oldest] = history_str;
- values_replace[pwpolicy->pw_inhistory] = NULL;
+
+ cur_time = current_time();
+ str = format_genTime(cur_time);
+ /* values_replace is sorted. */
+ if (old_pw) {
+ if ( vacnt >= pwpolicy->pw_inhistory ) {
+ slapi_ch_free_string(&values_replace[0]);
+ values_replace[0] = slapi_ch_smprintf("%s%s", str, old_pw);
+ } else {
+ /* add old_pw at the end of password history */
+ values_replace = (char **)slapi_ch_realloc((char *)values_replace, sizeof(char *) * (vacnt + 2));
+ values_replace[vacnt] = slapi_ch_smprintf("%s%s", str, old_pw);
+ values_replace[vacnt+1] = NULL;
+ }
+ qsort((void *)values_replace, vacnt, (size_t)sizeof(char *), pw_history_cmp);
} else {
- /* add old_pw at the end of password history */
- values_replace[i] = history_str;
- values_replace[++i]=NULL;
+ int i;
+ /* vacnt > pwpolicy->pw_inhistory */
+ for (i = 0; i < vacnt_todelete; i++) {
+ slapi_ch_free_string(&values_replace[i]);
+ }
+ memmove(values_replace, values_replace + vacnt_todelete, sizeof(char *) * pwpolicy->pw_inhistory);
+ values_replace[pwpolicy->pw_inhistory] = NULL;
}
/* modify the attribute */
@@ -1195,21 +1232,19 @@ update_pw_history( Slapi_PBlock *pb, const Slapi_DN *sdn, char *old_pw )
list_of_mods[1] = NULL;
pblock_init(&mod_pb);
- slapi_modify_internal_set_pb_ext(&mod_pb, sdn, list_of_mods, NULL, NULL,
- pw_get_componentID(), 0);
+ slapi_modify_internal_set_pb_ext(&mod_pb, sdn, list_of_mods, NULL, NULL, pw_get_componentID(), 0);
slapi_modify_internal_pb(&mod_pb);
slapi_pblock_get(&mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
if (res != LDAP_SUCCESS){
LDAPDebug2Args(LDAP_DEBUG_ANY,
"WARNING: passwordPolicy modify error %d on entry '%s'\n", res, dn);
}
-
pblock_done(&mod_pb);
-
- slapi_ch_free((void **) &str );
- slapi_ch_free((void **) &history_str );
+ slapi_ch_free_string(&str);
+bail:
+ slapi_ch_array_free(values_replace);
slapi_entry_free( e );
- return 0;
+ return res;
}
static
8 years, 8 months
Branch '389-ds-base-1.3.4' - ldap/servers
by Mark Reynolds
ldap/servers/plugins/memberof/memberof.c | 217 +++++++++++++-------
ldap/servers/plugins/memberof/memberof.h | 8
ldap/servers/plugins/memberof/memberof_config.c | 249 +++++++++++++++++-------
ldap/servers/plugins/retrocl/retrocl.c | 183 +++++++++++++++--
ldap/servers/plugins/retrocl/retrocl.h | 4
ldap/servers/plugins/retrocl/retrocl_po.c | 41 +++
6 files changed, 516 insertions(+), 186 deletions(-)
New commits:
commit d8108476d3bedbcc03f6c61bfb3d50e921faaf42
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Tue Aug 4 12:19:31 2015 -0400
Ticket 47931 - memberOf & retrocl deadlocks
Bug Description: When concurrently updating multiple backends the
memberOf and retrocl plugins can deadlock on each
other. This is caused by the required retrocl lock,
and the db lock on the changenumber index in the
retrocl db.
Fix Description: Added scoping to the retrocl that allows subtrees/suffixes
to be included or excluded. Also moved the existing
memberOf scoping outside of its global lock.
Also improved the memberOf config copying to be consistent
and more efficient. Improved the memberOf scoping attributes
to be multivalued. And, properly valdiated new config
settings in the preop valdiation function, instead of the
"apply config" function.
https://fedorahosted.org/389/ticket/47931
Valgrind: passed
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit fd959ac864d6d86d24928bc2c6f097d1a6031ecd)
diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
index da52bc8..9b577b9 100644
--- a/ldap/servers/plugins/memberof/memberof.c
+++ b/ldap/servers/plugins/memberof/memberof.c
@@ -116,7 +116,7 @@ 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);
static int memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_DN *sdn);
-static int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
+static int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn, MemberOfConfig *config,
char **types, plugin_search_entry_callback callback, void *callback_data);
static int memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn,
Slapi_Value *memberdn);
@@ -144,7 +144,7 @@ static const char *fetch_attr(Slapi_Entry *e, const char *attrname,
static void memberof_fixup_task_thread(void *arg);
static int memberof_fix_memberof(MemberOfConfig *config, char *dn, char *filter_str);
static int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data);
-
+static int memberof_entry_in_scope(MemberOfConfig *config, Slapi_DN *sdn);
/*** implementation ***/
@@ -489,7 +489,8 @@ memberof_get_plugin_area()
int memberof_postop_del(Slapi_PBlock *pb)
{
int ret = SLAPI_PLUGIN_SUCCESS;
- MemberOfConfig configCopy = {0, 0, 0, 0};
+ MemberOfConfig *mainConfig = NULL;
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Slapi_DN *sdn;
void *caller_id = NULL;
@@ -509,12 +510,13 @@ int memberof_postop_del(Slapi_PBlock *pb)
struct slapi_entry *e = NULL;
slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &e );
-
- /* We need to get the config lock first. Trying to get the
- * config lock after we already hold the op lock can cause
- * a deadlock. */
memberof_rlock_config();
- /* copy config so it doesn't change out from under us */
+ mainConfig = memberof_get_config();
+ if(!memberof_entry_in_scope(mainConfig, slapi_entry_get_sdn(e))){
+ /* The entry is not in scope, bail...*/
+ memberof_unlock_config();
+ goto bail;
+ }
memberof_copy_config(&configCopy, memberof_get_config());
memberof_unlock_config();
@@ -529,7 +531,6 @@ int memberof_postop_del(Slapi_PBlock *pb)
"memberof_postop_del: error deleting dn (%s) from group. Error (%d)\n",
slapi_sdn_get_dn(sdn),ret);
memberof_unlock();
- memberof_free_config(&configCopy);
goto bail;
}
@@ -554,10 +555,10 @@ int memberof_postop_del(Slapi_PBlock *pb)
}
}
memberof_unlock();
+bail:
memberof_free_config(&configCopy);
}
-bail:
if(ret){
slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
ret = SLAPI_PLUGIN_FAILURE;
@@ -591,7 +592,7 @@ memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_DN *
groupattrs[0] = config->groupattrs[i];
- rc = memberof_call_foreach_dn(pb, sdn, groupattrs,
+ rc = memberof_call_foreach_dn(pb, sdn, config, groupattrs,
memberof_del_dn_type_callback, &data);
}
@@ -641,6 +642,20 @@ memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data)
return rc;
}
+/* Check if the the entry include scope is a child of the sdn */
+static Slapi_DN*
+memberof_scope_is_child_of_dn(MemberOfConfig *config, Slapi_DN *sdn)
+{
+ int i = 0;
+
+ while(config->entryScopes && config->entryScopes[i]){
+ if(slapi_sdn_issuffix(config->entryScopes[i], sdn)){
+ return config->entryScopes[i];
+ }
+ i++;
+ }
+ return NULL;
+}
/*
* Does a callback search of "type=dn" under the db suffix that "dn" is in,
* unless all_backends is set, then we look at all the backends. If "dn"
@@ -649,7 +664,7 @@ memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data)
*/
int
memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
- char **types, plugin_search_entry_callback callback, void *callback_data)
+ MemberOfConfig *config, char **types, plugin_search_entry_callback callback, void *callback_data)
{
Slapi_PBlock *search_pb = NULL;
Slapi_DN *base_sdn = NULL;
@@ -657,9 +672,7 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
char *escaped_filter_val;
char *filter_str = NULL;
char *cookie = NULL;
- int all_backends = memberof_config_get_all_backends();
- Slapi_DN *entry_scope = memberof_config_get_entry_scope();
- Slapi_DN *entry_scope_exclude_subtree = memberof_config_get_entry_scope_exclude_subtree();
+ int all_backends = config->allBackends;
int types_name_len = 0;
int num_types = 0;
int dn_len = slapi_sdn_get_ndn_len(sdn);
@@ -667,11 +680,7 @@ 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);
- }
-
- if (entry_scope_exclude_subtree && slapi_sdn_issuffix(sdn, entry_scope_exclude_subtree)) {
+ if (!memberof_entry_in_scope(config, sdn)) {
return (rc);
}
@@ -728,6 +737,8 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
search_pb = slapi_pblock_new();
be = slapi_get_first_backend(&cookie);
while(be){
+ Slapi_DN *scope_sdn = NULL;
+
if(!all_backends){
be = slapi_be_select(sdn);
if(be == NULL){
@@ -743,13 +754,14 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
continue;
}
}
- if (entry_scope) {
- if (slapi_sdn_issuffix(base_sdn, entry_scope)) {
+
+ if (config->entryScopes || config->entryScopeExcludeSubtrees) {
+ if (memberof_entry_in_scope(config, base_sdn)) {
/* do nothing, entry scope is spanning
* multiple suffixes, start at suffix */
- } else if (slapi_sdn_issuffix(entry_scope, base_sdn)) {
+ } else if ((scope_sdn = memberof_scope_is_child_of_dn(config, base_sdn))) {
/* scope is below suffix, set search base */
- base_sdn = entry_scope;
+ base_sdn = scope_sdn;
} else if(!all_backends){
break;
} else {
@@ -767,7 +779,6 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
break;
}
-
if(!all_backends){
break;
}
@@ -792,10 +803,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
{
int ret = SLAPI_PLUGIN_SUCCESS;
void *caller_id = NULL;
- Slapi_DN *entry_scope = NULL;
- Slapi_DN *entry_scope_exclude_subtree = memberof_config_get_entry_scope_exclude_subtree();
- entry_scope = memberof_config_get_entry_scope();
slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
"--> memberof_postop_modrdn\n" );
@@ -810,7 +818,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
if(memberof_oktodo(pb))
{
MemberOfConfig *mainConfig = 0;
- MemberOfConfig configCopy = {0, 0, 0, 0};
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
struct slapi_entry *pre_e = NULL;
struct slapi_entry *post_e = NULL;
Slapi_DN *pre_sdn = 0;
@@ -818,7 +826,6 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &pre_e );
slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &post_e );
-
if(pre_e && post_e)
{
pre_sdn = slapi_entry_get_sdn(pre_e);
@@ -831,11 +838,19 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
memberof_copy_config(&configCopy, mainConfig);
memberof_unlock_config();
+ /* Need to check both the pre/post entries */
+ if((pre_sdn && !memberof_entry_in_scope(&configCopy, pre_sdn)) &&
+ (post_sdn && !memberof_entry_in_scope(&configCopy, post_sdn)))
+ {
+ /* The entry is not in scope */
+ goto bail;
+ }
+
memberof_lock();
/* update any downstream members */
if(pre_sdn && post_sdn && configCopy.group_filter &&
- 0 == slapi_filter_test_simple(post_e, configCopy.group_filter))
+ 0 == slapi_filter_test_simple(post_e, configCopy.group_filter))
{
int i = 0;
Slapi_Attr *attr = 0;
@@ -847,7 +862,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
if(0 == slapi_entry_attr_find(post_e, configCopy.groupattrs[i], &attr))
{
if((ret = memberof_moddn_attr_list(pb, &configCopy, pre_sdn,
- post_sdn, attr) != 0))
+ post_sdn, attr) != 0))
{
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
"memberof_postop_modrdn - update failed for (%s), error (%d)\n",
@@ -862,49 +877,49 @@ 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 (ret == LDAP_SUCCESS && pre_sdn && post_sdn) {
- if ((entry_scope && !slapi_sdn_issuffix(post_sdn, entry_scope)) ||
- (entry_scope_exclude_subtree && slapi_sdn_issuffix(post_sdn, entry_scope_exclude_subtree))) {
+ if (!memberof_entry_in_scope(&configCopy, post_sdn)){
if((ret = memberof_del_dn_from_groups(pb, &configCopy, pre_sdn))){
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
"memberof_postop_modrdn - delete dn failed for (%s), error (%d)\n",
slapi_sdn_get_dn(pre_sdn), ret);
}
if(ret == LDAP_SUCCESS && pre_e && configCopy.group_filter &&
- 0 == slapi_filter_test_simple(pre_e, configCopy.group_filter)) {
+ 0 == slapi_filter_test_simple(pre_e, configCopy.group_filter))
+ {
/* is the entry of interest as a group? */
- int i = 0;
- Slapi_Attr *attr = 0;
-
- /* Loop through to find each grouping attribute separately. */
- for (i = 0; configCopy.groupattrs[i] && ret == LDAP_SUCCESS; i++) {
- if (0 == slapi_entry_attr_find(pre_e, configCopy.groupattrs[i], &attr)) {
- if((ret = memberof_del_attr_list(pb, &configCopy, pre_sdn, attr))){
- slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "memberof_postop_modrdn: error deleting attr list - dn (%s). Error (%d)\n",
- slapi_sdn_get_dn(pre_sdn),ret);
- }
+ int i = 0;
+ Slapi_Attr *attr = 0;
+ /* Loop through to find each grouping attribute separately. */
+ for (i = 0; configCopy.groupattrs[i] && ret == LDAP_SUCCESS; i++) {
+ if (0 == slapi_entry_attr_find(pre_e, configCopy.groupattrs[i], &attr)) {
+ if((ret = memberof_del_attr_list(pb, &configCopy, pre_sdn, attr))){
+ slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+ "memberof_postop_modrdn: error deleting attr list - dn (%s). Error (%d)\n",
+ slapi_sdn_get_dn(pre_sdn),ret);
}
+
}
- }
+ }
+ }
if(ret == LDAP_SUCCESS) {
- memberof_del_dn_data del_data = {0, configCopy.memberof_attr};
- if((ret = memberof_del_dn_type_callback(post_e, &del_data))){
- slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "memberof_postop_modrdn - delete dn callback failed for (%s), error (%d)\n",
- slapi_entry_get_dn(post_e), ret);
- }
+ memberof_del_dn_data del_data = {0, configCopy.memberof_attr};
+ if((ret = memberof_del_dn_type_callback(post_e, &del_data))){
+ slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+ "memberof_postop_modrdn - delete dn callback failed for (%s), error (%d)\n",
+ slapi_entry_get_dn(post_e), ret);
}
+ }
} else {
if((ret = memberof_replace_dn_from_groups(pb, &configCopy, pre_sdn, post_sdn))){
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "memberof_postop_modrdn - replace dne failed for (%s), error (%d)\n",
+ "memberof_postop_modrdn - replace dn failed for (%s), error (%d)\n",
slapi_sdn_get_dn(pre_sdn), ret);
}
}
}
-
memberof_unlock();
+bail:
memberof_free_config(&configCopy);
}
@@ -946,7 +961,7 @@ memberof_replace_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config,
groupattrs[0] = config->groupattrs[i];
- if((ret = memberof_call_foreach_dn(pb, pre_sdn, groupattrs,
+ if((ret = memberof_call_foreach_dn(pb, pre_sdn, config, groupattrs,
memberof_replace_dn_type_callback,
&data)))
{
@@ -1064,12 +1079,11 @@ int memberof_postop_modify(Slapi_PBlock *pb)
goto done;
}
-
- if(memberof_oktodo(pb) && (sdn = memberof_getsdn(pb)))
+ if(memberof_oktodo(pb))
{
int config_copied = 0;
MemberOfConfig *mainConfig = 0;
- MemberOfConfig configCopy = {0, 0, 0, 0};
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* get the mod set */
slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
@@ -1088,19 +1102,22 @@ int memberof_postop_modify(Slapi_PBlock *pb)
* only copy the config the first time it's needed so
* it remains the same for all mods in the operation,
* despite any config changes that may be made. */
- if (!config_copied)
- {
+ if (!config_copied){
memberof_rlock_config();
mainConfig = memberof_get_config();
if (memberof_is_grouping_attr(type, mainConfig))
{
interested = 1;
+ if (!memberof_entry_in_scope(mainConfig, sdn)){
+ /* Entry is not in scope */
+ memberof_unlock_config();
+ goto bail;
+ }
/* copy config so it doesn't change out from under us */
memberof_copy_config(&configCopy, mainConfig);
config_copied = 1;
}
-
memberof_unlock_config();
} else {
if (memberof_is_grouping_attr(type, &configCopy))
@@ -1197,8 +1214,7 @@ int memberof_postop_modify(Slapi_PBlock *pb)
}
bail:
- if (config_copied)
- {
+ if (config_copied){
memberof_free_config(&configCopy);
}
@@ -1244,22 +1260,25 @@ int memberof_postop_add(Slapi_PBlock *pb)
if(memberof_oktodo(pb) && (sdn = memberof_getsdn(pb)))
{
- MemberOfConfig *mainConfig = 0;
- MemberOfConfig configCopy = {0, 0, 0, 0};
struct slapi_entry *e = NULL;
-
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ MemberOfConfig *mainConfig;
slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &e );
-
/* is the entry of interest? */
memberof_rlock_config();
mainConfig = memberof_get_config();
if(e && mainConfig && mainConfig->group_filter &&
0 == slapi_filter_test_simple(e, mainConfig->group_filter))
+
{
interested = 1;
- /* copy config so it doesn't change out from under us */
- memberof_copy_config(&configCopy, mainConfig);
+ if(!memberof_entry_in_scope(mainConfig, slapi_entry_get_sdn(e))){
+ /* Entry is not in scope */
+ memberof_unlock_config();
+ goto bail;
+ }
+ memberof_copy_config(&configCopy, memberof_get_config());
}
memberof_unlock_config();
@@ -1284,11 +1303,11 @@ int memberof_postop_add(Slapi_PBlock *pb)
}
memberof_unlock();
-
memberof_free_config(&configCopy);
}
}
+bail:
if(ret){
slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
ret = SLAPI_PLUGIN_FAILURE;
@@ -1326,26 +1345,61 @@ int memberof_oktodo(Slapi_PBlock *pb)
}
if(slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
- {
+ {
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
"memberof_postop_oktodo: could not get parameters\n" );
ret = -1;
}
- /* this plugin should only execute if the operation succeeded
- */
- if(oprc != 0)
+ /* this plugin should only execute if the operation succeeded */
+ if(oprc != 0)
{
ret = 0;
}
-
+
+bail:
slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
"<-- memberof_postop_oktodo\n" );
-bail:
return ret;
}
+/*
+ * Return 1 if the entry is in the scope.
+ * For MODRDN the caller should check both the preop
+ * and postop entries. If we are moving out of, or
+ * into scope, we should process it.
+ */
+static int
+memberof_entry_in_scope(MemberOfConfig *config, Slapi_DN *sdn)
+{
+ if (config->entryScopeExcludeSubtrees){
+ int i = 0;
+
+ /* check the excludes */
+ while(config->entryScopeExcludeSubtrees[i]){
+ if (slapi_sdn_issuffix(sdn, config->entryScopeExcludeSubtrees[i])){
+ return 0;
+ }
+ i++;
+ }
+ }
+ if (config->entryScopes){
+ int i = 0;
+
+ /* check the excludes */
+ while(config->entryScopes[i]){
+ if (slapi_sdn_issuffix(sdn, config->entryScopes[i])){
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
static Slapi_DN *
memberof_getsdn(Slapi_PBlock *pb)
{
@@ -2013,7 +2067,7 @@ memberof_get_groups_r(MemberOfConfig *config, Slapi_DN *member_sdn,
{
/* Search for any grouping attributes that point to memberdn.
* For each match, add it to the list, recurse and do same search */
- return memberof_call_foreach_dn(NULL, member_sdn, config->groupattrs,
+ return memberof_call_foreach_dn(NULL, member_sdn, config, config->groupattrs,
memberof_get_groups_callback, data);
}
@@ -2030,7 +2084,6 @@ int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data)
Slapi_Value *group_dn_val = 0;
Slapi_ValueSet *groupvals = *((memberof_get_groups_data*)callback_data)->groupvals;
Slapi_ValueSet *group_norm_vals = *((memberof_get_groups_data*)callback_data)->group_norm_vals;
- Slapi_DN *entry_scope_exclude_subtree = memberof_config_get_entry_scope_exclude_subtree();
MemberOfConfig *config = ((memberof_get_groups_data*)callback_data)->config;
int rc = 0;
@@ -2086,7 +2139,7 @@ int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data)
}
/* if the group does not belong to an excluded subtree, adds it to the valueset */
- if (!(entry_scope_exclude_subtree && slapi_sdn_issuffix(group_sdn, entry_scope_exclude_subtree))) {
+ if (memberof_entry_in_scope(config, group_sdn)) {
/* Push group_dn_val into the valueset. This memory is now owned
* by the valueset. */
group_dn_val = slapi_value_new_string(group_dn);
@@ -2188,8 +2241,8 @@ memberof_test_membership(Slapi_PBlock *pb, MemberOfConfig *config,
{
char *attrs[2] = {config->memberof_attr, 0};
- return memberof_call_foreach_dn(pb, group_sdn, attrs,
- memberof_test_membership_callback , config);
+ return memberof_call_foreach_dn(pb, group_sdn, config, attrs,
+ memberof_test_membership_callback, config);
}
/*
diff --git a/ldap/servers/plugins/memberof/memberof.h b/ldap/servers/plugins/memberof/memberof.h
index 5a70400..9d9d158 100644
--- a/ldap/servers/plugins/memberof/memberof.h
+++ b/ldap/servers/plugins/memberof/memberof.h
@@ -52,8 +52,10 @@ typedef struct memberofconfig {
char **groupattrs;
char *memberof_attr;
int allBackends;
- Slapi_DN *entryScope;
- Slapi_DN *entryScopeExcludeSubtree;
+ Slapi_DN **entryScopes;
+ int entryScopeCount;
+ Slapi_DN **entryScopeExcludeSubtrees;
+ int entryExcludeScopeCount;
Slapi_Filter *group_filter;
Slapi_Attr **group_slapiattrs;
int skip_nested;
@@ -74,8 +76,6 @@ 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();
-Slapi_DN * memberof_config_get_entry_scope_exclude_subtree();
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 ac2d045..b4cc941 100644
--- a/ldap/servers/plugins/memberof/memberof_config.c
+++ b/ldap/servers/plugins/memberof/memberof_config.c
@@ -48,7 +48,7 @@ static int memberof_search (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_En
/* This is the main configuration which is updated from dse.ldif. The
* config will be copied when it is used by the plug-in to prevent it
* being changed out from under a running memberOf operation. */
-static MemberOfConfig theConfig = {NULL, NULL,0, NULL, NULL, NULL, NULL};
+static MemberOfConfig theConfig = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static Slapi_RWLock *memberof_config_lock = 0;
static int inited = 0;
@@ -60,6 +60,19 @@ static int dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Ent
return SLAPI_DSE_CALLBACK_ERROR;
}
+static void
+memberof_free_scope(Slapi_DN **scopes, int *count)
+{
+ int i = 0;
+
+ while(scopes && scopes[i]){
+ slapi_sdn_free(&scopes[i]);
+ i++;
+ }
+ slapi_ch_free((void**)&scopes);
+ *count = 0;
+}
+
/*
* memberof_config()
*
@@ -155,17 +168,22 @@ memberof_release_config()
*
* Validate the pending changes in the e entry.
*/
-static int
+int
memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
int *returncode, char *returntext, void *arg)
{
Slapi_Attr *memberof_attr = NULL;
Slapi_Attr *group_attr = NULL;
Slapi_DN *config_sdn = NULL;
+ Slapi_DN **include_dn = NULL;
+ Slapi_DN **exclude_dn = NULL;
char *syntaxoid = NULL;
char *config_dn = NULL;
char *skip_nested = NULL;
+ char **entry_scopes = NULL;
+ char **entry_exclude_scopes = NULL;
int not_dn_syntax = 0;
+ int num_vals = 0;
*returncode = LDAP_UNWILLING_TO_PERFORM; /* be pessimistic */
@@ -283,8 +301,112 @@ memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
*returncode = LDAP_UNWILLING_TO_PERFORM;
}
}
+ /*
+ * Check the entry scopes
+ */
+ entry_scopes = slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_ATTR, &num_vals);
+ if(entry_scopes){
+ int i = 0;
+
+ /* Validate the syntax before we create our DN array */
+ for (i = 0;i < num_vals; i++){
+ if(slapi_dn_syntax_check(pb, entry_scopes[i], 1)){
+ /* invalid dn syntax */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: Invalid DN (%s) for include suffix.",
+ MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]);
+ slapi_ch_array_free(entry_scopes);
+ theConfig.entryScopeCount = 0;
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ }
+ /* Now create our SDN array for conflict checking */
+ include_dn = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *), num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ include_dn[i] = slapi_sdn_new_dn_passin(entry_scopes[i]);
+ }
+ }
+ /*
+ * Check and process the entry exclude scopes
+ */
+ entry_exclude_scopes =
+ slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE, &num_vals);
+ if(entry_exclude_scopes){
+ int i = 0;
+
+ /* Validate the syntax before we create our DN array */
+ for (i = 0;i < num_vals; i++){
+ if(slapi_dn_syntax_check(pb, entry_exclude_scopes[i], 1)){
+ /* invalid dn syntax */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: Invalid DN (%s) for exclude suffix.",
+ MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]);
+ slapi_ch_array_free(entry_exclude_scopes);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ }
+ /* Now create our SDN array for conflict checking */
+ exclude_dn = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ exclude_dn[i] = slapi_sdn_new_dn_passin(entry_exclude_scopes[i]);
+ }
+ }
+ /*
+ * Need to do conflict checking
+ */
+ if(include_dn && exclude_dn){
+ /*
+ * Make sure we haven't mixed the same suffix, and there are no
+ * conflicts between the includes and excludes
+ */
+ int i = 0;
+
+ while(include_dn[i]){
+ int x = 0;
+ while(exclude_dn[x]){
+ if(slapi_sdn_compare(include_dn[i], exclude_dn[x] ) == 0)
+ {
+ /* we have a conflict */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: include suffix (%s) is also listed as an exclude suffix list",
+ MEMBEROF_PLUGIN_SUBSYSTEM, slapi_sdn_get_dn(include_dn[i]));
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ x++;
+ }
+ i++;
+ }
+
+ /* Check for parent/child conflicts */
+ i = 0;
+ while(include_dn[i]){
+ int x = 0;
+ while(exclude_dn[x]){
+ if(slapi_sdn_issuffix(include_dn[i], exclude_dn[x]))
+ {
+ /* we have a conflict */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: include suffix (%s) is a child of the exclude suffix(%s)",
+ MEMBEROF_PLUGIN_SUBSYSTEM,
+ slapi_sdn_get_dn(include_dn[i]),
+ slapi_sdn_get_dn(exclude_dn[i]));
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ x++;
+ }
+ i++;
+ }
+ }
done:
+ memberof_free_scope(exclude_dn, &num_vals);
+ memberof_free_scope(include_dn, &num_vals);
+ slapi_ch_free((void**)&entry_scopes);
+ slapi_ch_free((void**)&entry_exclude_scopes);
slapi_sdn_free(&config_sdn);
slapi_ch_free_string(&config_dn);
slapi_ch_free_string(&skip_nested);
@@ -299,7 +421,6 @@ done:
}
}
-
/*
* memberof_apply_config()
*
@@ -318,10 +439,11 @@ 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 *entryScopeExcludeSubtree = NULL;
+ char **entryScopes = NULL;
+ char **entryScopeExcludeSubtrees = NULL;
char *sharedcfg = NULL;
char *skip_nested = NULL;
+ int num_vals = 0;
*returncode = LDAP_SUCCESS;
@@ -353,8 +475,6 @@ 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);
- entryScopeExcludeSubtree = slapi_entry_attr_get_charptr(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE);
skip_nested = slapi_entry_attr_get_charptr(e, MEMBEROF_SKIP_NESTED_ATTR);
/*
@@ -480,49 +600,39 @@ memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
theConfig.allBackends = 0;
}
- slapi_sdn_free(&theConfig.entryScope);
- 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_passin(entryScope);
+ /*
+ * Check and process the entry scopes
+ */
+ memberof_free_scope(theConfig.entryScopes, &theConfig.entryScopeCount);
+ entryScopes = slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_ATTR, &num_vals);
+ if(entryScopes){
+ int i = 0;
+
+ /* Validation has already been performed in preop, just build the DN's */
+ theConfig.entryScopes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *), num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ theConfig.entryScopes[i] = slapi_sdn_new_dn_passin(entryScopes[i]);
}
- } else {
- theConfig.entryScope = NULL;
+ theConfig.entryScopeCount = num_vals; /* shortcut for config copy */
}
-
- slapi_sdn_free(&theConfig.entryScopeExcludeSubtree);
- if (entryScopeExcludeSubtree)
- {
- if (theConfig.entryScope == NULL) {
- slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "Error: Ignoring ExcludeSubtree (%s) because entryScope is not define\n",
- entryScopeExcludeSubtree);
- theConfig.entryScopeExcludeSubtree = NULL;
- slapi_ch_free_string(&entryScopeExcludeSubtree);
- } else if (slapi_dn_syntax_check(NULL, entryScopeExcludeSubtree, 1) == 1) {
- slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "Error: Ignoring invalid DN used as plugin entry exclude subtree: [%s]\n",
- entryScopeExcludeSubtree);
- theConfig.entryScopeExcludeSubtree = NULL;
- slapi_ch_free_string(&entryScopeExcludeSubtree);
- } else {
- theConfig.entryScopeExcludeSubtree = slapi_sdn_new_dn_passin(entryScopeExcludeSubtree);
+ /*
+ * Check and process the entry exclude scopes
+ */
+ memberof_free_scope(theConfig.entryScopeExcludeSubtrees,
+ &theConfig.entryExcludeScopeCount);
+ entryScopeExcludeSubtrees =
+ slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE, &num_vals);
+ if(entryScopeExcludeSubtrees){
+ int i = 0;
+
+ /* Validation has already been performed in preop, just build the DN's */
+ theConfig.entryScopeExcludeSubtrees =
+ (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ theConfig.entryScopeExcludeSubtrees[i] =
+ slapi_sdn_new_dn_passin(entryScopeExcludeSubtrees[i]);
}
- } else {
- theConfig.entryScopeExcludeSubtree = NULL;
- }
- if (theConfig.entryScopeExcludeSubtree && theConfig.entryScope && !slapi_sdn_issuffix(theConfig.entryScopeExcludeSubtree, theConfig.entryScope)) {
- slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "Error: Ignoring ExcludeSubtree (%s) that is out of the scope (%s)\n",
- slapi_sdn_get_dn(theConfig.entryScopeExcludeSubtree),
- slapi_sdn_get_dn(theConfig.entryScope));
- slapi_sdn_free(&theConfig.entryScopeExcludeSubtree);
+ theConfig.entryExcludeScopeCount = num_vals; /* shortcut for config copy */
}
/* release the lock */
@@ -536,6 +646,8 @@ done:
slapi_ch_free_string(&memberof_attr);
slapi_ch_free_string(&allBackends);
slapi_ch_free_string(&skip_nested);
+ slapi_ch_free((void **)&entryScopes);
+ slapi_ch_free((void **)&entryScopeExcludeSubtrees);
if (*returncode != LDAP_SUCCESS)
{
@@ -616,6 +728,23 @@ memberof_copy_config(MemberOfConfig *dest, MemberOfConfig *src)
{
dest->allBackends = src->allBackends;
}
+
+ if(src->entryScopes){
+ int num_vals = 0;
+
+ dest->entryScopes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),src->entryScopeCount+1);
+ for(num_vals = 0; src->entryScopes[num_vals]; num_vals++){
+ dest->entryScopes[num_vals] = slapi_sdn_dup(src->entryScopes[num_vals]);
+ }
+ }
+ if(src->entryScopeExcludeSubtrees){
+ int num_vals = 0;
+
+ dest->entryScopeExcludeSubtrees = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),src->entryExcludeScopeCount+1);
+ for(num_vals = 0; src->entryScopes[num_vals]; num_vals++){
+ dest->entryScopeExcludeSubtrees[num_vals] = slapi_sdn_dup(src->entryScopeExcludeSubtrees[num_vals]);
+ }
+ }
}
}
@@ -641,6 +770,8 @@ memberof_free_config(MemberOfConfig *config)
slapi_ch_free((void **)&config->group_slapiattrs);
slapi_ch_free_string(&config->memberof_attr);
+ memberof_free_scope(config->entryScopes, &config->entryScopeCount);
+ memberof_free_scope(config->entryScopeExcludeSubtrees, &config->entryExcludeScopeCount);
}
}
@@ -706,30 +837,6 @@ 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;
-}
-
-Slapi_DN *
-memberof_config_get_entry_scope_exclude_subtree()
-{
- Slapi_DN *entry_exclude_subtree;
-
- slapi_rwlock_rdlock(memberof_config_lock);
- entry_exclude_subtree = theConfig.entryScopeExcludeSubtree;
- slapi_rwlock_unlock(memberof_config_lock);
-
- return entry_exclude_subtree;
-}
-
/*
* Check if we are modifying the config, or changing the shared config entry
*/
diff --git a/ldap/servers/plugins/retrocl/retrocl.c b/ldap/servers/plugins/retrocl/retrocl.c
index 78a0c6d..4bcbb38 100644
--- a/ldap/servers/plugins/retrocl/retrocl.c
+++ b/ldap/servers/plugins/retrocl/retrocl.c
@@ -45,6 +45,9 @@ char **retrocl_attributes = NULL;
char **retrocl_aliases = NULL;
int retrocl_log_deleted = 0;
+static Slapi_DN **retrocl_includes = NULL;
+static Slapi_DN **retrocl_excludes = NULL;
+
/* ----------------------------- Retrocl Plugin */
static Slapi_PluginDesc retrocldesc = {"retrocl", VENDOR, DS_PACKAGE_VERSION, "Retrocl Plugin"};
@@ -349,6 +352,8 @@ static int retrocl_start (Slapi_PBlock *pb)
int rc = 0;
Slapi_Entry *e = NULL;
char **values = NULL;
+ int num_vals = 0;
+ int i = 0;
retrocl_rootdse_init(pb);
@@ -369,6 +374,87 @@ static int retrocl_start (Slapi_PBlock *pb)
return -1;
}
+ /* Get the exclude suffixes */
+ values = slapi_entry_attr_get_charray_ext(e, CONFIG_CHANGELOG_EXCLUDE_SUFFIX, &num_vals);
+ if(values){
+ /* Validate the syntax before we create our DN array */
+ for (i = 0;i < num_vals; i++){
+ if(slapi_dn_syntax_check(pb, values[i], 1)){
+ /* invalid dn syntax */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "Invalid DN (%s) for exclude suffix.\n", values[i] );
+ slapi_ch_array_free(values);
+ return -1;
+ }
+ }
+ /* Now create our SDN array */
+ retrocl_excludes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ retrocl_excludes[i] = slapi_sdn_new_dn_byval(values[i]);
+ }
+ slapi_ch_array_free(values);
+ }
+ /* Get the include suffixes */
+ values = slapi_entry_attr_get_charray_ext(e, CONFIG_CHANGELOG_INCLUDE_SUFFIX, &num_vals);
+ if(values){
+ for (i = 0;i < num_vals; i++){
+ /* Validate the syntax before we create our DN array */
+ if(slapi_dn_syntax_check(pb, values[i], 1)){
+ /* invalid dn syntax */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "Invalid DN (%s) for include suffix.\n", values[i] );
+ slapi_ch_array_free(values);
+ return -1;
+ }
+ }
+ /* Now create our SDN array */
+ retrocl_includes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ retrocl_includes[i] = slapi_sdn_new_dn_byval(values[i]);
+ }
+ slapi_ch_array_free(values);
+ }
+ if(retrocl_includes && retrocl_excludes){
+ /*
+ * Make sure we haven't mixed the same suffix, and there are no
+ * conflicts between the includes and excludes
+ */
+ int i = 0;
+
+ while(retrocl_includes[i]){
+ int x = 0;
+ while(retrocl_excludes[x]){
+ if(slapi_sdn_compare(retrocl_includes[i], retrocl_excludes[x] ) == 0){
+ /* we have a conflict */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "include suffix (%s) is also listed in exclude suffix list\n",
+ slapi_sdn_get_dn(retrocl_includes[i]));
+ return -1;
+ }
+ x++;
+ }
+ i++;
+ }
+
+ /* Check for parent/child conflicts */
+ i = 0;
+ while(retrocl_includes[i]){
+ int x = 0;
+ while(retrocl_excludes[x]){
+ if(slapi_sdn_issuffix(retrocl_includes[i], retrocl_excludes[x])){
+ /* we have a conflict */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "include suffix (%s) is a child of the exclude suffix(%s)\n",
+ slapi_sdn_get_dn(retrocl_includes[i]),
+ slapi_sdn_get_dn(retrocl_excludes[i]));
+ return -1;
+ }
+ x++;
+ }
+ i++;
+ }
+ }
+
values = slapi_entry_attr_get_charray(e, "nsslapd-attribute");
if (values != NULL) {
int n = 0;
@@ -434,6 +520,49 @@ static int retrocl_start (Slapi_PBlock *pb)
}
/*
+ * Check if an entry is in the configured scope.
+ * Return 1 if entry is in the scope, or 0 otherwise.
+ * For MODRDN the caller should check both the preop
+ * and postop entries. If we are moving out of, or
+ * into scope, we should record it.
+ */
+int
+retrocl_entry_in_scope(Slapi_Entry *e)
+{
+ Slapi_DN *sdn = slapi_entry_get_sdn(e);
+
+ if (e == NULL){
+ return 1;
+ }
+
+ if (retrocl_excludes){
+ int i = 0;
+
+ /* check the excludes */
+ while(retrocl_excludes[i]){
+ if (slapi_sdn_issuffix(sdn, retrocl_excludes[i])){
+ return 0;
+ }
+ i++;
+ }
+ }
+ if (retrocl_includes){
+ int i = 0;
+
+ /* check the excludes */
+ while(retrocl_includes[i]){
+ if (slapi_sdn_issuffix(sdn, retrocl_includes[i])){
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
* Function: retrocl_stop
*
* Returns: 0
@@ -446,26 +575,40 @@ static int retrocl_start (Slapi_PBlock *pb)
static int retrocl_stop (Slapi_PBlock *pb)
{
- int rc = 0;
-
- slapi_ch_array_free(retrocl_attributes);
- retrocl_attributes = NULL;
- slapi_ch_array_free(retrocl_aliases);
- retrocl_aliases = NULL;
-
- retrocl_stop_trimming();
- retrocl_be_changelog = NULL;
- retrocl_forget_changenumbers();
- PR_DestroyLock(retrocl_internal_lock);
- retrocl_internal_lock = NULL;
- slapi_destroy_rwlock(retrocl_cn_lock);
- retrocl_cn_lock = NULL;
- legacy_initialised = 0;
-
- slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, "",
- LDAP_SCOPE_BASE,"(objectclass=*)", retrocl_rootdse_search);
-
- return rc;
+ int rc = 0;
+ int i = 0;
+
+ slapi_ch_array_free(retrocl_attributes);
+ retrocl_attributes = NULL;
+ slapi_ch_array_free(retrocl_aliases);
+ retrocl_aliases = NULL;
+
+ while(retrocl_excludes && retrocl_excludes[i]){
+ slapi_sdn_free(&retrocl_excludes[i]);
+ i++;
+ }
+ slapi_ch_free((void**)&retrocl_excludes);
+ i = 0;
+
+ while(retrocl_includes && retrocl_includes[i]){
+ slapi_sdn_free(&retrocl_includes[i]);
+ i++;
+ }
+ slapi_ch_free((void**)&retrocl_includes);
+
+ retrocl_stop_trimming();
+ retrocl_be_changelog = NULL;
+ retrocl_forget_changenumbers();
+ PR_DestroyLock(retrocl_internal_lock);
+ retrocl_internal_lock = NULL;
+ slapi_destroy_rwlock(retrocl_cn_lock);
+ retrocl_cn_lock = NULL;
+ legacy_initialised = 0;
+
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, "",
+ LDAP_SCOPE_BASE,"(objectclass=*)", retrocl_rootdse_search);
+
+ return rc;
}
/*
diff --git a/ldap/servers/plugins/retrocl/retrocl.h b/ldap/servers/plugins/retrocl/retrocl.h
index ae0139c..7edd62f 100644
--- a/ldap/servers/plugins/retrocl/retrocl.h
+++ b/ldap/servers/plugins/retrocl/retrocl.h
@@ -67,6 +67,8 @@ typedef struct _cnumRet {
/* was originally changelogmaximumage */
#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage"
#define CONFIG_CHANGELOG_DIRECTORY_ATTRIBUTE "nsslapd-changelogdir"
+#define CONFIG_CHANGELOG_INCLUDE_SUFFIX "nsslapd-include-suffix"
+#define CONFIG_CHANGELOG_EXCLUDE_SUFFIX "nsslapd-exclude-suffix"
#define RETROCL_CHANGELOG_DN "cn=changelog"
#define RETROCL_MAPPINGTREE_DN "cn=\"cn=changelog\",cn=mapping tree,cn=config"
@@ -140,4 +142,6 @@ extern void retrocl_init_trimming(void);
extern void retrocl_stop_trimming(void);
extern char *retrocl_get_config_str(const char *attrt);
+int retrocl_entry_in_scope(Slapi_Entry *e);
+
#endif /* _H_RETROCL */
diff --git a/ldap/servers/plugins/retrocl/retrocl_po.c b/ldap/servers/plugins/retrocl/retrocl_po.c
index 7083d0a..f689373 100644
--- a/ldap/servers/plugins/retrocl/retrocl_po.c
+++ b/ldap/servers/plugins/retrocl/retrocl_po.c
@@ -140,6 +140,7 @@ write_replog_db(
int flag,
time_t curtime,
Slapi_Entry *log_e,
+ Slapi_Entry *post_entry,
const char *newrdn,
LDAPMod **modrdn_mods,
const char *newsuperior
@@ -156,11 +157,26 @@ write_replog_db(
int err = 0;
int ret = LDAP_SUCCESS;
int i;
+ int mark = 0;
if (!dn) {
slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "write_replog_db: NULL dn\n");
return ret;
}
+ mark = (post_entry && retrocl_entry_in_scope(post_entry));
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "post in scope (%d)\n",mark);
+
+ if (post_entry){
+ if(!retrocl_entry_in_scope(log_e) && !retrocl_entry_in_scope(post_entry)){
+ /* modrdn: entry not in scope, just return... */
+ return ret;
+ }
+ } else {
+ if(!retrocl_entry_in_scope(log_e)){
+ /* entry not in scope, just return... */
+ return ret;
+ }
+ }
PR_Lock(retrocl_internal_lock);
changenum = retrocl_assign_changenumber();
@@ -319,7 +335,7 @@ write_replog_db(
break;
case OP_DELETE:
- if (log_e) {
+ if (retrocl_log_deleted) {
/* we have to log the full entry */
if ( entry2reple( e, log_e, OP_DELETE ) != 0 ) {
err = SLAPI_PLUGIN_FAILURE;
@@ -559,7 +575,8 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
char *dn;
LDAPMod **log_m = NULL;
int flag = 0;
- Slapi_Entry *te = NULL;
+ Slapi_Entry *entry = NULL;
+ Slapi_Entry *post_entry = NULL;
Slapi_Operation *op = NULL;
LDAPMod **modrdn_mods = NULL;
char *newrdn = NULL;
@@ -624,7 +641,12 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
LDAPDebug0Args(LDAP_DEBUG_TRACE,"not applying change for nsTombstone entries\n");
return SLAPI_PLUGIN_SUCCESS;
}
-
+ /*
+ * Start by grabbing the preop entry, ADD will replace it as needed. Getting the entry
+ * allows up to perform scoping in write_replog_db() for all op types.
+ */
+ (void)slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &entry);
+
switch ( optype ) {
case OP_MODIFY:
(void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &log_m );
@@ -634,14 +656,14 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
* For adds, we want the unnormalized dn, so we can preserve
* spacing, case, when replicating it.
*/
- (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &te );
- if ( NULL != te ) {
- dn = slapi_entry_get_dn( te );
+ (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &entry );
+ if ( NULL != entry ) {
+ dn = slapi_entry_get_dn( entry );
}
break;
case OP_DELETE:
if (retrocl_log_deleted)
- (void)slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &te);
+ (void)slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &entry);
break;
case OP_MODRDN:
/* newrdn is used just for logging; no need to be normalized */
@@ -649,13 +671,14 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
(void)slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &flag );
(void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &modrdn_mods );
(void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperior );
+ (void)slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &post_entry);
break;
}
/* check if we should log change to retro changelog, and
* if so, do it here */
- if((rc = write_replog_db( pb, optype, dn, log_m, flag, curtime, te,
- newrdn, modrdn_mods, slapi_sdn_get_dn(newsuperior) )))
+ if((rc = write_replog_db( pb, optype, dn, log_m, flag, curtime, entry,
+ post_entry, newrdn, modrdn_mods, slapi_sdn_get_dn(newsuperior) )))
{
slapi_log_error(SLAPI_LOG_FATAL, "retrocl-plugin",
"retrocl_postob: operation failure [%d]\n", rc);
8 years, 8 months
ldap/servers
by Mark Reynolds
ldap/servers/plugins/memberof/memberof.c | 217 +++++++++++++-------
ldap/servers/plugins/memberof/memberof.h | 8
ldap/servers/plugins/memberof/memberof_config.c | 249 +++++++++++++++++-------
ldap/servers/plugins/retrocl/retrocl.c | 183 +++++++++++++++--
ldap/servers/plugins/retrocl/retrocl.h | 4
ldap/servers/plugins/retrocl/retrocl_po.c | 41 +++
6 files changed, 516 insertions(+), 186 deletions(-)
New commits:
commit fd959ac864d6d86d24928bc2c6f097d1a6031ecd
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Tue Aug 4 12:19:31 2015 -0400
Ticket 47931 - memberOf & retrocl deadlocks
Bug Description: When concurrently updating multiple backends the
memberOf and retrocl plugins can deadlock on each
other. This is caused by the required retrocl lock,
and the db lock on the changenumber index in the
retrocl db.
Fix Description: Added scoping to the retrocl that allows subtrees/suffixes
to be included or excluded. Also moved the existing
memberOf scoping outside of its global lock.
Also improved the memberOf config copying to be consistent
and more efficient. Improved the memberOf scoping attributes
to be multivalued. And, properly valdiated new config
settings in the preop valdiation function, instead of the
"apply config" function.
https://fedorahosted.org/389/ticket/47931
Valgrind: passed
Reviewed by: nhosoi(Thanks!)
diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
index da52bc8..9b577b9 100644
--- a/ldap/servers/plugins/memberof/memberof.c
+++ b/ldap/servers/plugins/memberof/memberof.c
@@ -116,7 +116,7 @@ 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);
static int memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_DN *sdn);
-static int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
+static int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn, MemberOfConfig *config,
char **types, plugin_search_entry_callback callback, void *callback_data);
static int memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn,
Slapi_Value *memberdn);
@@ -144,7 +144,7 @@ static const char *fetch_attr(Slapi_Entry *e, const char *attrname,
static void memberof_fixup_task_thread(void *arg);
static int memberof_fix_memberof(MemberOfConfig *config, char *dn, char *filter_str);
static int memberof_fix_memberof_callback(Slapi_Entry *e, void *callback_data);
-
+static int memberof_entry_in_scope(MemberOfConfig *config, Slapi_DN *sdn);
/*** implementation ***/
@@ -489,7 +489,8 @@ memberof_get_plugin_area()
int memberof_postop_del(Slapi_PBlock *pb)
{
int ret = SLAPI_PLUGIN_SUCCESS;
- MemberOfConfig configCopy = {0, 0, 0, 0};
+ MemberOfConfig *mainConfig = NULL;
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Slapi_DN *sdn;
void *caller_id = NULL;
@@ -509,12 +510,13 @@ int memberof_postop_del(Slapi_PBlock *pb)
struct slapi_entry *e = NULL;
slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &e );
-
- /* We need to get the config lock first. Trying to get the
- * config lock after we already hold the op lock can cause
- * a deadlock. */
memberof_rlock_config();
- /* copy config so it doesn't change out from under us */
+ mainConfig = memberof_get_config();
+ if(!memberof_entry_in_scope(mainConfig, slapi_entry_get_sdn(e))){
+ /* The entry is not in scope, bail...*/
+ memberof_unlock_config();
+ goto bail;
+ }
memberof_copy_config(&configCopy, memberof_get_config());
memberof_unlock_config();
@@ -529,7 +531,6 @@ int memberof_postop_del(Slapi_PBlock *pb)
"memberof_postop_del: error deleting dn (%s) from group. Error (%d)\n",
slapi_sdn_get_dn(sdn),ret);
memberof_unlock();
- memberof_free_config(&configCopy);
goto bail;
}
@@ -554,10 +555,10 @@ int memberof_postop_del(Slapi_PBlock *pb)
}
}
memberof_unlock();
+bail:
memberof_free_config(&configCopy);
}
-bail:
if(ret){
slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
ret = SLAPI_PLUGIN_FAILURE;
@@ -591,7 +592,7 @@ memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_DN *
groupattrs[0] = config->groupattrs[i];
- rc = memberof_call_foreach_dn(pb, sdn, groupattrs,
+ rc = memberof_call_foreach_dn(pb, sdn, config, groupattrs,
memberof_del_dn_type_callback, &data);
}
@@ -641,6 +642,20 @@ memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data)
return rc;
}
+/* Check if the the entry include scope is a child of the sdn */
+static Slapi_DN*
+memberof_scope_is_child_of_dn(MemberOfConfig *config, Slapi_DN *sdn)
+{
+ int i = 0;
+
+ while(config->entryScopes && config->entryScopes[i]){
+ if(slapi_sdn_issuffix(config->entryScopes[i], sdn)){
+ return config->entryScopes[i];
+ }
+ i++;
+ }
+ return NULL;
+}
/*
* Does a callback search of "type=dn" under the db suffix that "dn" is in,
* unless all_backends is set, then we look at all the backends. If "dn"
@@ -649,7 +664,7 @@ memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data)
*/
int
memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
- char **types, plugin_search_entry_callback callback, void *callback_data)
+ MemberOfConfig *config, char **types, plugin_search_entry_callback callback, void *callback_data)
{
Slapi_PBlock *search_pb = NULL;
Slapi_DN *base_sdn = NULL;
@@ -657,9 +672,7 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
char *escaped_filter_val;
char *filter_str = NULL;
char *cookie = NULL;
- int all_backends = memberof_config_get_all_backends();
- Slapi_DN *entry_scope = memberof_config_get_entry_scope();
- Slapi_DN *entry_scope_exclude_subtree = memberof_config_get_entry_scope_exclude_subtree();
+ int all_backends = config->allBackends;
int types_name_len = 0;
int num_types = 0;
int dn_len = slapi_sdn_get_ndn_len(sdn);
@@ -667,11 +680,7 @@ 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);
- }
-
- if (entry_scope_exclude_subtree && slapi_sdn_issuffix(sdn, entry_scope_exclude_subtree)) {
+ if (!memberof_entry_in_scope(config, sdn)) {
return (rc);
}
@@ -728,6 +737,8 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
search_pb = slapi_pblock_new();
be = slapi_get_first_backend(&cookie);
while(be){
+ Slapi_DN *scope_sdn = NULL;
+
if(!all_backends){
be = slapi_be_select(sdn);
if(be == NULL){
@@ -743,13 +754,14 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
continue;
}
}
- if (entry_scope) {
- if (slapi_sdn_issuffix(base_sdn, entry_scope)) {
+
+ if (config->entryScopes || config->entryScopeExcludeSubtrees) {
+ if (memberof_entry_in_scope(config, base_sdn)) {
/* do nothing, entry scope is spanning
* multiple suffixes, start at suffix */
- } else if (slapi_sdn_issuffix(entry_scope, base_sdn)) {
+ } else if ((scope_sdn = memberof_scope_is_child_of_dn(config, base_sdn))) {
/* scope is below suffix, set search base */
- base_sdn = entry_scope;
+ base_sdn = scope_sdn;
} else if(!all_backends){
break;
} else {
@@ -767,7 +779,6 @@ memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_DN *sdn,
break;
}
-
if(!all_backends){
break;
}
@@ -792,10 +803,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
{
int ret = SLAPI_PLUGIN_SUCCESS;
void *caller_id = NULL;
- Slapi_DN *entry_scope = NULL;
- Slapi_DN *entry_scope_exclude_subtree = memberof_config_get_entry_scope_exclude_subtree();
- entry_scope = memberof_config_get_entry_scope();
slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
"--> memberof_postop_modrdn\n" );
@@ -810,7 +818,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
if(memberof_oktodo(pb))
{
MemberOfConfig *mainConfig = 0;
- MemberOfConfig configCopy = {0, 0, 0, 0};
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
struct slapi_entry *pre_e = NULL;
struct slapi_entry *post_e = NULL;
Slapi_DN *pre_sdn = 0;
@@ -818,7 +826,6 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &pre_e );
slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &post_e );
-
if(pre_e && post_e)
{
pre_sdn = slapi_entry_get_sdn(pre_e);
@@ -831,11 +838,19 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
memberof_copy_config(&configCopy, mainConfig);
memberof_unlock_config();
+ /* Need to check both the pre/post entries */
+ if((pre_sdn && !memberof_entry_in_scope(&configCopy, pre_sdn)) &&
+ (post_sdn && !memberof_entry_in_scope(&configCopy, post_sdn)))
+ {
+ /* The entry is not in scope */
+ goto bail;
+ }
+
memberof_lock();
/* update any downstream members */
if(pre_sdn && post_sdn && configCopy.group_filter &&
- 0 == slapi_filter_test_simple(post_e, configCopy.group_filter))
+ 0 == slapi_filter_test_simple(post_e, configCopy.group_filter))
{
int i = 0;
Slapi_Attr *attr = 0;
@@ -847,7 +862,7 @@ int memberof_postop_modrdn(Slapi_PBlock *pb)
if(0 == slapi_entry_attr_find(post_e, configCopy.groupattrs[i], &attr))
{
if((ret = memberof_moddn_attr_list(pb, &configCopy, pre_sdn,
- post_sdn, attr) != 0))
+ post_sdn, attr) != 0))
{
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
"memberof_postop_modrdn - update failed for (%s), error (%d)\n",
@@ -862,49 +877,49 @@ 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 (ret == LDAP_SUCCESS && pre_sdn && post_sdn) {
- if ((entry_scope && !slapi_sdn_issuffix(post_sdn, entry_scope)) ||
- (entry_scope_exclude_subtree && slapi_sdn_issuffix(post_sdn, entry_scope_exclude_subtree))) {
+ if (!memberof_entry_in_scope(&configCopy, post_sdn)){
if((ret = memberof_del_dn_from_groups(pb, &configCopy, pre_sdn))){
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
"memberof_postop_modrdn - delete dn failed for (%s), error (%d)\n",
slapi_sdn_get_dn(pre_sdn), ret);
}
if(ret == LDAP_SUCCESS && pre_e && configCopy.group_filter &&
- 0 == slapi_filter_test_simple(pre_e, configCopy.group_filter)) {
+ 0 == slapi_filter_test_simple(pre_e, configCopy.group_filter))
+ {
/* is the entry of interest as a group? */
- int i = 0;
- Slapi_Attr *attr = 0;
-
- /* Loop through to find each grouping attribute separately. */
- for (i = 0; configCopy.groupattrs[i] && ret == LDAP_SUCCESS; i++) {
- if (0 == slapi_entry_attr_find(pre_e, configCopy.groupattrs[i], &attr)) {
- if((ret = memberof_del_attr_list(pb, &configCopy, pre_sdn, attr))){
- slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "memberof_postop_modrdn: error deleting attr list - dn (%s). Error (%d)\n",
- slapi_sdn_get_dn(pre_sdn),ret);
- }
+ int i = 0;
+ Slapi_Attr *attr = 0;
+ /* Loop through to find each grouping attribute separately. */
+ for (i = 0; configCopy.groupattrs[i] && ret == LDAP_SUCCESS; i++) {
+ if (0 == slapi_entry_attr_find(pre_e, configCopy.groupattrs[i], &attr)) {
+ if((ret = memberof_del_attr_list(pb, &configCopy, pre_sdn, attr))){
+ slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+ "memberof_postop_modrdn: error deleting attr list - dn (%s). Error (%d)\n",
+ slapi_sdn_get_dn(pre_sdn),ret);
}
+
}
- }
+ }
+ }
if(ret == LDAP_SUCCESS) {
- memberof_del_dn_data del_data = {0, configCopy.memberof_attr};
- if((ret = memberof_del_dn_type_callback(post_e, &del_data))){
- slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "memberof_postop_modrdn - delete dn callback failed for (%s), error (%d)\n",
- slapi_entry_get_dn(post_e), ret);
- }
+ memberof_del_dn_data del_data = {0, configCopy.memberof_attr};
+ if((ret = memberof_del_dn_type_callback(post_e, &del_data))){
+ slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
+ "memberof_postop_modrdn - delete dn callback failed for (%s), error (%d)\n",
+ slapi_entry_get_dn(post_e), ret);
}
+ }
} else {
if((ret = memberof_replace_dn_from_groups(pb, &configCopy, pre_sdn, post_sdn))){
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "memberof_postop_modrdn - replace dne failed for (%s), error (%d)\n",
+ "memberof_postop_modrdn - replace dn failed for (%s), error (%d)\n",
slapi_sdn_get_dn(pre_sdn), ret);
}
}
}
-
memberof_unlock();
+bail:
memberof_free_config(&configCopy);
}
@@ -946,7 +961,7 @@ memberof_replace_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config,
groupattrs[0] = config->groupattrs[i];
- if((ret = memberof_call_foreach_dn(pb, pre_sdn, groupattrs,
+ if((ret = memberof_call_foreach_dn(pb, pre_sdn, config, groupattrs,
memberof_replace_dn_type_callback,
&data)))
{
@@ -1064,12 +1079,11 @@ int memberof_postop_modify(Slapi_PBlock *pb)
goto done;
}
-
- if(memberof_oktodo(pb) && (sdn = memberof_getsdn(pb)))
+ if(memberof_oktodo(pb))
{
int config_copied = 0;
MemberOfConfig *mainConfig = 0;
- MemberOfConfig configCopy = {0, 0, 0, 0};
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* get the mod set */
slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
@@ -1088,19 +1102,22 @@ int memberof_postop_modify(Slapi_PBlock *pb)
* only copy the config the first time it's needed so
* it remains the same for all mods in the operation,
* despite any config changes that may be made. */
- if (!config_copied)
- {
+ if (!config_copied){
memberof_rlock_config();
mainConfig = memberof_get_config();
if (memberof_is_grouping_attr(type, mainConfig))
{
interested = 1;
+ if (!memberof_entry_in_scope(mainConfig, sdn)){
+ /* Entry is not in scope */
+ memberof_unlock_config();
+ goto bail;
+ }
/* copy config so it doesn't change out from under us */
memberof_copy_config(&configCopy, mainConfig);
config_copied = 1;
}
-
memberof_unlock_config();
} else {
if (memberof_is_grouping_attr(type, &configCopy))
@@ -1197,8 +1214,7 @@ int memberof_postop_modify(Slapi_PBlock *pb)
}
bail:
- if (config_copied)
- {
+ if (config_copied){
memberof_free_config(&configCopy);
}
@@ -1244,22 +1260,25 @@ int memberof_postop_add(Slapi_PBlock *pb)
if(memberof_oktodo(pb) && (sdn = memberof_getsdn(pb)))
{
- MemberOfConfig *mainConfig = 0;
- MemberOfConfig configCopy = {0, 0, 0, 0};
struct slapi_entry *e = NULL;
-
+ MemberOfConfig configCopy = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ MemberOfConfig *mainConfig;
slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &e );
-
/* is the entry of interest? */
memberof_rlock_config();
mainConfig = memberof_get_config();
if(e && mainConfig && mainConfig->group_filter &&
0 == slapi_filter_test_simple(e, mainConfig->group_filter))
+
{
interested = 1;
- /* copy config so it doesn't change out from under us */
- memberof_copy_config(&configCopy, mainConfig);
+ if(!memberof_entry_in_scope(mainConfig, slapi_entry_get_sdn(e))){
+ /* Entry is not in scope */
+ memberof_unlock_config();
+ goto bail;
+ }
+ memberof_copy_config(&configCopy, memberof_get_config());
}
memberof_unlock_config();
@@ -1284,11 +1303,11 @@ int memberof_postop_add(Slapi_PBlock *pb)
}
memberof_unlock();
-
memberof_free_config(&configCopy);
}
}
+bail:
if(ret){
slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret);
ret = SLAPI_PLUGIN_FAILURE;
@@ -1326,26 +1345,61 @@ int memberof_oktodo(Slapi_PBlock *pb)
}
if(slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
- {
+ {
slapi_log_error( SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
"memberof_postop_oktodo: could not get parameters\n" );
ret = -1;
}
- /* this plugin should only execute if the operation succeeded
- */
- if(oprc != 0)
+ /* this plugin should only execute if the operation succeeded */
+ if(oprc != 0)
{
ret = 0;
}
-
+
+bail:
slapi_log_error( SLAPI_LOG_TRACE, MEMBEROF_PLUGIN_SUBSYSTEM,
"<-- memberof_postop_oktodo\n" );
-bail:
return ret;
}
+/*
+ * Return 1 if the entry is in the scope.
+ * For MODRDN the caller should check both the preop
+ * and postop entries. If we are moving out of, or
+ * into scope, we should process it.
+ */
+static int
+memberof_entry_in_scope(MemberOfConfig *config, Slapi_DN *sdn)
+{
+ if (config->entryScopeExcludeSubtrees){
+ int i = 0;
+
+ /* check the excludes */
+ while(config->entryScopeExcludeSubtrees[i]){
+ if (slapi_sdn_issuffix(sdn, config->entryScopeExcludeSubtrees[i])){
+ return 0;
+ }
+ i++;
+ }
+ }
+ if (config->entryScopes){
+ int i = 0;
+
+ /* check the excludes */
+ while(config->entryScopes[i]){
+ if (slapi_sdn_issuffix(sdn, config->entryScopes[i])){
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
static Slapi_DN *
memberof_getsdn(Slapi_PBlock *pb)
{
@@ -2013,7 +2067,7 @@ memberof_get_groups_r(MemberOfConfig *config, Slapi_DN *member_sdn,
{
/* Search for any grouping attributes that point to memberdn.
* For each match, add it to the list, recurse and do same search */
- return memberof_call_foreach_dn(NULL, member_sdn, config->groupattrs,
+ return memberof_call_foreach_dn(NULL, member_sdn, config, config->groupattrs,
memberof_get_groups_callback, data);
}
@@ -2030,7 +2084,6 @@ int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data)
Slapi_Value *group_dn_val = 0;
Slapi_ValueSet *groupvals = *((memberof_get_groups_data*)callback_data)->groupvals;
Slapi_ValueSet *group_norm_vals = *((memberof_get_groups_data*)callback_data)->group_norm_vals;
- Slapi_DN *entry_scope_exclude_subtree = memberof_config_get_entry_scope_exclude_subtree();
MemberOfConfig *config = ((memberof_get_groups_data*)callback_data)->config;
int rc = 0;
@@ -2086,7 +2139,7 @@ int memberof_get_groups_callback(Slapi_Entry *e, void *callback_data)
}
/* if the group does not belong to an excluded subtree, adds it to the valueset */
- if (!(entry_scope_exclude_subtree && slapi_sdn_issuffix(group_sdn, entry_scope_exclude_subtree))) {
+ if (memberof_entry_in_scope(config, group_sdn)) {
/* Push group_dn_val into the valueset. This memory is now owned
* by the valueset. */
group_dn_val = slapi_value_new_string(group_dn);
@@ -2188,8 +2241,8 @@ memberof_test_membership(Slapi_PBlock *pb, MemberOfConfig *config,
{
char *attrs[2] = {config->memberof_attr, 0};
- return memberof_call_foreach_dn(pb, group_sdn, attrs,
- memberof_test_membership_callback , config);
+ return memberof_call_foreach_dn(pb, group_sdn, config, attrs,
+ memberof_test_membership_callback, config);
}
/*
diff --git a/ldap/servers/plugins/memberof/memberof.h b/ldap/servers/plugins/memberof/memberof.h
index 5a70400..9d9d158 100644
--- a/ldap/servers/plugins/memberof/memberof.h
+++ b/ldap/servers/plugins/memberof/memberof.h
@@ -52,8 +52,10 @@ typedef struct memberofconfig {
char **groupattrs;
char *memberof_attr;
int allBackends;
- Slapi_DN *entryScope;
- Slapi_DN *entryScopeExcludeSubtree;
+ Slapi_DN **entryScopes;
+ int entryScopeCount;
+ Slapi_DN **entryScopeExcludeSubtrees;
+ int entryExcludeScopeCount;
Slapi_Filter *group_filter;
Slapi_Attr **group_slapiattrs;
int skip_nested;
@@ -74,8 +76,6 @@ 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();
-Slapi_DN * memberof_config_get_entry_scope_exclude_subtree();
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 ac2d045..b4cc941 100644
--- a/ldap/servers/plugins/memberof/memberof_config.c
+++ b/ldap/servers/plugins/memberof/memberof_config.c
@@ -48,7 +48,7 @@ static int memberof_search (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_En
/* This is the main configuration which is updated from dse.ldif. The
* config will be copied when it is used by the plug-in to prevent it
* being changed out from under a running memberOf operation. */
-static MemberOfConfig theConfig = {NULL, NULL,0, NULL, NULL, NULL, NULL};
+static MemberOfConfig theConfig = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static Slapi_RWLock *memberof_config_lock = 0;
static int inited = 0;
@@ -60,6 +60,19 @@ static int dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Ent
return SLAPI_DSE_CALLBACK_ERROR;
}
+static void
+memberof_free_scope(Slapi_DN **scopes, int *count)
+{
+ int i = 0;
+
+ while(scopes && scopes[i]){
+ slapi_sdn_free(&scopes[i]);
+ i++;
+ }
+ slapi_ch_free((void**)&scopes);
+ *count = 0;
+}
+
/*
* memberof_config()
*
@@ -155,17 +168,22 @@ memberof_release_config()
*
* Validate the pending changes in the e entry.
*/
-static int
+int
memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
int *returncode, char *returntext, void *arg)
{
Slapi_Attr *memberof_attr = NULL;
Slapi_Attr *group_attr = NULL;
Slapi_DN *config_sdn = NULL;
+ Slapi_DN **include_dn = NULL;
+ Slapi_DN **exclude_dn = NULL;
char *syntaxoid = NULL;
char *config_dn = NULL;
char *skip_nested = NULL;
+ char **entry_scopes = NULL;
+ char **entry_exclude_scopes = NULL;
int not_dn_syntax = 0;
+ int num_vals = 0;
*returncode = LDAP_UNWILLING_TO_PERFORM; /* be pessimistic */
@@ -283,8 +301,112 @@ memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entr
*returncode = LDAP_UNWILLING_TO_PERFORM;
}
}
+ /*
+ * Check the entry scopes
+ */
+ entry_scopes = slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_ATTR, &num_vals);
+ if(entry_scopes){
+ int i = 0;
+
+ /* Validate the syntax before we create our DN array */
+ for (i = 0;i < num_vals; i++){
+ if(slapi_dn_syntax_check(pb, entry_scopes[i], 1)){
+ /* invalid dn syntax */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: Invalid DN (%s) for include suffix.",
+ MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]);
+ slapi_ch_array_free(entry_scopes);
+ theConfig.entryScopeCount = 0;
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ }
+ /* Now create our SDN array for conflict checking */
+ include_dn = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *), num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ include_dn[i] = slapi_sdn_new_dn_passin(entry_scopes[i]);
+ }
+ }
+ /*
+ * Check and process the entry exclude scopes
+ */
+ entry_exclude_scopes =
+ slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE, &num_vals);
+ if(entry_exclude_scopes){
+ int i = 0;
+
+ /* Validate the syntax before we create our DN array */
+ for (i = 0;i < num_vals; i++){
+ if(slapi_dn_syntax_check(pb, entry_exclude_scopes[i], 1)){
+ /* invalid dn syntax */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: Invalid DN (%s) for exclude suffix.",
+ MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]);
+ slapi_ch_array_free(entry_exclude_scopes);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ }
+ /* Now create our SDN array for conflict checking */
+ exclude_dn = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ exclude_dn[i] = slapi_sdn_new_dn_passin(entry_exclude_scopes[i]);
+ }
+ }
+ /*
+ * Need to do conflict checking
+ */
+ if(include_dn && exclude_dn){
+ /*
+ * Make sure we haven't mixed the same suffix, and there are no
+ * conflicts between the includes and excludes
+ */
+ int i = 0;
+
+ while(include_dn[i]){
+ int x = 0;
+ while(exclude_dn[x]){
+ if(slapi_sdn_compare(include_dn[i], exclude_dn[x] ) == 0)
+ {
+ /* we have a conflict */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: include suffix (%s) is also listed as an exclude suffix list",
+ MEMBEROF_PLUGIN_SUBSYSTEM, slapi_sdn_get_dn(include_dn[i]));
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ x++;
+ }
+ i++;
+ }
+
+ /* Check for parent/child conflicts */
+ i = 0;
+ while(include_dn[i]){
+ int x = 0;
+ while(exclude_dn[x]){
+ if(slapi_sdn_issuffix(include_dn[i], exclude_dn[x]))
+ {
+ /* we have a conflict */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: include suffix (%s) is a child of the exclude suffix(%s)",
+ MEMBEROF_PLUGIN_SUBSYSTEM,
+ slapi_sdn_get_dn(include_dn[i]),
+ slapi_sdn_get_dn(exclude_dn[i]));
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ x++;
+ }
+ i++;
+ }
+ }
done:
+ memberof_free_scope(exclude_dn, &num_vals);
+ memberof_free_scope(include_dn, &num_vals);
+ slapi_ch_free((void**)&entry_scopes);
+ slapi_ch_free((void**)&entry_exclude_scopes);
slapi_sdn_free(&config_sdn);
slapi_ch_free_string(&config_dn);
slapi_ch_free_string(&skip_nested);
@@ -299,7 +421,6 @@ done:
}
}
-
/*
* memberof_apply_config()
*
@@ -318,10 +439,11 @@ 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 *entryScopeExcludeSubtree = NULL;
+ char **entryScopes = NULL;
+ char **entryScopeExcludeSubtrees = NULL;
char *sharedcfg = NULL;
char *skip_nested = NULL;
+ int num_vals = 0;
*returncode = LDAP_SUCCESS;
@@ -353,8 +475,6 @@ 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);
- entryScopeExcludeSubtree = slapi_entry_attr_get_charptr(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE);
skip_nested = slapi_entry_attr_get_charptr(e, MEMBEROF_SKIP_NESTED_ATTR);
/*
@@ -480,49 +600,39 @@ memberof_apply_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
theConfig.allBackends = 0;
}
- slapi_sdn_free(&theConfig.entryScope);
- 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_passin(entryScope);
+ /*
+ * Check and process the entry scopes
+ */
+ memberof_free_scope(theConfig.entryScopes, &theConfig.entryScopeCount);
+ entryScopes = slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_ATTR, &num_vals);
+ if(entryScopes){
+ int i = 0;
+
+ /* Validation has already been performed in preop, just build the DN's */
+ theConfig.entryScopes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *), num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ theConfig.entryScopes[i] = slapi_sdn_new_dn_passin(entryScopes[i]);
}
- } else {
- theConfig.entryScope = NULL;
+ theConfig.entryScopeCount = num_vals; /* shortcut for config copy */
}
-
- slapi_sdn_free(&theConfig.entryScopeExcludeSubtree);
- if (entryScopeExcludeSubtree)
- {
- if (theConfig.entryScope == NULL) {
- slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "Error: Ignoring ExcludeSubtree (%s) because entryScope is not define\n",
- entryScopeExcludeSubtree);
- theConfig.entryScopeExcludeSubtree = NULL;
- slapi_ch_free_string(&entryScopeExcludeSubtree);
- } else if (slapi_dn_syntax_check(NULL, entryScopeExcludeSubtree, 1) == 1) {
- slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "Error: Ignoring invalid DN used as plugin entry exclude subtree: [%s]\n",
- entryScopeExcludeSubtree);
- theConfig.entryScopeExcludeSubtree = NULL;
- slapi_ch_free_string(&entryScopeExcludeSubtree);
- } else {
- theConfig.entryScopeExcludeSubtree = slapi_sdn_new_dn_passin(entryScopeExcludeSubtree);
+ /*
+ * Check and process the entry exclude scopes
+ */
+ memberof_free_scope(theConfig.entryScopeExcludeSubtrees,
+ &theConfig.entryExcludeScopeCount);
+ entryScopeExcludeSubtrees =
+ slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE, &num_vals);
+ if(entryScopeExcludeSubtrees){
+ int i = 0;
+
+ /* Validation has already been performed in preop, just build the DN's */
+ theConfig.entryScopeExcludeSubtrees =
+ (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ theConfig.entryScopeExcludeSubtrees[i] =
+ slapi_sdn_new_dn_passin(entryScopeExcludeSubtrees[i]);
}
- } else {
- theConfig.entryScopeExcludeSubtree = NULL;
- }
- if (theConfig.entryScopeExcludeSubtree && theConfig.entryScope && !slapi_sdn_issuffix(theConfig.entryScopeExcludeSubtree, theConfig.entryScope)) {
- slapi_log_error(SLAPI_LOG_FATAL, MEMBEROF_PLUGIN_SUBSYSTEM,
- "Error: Ignoring ExcludeSubtree (%s) that is out of the scope (%s)\n",
- slapi_sdn_get_dn(theConfig.entryScopeExcludeSubtree),
- slapi_sdn_get_dn(theConfig.entryScope));
- slapi_sdn_free(&theConfig.entryScopeExcludeSubtree);
+ theConfig.entryExcludeScopeCount = num_vals; /* shortcut for config copy */
}
/* release the lock */
@@ -536,6 +646,8 @@ done:
slapi_ch_free_string(&memberof_attr);
slapi_ch_free_string(&allBackends);
slapi_ch_free_string(&skip_nested);
+ slapi_ch_free((void **)&entryScopes);
+ slapi_ch_free((void **)&entryScopeExcludeSubtrees);
if (*returncode != LDAP_SUCCESS)
{
@@ -616,6 +728,23 @@ memberof_copy_config(MemberOfConfig *dest, MemberOfConfig *src)
{
dest->allBackends = src->allBackends;
}
+
+ if(src->entryScopes){
+ int num_vals = 0;
+
+ dest->entryScopes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),src->entryScopeCount+1);
+ for(num_vals = 0; src->entryScopes[num_vals]; num_vals++){
+ dest->entryScopes[num_vals] = slapi_sdn_dup(src->entryScopes[num_vals]);
+ }
+ }
+ if(src->entryScopeExcludeSubtrees){
+ int num_vals = 0;
+
+ dest->entryScopeExcludeSubtrees = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),src->entryExcludeScopeCount+1);
+ for(num_vals = 0; src->entryScopes[num_vals]; num_vals++){
+ dest->entryScopeExcludeSubtrees[num_vals] = slapi_sdn_dup(src->entryScopeExcludeSubtrees[num_vals]);
+ }
+ }
}
}
@@ -641,6 +770,8 @@ memberof_free_config(MemberOfConfig *config)
slapi_ch_free((void **)&config->group_slapiattrs);
slapi_ch_free_string(&config->memberof_attr);
+ memberof_free_scope(config->entryScopes, &config->entryScopeCount);
+ memberof_free_scope(config->entryScopeExcludeSubtrees, &config->entryExcludeScopeCount);
}
}
@@ -706,30 +837,6 @@ 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;
-}
-
-Slapi_DN *
-memberof_config_get_entry_scope_exclude_subtree()
-{
- Slapi_DN *entry_exclude_subtree;
-
- slapi_rwlock_rdlock(memberof_config_lock);
- entry_exclude_subtree = theConfig.entryScopeExcludeSubtree;
- slapi_rwlock_unlock(memberof_config_lock);
-
- return entry_exclude_subtree;
-}
-
/*
* Check if we are modifying the config, or changing the shared config entry
*/
diff --git a/ldap/servers/plugins/retrocl/retrocl.c b/ldap/servers/plugins/retrocl/retrocl.c
index 78a0c6d..4bcbb38 100644
--- a/ldap/servers/plugins/retrocl/retrocl.c
+++ b/ldap/servers/plugins/retrocl/retrocl.c
@@ -45,6 +45,9 @@ char **retrocl_attributes = NULL;
char **retrocl_aliases = NULL;
int retrocl_log_deleted = 0;
+static Slapi_DN **retrocl_includes = NULL;
+static Slapi_DN **retrocl_excludes = NULL;
+
/* ----------------------------- Retrocl Plugin */
static Slapi_PluginDesc retrocldesc = {"retrocl", VENDOR, DS_PACKAGE_VERSION, "Retrocl Plugin"};
@@ -349,6 +352,8 @@ static int retrocl_start (Slapi_PBlock *pb)
int rc = 0;
Slapi_Entry *e = NULL;
char **values = NULL;
+ int num_vals = 0;
+ int i = 0;
retrocl_rootdse_init(pb);
@@ -369,6 +374,87 @@ static int retrocl_start (Slapi_PBlock *pb)
return -1;
}
+ /* Get the exclude suffixes */
+ values = slapi_entry_attr_get_charray_ext(e, CONFIG_CHANGELOG_EXCLUDE_SUFFIX, &num_vals);
+ if(values){
+ /* Validate the syntax before we create our DN array */
+ for (i = 0;i < num_vals; i++){
+ if(slapi_dn_syntax_check(pb, values[i], 1)){
+ /* invalid dn syntax */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "Invalid DN (%s) for exclude suffix.\n", values[i] );
+ slapi_ch_array_free(values);
+ return -1;
+ }
+ }
+ /* Now create our SDN array */
+ retrocl_excludes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ retrocl_excludes[i] = slapi_sdn_new_dn_byval(values[i]);
+ }
+ slapi_ch_array_free(values);
+ }
+ /* Get the include suffixes */
+ values = slapi_entry_attr_get_charray_ext(e, CONFIG_CHANGELOG_INCLUDE_SUFFIX, &num_vals);
+ if(values){
+ for (i = 0;i < num_vals; i++){
+ /* Validate the syntax before we create our DN array */
+ if(slapi_dn_syntax_check(pb, values[i], 1)){
+ /* invalid dn syntax */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "Invalid DN (%s) for include suffix.\n", values[i] );
+ slapi_ch_array_free(values);
+ return -1;
+ }
+ }
+ /* Now create our SDN array */
+ retrocl_includes = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1);
+ for (i = 0;i < num_vals; i++){
+ retrocl_includes[i] = slapi_sdn_new_dn_byval(values[i]);
+ }
+ slapi_ch_array_free(values);
+ }
+ if(retrocl_includes && retrocl_excludes){
+ /*
+ * Make sure we haven't mixed the same suffix, and there are no
+ * conflicts between the includes and excludes
+ */
+ int i = 0;
+
+ while(retrocl_includes[i]){
+ int x = 0;
+ while(retrocl_excludes[x]){
+ if(slapi_sdn_compare(retrocl_includes[i], retrocl_excludes[x] ) == 0){
+ /* we have a conflict */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "include suffix (%s) is also listed in exclude suffix list\n",
+ slapi_sdn_get_dn(retrocl_includes[i]));
+ return -1;
+ }
+ x++;
+ }
+ i++;
+ }
+
+ /* Check for parent/child conflicts */
+ i = 0;
+ while(retrocl_includes[i]){
+ int x = 0;
+ while(retrocl_excludes[x]){
+ if(slapi_sdn_issuffix(retrocl_includes[i], retrocl_excludes[x])){
+ /* we have a conflict */
+ slapi_log_error(SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "include suffix (%s) is a child of the exclude suffix(%s)\n",
+ slapi_sdn_get_dn(retrocl_includes[i]),
+ slapi_sdn_get_dn(retrocl_excludes[i]));
+ return -1;
+ }
+ x++;
+ }
+ i++;
+ }
+ }
+
values = slapi_entry_attr_get_charray(e, "nsslapd-attribute");
if (values != NULL) {
int n = 0;
@@ -434,6 +520,49 @@ static int retrocl_start (Slapi_PBlock *pb)
}
/*
+ * Check if an entry is in the configured scope.
+ * Return 1 if entry is in the scope, or 0 otherwise.
+ * For MODRDN the caller should check both the preop
+ * and postop entries. If we are moving out of, or
+ * into scope, we should record it.
+ */
+int
+retrocl_entry_in_scope(Slapi_Entry *e)
+{
+ Slapi_DN *sdn = slapi_entry_get_sdn(e);
+
+ if (e == NULL){
+ return 1;
+ }
+
+ if (retrocl_excludes){
+ int i = 0;
+
+ /* check the excludes */
+ while(retrocl_excludes[i]){
+ if (slapi_sdn_issuffix(sdn, retrocl_excludes[i])){
+ return 0;
+ }
+ i++;
+ }
+ }
+ if (retrocl_includes){
+ int i = 0;
+
+ /* check the excludes */
+ while(retrocl_includes[i]){
+ if (slapi_sdn_issuffix(sdn, retrocl_includes[i])){
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
* Function: retrocl_stop
*
* Returns: 0
@@ -446,26 +575,40 @@ static int retrocl_start (Slapi_PBlock *pb)
static int retrocl_stop (Slapi_PBlock *pb)
{
- int rc = 0;
-
- slapi_ch_array_free(retrocl_attributes);
- retrocl_attributes = NULL;
- slapi_ch_array_free(retrocl_aliases);
- retrocl_aliases = NULL;
-
- retrocl_stop_trimming();
- retrocl_be_changelog = NULL;
- retrocl_forget_changenumbers();
- PR_DestroyLock(retrocl_internal_lock);
- retrocl_internal_lock = NULL;
- slapi_destroy_rwlock(retrocl_cn_lock);
- retrocl_cn_lock = NULL;
- legacy_initialised = 0;
-
- slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, "",
- LDAP_SCOPE_BASE,"(objectclass=*)", retrocl_rootdse_search);
-
- return rc;
+ int rc = 0;
+ int i = 0;
+
+ slapi_ch_array_free(retrocl_attributes);
+ retrocl_attributes = NULL;
+ slapi_ch_array_free(retrocl_aliases);
+ retrocl_aliases = NULL;
+
+ while(retrocl_excludes && retrocl_excludes[i]){
+ slapi_sdn_free(&retrocl_excludes[i]);
+ i++;
+ }
+ slapi_ch_free((void**)&retrocl_excludes);
+ i = 0;
+
+ while(retrocl_includes && retrocl_includes[i]){
+ slapi_sdn_free(&retrocl_includes[i]);
+ i++;
+ }
+ slapi_ch_free((void**)&retrocl_includes);
+
+ retrocl_stop_trimming();
+ retrocl_be_changelog = NULL;
+ retrocl_forget_changenumbers();
+ PR_DestroyLock(retrocl_internal_lock);
+ retrocl_internal_lock = NULL;
+ slapi_destroy_rwlock(retrocl_cn_lock);
+ retrocl_cn_lock = NULL;
+ legacy_initialised = 0;
+
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, "",
+ LDAP_SCOPE_BASE,"(objectclass=*)", retrocl_rootdse_search);
+
+ return rc;
}
/*
diff --git a/ldap/servers/plugins/retrocl/retrocl.h b/ldap/servers/plugins/retrocl/retrocl.h
index ae0139c..7edd62f 100644
--- a/ldap/servers/plugins/retrocl/retrocl.h
+++ b/ldap/servers/plugins/retrocl/retrocl.h
@@ -67,6 +67,8 @@ typedef struct _cnumRet {
/* was originally changelogmaximumage */
#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage"
#define CONFIG_CHANGELOG_DIRECTORY_ATTRIBUTE "nsslapd-changelogdir"
+#define CONFIG_CHANGELOG_INCLUDE_SUFFIX "nsslapd-include-suffix"
+#define CONFIG_CHANGELOG_EXCLUDE_SUFFIX "nsslapd-exclude-suffix"
#define RETROCL_CHANGELOG_DN "cn=changelog"
#define RETROCL_MAPPINGTREE_DN "cn=\"cn=changelog\",cn=mapping tree,cn=config"
@@ -140,4 +142,6 @@ extern void retrocl_init_trimming(void);
extern void retrocl_stop_trimming(void);
extern char *retrocl_get_config_str(const char *attrt);
+int retrocl_entry_in_scope(Slapi_Entry *e);
+
#endif /* _H_RETROCL */
diff --git a/ldap/servers/plugins/retrocl/retrocl_po.c b/ldap/servers/plugins/retrocl/retrocl_po.c
index 7083d0a..f689373 100644
--- a/ldap/servers/plugins/retrocl/retrocl_po.c
+++ b/ldap/servers/plugins/retrocl/retrocl_po.c
@@ -140,6 +140,7 @@ write_replog_db(
int flag,
time_t curtime,
Slapi_Entry *log_e,
+ Slapi_Entry *post_entry,
const char *newrdn,
LDAPMod **modrdn_mods,
const char *newsuperior
@@ -156,11 +157,26 @@ write_replog_db(
int err = 0;
int ret = LDAP_SUCCESS;
int i;
+ int mark = 0;
if (!dn) {
slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "write_replog_db: NULL dn\n");
return ret;
}
+ mark = (post_entry && retrocl_entry_in_scope(post_entry));
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "post in scope (%d)\n",mark);
+
+ if (post_entry){
+ if(!retrocl_entry_in_scope(log_e) && !retrocl_entry_in_scope(post_entry)){
+ /* modrdn: entry not in scope, just return... */
+ return ret;
+ }
+ } else {
+ if(!retrocl_entry_in_scope(log_e)){
+ /* entry not in scope, just return... */
+ return ret;
+ }
+ }
PR_Lock(retrocl_internal_lock);
changenum = retrocl_assign_changenumber();
@@ -319,7 +335,7 @@ write_replog_db(
break;
case OP_DELETE:
- if (log_e) {
+ if (retrocl_log_deleted) {
/* we have to log the full entry */
if ( entry2reple( e, log_e, OP_DELETE ) != 0 ) {
err = SLAPI_PLUGIN_FAILURE;
@@ -559,7 +575,8 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
char *dn;
LDAPMod **log_m = NULL;
int flag = 0;
- Slapi_Entry *te = NULL;
+ Slapi_Entry *entry = NULL;
+ Slapi_Entry *post_entry = NULL;
Slapi_Operation *op = NULL;
LDAPMod **modrdn_mods = NULL;
char *newrdn = NULL;
@@ -624,7 +641,12 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
LDAPDebug0Args(LDAP_DEBUG_TRACE,"not applying change for nsTombstone entries\n");
return SLAPI_PLUGIN_SUCCESS;
}
-
+ /*
+ * Start by grabbing the preop entry, ADD will replace it as needed. Getting the entry
+ * allows up to perform scoping in write_replog_db() for all op types.
+ */
+ (void)slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &entry);
+
switch ( optype ) {
case OP_MODIFY:
(void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &log_m );
@@ -634,14 +656,14 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
* For adds, we want the unnormalized dn, so we can preserve
* spacing, case, when replicating it.
*/
- (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &te );
- if ( NULL != te ) {
- dn = slapi_entry_get_dn( te );
+ (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &entry );
+ if ( NULL != entry ) {
+ dn = slapi_entry_get_dn( entry );
}
break;
case OP_DELETE:
if (retrocl_log_deleted)
- (void)slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &te);
+ (void)slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &entry);
break;
case OP_MODRDN:
/* newrdn is used just for logging; no need to be normalized */
@@ -649,13 +671,14 @@ int retrocl_postob (Slapi_PBlock *pb, int optype)
(void)slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &flag );
(void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &modrdn_mods );
(void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperior );
+ (void)slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &post_entry);
break;
}
/* check if we should log change to retro changelog, and
* if so, do it here */
- if((rc = write_replog_db( pb, optype, dn, log_m, flag, curtime, te,
- newrdn, modrdn_mods, slapi_sdn_get_dn(newsuperior) )))
+ if((rc = write_replog_db( pb, optype, dn, log_m, flag, curtime, entry,
+ post_entry, newrdn, modrdn_mods, slapi_sdn_get_dn(newsuperior) )))
{
slapi_log_error(SLAPI_LOG_FATAL, "retrocl-plugin",
"retrocl_postob: operation failure [%d]\n", rc);
8 years, 8 months