The Samba-Bugzilla – Attachment 9090 Details for
Bug 9029
Replication with --domain-crictical-only fails to fill in backlinks
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
4.1 patch cherry-picked from master
4.1-drs.patch (text/plain), 27.67 KB, created by
Andrew Bartlett
on 2013-07-30 21:51:26 UTC
(
hide
)
Description:
4.1 patch cherry-picked from master
Filename:
MIME Type:
Creator:
Andrew Bartlett
Created:
2013-07-30 21:51:26 UTC
Size:
27.67 KB
patch
obsolete
>From 8fbcc69b6b98edec2f36f7d3fe6d6355155f008e Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Tue, 4 Jun 2013 19:57:06 +1000 >Subject: [PATCH 1/4] dsdb: Improve DRS deleted link source/target handing in > repl_meta_data > >We now correctly ignore the link updates if the source or target is >deleted locally. > >This fixes the long-standing failure in the vampire_dc dbcheck test. > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> > >Andrew Bartlett > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> >(cherry picked from commit 0162be32ab4f9716a4300d1f1a0caae8b0133f7c) >--- > selftest/knownfail | 1 - > source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 105 +++++++++++++++++++++-- > 2 files changed, 97 insertions(+), 9 deletions(-) > >diff --git a/selftest/knownfail b/selftest/knownfail >index 313d6c9..3943e60 100644 >--- a/selftest/knownfail >+++ b/selftest/knownfail >@@ -175,7 +175,6 @@ > ^samba4.ntvfs.cifs.krb5.base.createx_access.createx_access\(.*\)$ > ^samba4.rpc.lsa.forest.trust #Not fully provided by Samba4 > ^samba4.blackbox.kinit\(.*\).kinit with user password for expired password\(.*\) # We need to work out why this fails only during the pw change >-^samba4.blackbox.dbcheck\(vampire_dc\).dbcheck\(vampire_dc:local\) # Due to replicating with --domain-critical-only we fail dbcheck on this database > ^samba4.blackbox.upgradeprovision.alpha13.ldapcmp_sd\(none\) # Due to something rewriting the NT ACL on DNS objects > ^samba4.blackbox.upgradeprovision.alpha13.ldapcmp_full_sd\(none\) # Due to something rewriting the NT ACL on DNS objects > ^samba4.blackbox.upgradeprovision.release-4-0-0.ldapcmp_sd\(none\) # Due to something rewriting the NT ACL on DNS objects >diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c >index 591f071..0bfdd42 100644 >--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c >+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c >@@ -5182,6 +5182,7 @@ static int replmd_process_linked_attribute(struct ldb_module *module, > struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la; > struct ldb_context *ldb = ldb_module_get_ctx(module); > struct ldb_message *msg; >+ struct ldb_message *target_msg = NULL; > TALLOC_CTX *tmp_ctx = talloc_new(la_entry); > const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx); > int ret; >@@ -5192,13 +5193,18 @@ static int replmd_process_linked_attribute(struct ldb_module *module, > WERROR status; > time_t t = time(NULL); > struct ldb_result *res; >- const char *attrs[2]; >+ struct ldb_result *target_res; >+ const char *attrs[4]; >+ const char *attrs2[] = { "isDeleted", "isRecycled", NULL }; > struct parsed_dn *pdn_list, *pdn; > struct GUID guid = GUID_zero(); > NTSTATUS ntstatus; > bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false; > const struct GUID *our_invocation_id; > >+ enum deletion_state deletion_state = OBJECT_NOT_DELETED; >+ enum deletion_state target_deletion_state = OBJECT_NOT_DELETED; >+ > /* > linked_attributes[0]: > &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute >@@ -5243,7 +5249,9 @@ linked_attributes[0]: > } > > attrs[0] = attr->lDAPDisplayName; >- attrs[1] = NULL; >+ attrs[1] = "isDeleted"; >+ attrs[1] = "isRecycled"; >+ attrs[2] = NULL; > > /* get the existing message from the db for the object with > this GUID, returning attribute being modified. We will then >@@ -5268,7 +5276,23 @@ linked_attributes[0]: > } > msg = res->msgs[0]; > >- if (msg->num_elements == 0) { >+ /* >+ * Check for deleted objects per MS-DRSR 4.1.10.6.13 >+ * ProcessLinkValue, because link updates are not applied to >+ * recycled and tombstone objects. We don't have to delete >+ * any existing link, that should have happened when the >+ * object deletion was replicated or initiated. >+ */ >+ >+ replmd_deletion_state(module, msg, &deletion_state, NULL); >+ >+ if (deletion_state >= OBJECT_RECYCLED) { >+ talloc_free(tmp_ctx); >+ return LDB_SUCCESS; >+ } >+ >+ old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName); >+ if (old_el == NULL) { > ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el); > if (ret != LDB_SUCCESS) { > ldb_module_oom(module); >@@ -5276,7 +5300,6 @@ linked_attributes[0]: > return LDB_ERR_OPERATIONS_ERROR; > } > } else { >- old_el = &msg->elements[0]; > old_el->flags = LDB_FLAG_MOD_REPLACE; > } > >@@ -5305,25 +5328,91 @@ linked_attributes[0]: > if (!W_ERROR_IS_OK(status)) { > ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n", > old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status)); >+ talloc_free(tmp_ctx); > return LDB_ERR_OPERATIONS_ERROR; > } > > ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID"); >- if (!NT_STATUS_IS_OK(ntstatus) && active) { >+ if (!NT_STATUS_IS_OK(ntstatus) && !active) { >+ /* >+ * This strange behaviour (allowing a NULL/missing >+ * GUID) originally comes from: >+ * >+ * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd >+ * Author: Andrew Tridgell <tridge@samba.org> >+ * Date: Mon Dec 21 21:21:55 2009 +1100 >+ * >+ * s4-drs: cope better with NULL GUIDS from DRS >+ * >+ * It is valid to get a NULL GUID over DRS for a deleted forward link. We >+ * need to match by DN if possible when seeing if we should update an >+ * existing link. >+ * >+ * Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org> >+ */ >+ >+ ret = dsdb_module_search_dn(module, tmp_ctx, &target_res, >+ dsdb_dn->dn, attrs2, >+ DSDB_FLAG_NEXT_MODULE | >+ DSDB_SEARCH_SHOW_RECYCLED | >+ DSDB_SEARCH_SEARCH_ALL_PARTITIONS | >+ DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, >+ parent); >+ } else if (!NT_STATUS_IS_OK(ntstatus)) { > ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s", > old_el->name, > ldb_dn_get_linearized(dsdb_dn->dn), > ldb_dn_get_linearized(msg->dn)); >+ talloc_free(tmp_ctx); > return LDB_ERR_OPERATIONS_ERROR; >+ } else { >+ ret = dsdb_module_search(module, tmp_ctx, &target_res, >+ NULL, LDB_SCOPE_SUBTREE, >+ attrs2, >+ DSDB_FLAG_NEXT_MODULE | >+ DSDB_SEARCH_SHOW_RECYCLED | >+ DSDB_SEARCH_SEARCH_ALL_PARTITIONS | >+ DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, >+ parent, >+ "objectGUID=%s", >+ GUID_string(tmp_ctx, &guid)); > } > >- /* re-resolve the DN by GUID, as the DRS server may give us an >- old DN value */ >- ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent); > if (ret != LDB_SUCCESS) { >+ ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n", >+ GUID_string(tmp_ctx, &guid), >+ ldb_errstring(ldb_module_get_ctx(module))); >+ talloc_free(tmp_ctx); >+ return ret; >+ } >+ >+ if (target_res->count == 0) { > DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n", > GUID_string(tmp_ctx, &guid), > ldb_dn_get_linearized(dsdb_dn->dn))); >+ } else if (target_res->count != 1) { >+ ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n", >+ GUID_string(tmp_ctx, &guid)); >+ talloc_free(tmp_ctx); >+ return LDB_ERR_OPERATIONS_ERROR; >+ } else { >+ target_msg = target_res->msgs[0]; >+ dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn); >+ } >+ >+ /* >+ * Check for deleted objects per MS-DRSR 4.1.10.6.13 >+ * ProcessLinkValue, because link updates are not applied to >+ * recycled and tombstone objects. We don't have to delete >+ * any existing link, that should have happened when the >+ * object deletion was replicated or initiated. >+ */ >+ replmd_deletion_state(module, target_msg, >+ &target_deletion_state, NULL); >+ >+ if (target_deletion_state >= OBJECT_RECYCLED) { >+ talloc_free(tmp_ctx); >+ return LDB_SUCCESS; > } > > /* see if this link already exists */ >-- >1.7.10.4 > > >From 2525d3679442e1e2778f1986bb32b21717268422 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 3 Jun 2013 17:51:41 +1000 >Subject: [PATCH 2/4] dsdb tests: Add member/memberOf checking to > delete_objects testing > >Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Signed-off-by: Stefan Metzmacher <metze@samba.org> >(cherry picked from commit a9e565a5a4478f7b923f35311e170de2044ff848) >--- > source4/torture/drs/python/delete_object.py | 278 +++++++++++++++++++++++++-- > 1 file changed, 257 insertions(+), 21 deletions(-) > >diff --git a/source4/torture/drs/python/delete_object.py b/source4/torture/drs/python/delete_object.py >index f36232e..3e20b6d 100644 >--- a/source4/torture/drs/python/delete_object.py >+++ b/source4/torture/drs/python/delete_object.py >@@ -30,10 +30,10 @@ import time > > > from ldb import ( >- SCOPE_SUBTREE >+ SCOPE_SUBTREE, > ) > >-import drs_base >+import drs_base, ldb > > > class DrsDeleteObjectTestCase(drs_base.DrsBaseTestCase): >@@ -55,9 +55,10 @@ class DrsDeleteObjectTestCase(drs_base.DrsBaseTestCase): > def _make_username(self): > return "DrsDelObjUser_" + time.strftime("%s", time.gmtime()) > >- def _check_user(self, sam_ldb, user_orig, is_deleted): >+ # now also used to check the group >+ def _check_obj(self, sam_ldb, obj_orig, is_deleted): > # search the user by guid as it may be deleted >- guid_str = self._GUID_string(user_orig["objectGUID"][0]) >+ guid_str = self._GUID_string(obj_orig["objectGUID"][0]) > expression = "(objectGUID=%s)" % guid_str > res = sam_ldb.search(base=self.domain_dn, > expression=expression, >@@ -67,29 +68,38 @@ class DrsDeleteObjectTestCase(drs_base.DrsBaseTestCase): > # Deleted Object base DN > dodn = self._deleted_objects_dn(sam_ldb) > # now check properties of the user >- name_orig = user_orig["cn"][0] >+ name_orig = obj_orig["cn"][0] > name_cur = user_cur["cn"][0] > if is_deleted: > self.assertEquals(user_cur["isDeleted"][0],"TRUE") >- self.assertTrue(not("objectCategory" in user_cur)) >- self.assertTrue(not("sAMAccountType" in user_cur)) >+ self.assertFalse("objectCategory" in user_cur) >+ self.assertFalse("sAMAccountType" in user_cur) >+ self.assertFalse("description" in user_cur) >+ self.assertFalse("memberOf" in user_cur) >+ self.assertFalse("member" in user_cur) > self.assertTrue(dodn in str(user_cur["dn"]), > "User %s is deleted but it is not located under %s (found at %s)!" % (name_orig, dodn, user_cur["dn"])) > self.assertEquals(name_cur, name_orig + "\nDEL:" + guid_str) > else: >- self.assertTrue(not("isDeleted" in user_cur)) >+ self.assertFalse("isDeleted" in user_cur) > self.assertEquals(name_cur, name_orig) >- self.assertEquals(user_orig["dn"], user_cur["dn"]) >+ self.assertEquals(obj_orig["dn"], user_cur["dn"]) > self.assertTrue(dodn not in str(user_cur["dn"])) >+ return user_cur > >- def test_ReplicateDeteleteObject(self): >+ def test_ReplicateDeletedObject1(self): > """Verifies how a deleted-object is replicated between two DCs. > This test should verify that: > - deleted-object is replicated properly >- TODO: We should verify that after replication, >- object's state to conform to a deleted-object state >- or tombstone -object, depending on DC's features >- It will also be great if check replPropertyMetaData.""" >+ - We verify that after replication, >+ object's state to conform to a tombstone-object state >+ - This test replicates the object modifications to >+ the server with the user deleted first >+ >+ TODO: It will also be great if check replPropertyMetaData. >+ TODO: Check for deleted-object state, depending on DC's features >+ when recycle-bin is enabled >+ """ > # work-out unique username to test with > username = self._make_username() > >@@ -104,7 +114,7 @@ class DrsDeleteObjectTestCase(drs_base.DrsBaseTestCase): > > # check user info on DC1 > print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])) >- self._check_user(sam_ldb=self.ldb_dc1, user_orig=user_orig, is_deleted=False) >+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False) > > # trigger replication from DC1 to DC2 > self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True) >@@ -112,23 +122,249 @@ class DrsDeleteObjectTestCase(drs_base.DrsBaseTestCase): > # delete user on DC1 > self.ldb_dc1.delete(user_dn) > # check user info on DC1 - should be deleted >- self._check_user(sam_ldb=self.ldb_dc1, user_orig=user_orig, is_deleted=True) >+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True) >+ # check user info on DC2 - should be valid user >+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False) >+ >+ # The user should not have a description or memberOf yet >+ self.assertFalse("description" in user_cur) >+ self.assertFalse("memberOf" in user_cur) >+ >+ self.ldb_dc2.newgroup("group_%s" % username) >+ >+ self.ldb_dc2.newgroup("group2_%s" % username) >+ >+ ldb_res = self.ldb_dc2.search(base=self.domain_dn, >+ scope=SCOPE_SUBTREE, >+ expression="(samAccountName=group_%s)" % username) >+ self.assertTrue(len(ldb_res) == 1) >+ self.assertTrue("sAMAccountName" in ldb_res[0]) >+ group_orig = ldb_res[0] >+ group_dn = ldb_res[0]["dn"] >+ >+ # modify user on DC2 to have a description and be a member of the group >+ m = ldb.Message() >+ m.dn = user_dn >+ m["description"] = ldb.MessageElement("a description", >+ ldb.FLAG_MOD_ADD, "description") >+ self.ldb_dc2.modify(m) >+ m = ldb.Message() >+ m.dn = group_dn >+ m["member"] = ldb.MessageElement(str(user_dn), >+ ldb.FLAG_MOD_ADD, "member") >+ self.ldb_dc2.modify(m) >+ >+ ldb_res = self.ldb_dc2.search(base=self.domain_dn, >+ scope=SCOPE_SUBTREE, >+ expression="(samAccountName=group2_%s)" % username) >+ self.assertTrue(len(ldb_res) == 1) >+ self.assertTrue("sAMAccountName" in ldb_res[0]) >+ group2_dn = ldb_res[0]["dn"] >+ group2_orig = ldb_res[0] >+ >+ m = ldb.Message() >+ m.dn = group2_dn >+ m["member"] = ldb.MessageElement(str(group_dn), >+ ldb.FLAG_MOD_ADD, "member") >+ self.ldb_dc2.modify(m) >+ > # check user info on DC2 - should be valid user >- self._check_user(sam_ldb=self.ldb_dc2, user_orig=user_orig, is_deleted=False) >+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False) >+ >+ # The user should not have a description yet >+ self.assertTrue("description" in user_cur) >+ self.assertTrue("memberOf" in user_cur) >+ >+ ldb_res = self.ldb_dc2.search(base=self.domain_dn, >+ scope=SCOPE_SUBTREE, >+ expression="(samAccountName=group_%s)" % username) >+ self.assertTrue(len(ldb_res) == 1) >+ >+ # This group is a member of another group >+ self.assertTrue("memberOf" in ldb_res[0]) >+ >+ # The user was deleted on DC1, but check the modify we just did on DC2 >+ self.assertTrue("member" in ldb_res[0]) > > # trigger replication from DC2 to DC1 > # to check if deleted object gets restored > self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True) > # check user info on DC1 - should be deleted >- self._check_user(sam_ldb=self.ldb_dc1, user_orig=user_orig, is_deleted=True) >+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True) > # check user info on DC2 - should be valid user >- self._check_user(sam_ldb=self.ldb_dc2, user_orig=user_orig, is_deleted=False) >+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False) >+ >+ ldb_res = self.ldb_dc1.search(base=self.domain_dn, >+ scope=SCOPE_SUBTREE, >+ expression="(samAccountName=group_%s)" % username) >+ self.assertTrue(len(ldb_res) == 1) >+ >+ # This group is a member of another group >+ self.assertTrue("memberOf" in ldb_res[0]) >+ >+ # The user was deleted on DC1, but the modify we did on DC2, check it never replicated in >+ self.assertFalse("member" in ldb_res[0]) > > # trigger replication from DC1 to DC2 > # to check if deleted object is replicated > self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True) > # check user info on DC1 - should be deleted >- self._check_user(sam_ldb=self.ldb_dc1, user_orig=user_orig, is_deleted=True) >+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True) > # check user info on DC2 - should be deleted >- self._check_user(sam_ldb=self.ldb_dc2, user_orig=user_orig, is_deleted=True) >+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=True) >+ >+ # delete group on DC1 >+ self.ldb_dc1.delete(group_dn) >+ >+ # trigger replication from DC1 to DC2 >+ # to check if deleted object is replicated >+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True) >+ >+ # check group info on DC1 - should be deleted >+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=group_orig, is_deleted=True) >+ # check group info on DC2 - should be deleted >+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=group_orig, is_deleted=True) >+ >+ ldb_res = self.ldb_dc2.search(base=self.domain_dn, >+ scope=SCOPE_SUBTREE, >+ expression="(samAccountName=group2_%s)" % username) >+ self.assertTrue(len(ldb_res) == 1) >+ self.assertFalse("member" in ldb_res[0]) >+ >+ # delete group on DC1 >+ self.ldb_dc1.delete(group2_dn) >+ >+ # trigger replication from DC1 to DC2 >+ # to check if deleted object is replicated >+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True) >+ >+ # check group info on DC1 - should be deleted >+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=group2_orig, is_deleted=True) >+ # check group info on DC2 - should be deleted >+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=group2_orig, is_deleted=True) >+ >+ def test_ReplicateDeletedObject2(self): >+ """Verifies how a deleted-object is replicated between two DCs. >+ This test should verify that: >+ - deleted-object is replicated properly >+ - We verify that after replication, >+ object's state to conform to a tombstone-object state >+ - This test replicates the delete to the server with the >+ object modifications first >+ >+ TODO: It will also be great if check replPropertyMetaData. >+ TODO: Check for deleted-object state, depending on DC's features >+ when recycle-bin is enabled >+ """ >+ # work-out unique username to test with >+ username = self._make_username() >+ >+ # create user on DC1 >+ self.ldb_dc1.newuser(username=username, password="P@sswOrd!") >+ ldb_res = self.ldb_dc1.search(base=self.domain_dn, >+ scope=SCOPE_SUBTREE, >+ expression="(samAccountName=%s)" % username) >+ self.assertEquals(len(ldb_res), 1) >+ user_orig = ldb_res[0] >+ user_dn = ldb_res[0]["dn"] >+ >+ # check user info on DC1 >+ print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])) >+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False) >+ >+ # trigger replication from DC1 to DC2 >+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True) >+ >+ # delete user on DC1 >+ self.ldb_dc1.delete(user_dn) >+ # check user info on DC1 - should be deleted >+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True) >+ # check user info on DC2 - should be valid user >+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False) >+ >+ # The user should not have a description or memberOf yet >+ self.assertFalse("description" in user_cur) >+ self.assertFalse("memberOf" in user_cur) >+ >+ self.ldb_dc2.newgroup("group_%s" % username) >+ >+ self.ldb_dc2.newgroup("group2_%s" % username) >+ >+ ldb_res = self.ldb_dc2.search(base=self.domain_dn, >+ scope=SCOPE_SUBTREE, >+ expression="(samAccountName=group_%s)" % username) >+ self.assertTrue(len(ldb_res) == 1) >+ self.assertTrue("sAMAccountName" in ldb_res[0]) >+ group_orig = ldb_res[0] >+ group_dn = ldb_res[0]["dn"] >+ >+ # modify user on DC2 to have a description and be a member of the group >+ m = ldb.Message() >+ m.dn = user_dn >+ m["description"] = ldb.MessageElement("a description", >+ ldb.FLAG_MOD_ADD, "description") >+ self.ldb_dc2.modify(m) >+ m = ldb.Message() >+ m.dn = group_dn >+ m["member"] = ldb.MessageElement(str(user_dn), >+ ldb.FLAG_MOD_ADD, "member") >+ self.ldb_dc2.modify(m) >+ >+ ldb_res = self.ldb_dc2.search(base=self.domain_dn, >+ scope=SCOPE_SUBTREE, >+ expression="(samAccountName=group2_%s)" % username) >+ self.assertTrue(len(ldb_res) == 1) >+ self.assertTrue("sAMAccountName" in ldb_res[0]) >+ group2_dn = ldb_res[0]["dn"] >+ group2_orig = ldb_res[0] >+ >+ m = ldb.Message() >+ m.dn = group2_dn >+ m["member"] = ldb.MessageElement(str(group_dn), >+ ldb.FLAG_MOD_ADD, "member") >+ self.ldb_dc2.modify(m) >+ >+ # check user info on DC2 - should be valid user >+ user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False) >+ >+ # The user should not have a description yet >+ self.assertTrue("description" in user_cur) >+ self.assertTrue("memberOf" in user_cur) >+ >+ # trigger replication from DC1 to DC2 >+ # to check if deleted object gets restored >+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True) >+ # check user info on DC1 - should be deleted >+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True) >+ # check user info on DC2 - should be deleted >+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=True) >+ >+ ldb_res = self.ldb_dc2.search(base=self.domain_dn, >+ scope=SCOPE_SUBTREE, >+ expression="(samAccountName=group_%s)" % username) >+ self.assertTrue(len(ldb_res) == 1) >+ self.assertTrue("memberOf" in ldb_res[0]) >+ self.assertFalse("member" in ldb_res[0]) >+ >+ # trigger replication from DC2 to DC1 >+ # to check if deleted object is replicated >+ self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True) >+ # check user info on DC1 - should be deleted >+ self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=True) >+ # check user info on DC2 - should be deleted >+ self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=True) >+ >+ ldb_res = self.ldb_dc1.search(base=self.domain_dn, >+ scope=SCOPE_SUBTREE, >+ expression="(samAccountName=group_%s)" % username) >+ self.assertTrue(len(ldb_res) == 1) >+ self.assertTrue("memberOf" in ldb_res[0]) >+ self.assertFalse("member" in ldb_res[0]) >+ >+ # delete group on DC1 >+ self.ldb_dc1.delete(group_dn) >+ self.ldb_dc1.delete(group2_dn) >+ >+ # trigger replication from DC1 to DC2, for cleanup >+ self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True) > >-- >1.7.10.4 > > >From 2739a7e497c7ac4e665eaff0600866db1ef281fb Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Tue, 4 Jun 2013 20:22:31 +1000 >Subject: [PATCH 3/4] dsdb: Include MS-ADTS doc references on deleted object > contstraints > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Stefan Metzmacher <metze@samba.org> >(cherry picked from commit f2afdb61698c37389be286f9443471d4aeba49b8) >--- > source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 16 ++++++++++++++++ > 1 file changed, 16 insertions(+) > >diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c >index 0bfdd42..c8cdfec 100644 >--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c >+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c >@@ -3147,6 +3147,17 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request > case OBJECT_TOMBSTONE: > > /* >+ * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements >+ * describes what must be removed from a tombstone >+ * object >+ * >+ * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements >+ * describes what must be removed from a recycled >+ * object >+ * >+ */ >+ >+ /* > * we also mark it as recycled, meaning this object can't be > * recovered (we are stripping its attributes). > * This is done only if we have this schema object of course ... >@@ -3223,6 +3234,11 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request > break; > > case OBJECT_DELETED: >+ /* >+ * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements >+ * describes what must be removed from a deleted >+ * object >+ */ > > ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL); > if (ret != LDB_SUCCESS) { >-- >1.7.10.4 > > >From 800fd7d2ae6de1578aa48f3f5ce4f918e35a45be Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Sun, 14 Apr 2013 13:32:49 +1000 >Subject: [PATCH 4/4] samba-tool dbcheck: Correctly remove deleted DNs in > dbcheck > >The previous pattern never matched, as it was a typo. > >Andrew Bartlett > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Stefan Metzmacher <metze@samba.org> > >Autobuild-User(master): Stefan Metzmacher <metze@samba.org> >Autobuild-Date(master): Tue Jul 30 12:55:00 CEST 2013 on sn-devel-104 >(cherry picked from commit 7615b2549d9549683978cb3e85b926e2ba63e294) >--- > python/samba/dbchecker.py | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py >index e88f876..8b175c2 100644 >--- a/python/samba/dbchecker.py >+++ b/python/samba/dbchecker.py >@@ -271,7 +271,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base))) > """handle a missing target DN (both GUID and DN string form are missing)""" > # check if its a backlink > linkID = self.samdb_schema.get_linkId_from_lDAPDisplayName(attrname) >- if (linkID & 1 == 0) and str(dsdb_dn).find('DEL\\0A') == -1: >+ if (linkID & 1 == 0) and str(dsdb_dn).find('\\0ADEL') == -1: > self.report("Not removing dangling forward link") > return > self.err_deleted_dn(dn, attrname, val, dsdb_dn, dsdb_dn) >-- >1.7.10.4 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Flags:
metze
:
review+
Actions:
View
Attachments on
bug 9029
: 9090