From 543d4a6ba316062fae1d1f27e1a66c5347dcca42 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Fri, 8 Jun 2018 18:20:16 +0200 Subject: [PATCH 1/8] CVE-2018-1140 dns: Add a test to trigger the LDB casefolding issue on invalid chars BUG: https://bugzilla.samba.org/show_bug.cgi?id=13466 Signed-off-by: Kai Blin --- python/samba/tests/dns_invalid.py | 87 +++++++++++++++++++++++++++++++++++++++ selftest/knownfail.d/dns | 3 ++ source4/selftest/tests.py | 3 ++ 3 files changed, 93 insertions(+) create mode 100644 python/samba/tests/dns_invalid.py diff --git a/python/samba/tests/dns_invalid.py b/python/samba/tests/dns_invalid.py new file mode 100644 index 00000000000..9f87cd56084 --- /dev/null +++ b/python/samba/tests/dns_invalid.py @@ -0,0 +1,87 @@ +# Unix SMB/CIFS implementation. +# Copyright (C) Kai Blin 2018 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os +import sys +import struct +import random +import socket +import samba.ndr as ndr +from samba import credentials, param +from samba.dcerpc import dns, dnsp, dnsserver +from samba.netcmd.dns import TXTRecord, dns_record_match, data_to_dns_record +from samba.tests.subunitrun import SubunitOptions, TestProgram +from samba import werror, WERRORError +from samba.tests.dns_base import DNSTest +import samba.getopt as options +import optparse + +parser = optparse.OptionParser("dns_invalid.py [options]") +sambaopts = options.SambaOptions(parser) +parser.add_option_group(sambaopts) + +# This timeout only has relevance when testing against Windows +# Format errors tend to return patchy responses, so a timeout is needed. +parser.add_option("--timeout", type="int", dest="timeout", + help="Specify timeout for DNS requests") + +# use command line creds if available +credopts = options.CredentialsOptions(parser) +parser.add_option_group(credopts) +subunitopts = SubunitOptions(parser) +parser.add_option_group(subunitopts) + +opts, args = parser.parse_args() + +lp = sambaopts.get_loadparm() +creds = credopts.get_credentials(lp) + +timeout = opts.timeout + +if len(args) < 1: + parser.print_usage() + sys.exit(1) + +server_ip = args[0] +creds.set_krb_forwardable(credentials.NO_KRB_FORWARDABLE) + + +class TestBrokenQueries(DNSTest): + def setUp(self): + super(TestBrokenQueries, self).setUp() + global server, server_ip, lp, creds, timeout + self.server_ip = server_ip + self.lp = lp + self.creds = creds + self.timeout = timeout + + def test_invalid_chars_in_name(self): + """Check the server refuses invalid characters in the query name""" + p = self.make_name_packet(dns.DNS_OPCODE_QUERY) + questions = [] + + name = "\x10\x11\x05\xa8.%s" % self.get_dns_domain() + q = self.make_name_question(name, dns.DNS_QTYPE_A, dns.DNS_QCLASS_IN) + print "asking for ", q.name + questions.append(q) + + self.finish_name_packet(p, questions) + (response, response_packet) = self.dns_transaction_udp(p, host=server_ip) + self.assert_dns_rcode_equals(response, dns.DNS_RCODE_NXDOMAIN) + + +TestProgram(module=__name__, opts=subunitopts) diff --git a/selftest/knownfail.d/dns b/selftest/knownfail.d/dns index cb3003240ea..140ded24fa0 100644 --- a/selftest/knownfail.d/dns +++ b/selftest/knownfail.d/dns @@ -45,3 +45,6 @@ samba.tests.dns.__main__.TestSimpleQueries.test_qtype_all_query\(rodc:local\) # The SOA override should not pass against the RODC, it must not overstamp samba.tests.dns.__main__.TestSimpleQueries.test_one_SOA_query\(rodc:local\) + +# This still needs to be fixed in LDB +samba.tests.dns_invalid.__main__.TestBrokenQueries.test_invalid_chars_in_name\(ad_dc:local\) diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 2551603d52b..ec717377e6e 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -376,6 +376,9 @@ plantestsuite_loadlist("samba.tests.dns_forwarder", "fl2003dc:local", [python, o plantestsuite_loadlist("samba.tests.dns_tkey", "fl2008r2dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_tkey.py"), '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) plantestsuite_loadlist("samba.tests.dns_wildcard", "ad_dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_wildcard.py"), '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) + +plantestsuite_loadlist("samba.tests.dns_invalid", "ad_dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_invalid.py"), '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) + for t in smbtorture4_testsuites("dns_internal."): plansmbtorture4testsuite(t, "ad_dc_ntvfs:local", '//$SERVER/whavever') -- 2.11.0 From c380aca952e7bbba6d748bd8ac8a471ff54c50e5 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 2 Jul 2018 16:49:37 +1200 Subject: [PATCH 2/8] CVE-2018-1140 dns_server: Be strict when constructing a LDB DN from an untrusted DNS name This changes our DNS server to be much more careful when constructing DNS names into LDB DN values. This avoids a segfault deep in the LDB code if the ldb_dn_get_casefold() fails there. A seperate patch will address that part of the issue. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13466 Signed-off-by: Andrew Bartlett --- selftest/knownfail.d/dns | 3 -- source4/dns_server/dnsserver_common.c | 53 +++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/selftest/knownfail.d/dns b/selftest/knownfail.d/dns index 140ded24fa0..cb3003240ea 100644 --- a/selftest/knownfail.d/dns +++ b/selftest/knownfail.d/dns @@ -45,6 +45,3 @@ samba.tests.dns.__main__.TestSimpleQueries.test_qtype_all_query\(rodc:local\) # The SOA override should not pass against the RODC, it must not overstamp samba.tests.dns.__main__.TestSimpleQueries.test_one_SOA_query\(rodc:local\) - -# This still needs to be fixed in LDB -samba.tests.dns_invalid.__main__.TestBrokenQueries.test_invalid_chars_in_name\(ad_dc:local\) diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index 6c7ab802575..ce38b78ee9f 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -915,7 +915,11 @@ WERROR dns_common_name2dn(struct ldb_context *samdb, struct ldb_dn *dn; const struct dns_server_zone *z; size_t host_part_len = 0; + struct ldb_val host_part; WERROR werr; + bool ok; + int ret; + const char *casefold = NULL; if (name == NULL) { return DNS_ERR(FORMAT_ERROR); @@ -924,7 +928,13 @@ WERROR dns_common_name2dn(struct ldb_context *samdb, if (strcmp(name, "") == 0) { base = ldb_get_default_basedn(samdb); dn = ldb_dn_copy(mem_ctx, base); - ldb_dn_add_child_fmt(dn, "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System"); + ok = ldb_dn_add_child_fmt(dn, + "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System"); + if (ok == false) { + TALLOC_FREE(dn); + return WERR_NOT_ENOUGH_MEMORY; + } + *_dn = dn; return WERR_OK; } @@ -956,7 +966,46 @@ WERROR dns_common_name2dn(struct ldb_context *samdb, } dn = ldb_dn_copy(mem_ctx, z->dn); - ldb_dn_add_child_fmt(dn, "DC=%*.*s", (int)host_part_len, (int)host_part_len, name); + if (dn == NULL) { + TALLOC_FREE(dn); + return WERR_NOT_ENOUGH_MEMORY; + } + + ok = ldb_dn_add_child_fmt(dn, "DC=X"); + + if (ok == false) { + TALLOC_FREE(dn); + return WERR_NOT_ENOUGH_MEMORY; + } + + host_part = data_blob_const(name, host_part_len); + + ret = ldb_dn_set_component(dn, 0, "DC", host_part); + if (ret != LDB_SUCCESS) { + TALLOC_FREE(dn); + return WERR_NOT_ENOUGH_MEMORY; + } + + /* + * Check the new DN here for validity, so as to catch errors + * early + */ + ok = ldb_dn_validate(dn); + if (ok == false) { + TALLOC_FREE(dn); + return DNS_ERR(NAME_ERROR); + } + + /* + * The value from this check is saved in the DN, and doing + * this here allows an easy return here. + */ + casefold = ldb_dn_get_casefold(dn); + if (casefold == NULL) { + TALLOC_FREE(dn); + return DNS_ERR(NAME_ERROR); + } + *_dn = dn; return WERR_OK; } -- 2.11.0 From f2a5e7fd9b5665b923a65c919eee14e2a27f31c6 Mon Sep 17 00:00:00 2001 From: Andrej Gessel Date: Fri, 6 Apr 2018 18:18:33 +0200 Subject: [PATCH 3/8] CVE-2018-1140 Add NULL check for ldb_dn_get_casefold() in ltdb_index_dn_attr() Signed-off-by: Andrej Gessel BUG: https://bugzilla.samba.org/show_bug.cgi?id=13374 --- lib/ldb/ldb_tdb/ldb_index.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c index fb606124fb4..77351f3c286 100644 --- a/lib/ldb/ldb_tdb/ldb_index.c +++ b/lib/ldb/ldb_tdb/ldb_index.c @@ -1597,6 +1597,15 @@ static int ltdb_index_dn_attr(struct ldb_module *module, /* work out the index key from the parent DN */ val.data = (uint8_t *)((uintptr_t)ldb_dn_get_casefold(dn)); + if (val.data == NULL) { + const char *dn_str = ldb_dn_get_linearized(dn); + ldb_asprintf_errstring(ldb_module_get_ctx(module), + __location__ + ": Failed to get casefold DN" + "from: %s", + dn_str); + return LDB_ERR_OPERATIONS_ERROR; + } val.length = strlen((char *)val.data); key = ltdb_index_key(ldb, ltdb, attr, &val, NULL, truncation); if (!key) { -- 2.11.0 From 22aae0f8bd2fcb6f2d46b982280df95b11659518 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 21 May 2018 14:50:50 +1200 Subject: [PATCH 4/8] CVE-2018-1140 ldb: Check for ldb_dn_get_casefold() failure in ldb_sqlite Signed-off-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=13374 --- lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index f94dc993904..0f5abf87547 100644 --- a/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -323,6 +323,9 @@ static char *parsetree_to_sql(struct ldb_module *module, const char *cdn = ldb_dn_get_casefold( ldb_dn_new(mem_ctx, ldb, (const char *)value.data)); + if (cdn == NULL) { + return NULL; + } return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_entry " -- 2.11.0 From 1c4d528de02c0bc9d7f5c4d3c17384a279b66b87 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 21 May 2018 15:20:26 +1200 Subject: [PATCH 5/8] CVE-2018-1140 ldb_tdb: Ensure the dn in distinguishedName= is valid before use ldb_dn_from_ldb_val() does not validate this untrusted input, so a later call to ldb_dn_get_casefold() can fail if the input is not valid. Signed-off-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=13374 --- lib/ldb/ldb_tdb/ldb_index.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/ldb/ldb_tdb/ldb_index.c b/lib/ldb/ldb_tdb/ldb_index.c index 77351f3c286..b9bc477d2a9 100644 --- a/lib/ldb/ldb_tdb/ldb_index.c +++ b/lib/ldb/ldb_tdb/ldb_index.c @@ -1155,6 +1155,7 @@ static int ltdb_index_dn_leaf(struct ldb_module *module, } if (ldb_attr_dn(tree->u.equality.attr) == 0) { enum key_truncation truncation = KEY_NOT_TRUNCATED; + bool valid_dn = false; struct ldb_dn *dn = ldb_dn_from_ldb_val(list, ldb_module_get_ctx(module), @@ -1166,6 +1167,14 @@ static int ltdb_index_dn_leaf(struct ldb_module *module, return LDB_SUCCESS; } + valid_dn = ldb_dn_validate(dn); + if (valid_dn == false) { + /* If we can't parse it, no match */ + list->dn = NULL; + list->count = 0; + return LDB_SUCCESS; + } + /* * Re-use the same code we use for a SCOPE_BASE * search -- 2.11.0 From 01b433c257235016f968e3834156860335dff17b Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 21 May 2018 15:23:53 +1200 Subject: [PATCH 6/8] CVE-2018-1140 ldb_tdb: Check for DN validity in add, rename and search This ensures we fail with a good error code before an eventual ldb_dn_get_casefold() which would otherwise fail. Signed-off-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=13374 --- lib/ldb/ldb_tdb/ldb_search.c | 16 ++++++++++++++++ lib/ldb/ldb_tdb/ldb_tdb.c | 27 ++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c index 832be9a598b..af66a097ad5 100644 --- a/lib/ldb/ldb_tdb/ldb_search.c +++ b/lib/ldb/ldb_tdb/ldb_search.c @@ -297,6 +297,14 @@ int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_mes }; TALLOC_CTX *tdb_key_ctx = NULL; + bool valid_dn = ldb_dn_validate(dn); + if (valid_dn == false) { + ldb_asprintf_errstring(ldb_module_get_ctx(module), + "Invalid Base DN: %s", + ldb_dn_get_linearized(dn)); + return LDB_ERR_INVALID_DN_SYNTAX; + } + if (ltdb->cache->GUID_index_attribute == NULL || ldb_dn_is_special(dn)) { @@ -791,6 +799,14 @@ int ltdb_search(struct ltdb_context *ctx) ldb_dn_get_linearized(req->op.search.base)); } + } else if (ldb_dn_validate(req->op.search.base) == false) { + + /* We don't want invalid base DNs here */ + ldb_asprintf_errstring(ldb, + "Invalid Base DN: %s", + ldb_dn_get_linearized(req->op.search.base)); + ret = LDB_ERR_INVALID_DN_SYNTAX; + } else { /* If we are not checking the base DN life is easy */ ret = LDB_SUCCESS; diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c index daf9a778f5b..a83bc34f58b 100644 --- a/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/lib/ldb/ldb_tdb/ldb_tdb.c @@ -566,6 +566,16 @@ static int ltdb_add_internal(struct ldb_module *module, struct ldb_context *ldb = ldb_module_get_ctx(module); int ret = LDB_SUCCESS; unsigned int i; + bool valid_dn = false; + + /* Check the new DN is reasonable */ + valid_dn = ldb_dn_validate(msg->dn); + if (valid_dn == false) { + ldb_asprintf_errstring(ldb_module_get_ctx(module), + "Invalid DN in ADD: %s", + ldb_dn_get_linearized(msg->dn)); + return LDB_ERR_INVALID_DN_SYNTAX; + } for (i=0;inum_elements;i++) { struct ldb_message_element *el = &msg->elements[i]; @@ -1369,6 +1379,7 @@ static int ltdb_rename(struct ltdb_context *ctx) int ret = LDB_SUCCESS; TDB_DATA tdb_key, tdb_key_old; struct ldb_dn *db_dn; + bool valid_dn = false; ldb_request_set_state(req, LDB_ASYNC_PENDING); @@ -1381,10 +1392,24 @@ static int ltdb_rename(struct ltdb_context *ctx) return LDB_ERR_OPERATIONS_ERROR; } + /* Check the new DN is reasonable */ + valid_dn = ldb_dn_validate(req->op.rename.newdn); + if (valid_dn == false) { + ldb_asprintf_errstring(ldb_module_get_ctx(module), + "Invalid New DN: %s", + ldb_dn_get_linearized(req->op.rename.newdn)); + return LDB_ERR_INVALID_DN_SYNTAX; + } + /* we need to fetch the old record to re-add under the new name */ ret = ltdb_search_dn1(module, req->op.rename.olddn, msg, LDB_UNPACK_DATA_FLAG_NO_DATA_ALLOC); - if (ret != LDB_SUCCESS) { + if (ret == LDB_ERR_INVALID_DN_SYNTAX) { + ldb_asprintf_errstring(ldb_module_get_ctx(module), + "Invalid Old DN: %s", + ldb_dn_get_linearized(req->op.rename.newdn)); + return ret; + } else if (ret != LDB_SUCCESS) { /* not finding the old record is an error */ return ret; } -- 2.11.0 From 6f7f0273db3f675c16ae823a60422569667cf0b4 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 21 May 2018 15:25:33 +1200 Subject: [PATCH 7/8] CVE-2018-1140 ldb_tdb: Remove pointless check of ldb_dn_is_valid() If the DN is not valid the ltdb_search_dn1() will catch it with ldb_dn_validate() which is the only safe way to check this. ldb_dn_is_valid() does not actually check, but instead returns only the result of the previous checks, if there was one. Signed-off-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=13374 --- lib/ldb/ldb_tdb/ldb_search.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c index af66a097ad5..1fd6adb6db4 100644 --- a/lib/ldb/ldb_tdb/ldb_search.c +++ b/lib/ldb/ldb_tdb/ldb_search.c @@ -759,14 +759,6 @@ int ltdb_search(struct ltdb_context *ctx) /* We accept subtree searches from a NULL base DN, ie over the whole DB */ ret = LDB_SUCCESS; } - } else if (ldb_dn_is_valid(req->op.search.base) == false) { - - /* We don't want invalid base DNs here */ - ldb_asprintf_errstring(ldb, - "Invalid Base DN: %s", - ldb_dn_get_linearized(req->op.search.base)); - ret = LDB_ERR_INVALID_DN_SYNTAX; - } else if (req->op.search.scope == LDB_SCOPE_BASE) { /* -- 2.11.0 From bef6a051f91957d8cd981542ec54c6d2eaa4d84e Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 21 May 2018 15:25:58 +1200 Subject: [PATCH 8/8] CVE-2018-1140 ldb: Add tests for search add and rename with a bad dn= DN Signed-off-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=13374 --- lib/ldb/tests/python/api.py | 156 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/lib/ldb/tests/python/api.py b/lib/ldb/tests/python/api.py index 9d01535e29c..e4010960697 100755 --- a/lib/ldb/tests/python/api.py +++ b/lib/ldb/tests/python/api.py @@ -423,6 +423,19 @@ class SimpleLdb(LdbBaseTest): finally: l.delete(ldb.Dn(l, "dc=bar")) + def test_rename_bad_string_dns(self): + l = ldb.Ldb(self.url(), flags=self.flags()) + m = ldb.Message() + m.dn = ldb.Dn(l, "dc=foo8") + m["bla"] = b"bla" + m["objectUUID"] = b"0123456789abcdef" + self.assertEqual(len(l.search()), 0) + l.add(m) + self.assertEqual(len(l.search()), 1) + self.assertRaises(ldb.LdbError,lambda: l.rename("dcXfoo8", "dc=bar")) + self.assertRaises(ldb.LdbError,lambda: l.rename("dc=foo8", "dcXbar")) + l.delete(ldb.Dn(l, "dc=foo8")) + def test_empty_dn(self): l = ldb.Ldb(self.url(), flags=self.flags()) self.assertEqual(0, len(l.search())) @@ -1192,6 +1205,110 @@ class SearchTests(LdbBaseTest): # At some point we should fix this, but it isn't trivial self.assertEqual(len(res11), 1) + def test_distinguishedName_filter_one(self): + """Testing that a distinguishedName= filter succeeds + when the scope is SCOPE_ONELEVEL. + + This should be made more consistent, but for now lock in + the behaviour + + """ + + res11 = self.l.search(base="DC=SAMBA,DC=ORG", + scope=ldb.SCOPE_ONELEVEL, + expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)") + self.assertEqual(len(res11), 1) + + def test_distinguishedName_filter_subtree(self): + """Testing that a distinguishedName= filter succeeds + when the scope is SCOPE_SUBTREE""" + + res11 = self.l.search(base="DC=SAMBA,DC=ORG", + scope=ldb.SCOPE_SUBTREE, + expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)") + self.assertEqual(len(res11), 1) + + def test_distinguishedName_filter_base(self): + """Testing that (incorrectly) a distinguishedName= filter works + when the scope is SCOPE_BASE""" + + res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG", + scope=ldb.SCOPE_BASE, + expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)") + + # At some point we should fix this, but it isn't trivial + self.assertEqual(len(res11), 1) + + def test_bad_dn_filter_base(self): + """Testing that a dn= filter on an invalid DN works + when the scope is SCOPE_BASE but + returns zero results""" + + res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG", + scope=ldb.SCOPE_BASE, + expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)") + + # At some point we should fix this, but it isn't trivial + self.assertEqual(len(res11), 0) + + + def test_bad_dn_filter_one(self): + """Testing that a dn= filter succeeds but returns zero + results when the DN is not valid on a SCOPE_ONELEVEL search + + """ + + res11 = self.l.search(base="DC=SAMBA,DC=ORG", + scope=ldb.SCOPE_ONELEVEL, + expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)") + self.assertEqual(len(res11), 0) + + def test_bad_dn_filter_subtree(self): + """Testing that a dn= filter succeeds but returns zero + results when the DN is not valid on a SCOPE_SUBTREE search + + """ + + res11 = self.l.search(base="DC=SAMBA,DC=ORG", + scope=ldb.SCOPE_SUBTREE, + expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)") + self.assertEqual(len(res11), 0) + + def test_bad_distinguishedName_filter_base(self): + """Testing that a distinguishedName= filter on an invalid DN works + when the scope is SCOPE_BASE but + returns zero results""" + + res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG", + scope=ldb.SCOPE_BASE, + expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)") + + # At some point we should fix this, but it isn't trivial + self.assertEqual(len(res11), 0) + + + def test_bad_distinguishedName_filter_one(self): + """Testing that a distinguishedName= filter succeeds but returns zero + results when the DN is not valid on a SCOPE_ONELEVEL search + + """ + + res11 = self.l.search(base="DC=SAMBA,DC=ORG", + scope=ldb.SCOPE_ONELEVEL, + expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)") + self.assertEqual(len(res11), 0) + + def test_bad_distinguishedName_filter_subtree(self): + """Testing that a distinguishedName= filter succeeds but returns zero + results when the DN is not valid on a SCOPE_SUBTREE search + + """ + + res11 = self.l.search(base="DC=SAMBA,DC=ORG", + scope=ldb.SCOPE_SUBTREE, + expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)") + self.assertEqual(len(res11), 0) + # Run the search tests against an lmdb backend class SearchTestsLmdb(SearchTests): @@ -1383,6 +1500,17 @@ class AddModifyTests(LdbBaseTest): enum = err.args[0] self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS) + def test_add_bad(self): + try: + self.l.add({"dn": "BAD,DC=SAMBA,DC=ORG", + "name": b"Admins", + "x": "z", "y": "a", + "objectUUID": b"0123456789abcde1"}) + self.fail("Should have failed adding entry with invalid DN") + except ldb.LdbError as err: + enum = err.args[0] + self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX) + def test_add_del_add(self): self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG", "name": b"Admins", @@ -1477,6 +1605,34 @@ class AddModifyTests(LdbBaseTest): enum = err.args[0] self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT) + def test_move_bad(self): + self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG", + "name": b"Admins", + "x": "z", "y": "a", + "objectUUID": b"0123456789abcde2"}) + + try: + self.l.rename("OUXDUP,DC=SAMBA,DC=ORG", + "OU=DUP2,DC=SAMBA,DC=ORG") + self.fail("Should have failed on invalid DN") + except ldb.LdbError as err: + enum = err.args[0] + self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX) + + def test_move_bad2(self): + self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG", + "name": b"Admins", + "x": "z", "y": "a", + "objectUUID": b"0123456789abcde2"}) + + try: + self.l.rename("OU=DUP,DC=SAMBA,DC=ORG", + "OUXDUP2,DC=SAMBA,DC=ORG") + self.fail("Should have failed on missing") + except ldb.LdbError as err: + enum = err.args[0] + self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX) + def test_move_fail_move_add(self): self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG", "name": b"Admins", -- 2.11.0