[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Mon Jun 6 18:33:03 UTC 2016


The branch, master has been updated
       via  ae3d0fe selftest: Add tests to show that we can not create duplicate schema entries
       via  8f93bfc samldb: Make checks for schema attributes much more strict
       via  cccd20f Remove the try/catch from urgent_replication.py
       via  f7eb865 selftest: Assert that name, the RDN attribute and actual RDN are in sync
       via  39ac5ad selftest: Add another test case to replica_sync test
       via  4271692 repl: Do not report all replication failures at level 0
       via  ca37c71 selftest/drs: Show we return the correct 3 objects for DRSUAPI_EXOP_FSMO_RID_ALLOC
       via  c5ed894 selftest: initial version of new repl_move test
       via  9aa2d44 dsdb: Give the objectGUID ahead of LDIF dump of replicated changes
       via  90581b2 dsdb: Simplify replmd_op_possible_conflict_callback behaviour
       via  8938f38 dsdb: Split rename case out of replmd_op_possible_conflict_callback
       via  e1dcd45 repl_meta_data: Give more information on replication rename behaviour
       via  7773116 repl_meta_data: Fail to replicate over local objects not NC_HEAD with a all-zero parentGUID
       via  fb9f526 dsdb: Give more errors in operational module when building the parentGUID
       via  1e21a5a dsdb: Clearly fail to replicate objects not NC_HEAD with a all-zero parentGUID
       via  449271d repl: Enforce that we have parent objects for all replicated objects
       via  2d67128 dsdb: Move operational below repl_meta_data so we can query parentGUID
      from  a936234 Add yet another error code when forking an smbd and ctdb is not there. We can see NT_STATUS_CONNECTION_REFUSED in the logs upon such a rare case.

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit ae3d0fecd6ad7f10e80b66070dc32d1ac7099a6f
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Apr 19 13:37:19 2016 +1200

    selftest: Add tests to show that we can not create duplicate schema entries
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Mon Jun  6 20:32:54 CEST 2016 on sn-devel-144

commit 8f93bfc75c6e933bd68190d5cd72678313aa1142
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Apr 19 17:22:35 2016 +1200

    samldb: Make checks for schema attributes much more strict
    
    This avoids corrupting Samba when invalid schema is imported
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>

commit cccd20ff55d2aaed4fe5cf9b8727186180baf09f
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Apr 18 14:59:21 2016 +1200

    Remove the try/catch from urgent_replication.py
    
    This meant that for ages, the duplicate OID was unnoticed, and when the syntax
    was corrected recently, this caused the test to run, and so cause trouble
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit f7eb865cd9e572ace6b32f1b796b0b5f113e6d5d
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Sun Mar 27 14:43:32 2016 +1300

    selftest: Assert that name, the RDN attribute and actual RDN are in sync
    
    This allows us to catch such errors here, rather than just on dbcheck later
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit 39ac5ad90f4b174cb5ae3e92f3bdf17bc5d2cb66
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Mar 24 14:06:12 2016 +1300

    selftest: Add another test case to replica_sync test
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit 4271692d865029ba39ebcef334cde4342bb3f72e
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Mar 21 15:51:12 2016 +1300

    repl: Do not report all replication failures at level 0
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit ca37c7146c35cb4e672dd2b859b31bf9b10cf332
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Mar 4 13:12:42 2016 +1300

    selftest/drs: Show we return the correct 3 objects for DRSUAPI_EXOP_FSMO_RID_ALLOC
    
    This does not depend on DRSUAPI_DRS_GET_ANC.
    
    This test is not new, but it was not previously being run.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit c5ed8940060069c58c20e2331727f5cb7afe6fb8
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Dec 9 14:00:10 2015 +1300

    selftest: initial version of new repl_move test
    
    This tests complex rename and modify combinations in a way that
    demonstrated a number of replication failures, due to incorrect
    handling in Samba when the parent of the record changes.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit 9aa2d44462a1d61a0809ccd6eb5a3d30dfaa7a55
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Mar 21 14:06:21 2016 +1300

    dsdb: Give the objectGUID ahead of LDIF dump of replicated changes
    
    This can help isolate which object this is when the object is involved
    in a rename.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 90581b261340f5b5c46a8e2641832ab21f83b094
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Sun Mar 27 15:39:03 2016 +1300

    dsdb: Simplify replmd_op_possible_conflict_callback behaviour
    
    The previous behaviour of this code was to overwrite the req->callback of the original, failed request.
    
    This is a problem for many reasons - including that ldb_module_done() may already have been
    called on that pointer.
    
    The correct pattern is to create a new request, and to call ldb_module_done() on the parent
    request (the one in ar->req) not in this one, in the error case.
    
    We use the passed in new callback either as the callback to call on success, or
    as the callback to the ADD request.  We overwrite it with replmd_op_name_modify_callback
    in the rename remote case, as before, but no longer modify req->callback as
    this will not be used again.
    
    This is less tricky and a little simpler to follow, as we also remove the
    now unused handling for RENAME, which is in a separate routine now
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 8938f384b7aaeea5131eb854307787805b648f34
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Mar 21 13:32:55 2016 +1300

    dsdb: Split rename case out of replmd_op_possible_conflict_callback
    
    This avoids running this code path, originally written for the add case, in
    a semi-async manner in the rename case, which caused both bugs and complexity.
    
    This does create a deal of duplicated code, but it is easier to follow because
    there are no longer special cases for ADD and RENAME in the "common" code and
    the behaviour of ldb_module_done() and the callbacks is well defined and expected
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit e1dcd45d9e76ff2324750133d687ba8e952a1e47
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Mar 15 15:19:21 2016 +1300

    repl_meta_data: Give more information on replication rename behaviour
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 7773116f9074d2ee89aa1828bf6a3807680d9370
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Mar 15 15:15:07 2016 +1300

    repl_meta_data: Fail to replicate over local objects not NC_HEAD with a all-zero parentGUID
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit fb9f5264ef709e110bf11cff3fa0f7c371ea67ce
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Mar 15 15:11:54 2016 +1300

    dsdb: Give more errors in operational module when building the parentGUID
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 1e21a5ad619c8c3611abb0d3c3a513c62ebc7c2a
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Mar 15 15:09:50 2016 +1300

    dsdb: Clearly fail to replicate objects not NC_HEAD with a all-zero parentGUID
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 449271defc25d66bf84afa7f9b3c9591bbc762bf
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Dec 9 17:05:56 2015 +1300

    repl: Enforce that we have parent objects for all replicated objects
    
    The creating of replicated objects without their parent object allows database corruption as they can end up under
    the wrong object.  We need to re-try the replication with the DRSUAPI_DRS_GET_ANC flag
    set to get the objects in tree order.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 2d67128814f27731d1cd7d137e822c894ab87a4b
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Mar 15 15:11:30 2016 +1300

    dsdb: Move operational below repl_meta_data so we can query parentGUID
    
    This avoids re-adding the same code in repl_meta_data or making a shared subroutine
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

-----------------------------------------------------------------------

Summary of changes:
 source4/dsdb/repl/drepl_out_helpers.c              |  26 +-
 source4/dsdb/repl/replicated_objects.c             |  37 +-
 source4/dsdb/samdb/ldb_modules/objectclass_attrs.c |   3 +-
 source4/dsdb/samdb/ldb_modules/operational.c       |   4 +-
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c    | 558 +++++++++----
 source4/dsdb/samdb/ldb_modules/samba_dsdb.c        |   2 +-
 source4/dsdb/samdb/ldb_modules/samldb.c            | 269 +++---
 source4/dsdb/samdb/samdb.h                         |   7 +-
 source4/dsdb/tests/python/deletetest.py            |   4 +-
 source4/dsdb/tests/python/ldap_schema.py           | 657 ++++++++++++++-
 source4/dsdb/tests/python/urgent_replication.py    |  14 +-
 source4/selftest/tests.py                          |  10 +
 source4/torture/drs/python/delete_object.py        |  12 +-
 source4/torture/drs/python/getnc_exop.py           | 109 ++-
 source4/torture/drs/python/repl_move.py            | 929 +++++++++++++++++++++
 source4/torture/drs/python/replica_sync.py         | 127 +++
 16 files changed, 2481 insertions(+), 287 deletions(-)
 create mode 100644 source4/torture/drs/python/repl_move.py


Changeset truncated at 500 lines:

diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c
index 54f44c6..6493c1e 100644
--- a/source4/dsdb/repl/drepl_out_helpers.c
+++ b/source4/dsdb/repl/drepl_out_helpers.c
@@ -458,6 +458,10 @@ static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
 	replica_flags = rf1->replica_flags;
 	highwatermark = rf1->highwatermark;
 
+	if (state->op->options & DRSUAPI_DRS_GET_ANC) {
+		replica_flags |= DRSUAPI_DRS_GET_ANC;
+	}
+
 	if (partition->partial_replica) {
 		status = dreplsrv_get_gc_partial_attribute_set(service, r, &pas);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -873,7 +877,27 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
 	talloc_free(objects);
 
 	if (!W_ERROR_IS_OK(status)) {
-		nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
+
+		/*
+		 * If we failed to apply the records due to a missing
+		 * parent, try again after asking for the parent
+		 * records first.  Because we don't update the
+		 * highwatermark, we start this part of the cycle
+		 * again.
+		 */
+		if (((state->op->options & DRSUAPI_DRS_GET_ANC) == 0)
+		    && W_ERROR_EQUAL(status, WERR_DS_DRA_MISSING_PARENT)) {
+			state->op->options |= DRSUAPI_DRS_GET_ANC;
+			DEBUG(4,("Missing parent object when we didn't set the DRSUAPI_DRS_GET_ANC flag, retrying\n"));
+			dreplsrv_op_pull_source_get_changes_trigger(req);
+			return;
+		} else if (((state->op->options & DRSUAPI_DRS_GET_ANC))
+			   && W_ERROR_EQUAL(status, WERR_DS_DRA_MISSING_PARENT)) {
+			DEBUG(1,("Missing parent object despite setting DRSUAPI_DRS_GET_ANC flag\n"));
+			nt_status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+		} else {
+			nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
+		}
 		DEBUG(0,("Failed to commit objects: %s/%s\n",
 			  win_errstr(status), nt_errstr(nt_status)));
 		tevent_req_nterror(req, nt_status);
diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c
index 44a766b..674074c 100644
--- a/source4/dsdb/repl/replicated_objects.c
+++ b/source4/dsdb/repl/replicated_objects.c
@@ -348,15 +348,12 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 			      TALLOC_CTX *mem_ctx,
 			      struct dsdb_extended_replicated_object *out)
 {
-	NTSTATUS nt_status;
 	WERROR status = WERR_OK;
 	uint32_t i;
 	struct ldb_message *msg;
 	struct replPropertyMetaDataBlob *md;
 	int instanceType;
 	struct ldb_message_element *instanceType_e = NULL;
-	struct ldb_val guid_value;
-	struct ldb_val parent_guid_value;
 	NTTIME whenChanged = 0;
 	time_t whenChanged_t;
 	const char *whenChanged_s;
@@ -615,23 +612,22 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 	whenChanged_s = ldb_timestring(msg, whenChanged_t);
 	W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
 
-	nt_status = GUID_to_ndr_blob(&in->object.identifier->guid, msg, &guid_value);
-	if (!NT_STATUS_IS_OK(nt_status)) {
-		return ntstatus_to_werror(nt_status);
-	}
+	out->object_guid = in->object.identifier->guid;
 
-	if (in->parent_object_guid) {
-		nt_status = GUID_to_ndr_blob(in->parent_object_guid, msg, &parent_guid_value);
-		if (!NT_STATUS_IS_OK(nt_status)) {
-			return ntstatus_to_werror(nt_status);
+	if (in->parent_object_guid == NULL) {
+		out->parent_guid = NULL;
+		if ((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0) {
+			DEBUG(0, ("Refusing to replicate %s from a server that did not provide a parentGUID!\n",
+				  ldb_dn_get_linearized(msg->dn)));
+			return WERR_DS_DRA_INCONSISTENT_DIT;
 		}
 	} else {
-		parent_guid_value = data_blob_null;
+		out->parent_guid = talloc(mem_ctx, struct GUID);
+		W_ERROR_HAVE_NO_MEMORY(out->parent_guid);
+		*out->parent_guid = *in->parent_object_guid;
 	}
 
 	out->msg		= msg;
-	out->guid_value		= guid_value;
-	out->parent_guid_value	= parent_guid_value;
 	out->when_changed	= whenChanged_s;
 	out->meta_data		= md;
 	return WERR_OK;
@@ -840,10 +836,19 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
 			dsdb_reference_schema(ldb, cur_schema, false);
 		}
 
-		DEBUG(0,("Failed to apply records: %s: %s\n",
-			 ldb_errstring(ldb), ldb_strerror(ret)));
+		if (!W_ERROR_EQUAL(objects->error, WERR_DS_DRA_MISSING_PARENT)) {
+			DEBUG(1,("Failed to apply records: %s: %s\n",
+				 ldb_errstring(ldb), ldb_strerror(ret)));
+		} else {
+			DEBUG(3,("Missing parent while attempting to apply records: %s\n",
+				 ldb_errstring(ldb)));
+		}
 		ldb_transaction_cancel(ldb);
 		TALLOC_FREE(tmp_ctx);
+
+		if (!W_ERROR_IS_OK(objects->error)) {
+			return objects->error;
+		}
 		return WERR_FOOBAR;
 	}
 	talloc_free(ext_res);
diff --git a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
index 316dcf8..e051913 100644
--- a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
+++ b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
@@ -512,6 +512,7 @@ static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
 	struct ldb_request *search_req;
 	struct ldb_dn *base_dn;
 	int ret;
+	static const char *attrs[] = {"nTSecurityDescriptor", "*", NULL};
 
 	ac = talloc_get_type(req->context, struct oc_context);
 	ldb = ldb_module_get_ctx(ac->module);
@@ -544,7 +545,7 @@ static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares)
 		: ac->req->op.mod.message->dn;
 	ret = ldb_build_search_req(&search_req, ldb, ac, base_dn,
 				   LDB_SCOPE_BASE, "(objectClass=*)",
-				   NULL, NULL, ac,
+				   attrs, NULL, ac,
 				   get_search_callback, ac->req);
 	LDB_REQ_SET_LOCATION(search_req);
 	if (ret != LDB_SUCCESS) {
diff --git a/source4/dsdb/samdb/ldb_modules/operational.c b/source4/dsdb/samdb/ldb_modules/operational.c
index 0dd420a..4205c4b 100644
--- a/source4/dsdb/samdb/ldb_modules/operational.c
+++ b/source4/dsdb/samdb/ldb_modules/operational.c
@@ -352,7 +352,7 @@ static int construct_parent_guid(struct ldb_module *module,
 	if (parent_dn == NULL) {
 		DEBUG(4,(__location__ ": Failed to find parent for dn %s\n",
 					 ldb_dn_get_linearized(msg->dn)));
-		return LDB_SUCCESS;
+		return LDB_ERR_OTHER;
 	}
 	ret = dsdb_module_search_dn(module, msg, &parent_res, parent_dn, attrs2,
 	                            DSDB_FLAG_NEXT_MODULE |
@@ -372,7 +372,7 @@ static int construct_parent_guid(struct ldb_module *module,
 	parent_guid = ldb_msg_find_ldb_val(parent_res->msgs[0], "objectGUID");
 	if (!parent_guid) {
 		talloc_free(parent_res);
-		return LDB_SUCCESS;
+		return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
 	}
 
 	v = data_blob_dup_talloc(parent_res, *parent_guid);
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 6596d45..f1d3958 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -91,6 +91,7 @@ struct replmd_replicated_request {
 	struct dsdb_extended_replicated_objects *objs;
 
 	struct ldb_message *search_msg;
+	struct GUID local_parent_guid;
 
 	uint64_t seq_num;
 	bool is_urgent;
@@ -3527,6 +3528,10 @@ static int replmd_replicated_request_werror(struct replmd_replicated_request *ar
 {
 	int ret = LDB_ERR_OTHER;
 	/* TODO: do some error mapping */
+
+	/* Let the caller know the full WERROR */
+	ar->objs->error = status;
+
 	return ret;
 }
 
@@ -3755,7 +3760,7 @@ static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_re
 }
 
 /*
-  callback for replmd_replicated_apply_add() and replmd_replicated_handle_rename()
+  callback for replmd_replicated_apply_add()
   This copes with the creation of conflict records in the case where
   the DN exists, but with a different objectGUID
  */
@@ -3773,36 +3778,37 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
 	bool rename_incoming_record, rodc;
 	struct replPropertyMetaData1 *rmd_name, *omd_name;
 	struct ldb_message *msg;
+	struct ldb_request *down_req = NULL;
 
-	req->callback = callback;
-
-	if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
-		/* call the normal callback for everything except
-		   conflicts */
-		return ldb_module_done(req, ares->controls, ares->response, ares->error);
+	/* call the normal callback for success */
+	if (ares->error == LDB_SUCCESS) {
+		return callback(req, ares);
 	}
 
-	ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
-	if (ret != LDB_SUCCESS) {
-		ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to determine if we are an RODC when attempting to form conflict DN: %s", ldb_errstring(ldb_module_get_ctx(ar->module)));
-		return ldb_module_done(req, ares->controls, ares->response, LDB_ERR_OPERATIONS_ERROR);
-	}
 	/*
 	 * we have a conflict, and need to decide if we will keep the
 	 * new record or the old record
 	 */
 
 	msg = ar->objs->objects[ar->index_current].msg;
+	conflict_dn = msg->dn;
+
+	/* For failures other than conflicts, fail the whole operation here */
+	if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
+		ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
+				       ldb_dn_get_linearized(conflict_dn),
+				       ldb_errstring(ldb_module_get_ctx(ar->module)));
+
+		return ldb_module_done(ar->req, NULL, NULL,
+				       LDB_ERR_OPERATIONS_ERROR);
+	}
+
+	ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
+	if (ret != LDB_SUCCESS) {
+		ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to determine if we are an RODC when attempting to form conflict DN: %s", ldb_errstring(ldb_module_get_ctx(ar->module)));
+		return ldb_module_done(ar->req, NULL, NULL,
+				       LDB_ERR_OPERATIONS_ERROR);
 
-	switch (req->operation) {
-	case LDB_ADD:
-		conflict_dn = msg->dn;
-		break;
-	case LDB_RENAME:
-		conflict_dn = req->op.rename.newdn;
-		break;
-	default:
-		return ldb_module_done(req, ares->controls, ares->response, ldb_module_operr(ar->module));
 	}
 
 	if (rodc) {
@@ -3821,7 +3827,7 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
 
 	/*
 	 * first we need the replPropertyMetaData attribute from the
-	 * old record
+	 * local, conflicting record
 	 */
 	ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
 				    attrs,
@@ -3868,23 +3874,6 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
 		struct GUID guid;
 		struct ldb_dn *new_dn;
 
-		/*
-		 * We want to run the original callback here, which
-		 * will return LDB_ERR_ENTRY_ALREADY_EXISTS to the
-		 * caller, which will in turn know to rename the
-		 * incoming record.  The error string is set in case
-		 * this isn't handled properly at some point in the
-		 * future.
-		 */
-		if (req->operation == LDB_RENAME) {
-			ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
-					       "Unable to handle incoming renames where this would "
-					       "create a conflict. Incoming record is %s (caller to handle)\n",
-					       ldb_dn_get_extended_linearized(req, conflict_dn, 1));
-
-			goto failed;
-		}
-
 		guid = samdb_result_guid(msg, "objectGUID");
 		if (GUID_all_zero(&guid)) {
 			DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
@@ -3901,12 +3890,9 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
 		DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
 			 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
 
-		/* re-submit the request, but with a different
-		   callback, so we don't loop forever. */
+		/* re-submit the request, but with the new DN */
+		callback = replmd_op_name_modify_callback;
 		msg->dn = new_dn;
-		req->callback = replmd_op_name_modify_callback;
-
-		return ldb_next_request(ar->module, req);
 	} else {
 		/* we are renaming the existing record */
 		struct GUID guid;
@@ -3948,15 +3934,55 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
 			goto failed;
 		}
 
-		return ldb_next_request(ar->module, req);
+		DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
+			 ldb_dn_get_linearized(req->op.add.message->dn)));
+	}
+
+	ret = ldb_build_add_req(&down_req,
+				ldb_module_get_ctx(ar->module),
+				req,
+				msg,
+				ar->controls,
+				ar,
+				callback,
+				req);
+	if (ret != LDB_SUCCESS) {
+		goto failed;
+	}
+	LDB_REQ_SET_LOCATION(down_req);
+
+	/* current partition control needed by "repmd_op_callback" */
+	ret = ldb_request_add_control(down_req,
+				      DSDB_CONTROL_CURRENT_PARTITION_OID,
+				      false, NULL);
+	if (ret != LDB_SUCCESS) {
+		return replmd_replicated_request_error(ar, ret);
 	}
 
+	if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
+		/* this tells the partition module to make it a
+		   partial replica if creating an NC */
+		ret = ldb_request_add_control(down_req,
+					      DSDB_CONTROL_PARTIAL_REPLICA,
+					      false, NULL);
+		if (ret != LDB_SUCCESS) {
+			return replmd_replicated_request_error(ar, ret);
+		}
+	}
+
+	/*
+	 * Finally we re-run the add, otherwise the new record won't
+	 * exist, as we are here because of that exact failure!
+	 */
+	return ldb_next_request(ar->module, down_req);
 failed:
-	/* on failure do the original callback. This means replication
-	 * will stop with an error, but there is not much else we can
-	 * do
+
+	/* on failure make the caller get the error. This means
+	 * replication will stop with an error, but there is not much
+	 * else we can do.
 	 */
-	return ldb_module_done(req, ares->controls, ares->response, ares->error);
+	return ldb_module_done(ar->req, NULL, NULL,
+			       ret);
 }
 
 /*
@@ -3979,16 +4005,6 @@ static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *are
 }
 
 /*
-  callback for replmd_replicated_handle_rename()
-  This copes with the creation of conflict records in the case where
-  the DN exists, but with a different objectGUID
- */
-static int replmd_op_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
-	return replmd_op_possible_conflict_callback(req, ares, ldb_modify_default_callback);
-}
-
-/*
   this is called when a new object comes in over DRS
  */
 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
@@ -4014,7 +4030,9 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
 		return replmd_replicated_request_error(ar, ret);
 	}
 
