From 07e2a2612002741cda09ff44c93ccc62ed352fc8 Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Wed, 25 Oct 2017 10:54:42 +1300 Subject: [PATCH 1/2] linked attribute tests: test against duplicates in replace We should not be able to introduce duplicate links using MOD_REPLACE. It turns out we could and weren't testing. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13095 Signed-off-by: Douglas Bagnall Reviewed-by: Andrew Bartlett (cherry picked from commit 046fc1f7de685afcbb7f0b92f0280ff0109ed4b7) --- selftest/knownfail.d/ldap-linked-attributes | 3 +++ source4/dsdb/tests/python/linked_attributes.py | 10 ++++++++++ 2 files changed, 13 insertions(+) create mode 100644 selftest/knownfail.d/ldap-linked-attributes diff --git a/selftest/knownfail.d/ldap-linked-attributes b/selftest/knownfail.d/ldap-linked-attributes new file mode 100644 index 00000000000..5fa50e3ea0c --- /dev/null +++ b/selftest/knownfail.d/ldap-linked-attributes @@ -0,0 +1,3 @@ +# linked attribute replacement isn't checking for duplicates. + +samba4.ldap.linked_attributes.python.*test_la_links_replace diff --git a/source4/dsdb/tests/python/linked_attributes.py b/source4/dsdb/tests/python/linked_attributes.py index 6235bf77a89..705c9d5c0db 100644 --- a/source4/dsdb/tests/python/linked_attributes.py +++ b/source4/dsdb/tests/python/linked_attributes.py @@ -464,6 +464,16 @@ class LATests(samba.tests.TestCase): self.assert_back_links(u3, [g1]) self.assert_back_links(u4, []) + try: + # adding u2 twice should be an error + self.replace_linked_attribute(g2, [u1, u2, u3, u2]) + except ldb.LdbError as (num, msg): + if num != ldb.ERR_ENTRY_ALREADY_EXISTS: + self.fail("adding duplicate values, expected " + "ERR_ENTRY_ALREADY_EXISTS, (%d) " + "got %d" % (ldb.ERR_ENTRY_ALREADY_EXISTS, num)) + else: + self.fail("replacing duplicate values succeeded when it shouldn't") def test_la_links_replace2(self): users = self.add_objects(12, 'user', 'u_replace2') -- 2.11.0 From 1eb7a4ba863d0413811a1361f249dff91eda85e4 Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Wed, 25 Oct 2017 10:12:09 +1300 Subject: [PATCH 2/2] replmd: check for duplicate values in MOD_REPLACE case 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 Reviewed-by: Andrew Bartlett (cherry picked from commit 625e65d9f354059d0b44ca7df329d862d93378c4) --- selftest/knownfail.d/ldap-linked-attributes | 3 -- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 37 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) delete mode 100644 selftest/knownfail.d/ldap-linked-attributes diff --git a/selftest/knownfail.d/ldap-linked-attributes b/selftest/knownfail.d/ldap-linked-attributes deleted file mode 100644 index 5fa50e3ea0c..00000000000 --- a/selftest/knownfail.d/ldap-linked-attributes +++ /dev/null @@ -1,3 +0,0 @@ -# linked attribute replacement isn't checking for duplicates. - -samba4.ldap.linked_attributes.python.*test_la_links_replace diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index e4c3cda8cda..8c6040a3d52 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2090,6 +2090,37 @@ static int get_parsed_dns_trusted(struct ldb_module *module, } /* + 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 RMD_FLAGS = DSDB_RMD_FLAG_* bits @@ -2900,6 +2931,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) { -- 2.11.0