From 799b7c49662cfa3385bf9b049550921b0c5ead16 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Mon, 20 Oct 2014 13:02:29 +0300 Subject: [PATCH] Support excluding subtrees in uniqueness plugin Exclude subtrees from uniqueness check if they are specified in the plugin config. To exclude certain parts of the tree from uniqueness check, set uniqueness-exclude-subtrees: cn=subtree,dc=example,dc=com in the plugin's configuration. Only new style configuration is supported for specifying excludes. Fixes https://fedorahosted.org/389/ticket/47927 --- ldap/servers/plugins/uiduniq/uid.c | 98 +++++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 17 deletions(-) diff --git a/ldap/servers/plugins/uiduniq/uid.c b/ldap/servers/plugins/uiduniq/uid.c index 07ff0ec..acb5bfd 100644 --- a/ldap/servers/plugins/uiduniq/uid.c +++ b/ldap/servers/plugins/uiduniq/uid.c @@ -70,7 +70,7 @@ int ldap_quote_filter_value( static int search_one_berval(Slapi_DN *baseDN, const char *attrName, - const struct berval *value, const char *requiredObjectClass, Slapi_DN *target); + const struct berval *value, const char *requiredObjectClass, Slapi_DN *target, Slapi_DN **excludes); /* * ISSUES: @@ -102,6 +102,7 @@ static void* plugin_identity = NULL; typedef struct attr_uniqueness_config { char *attr; Slapi_DN **subtrees; + Slapi_DN **exclude_subtrees; PRBool unique_in_all_subtrees; char *top_entry_oc; char *subtree_entries_oc; @@ -110,6 +111,7 @@ typedef struct attr_uniqueness_config { #define ATTR_UNIQUENESS_ATTRIBUTE_NAME "uniqueness-attribute-name" #define ATTR_UNIQUENESS_SUBTREES "uniqueness-subtrees" +#define ATTR_UNIQUENESS_EXCLUDE_SUBTREES "uniqueness-exclude-subtrees" #define ATTR_UNIQUENESS_ACROSS_ALL_SUBTREES "uniqueness-across-all-subtrees" #define ATTR_UNIQUENESS_TOP_ENTRY_OC "uniqueness-top-entry-oc" #define ATTR_UNIQUENESS_SUBTREE_ENTRIES_OC "uniqueness-subtree-entries-oc" @@ -132,7 +134,11 @@ free_uniqueness_config(struct attr_uniqueness_config *config) for (i = 0; config->subtrees && config->subtrees[i]; i++) { slapi_sdn_free(&config->subtrees[i]); } + for (i = 0; config->exclude_subtrees && config->exclude_subtrees[i]; i++) { + slapi_sdn_free(&config->exclude_subtrees[i]); + } slapi_ch_free((void **) &config->subtrees); + slapi_ch_free((void **) &config->exclude_subtrees); slapi_ch_free_string((char **) &config->top_entry_oc); slapi_ch_free_string((char **) &config->subtree_entries_oc); } @@ -144,6 +150,7 @@ free_uniqueness_config(struct attr_uniqueness_config *config) * uniqueness-attribute-name: uid * uniqueness-subtrees: dc=people,dc=example,dc=com * uniqueness-subtrees: dc=sales, dc=example,dc=com + * uniqueness-exclude-subtrees: dc=machines, dc=examples, dc=com * uniqueness-across-all-subtrees: on * * or @@ -241,6 +248,26 @@ uniqueness_entry_to_config(Slapi_PBlock *pb, Slapi_Entry *config_entry) values = NULL; } + /* Subtrees where uniqueness is explicitly ignored */ + values = slapi_entry_attr_get_charray(config_entry, ATTR_UNIQUENESS_EXCLUDE_SUBTREES); + if (values) { + for (i = 0; values && values[i]; i++); + /* slapi_ch_calloc never returns NULL unless the 2 args are 0 or negative. */ + tmp_config->exclude_subtrees = (Slapi_DN **) slapi_ch_calloc(i + 1, sizeof (Slapi_DN *)); + /* copy the valid subtree DN into the config */ + for (i = 0, nb_subtrees = 0; values && values[i]; i++) { + if (slapi_dn_syntax_check(pb, values[i], 1)) { /* syntax check failed */ + slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Config info: Invalid DN (skipped): %s\n", values[i]); + continue; + } + tmp_config->exclude_subtrees[nb_subtrees] = slapi_sdn_new_dn_byval(values[i]); + nb_subtrees++; + + } + + slapi_ch_array_free(values); + values = NULL; + } /* Uniqueness may be enforced accross all the subtrees, by default it is not */ tmp_config->unique_in_all_subtrees = slapi_entry_attr_get_bool(config_entry, ATTR_UNIQUENESS_ACROSS_ALL_SUBTREES); @@ -345,7 +372,8 @@ uniqueness_entry_to_config(Slapi_PBlock *pb, Slapi_Entry *config_entry) rc = SLAPI_PLUGIN_FAILURE; goto done; } - + + /* Only ensure subtrees are set, no need to check excluded subtrees as setting exclusion without actual subtrees make little sense */ if (tmp_config->subtrees == NULL) { /* Uniqueness is enforced on entries matching objectclass */ if (tmp_config->subtree_entries_oc == NULL) { @@ -492,7 +520,7 @@ create_filter(const char *attribute, const struct berval *value, const char *req static int search(Slapi_DN *baseDN, const char *attrName, Slapi_Attr *attr, struct berval **values, const char *requiredObjectClass, - Slapi_DN *target) + Slapi_DN *target, Slapi_DN **excludes) { int result; @@ -526,7 +554,7 @@ search(Slapi_DN *baseDN, const char *attrName, Slapi_Attr *attr, { result = search_one_berval(baseDN, attrName, slapi_value_get_berval(v), - requiredObjectClass, target); + requiredObjectClass, target, excludes); } } else @@ -534,7 +562,7 @@ search(Slapi_DN *baseDN, const char *attrName, Slapi_Attr *attr, for (;*values != NULL && LDAP_SUCCESS == result; values++) { result = search_one_berval(baseDN, attrName, *values, requiredObjectClass, - target); + target, excludes); } } @@ -550,7 +578,7 @@ search(Slapi_DN *baseDN, const char *attrName, Slapi_Attr *attr, static int search_one_berval(Slapi_DN *baseDN, const char *attrName, const struct berval *value, const char *requiredObjectClass, - Slapi_DN *target) + Slapi_DN *target, Slapi_DN **excludes) { int result; char *filter; @@ -569,6 +597,7 @@ search_one_berval(Slapi_DN *baseDN, const char *attrName, int err; int sres; Slapi_Entry **entries; + Slapi_DN **exc; static char *attrs[] = { "1.1", 0 }; /* Create the filter - this needs to be freed */ @@ -618,7 +647,26 @@ search_one_berval(Slapi_DN *baseDN, const char *attrName, if (!target || slapi_sdn_compare(slapi_entry_get_sdn(*entries), target) != 0) { result = LDAP_CONSTRAINT_VIOLATION; - break; + if (excludes == NULL || *excludes == NULL) + { + break; + } + + /* Do the same check for excluded subtrees as resulted entries may have matched them */ + for(exc = excludes; *exc; exc++) + { + Slapi_DN *entry_dn = slapi_entry_get_sdn(*entries); + if (slapi_sdn_issuffix(entry_dn, exc) != 0) + { + result = LDAP_SUCCESS; + break; + } + } + + if (result == LDAP_CONSTRAINT_VIOLATION) + { + break; + } } } @@ -656,7 +704,7 @@ search_one_berval(Slapi_DN *baseDN, const char *attrName, * LDAP_OPERATIONS_ERROR - a server failure. */ static int -searchAllSubtrees(Slapi_DN **subtrees, const char *attrName, +searchAllSubtrees(Slapi_DN **subtrees, Slapi_DN **exclude_subtrees, const char *attrName, Slapi_Attr *attr, struct berval **values, const char *requiredObjectClass, Slapi_DN *dn, PRBool unique_in_all_subtrees) { @@ -684,6 +732,22 @@ searchAllSubtrees(Slapi_DN **subtrees, const char *attrName, return result; } } + + /* If DN is in the excluded subtrees, we should ignore it in any case, not only + * in the case of uniqueness in all subtrees. */ + if (exclude_subtrees != NULL) + { + PRBool in_a_subtree = PR_FALSE; + for (i = 0;exclude_subtrees && exclude_subtrees[i]; i++) { + if (slapi_sdn_issuffix(dn, exclude_subtrees[i])) { + in_a_subtree = PR_FALSE; + break; + } + } + if (in_a_subtree) { + return result; + } + } /* * For each DN in the managed list, do uniqueness checking if @@ -697,7 +761,7 @@ searchAllSubtrees(Slapi_DN **subtrees, const char *attrName, * worry about that here. */ if (unique_in_all_subtrees || slapi_sdn_issuffix(dn, sufdn)) { - result = search(sufdn, attrName, attr, values, requiredObjectClass, dn); + result = search(sufdn, attrName, attr, values, requiredObjectClass, dn, exclude_subtrees); if (result) break; } } @@ -787,7 +851,7 @@ getArguments(Slapi_PBlock *pb, char **attrName, char **markerObjectClass, static int findSubtreeAndSearch(Slapi_DN *parentDN, const char *attrName, Slapi_Attr *attr, struct berval **values, const char *requiredObjectClass, Slapi_DN *target, - const char *markerObjectClass) + const char *markerObjectClass, Slapi_DN **excludes) { int result = LDAP_SUCCESS; Slapi_PBlock *spb = NULL; @@ -805,7 +869,7 @@ findSubtreeAndSearch(Slapi_DN *parentDN, const char *attrName, Slapi_Attr *attr, * to have the attribute already. */ result = search(curpar, attrName, attr, values, requiredObjectClass, - target); + target, excludes); break; } newpar = slapi_sdn_new(); @@ -914,11 +978,11 @@ preop_add(Slapi_PBlock *pb) /* Subtree defined by location of marker object class */ result = findSubtreeAndSearch(sdn, attrName, attr, NULL, requiredObjectClass, sdn, - markerObjectClass); + markerObjectClass, config->exclude_subtrees); } else { /* Subtrees listed on invocation line */ - result = searchAllSubtrees(config->subtrees, attrName, attr, NULL, + result = searchAllSubtrees(config->subtrees, config->exclude_subtrees, attrName, attr, NULL, requiredObjectClass, sdn, config->unique_in_all_subtrees); } END @@ -1073,11 +1137,11 @@ preop_modify(Slapi_PBlock *pb) /* Subtree defined by location of marker object class */ result = findSubtreeAndSearch(sdn, attrName, NULL, mod->mod_bvalues, requiredObjectClass, - sdn, markerObjectClass); + sdn, markerObjectClass, config->exclude_subtrees); } else { /* Subtrees listed on invocation line */ - result = searchAllSubtrees(config->subtrees, attrName, NULL, + result = searchAllSubtrees(config->subtrees, config->exclude_subtrees, attrName, NULL, mod->mod_bvalues, requiredObjectClass, sdn, config->unique_in_all_subtrees); } } @@ -1233,11 +1297,11 @@ preop_modrdn(Slapi_PBlock *pb) /* Subtree defined by location of marker object class */ result = findSubtreeAndSearch(slapi_entry_get_sdn(e), attrName, attr, NULL, requiredObjectClass, sdn, - markerObjectClass); + markerObjectClass, config->exclude_subtrees); } else { /* Subtrees listed on invocation line */ - result = searchAllSubtrees(config->subtrees, attrName, attr, NULL, + result = searchAllSubtrees(config->subtrees, config->exclude_subtrees, attrName, attr, NULL, requiredObjectClass, sdn, config->unique_in_all_subtrees); } END -- 2.1.0