-	ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
+	ret = dsdb_msg_add_guid(msg,
+				&ar->objs->objects[ar->index_current].object_guid,
+				"objectGUID");
 	if (ret != LDB_SUCCESS) {
 		return replmd_replicated_request_error(ar, ret);
 	}
@@ -4056,8 +4074,12 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
 	}
 
 	if (DEBUGLVL(4)) {
+		struct GUID_txt_buf guid_txt;
+
 		char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
-		DEBUG(4, ("DRS replication add message:\n%s\n", s));
+		DEBUG(4, ("DRS replication add message of %s:\n%s\n",
+			  GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
+			  s));
 		talloc_free(s);
 	}
 
@@ -4154,12 +4176,14 @@ static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request
 		return ldb_module_done(ar->req, NULL, NULL,
 					LDB_ERR_OPERATIONS_ERROR);
 	}
-	if (ares->error != LDB_SUCCESS &&
-	    ares->error != LDB_ERR_NO_SUCH_OBJECT) {
-		/*
-		 * TODO: deal with the above error that the parent object doesn't exist
-		 */
 
+	/*
+	 * The error NO_SUCH_OBJECT is not expected, unless the search
+	 * base is the partition DN, and that case doesn't happen here
+	 * because then we wouldn't get a parent_guid_value in any
+	 * case.
+	 */
+	if (ares->error != LDB_SUCCESS) {
 		return ldb_module_done(ar->req, ares->controls,
 					ares->response, ares->error);
 	}
@@ -4217,9 +4241,13 @@ static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request
 			}
 			ar->objs->objects[ar->index_current].last_known_parent
 				= talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
