CVE-2019-12436 dsdb/paged_results: ignore successful results without messages master
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>
Fri, 17 May 2019 02:42:24 +0000 (14:42 +1200)
committerKarolin Seeger <kseeger@samba.org>
Wed, 19 Jun 2019 08:16:39 +0000 (08:16 +0000)
So that we don't dereference result->msgs[0] when it doesn't exist.
This can happen when the object has changed in such a way that it no
longer matches the original search query.

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

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Autobuild-User(master): Karolin Seeger <kseeger@samba.org>
Autobuild-Date(master): Wed Jun 19 08:16:39 UTC 2019 on sn-devel-184

source4/dsdb/samdb/ldb_modules/paged_results.c
source4/dsdb/tests/python/vlv.py

index e70f462..940d225 100644 (file)
@@ -266,7 +266,8 @@ static int paged_results(struct paged_context *ac)
                ret = paged_search_by_dn_guid(ac->module, ac, &result, guid,
                                            ac->req->op.search.attrs,
                                            ac->store->expr);
-               if (ret == LDAP_NO_SUCH_OBJECT /* TODO or no result */) {
+               if (ret == LDAP_NO_SUCH_OBJECT ||
+                   (ret == LDB_SUCCESS && result->count == 0)) {
                        /* The thing isn't there TODO, which we quietly
                           ignore and go on to send an extra one
                           instead. */
index 29cc171..2efcaa5 100644 (file)
@@ -105,6 +105,7 @@ class TestsWithUserOU(samba.tests.TestCase):
             'givenName': "abcdefghijklmnopqrstuvwxyz"[i % 26],
             "roomNumber": "%sbc" % (n - i),
             "carLicense": "后来经",
+            "facsimileTelephoneNumber": name,
             "employeeNumber": "%s%sx" % (abs(i * (99 - i)), '\n' * (i & 255)),
             "accountExpires": "%s" % (10 ** 9 + 1000000 * i),
             "msTSExpireDate4": "19%02d0101010000.0Z" % (i % 100),
@@ -1338,7 +1339,7 @@ class PagedResultsTests(TestsWithUserOU):
 
         self.assertEqual(results, expected_results)
 
-    def test_paged_modify_during_search(self):
+    def test_paged_rename_during_search(self):
         expr = "(objectClass=*)"
 
         # Start new search
@@ -1421,6 +1422,53 @@ class PagedResultsTests(TestsWithUserOU):
 
         self.assertEqual(results, expected_results)
 
+    def test_paged_modify_one_during_search(self):
+        prefix = "change_during_search_"
+        num_users = 5
+        users = [self.create_user(i, num_users, prefix=prefix)
+                 for i in range(num_users)]
+        expr = "(&(objectClass=user)(facsimileTelephoneNumber=%s*))" % (prefix)
+
+        # Get the first page, then change the searched attribute and
+        # try for the second page.
+        results, cookie = self.paged_search(expr, page_size=1)
+        self.assertEqual(len(results), 1)
+        unwalked_users = [u for u in users if u['cn'] != results[0]]
+        self.assertEqual(len(unwalked_users), num_users-1)
+
+        mod_dn = unwalked_users[0]['dn']
+        self.ldb.modify_ldif("dn: %s\n"
+                             "changetype: modify\n"
+                             "replace: facsimileTelephoneNumber\n"
+                             "facsimileTelephoneNumber: 123" % mod_dn)
+
+        results, _ = self.paged_search(expr, cookie=cookie,
+                                       page_size=len(self.users))
+        expected_cns = {u['cn'] for u in unwalked_users if u['dn'] != mod_dn}
+        self.assertEqual(set(results), expected_cns)
+
+    def test_paged_modify_all_during_search(self):
+        prefix = "change_during_search_"
+        num_users = 5
+        users = [self.create_user(i, num_users, prefix=prefix)
+                 for i in range(num_users)]
+        expr = "(&(objectClass=user)(facsimileTelephoneNumber=%s*))" % (prefix)
+
+        # Get the first page, then change the searched attribute and
+        # try for the second page.
+        results, cookie = self.paged_search(expr, page_size=1)
+        unwalked_users = [u for u in users if u['cn'] != results[0]]
+
+        for u in users:
+            self.ldb.modify_ldif("dn: %s\n"
+                                 "changetype: modify\n"
+                                 "replace: facsimileTelephoneNumber\n"
+                                 "facsimileTelephoneNumber: 123" % u['dn'])
+
+        results, _ = self.paged_search(expr, cookie=cookie,
+                                       page_size=len(self.users))
+        self.assertEqual(results, [])
+
     def assertPagedSearchRaises(self, err_num, expr, cookie, attrs=None,
                                 extra_ctrls=None):
         try: