replmd: check for duplicate values in MOD_REPLACE case
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>
Tue, 24 Oct 2017 21:12:09 +0000 (10:12 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 25 Oct 2017 23:32:14 +0000 (01:32 +0200)
Because we already have a sorted parsed_dn list, this is a simple
linear scan.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
selftest/knownfail.d/ldap-linked-attributes [deleted file]
source4/dsdb/samdb/ldb_modules/repl_meta_data.c

diff --git a/selftest/knownfail.d/ldap-linked-attributes b/selftest/knownfail.d/ldap-linked-attributes
deleted file mode 100644 (file)
index 5fa50e3..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# linked attribute replacement isn't checking for duplicates.
-
-samba4.ldap.linked_attributes.python.*test_la_links_replace
index 1901ee1cc94cc30d1fa817df9b5cd0ab4cf5054c..364219462e1b18c64a964b6c1dd30f7607c6caa1 100644 (file)
@@ -2132,6 +2132,37 @@ static int get_parsed_dns_trusted(struct ldb_module *module,
        return LDB_SUCCESS;
 }
 
+/*
+   Return LDB_SUCCESS if a parsed_dn list contains no duplicate values,
+   otherwise an error code. For compatibility the error code differs depending
+   on whether or not the attribute is "member".
+
+   As always, the parsed_dn list is assumed to be sorted.
+ */
+static int check_parsed_dn_duplicates(struct ldb_module *module,
+                                     struct ldb_message_element *el,
+                                     struct parsed_dn *pdn)
+{
+       unsigned int i;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+
+       for (i = 1; i < el->num_values; i++) {
+               struct parsed_dn *p = &pdn[i];
+               if (parsed_dn_compare(p, &pdn[i - 1]) == 0) {
+                       ldb_asprintf_errstring(ldb,
+                                              "Linked attribute %s has "
+                                              "multiple identical values",
+                                              el->name);
+                       if (ldb_attr_cmp(el->name, "member") == 0) {
+                               return LDB_ERR_ENTRY_ALREADY_EXISTS;
+                       } else {
+                               return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+                       }
+               }
+       }
+       return LDB_SUCCESS;
+}
+
 /*
   build a new extended DN, including all meta data fields
 
@@ -2901,6 +2932,12 @@ static int replmd_modify_la_replace(struct ldb_module *module,
                return ret;
        }
 
+       ret = check_parsed_dn_duplicates(module, el, dns);
+       if (ret != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+
        ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
                             ldap_oid, parent);
        if (ret != LDB_SUCCESS) {