+
 		} else {
-			parent_dn = parent_msg->dn;
+			parent_dn
+				= talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
+
 		}
+		ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
 
 		comp_num = ldb_dn_get_comp_num(msg->dn);
 		if (comp_num > 1) {
@@ -4239,6 +4267,32 @@ static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request
 		break;
 
 	case LDB_REPLY_DONE:
+
+		if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
+			struct GUID_txt_buf str_buf;
+			if (ar->search_msg != NULL) {
+				ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
+						       "No parent with GUID %s found for object locally known as %s",
+						       GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
+						       ldb_dn_get_linearized(ar->search_msg->dn));
+			} else {
+				ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
+						       "No parent with GUID %s found for object remotely known as %s",
+						       GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
+						       ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
+			}
+
+			/*
+			 * This error code is really important, as it
+			 * is the flag back to the callers to retry
+			 * this with DRSUAPI_DRS_GET_ANC, and so get
+			 * the parent objects before the child
+			 * objects
+			 */
+			return ldb_module_done(ar->req, NULL, NULL,
+					       replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
+		}
+
 		if (ar->search_msg != NULL) {
 			ret = replmd_replicated_apply_merge(ar);
 		} else {
@@ -4268,10 +4322,11 @@ static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_re
 	char *filter;
 	struct ldb_request *search_req;
 	static const char *attrs[] = {"isDeleted", NULL};
+	struct GUID_txt_buf guid_str_buf;
 
 	ldb = ldb_module_get_ctx(ar->module);
 
-	if (!ar->objs->objects[ar->index_current].parent_guid_value.data) {
+	if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
 		if (ar->search_msg != NULL) {
 			return replmd_replicated_apply_merge(ar);
 		} else {
@@ -4279,12 +4334,11 @@ static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_re
 		}
 	}
 
-	tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].parent_guid_value);
-	if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
+	tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
+				  &guid_str_buf);
 
 	filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
 	if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
-	talloc_free(tmp_str);
 
 	ret = ldb_build_search_req(&search_req,
 				   ldb,


-- 
Samba Shared Repository



More information about the samba-cvs mailing list