dirsrvtests/suites/dynamic-plugins/plugin_tests.py | 83 ++++++
ldap/servers/plugins/uiduniq/uid.c | 286 ++++++++++++++-------
2 files changed, 275 insertions(+), 94 deletions(-)
New commits:
commit 430410d75446cdf58e6f020e1463b590abd870ab
Author: William B <william.e.brown(a)adelaide.edu.au>
Date: Sun Feb 8 09:42:59 2015 +1030
Ticket #48026 - Support for uniqueness plugin to enforce uniqueness on a set of
attributes.
This allows defining multiple value to uniqueness-attribute-name, that will be
taken as a set of values to maintain uniqueness for. IE mail, mailAlternate.
If a value exists in mail, it may not exist in any other objects mail OR
mailAlternate.
https://fedorahosted.org/389/ticket/48026
Reviewed by nhosoi(a)redhat.com.
diff --git a/dirsrvtests/suites/dynamic-plugins/plugin_tests.py
b/dirsrvtests/suites/dynamic-plugins/plugin_tests.py
index 43d0244..03aca80 100644
--- a/dirsrvtests/suites/dynamic-plugins/plugin_tests.py
+++ b/dirsrvtests/suites/dynamic-plugins/plugin_tests.py
@@ -296,6 +296,7 @@ def test_attruniq(inst, args=None):
'cn': 'user 1',
'uid': 'user1',
'mail': 'user1(a)example.com',
+ 'mailAlternateAddress' :
'user1(a)alt.example.com',
'userpassword': 'password'})))
except ldap.LDAPError, e:
log.fatal('test_attruniq: Failed to add test user' + USER1_DN + ':
error ' + e.message['desc'])
@@ -346,6 +347,88 @@ def test_attruniq(inst, args=None):
assert False
############################################################################
+ # Reconfigure plugin for mail and mailAlternateAddress
+ ############################################################################
+
+ try:
+ inst.modify_s('cn=' + PLUGIN_ATTR_UNIQUENESS +
',cn=plugins,cn=config',
+ [(ldap.MOD_REPLACE, 'uniqueness-attribute-name',
'mail'),
+ (ldap.MOD_ADD, 'uniqueness-attribute-name',
+ 'mailAlternateAddress')])
+
+ except ldap.LDAPError, e:
+ log.error('test_attruniq: Failed to reconfigure plugin for "mail
mailAlternateAddress": error ' + e.message['desc'])
+ assert False
+
+ ############################################################################
+ # Test plugin - Add an entry, that has a duplicate "mail" value
+ ############################################################################
+
+ try:
+ inst.add_s(Entry((USER2_DN, {'objectclass': "top
extensibleObject".split(),
+ 'sn': '2',
+ 'cn': 'user 2',
+ 'uid': 'user2',
+ 'mail': 'user1(a)example.com',
+ 'userpassword': 'password'})))
+ except ldap.CONSTRAINT_VIOLATION:
+ pass
+ else:
+ log.error('test_attruniq: Adding of 3rd entry(mail) incorrectly
succeeded')
+ assert False
+
+ ############################################################################
+ # Test plugin - Add an entry, that has a duplicate "mailAlternateAddress"
value
+ ############################################################################
+
+ try:
+ inst.add_s(Entry((USER2_DN, {'objectclass': "top
extensibleObject".split(),
+ 'sn': '2',
+ 'cn': 'user 2',
+ 'uid': 'user2',
+ 'mailAlternateAddress':
'user1(a)alt.example.com',
+ 'userpassword': 'password'})))
+ except ldap.CONSTRAINT_VIOLATION:
+ pass
+ else:
+ log.error('test_attruniq: Adding of 4th entry(mailAlternateAddress)
incorrectly succeeded')
+ assert False
+
+ ############################################################################
+ # Test plugin - Add an entry, that has a duplicate "mail" value conflicting
mailAlternateAddress
+ ############################################################################
+
+ try:
+ inst.add_s(Entry((USER2_DN, {'objectclass': "top
extensibleObject".split(),
+ 'sn': '2',
+ 'cn': 'user 2',
+ 'uid': 'user2',
+ 'mail': 'user1(a)alt.example.com',
+ 'userpassword': 'password'})))
+ except ldap.CONSTRAINT_VIOLATION:
+ pass
+ else:
+ log.error('test_attruniq: Adding of 5th entry(mailAlternateAddress)
incorrectly succeeded')
+ assert False
+
+ ############################################################################
+ # Test plugin - Add an entry, that has a duplicate "mailAlternateAddress"
conflicting mail
+ ############################################################################
+
+ try:
+ inst.add_s(Entry((USER2_DN, {'objectclass': "top
extensibleObject".split(),
+ 'sn': '2',
+ 'cn': 'user 2',
+ 'uid': 'user2',
+ 'mailAlternateAddress':
'user1(a)example.com',
+ 'userpassword': 'password'})))
+ except ldap.CONSTRAINT_VIOLATION:
+ pass
+ else:
+ log.error('test_attruniq: Adding of 6th entry(mail) incorrectly
succeeded')
+ assert False
+
+ ############################################################################
# Test plugin dependency
############################################################################
diff --git a/ldap/servers/plugins/uiduniq/uid.c b/ldap/servers/plugins/uiduniq/uid.c
index 2120b4f..282f618 100644
--- a/ldap/servers/plugins/uiduniq/uid.c
+++ b/ldap/servers/plugins/uiduniq/uid.c
@@ -69,7 +69,7 @@ int ldap_quote_filter_value(
int *outLen);
-static int search_one_berval(Slapi_DN *baseDN, const char *attrName,
+static int search_one_berval(Slapi_DN *baseDN, const char **attrNames,
const struct berval *value, const char *requiredObjectClass, Slapi_DN *target);
/*
@@ -100,7 +100,8 @@ pluginDesc = {
};
static void* plugin_identity = NULL;
typedef struct attr_uniqueness_config {
- char *attr;
+ const char **attrs;
+ char *attr_friendly;
Slapi_DN **subtrees;
PRBool unique_in_all_subtrees;
char *top_entry_oc;
@@ -128,7 +129,9 @@ free_uniqueness_config(struct attr_uniqueness_config *config)
{
int i;
- slapi_ch_free_string((char **) &config->attr);
+ for (i = 0; config->attrs && config->attrs[i]; i++) {
+ slapi_ch_free_string((char **) &(config->attrs[i]));
+ }
for (i = 0; config->subtrees && config->subtrees[i]; i++) {
slapi_sdn_free(&config->subtrees[i]);
}
@@ -183,6 +186,8 @@ uniqueness_entry_to_config(Slapi_PBlock *pb, Slapi_Entry
*config_entry)
char **argv = NULL;
int rc = SLAPI_PLUGIN_SUCCESS;
int i;
+ int attrLen = 0;
+ char *fp;
int nb_subtrees = 0;
if (config_entry == NULL) {
@@ -218,8 +223,18 @@ uniqueness_entry_to_config(Slapi_PBlock *pb, Slapi_Entry
*config_entry)
*/
/* Attribute name of the attribute we are going to check value uniqueness
*/
- tmp_config->attr = slapi_entry_attr_get_charptr(config_entry,
ATTR_UNIQUENESS_ATTRIBUTE_NAME);
-
+ values = slapi_entry_attr_get_charray(config_entry,
ATTR_UNIQUENESS_ATTRIBUTE_NAME);
+ if (values) {
+ for (i = 0; values && values[i]; i++);
+ tmp_config->attrs = (const char **) slapi_ch_calloc(i + 1,
sizeof(char *));
+ for (i = 0; values && values[i]; i++) {
+ tmp_config->attrs[i] = slapi_ch_strdup(values[i]);
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
"Adding attribute %s to uniqueness set\n", tmp_config->attrs[i]);
+ }
+ slapi_ch_array_free(values);
+ values = NULL;
+ }
+
/* Subtrees where uniqueness is tested */
values = slapi_entry_attr_get_charray(config_entry,
ATTR_UNIQUENESS_SUBTREES);
if (values) {
@@ -283,7 +298,8 @@ uniqueness_entry_to_config(Slapi_PBlock *pb, Slapi_Entry
*config_entry)
}
/* Store attrName in the config */
- tmp_config->attr = slapi_ch_strdup(attrName);
+ tmp_config->attrs = (const char **) slapi_ch_calloc(1,
sizeof(char *));
+ tmp_config->attrs[0] = slapi_ch_strdup(attrName);
argc--;
argv++; /* First argument was attribute name and remaining are
subtrees */
@@ -323,7 +339,8 @@ uniqueness_entry_to_config(Slapi_PBlock *pb, Slapi_Entry
*config_entry)
* - requiredObjectClass
*/
/* Store attrName in the config */
- tmp_config->attr = slapi_ch_strdup(attrName);
+ tmp_config->attrs = (const char **) slapi_ch_calloc(1,
sizeof(char *));
+ tmp_config->attrs[0] = slapi_ch_strdup(attrName);
/* There is no subtrees */
tmp_config->subtrees = NULL;
@@ -340,12 +357,25 @@ uniqueness_entry_to_config(Slapi_PBlock *pb, Slapi_Entry
*config_entry)
}
/* Time to check that the new configuration is valid */
- if (tmp_config->attr == NULL) {
+ /* Check that we have 1 or more value */
+ if (tmp_config->attrs == NULL) {
slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "Config info:
attribute name not defined \n");
rc = SLAPI_PLUGIN_FAILURE;
goto done;
}
-
+ /* If the config is valid, prepare the friendly string for error messages */
+ for (i = 0; tmp_config->attrs && (tmp_config->attrs)[i]; i++) {
+ attrLen += strlen((tmp_config->attrs)[i]) + 1;
+ }
+ tmp_config->attr_friendly = (char *) slapi_ch_calloc(attrLen, sizeof(char
*));
+ fp = tmp_config->attr_friendly;
+ for (i = 0; tmp_config->attrs && (tmp_config->attrs)[i]; i++) {
+ strcpy(fp, (tmp_config->attrs)[i] );
+ fp += strlen((tmp_config->attrs)[i]);
+ strcpy(fp, " ");
+ fp++;
+ }
+
if (tmp_config->subtrees == NULL) {
/* Uniqueness is enforced on entries matching objectclass */
if (tmp_config->subtree_entries_oc == NULL) {
@@ -407,20 +437,39 @@ uid_op_error(int internal_error)
*/
static char *
-create_filter(const char *attribute, const struct berval *value, const char
*requiredObjectClass)
+create_filter(const char **attributes, const struct berval *value, const char
*requiredObjectClass)
{
char *filter;
char *fp;
char *max;
- int attrLen;
+ int *attrLen;
+ int totalAttrLen = 0;
+ int attrCount = 0;
int valueLen;
int classLen = 0;
int filterLen;
+ int i = 0;
- PR_ASSERT(attribute);
+ PR_ASSERT(attributes);
/* Compute the length of the required buffer */
- attrLen = strlen(attribute);
+ for (attrCount = 0; attributes && attributes[attrCount]; attrCount++);
+ attrCount++;
+ attrLen = (int *) slapi_ch_calloc(attrCount, sizeof(int));
+ for (i = 0; attributes && attributes[i]; i++) {
+ attrLen[i] += strlen(attributes[i]);
+ totalAttrLen += attrLen[i];
+ }
+
+ /* if attrCount is 1, attrLen is already corect for usage.*/
+ if (attrCount > 1) {
+ /* Filter will be (|(attr=value)(attr=value)) */
+ /* 3 for the (| ) */
+ /* 3 for each attr for (=) not in attr or value */
+ totalAttrLen += 3 + (attrCount * 3);
+ } else {
+ totalAttrLen += 3;
+ }
if (ldap_quote_filter_value(value->bv_val,
value->bv_len, 0, 0, &valueLen))
@@ -428,10 +477,10 @@ create_filter(const char *attribute, const struct berval *value,
const char *req
if (requiredObjectClass) {
classLen = strlen(requiredObjectClass);
- /* "(&(objectClass=)())" == 19 */
- filterLen = attrLen + 1 + valueLen + classLen + 19 + 1;
+ /* "(&(objectClass=)<Filter here>)" == 17 */
+ filterLen = totalAttrLen + 1 + (valueLen * attrCount) + classLen + 17 + 1;
} else {
- filterLen = attrLen + 1 + valueLen + 1;
+ filterLen = totalAttrLen + 1 + (valueLen * attrCount) + 1;
}
/* Allocate the buffer */
@@ -446,30 +495,58 @@ create_filter(const char *attribute, const struct berval *value,
const char *req
strcpy(fp, requiredObjectClass);
fp += classLen;
*fp++ = ')';
- *fp++ = '(';
}
- /* Place attribute name in filter */
- strcpy(fp, attribute);
- fp += attrLen;
+ if (attrCount == 1) {
+ *fp++ = '(';
+ /* Place attribute name in filter */
+ strcpy(fp, attributes[0]);
+ fp += attrLen[0];
- /* Place comparison operator */
- *fp++ = '=';
+ /* Place comparison operator */
+ *fp++ = '=';
- /* Place value in filter */
- if (ldap_quote_filter_value(value->bv_val, value->bv_len,
- fp, max-fp, &valueLen)) { slapi_ch_free((void**)&filter); return 0; }
- fp += valueLen;
+ /* Place value in filter */
+ if (ldap_quote_filter_value(value->bv_val, value->bv_len,
+ fp, max-fp, &valueLen)) { slapi_ch_free((void**)&filter); return 0; }
+ fp += valueLen;
+ *fp++ = ')';
+ } else {
+ strcpy(fp, "(|");
+ fp += 2;
+
+ for (i = 0; attributes && attributes[i]; i++) {
+ strcpy(fp, "(");
+ fp += 1;
+ /* Place attribute name in filter */
+ strcpy(fp, attributes[i]);
+ fp += attrLen[i];
+
+ /* Place comparison operator */
+ *fp++ = '=';
+
+ /* Place value in filter */
+ if (ldap_quote_filter_value(value->bv_val, value->bv_len,
+ fp, max-fp, &valueLen)) { slapi_ch_free((void**)&filter); return 0;
}
+ fp += valueLen;
+
+ strcpy(fp, ")");
+ fp += 1;
+ }
+ strcpy(fp, ")");
+ fp += 1;
+ }
/* Close AND expression if a requiredObjectClass was set */
if (requiredObjectClass) {
*fp++ = ')';
- *fp++ = ')';
}
/* Terminate */
*fp = 0;
+ slapi_ch_free((void **) &attrLen);
+
return filter;
}
@@ -490,15 +567,16 @@ create_filter(const char *attribute, const struct berval *value,
const char *req
* LDAP_OPERATIONS_ERROR - a server failure.
*/
static int
-search(Slapi_DN *baseDN, const char *attrName, Slapi_Attr *attr,
+search(Slapi_DN *baseDN, const char **attrNames, Slapi_Attr *attr,
struct berval **values, const char *requiredObjectClass,
Slapi_DN *target)
{
int result;
#ifdef DEBUG
+ /* Fix this later to print all the attr names */
slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
- "SEARCH baseDN=%s attr=%s target=%s\n",
slapi_sdn_get_dn(baseDN), attrName,
+ "SEARCH baseDN=%s attr=%s target=%s\n",
slapi_sdn_get_dn(baseDN), attrNames[0],
target?slapi_sdn_get_dn(target):"None");
#endif
@@ -524,7 +602,7 @@ search(Slapi_DN *baseDN, const char *attrName, Slapi_Attr *attr,
vhint != -1 && LDAP_SUCCESS == result;
vhint = slapi_attr_next_value( attr, vhint, &v ))
{
- result = search_one_berval(baseDN, attrName,
+ result = search_one_berval(baseDN, attrNames,
slapi_value_get_berval(v),
requiredObjectClass, target);
}
@@ -533,7 +611,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,
+ result = search_one_berval(baseDN, attrNames, *values, requiredObjectClass,
target);
}
}
@@ -548,7 +626,7 @@ search(Slapi_DN *baseDN, const char *attrName, Slapi_Attr *attr,
static int
-search_one_berval(Slapi_DN *baseDN, const char *attrName,
+search_one_berval(Slapi_DN *baseDN, const char **attrNames,
const struct berval *value, const char *requiredObjectClass,
Slapi_DN *target)
{
@@ -572,7 +650,7 @@ search_one_berval(Slapi_DN *baseDN, const char *attrName,
static char *attrs[] = { "1.1", 0 };
/* Create the filter - this needs to be freed */
- filter = create_filter(attrName, value, requiredObjectClass);
+ filter = create_filter(attrNames, value, requiredObjectClass);
#ifdef DEBUG
slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
@@ -656,7 +734,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, const char **attrNames,
Slapi_Attr *attr, struct berval **values, const char *requiredObjectClass,
Slapi_DN *dn, PRBool unique_in_all_subtrees)
{
@@ -697,7 +775,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, attrNames, attr, values, requiredObjectClass, dn);
if (result) break;
}
}
@@ -785,7 +863,7 @@ getArguments(Slapi_PBlock *pb, char **attrName, char
**markerObjectClass,
* LDAP_OPERATIONS_ERROR - a server failure.
*/
static int
-findSubtreeAndSearch(Slapi_DN *parentDN, const char *attrName, Slapi_Attr *attr,
+findSubtreeAndSearch(Slapi_DN *parentDN, const char **attrNames, Slapi_Attr *attr,
struct berval **values, const char *requiredObjectClass, Slapi_DN *target,
const char *markerObjectClass)
{
@@ -804,7 +882,7 @@ findSubtreeAndSearch(Slapi_DN *parentDN, const char *attrName,
Slapi_Attr *attr,
* Do the search. There is no entry that is allowed
* to have the attribute already.
*/
- result = search(curpar, attrName, attr, values, requiredObjectClass,
+ result = search(curpar, attrNames, attr, values, requiredObjectClass,
target);
break;
}
@@ -827,7 +905,8 @@ preop_add(Slapi_PBlock *pb)
{
int result;
char *errtext = NULL;
- char *attrName = NULL;
+ const char **attrNames = NULL;
+ char * attr_friendly = NULL;
#ifdef DEBUG
slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD begin\n");
@@ -848,6 +927,7 @@ preop_add(Slapi_PBlock *pb)
Slapi_Entry *e;
Slapi_Attr *attr;
struct attr_uniqueness_config *config = NULL;
+ int i = 0;
/*
* If this is a replication update, just be a noop.
@@ -868,9 +948,10 @@ preop_add(Slapi_PBlock *pb)
/*
* Get the arguments
*/
- attrName = config->attr;
+ attrNames = config->attrs;
markerObjectClass = config->top_entry_oc;
requiredObjectClass = config->subtree_entries_oc;
+ attr_friendly = config->attr_friendly;
/*
* Get the target DN for this add operation
@@ -889,9 +970,6 @@ preop_add(Slapi_PBlock *pb)
err = slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
if (err) { result = uid_op_error(52); break; }
- err = slapi_entry_attr_find(e, attrName, &attr);
- if (err) break; /* no unique attribute */
-
/*
* Check if it contains the required object class
*/
@@ -904,22 +982,30 @@ preop_add(Slapi_PBlock *pb)
}
}
- /*
- * Passed all the requirements - this is an operation we
- * need to enforce uniqueness on. Now find all parent entries
- * with the marker object class, and do a search for each one.
- */
- if (NULL != markerObjectClass)
- {
- /* Subtree defined by location of marker object class */
- result = findSubtreeAndSearch(sdn, attrName, attr, NULL,
- requiredObjectClass, sdn,
- markerObjectClass);
- } else
- {
- /* Subtrees listed on invocation line */
- result = searchAllSubtrees(config->subtrees, attrName, attr, NULL,
- requiredObjectClass, sdn,
config->unique_in_all_subtrees);
+ for (i = 0; attrNames && attrNames[i]; i++) {
+ err = slapi_entry_attr_find(e, attrNames[i], &attr);
+ if (!err) {
+ /*
+ * Passed all the requirements - this is an operation we
+ * need to enforce uniqueness on. Now find all parent entries
+ * with the marker object class, and do a search for each one.
+ */
+ if (NULL != markerObjectClass)
+ {
+ /* Subtree defined by location of marker object class */
+ result = findSubtreeAndSearch(sdn, attrNames, attr, NULL,
+ requiredObjectClass, sdn,
+ markerObjectClass);
+ } else
+ {
+ /* Subtrees listed on invocation line */
+ result = searchAllSubtrees(config->subtrees, attrNames, attr, NULL,
+ requiredObjectClass, sdn,
config->unique_in_all_subtrees);
+ }
+ if (result != LDAP_SUCCESS) {
+ break;
+ }
+ }
}
END
@@ -929,7 +1015,7 @@ preop_add(Slapi_PBlock *pb)
"ADD result %d\n", result);
if (result == LDAP_CONSTRAINT_VIOLATION) {
- errtext = slapi_ch_smprintf(moreInfo, attrName);
+ errtext = slapi_ch_smprintf(moreInfo, attr_friendly);
} else {
errtext = slapi_ch_strdup("Error checking for attribute uniqueness.");
}
@@ -971,8 +1057,9 @@ preop_modify(Slapi_PBlock *pb)
LDAPMod **checkmods = NULL;
int checkmodsCapacity = 0;
char *errtext = NULL;
- char *attrName = NULL;
+ const char **attrNames = NULL;
struct attr_uniqueness_config *config = NULL;
+ char *attr_friendly = NULL;
#ifdef DEBUG
slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
@@ -989,6 +1076,7 @@ preop_modify(Slapi_PBlock *pb)
LDAPMod *mod;
Slapi_DN *sdn = NULL;
int isupdatedn;
+ int i = 0;
/*
* If this is a replication update, just be a noop.
@@ -1009,9 +1097,10 @@ preop_modify(Slapi_PBlock *pb)
/*
* Get the arguments
*/
- attrName = config->attr;
+ attrNames = config->attrs;
markerObjectClass = config->top_entry_oc;
requiredObjectClass = config->subtree_entries_oc;
+ attr_friendly = config->attr_friendly;
err = slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
@@ -1032,14 +1121,16 @@ preop_modify(Slapi_PBlock *pb)
for(;mods && *mods;mods++)
{
mod = *mods;
- if ((slapi_attr_type_cmp(mod->mod_type, attrName, 1) == 0) && /* mod
contains target attr */
- (mod->mod_op & LDAP_MOD_BVALUES) && /* mod is bval encoded
(not string val) */
- (mod->mod_bvalues && mod->mod_bvalues[0]) && /* mod
actually contains some values */
- (SLAPI_IS_MOD_ADD(mod->mod_op) || /* mod is add */
- SLAPI_IS_MOD_REPLACE(mod->mod_op))) /* mod is replace */
- {
- addMod(&checkmods, &checkmodsCapacity, &modcount, mod);
- }
+ for (i = 0; attrNames && attrNames[i]; i++) {
+ if ((slapi_attr_type_cmp(mod->mod_type, attrNames[i], 1) == 0) && /*
mod contains target attr */
+ (mod->mod_op & LDAP_MOD_BVALUES) && /* mod is bval encoded
(not string val) */
+ (mod->mod_bvalues && mod->mod_bvalues[0]) && /* mod
actually contains some values */
+ (SLAPI_IS_MOD_ADD(mod->mod_op) || /* mod is add */
+ SLAPI_IS_MOD_REPLACE(mod->mod_op))) /* mod is replace */
+ {
+ addMod(&checkmods, &checkmodsCapacity, &modcount, mod);
+ }
+ }
}
if (modcount == 0) {
break; /* no mods to check, we are done */
@@ -1071,13 +1162,13 @@ preop_modify(Slapi_PBlock *pb)
if (NULL != markerObjectClass)
{
/* Subtree defined by location of marker object class */
- result = findSubtreeAndSearch(sdn, attrName, NULL,
+ result = findSubtreeAndSearch(sdn, attrNames, NULL,
mod->mod_bvalues, requiredObjectClass,
sdn, markerObjectClass);
} else
{
/* Subtrees listed on invocation line */
- result = searchAllSubtrees(config->subtrees, attrName, NULL,
+ result = searchAllSubtrees(config->subtrees, attrNames, NULL,
mod->mod_bvalues, requiredObjectClass, sdn,
config->unique_in_all_subtrees);
}
}
@@ -1091,7 +1182,7 @@ preop_modify(Slapi_PBlock *pb)
"MODIFY result %d\n", result);
if (result == LDAP_CONSTRAINT_VIOLATION) {
- errtext = slapi_ch_smprintf(moreInfo, attrName);
+ errtext = slapi_ch_smprintf(moreInfo, attr_friendly);
} else {
errtext = slapi_ch_strdup("Error checking for attribute uniqueness.");
}
@@ -1119,7 +1210,7 @@ preop_modrdn(Slapi_PBlock *pb)
Slapi_Entry *e = NULL;
Slapi_Value *sv_requiredObjectClass = NULL;
char *errtext = NULL;
- char *attrName = NULL;
+ const char **attrNames = NULL;
struct attr_uniqueness_config *config = NULL;
#ifdef DEBUG
@@ -1137,6 +1228,7 @@ preop_modrdn(Slapi_PBlock *pb)
int deloldrdn = 0;
int isupdatedn;
Slapi_Attr *attr;
+ int i = 0;
/*
* If this is a replication update, just be a noop.
@@ -1157,7 +1249,7 @@ preop_modrdn(Slapi_PBlock *pb)
/*
* Get the arguments
*/
- attrName = config->attr;
+ attrNames = config->attrs;
markerObjectClass = config->top_entry_oc;
requiredObjectClass = config->subtree_entries_oc;
@@ -1211,11 +1303,6 @@ preop_modrdn(Slapi_PBlock *pb)
err = slapi_entry_rename(e, rdn, deloldrdn, superior);
if (err != LDAP_SUCCESS) { result = uid_op_error(36); break; }
- /*
- * Find any unique attribute data in the new RDN
- */
- err = slapi_entry_attr_find(e, attrName, &attr);
- if (err) break; /* no UID attribute */
/*
* Check if it has the required object class
@@ -1224,21 +1311,32 @@ preop_modrdn(Slapi_PBlock *pb)
!slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS,
sv_requiredObjectClass)) { break; }
/*
- * Passed all the requirements - this is an operation we
- * need to enforce uniqueness on. Now find all parent entries
- * with the marker object class, and do a search for each one.
+ * Find any unique attribute data in the new RDN
*/
- if (NULL != markerObjectClass)
- {
- /* Subtree defined by location of marker object class */
- result = findSubtreeAndSearch(slapi_entry_get_sdn(e), attrName, attr,
NULL,
- requiredObjectClass, sdn,
- markerObjectClass);
- } else
- {
- /* Subtrees listed on invocation line */
- result = searchAllSubtrees(config->subtrees, attrName, attr, NULL,
- requiredObjectClass, sdn,
config->unique_in_all_subtrees);
+ for (i = 0; attrNames && attrNames[i]; i++) {
+ err = slapi_entry_attr_find(e, attrNames[i], &attr);
+ if (!err) {
+ /*
+ * Passed all the requirements - this is an operation we
+ * need to enforce uniqueness on. Now find all parent entries
+ * with the marker object class, and do a search for each one.
+ */
+ if (NULL != markerObjectClass)
+ {
+ /* Subtree defined by location of marker object class */
+ result = findSubtreeAndSearch(slapi_entry_get_sdn(e), attrNames,
attr, NULL,
+ requiredObjectClass, sdn,
+ markerObjectClass);
+ } else
+ {
+ /* Subtrees listed on invocation line */
+ result = searchAllSubtrees(config->subtrees, attrNames, attr, NULL,
+ requiredObjectClass, sdn,
config->unique_in_all_subtrees);
+ }
+ if (result != LDAP_SUCCESS) {
+ break;
+ }
+ }
}
END
/* Clean-up */
@@ -1251,7 +1349,7 @@ preop_modrdn(Slapi_PBlock *pb)
"MODRDN result %d\n", result);
if (result == LDAP_CONSTRAINT_VIOLATION) {
- errtext = slapi_ch_smprintf(moreInfo, attrName);
+ errtext = slapi_ch_smprintf(moreInfo, config->attr_friendly);
} else {
errtext = slapi_ch_strdup("Error checking for attribute uniqueness.");
}