static int replmd_replicated_apply_search_callback(struct ldb_request *req,
						   struct ldb_reply *ares)
{
	struct replmd_replicated_request *ar = talloc_get_type(req->context,
					       struct replmd_replicated_request);
	int ret;

	if (!ares) {
		return ldb_module_done(ar->req, NULL, NULL,
					LDB_ERR_OPERATIONS_ERROR);
	}
	if (ares->error != LDB_SUCCESS &&
	    ares->error != LDB_ERR_NO_SUCH_OBJECT) {
		return ldb_module_done(ar->req, ares->controls,
					ares->response, ares->error);
	}

	switch (ares->type) {
	case LDB_REPLY_ENTRY:
		ar->search_msg = talloc_steal(ar, ares->message);
		break;

	case LDB_REPLY_REFERRAL:
		/* we ignore referrals */
		break;

	case LDB_REPLY_DONE:
	{
		struct replPropertyMetaData1 *md_remote;
		struct replPropertyMetaData1 *md_local;

		struct replPropertyMetaDataBlob omd;
		const struct ldb_val *omd_value;
		struct replPropertyMetaDataBlob *rmd;
		struct ldb_message *msg;
		int instanceType;
		ar->objs->objects[ar->index_current].local_parent_dn = NULL;
		ar->objs->objects[ar->index_current].last_known_parent = NULL;

		/*
		 * This is the ADD case, find the appropriate parent,
		 * as this object doesn't exist locally:
		 */
		if (ar->search_msg == NULL) {
			ret = replmd_replicated_apply_search_for_parent(ar);
			if (ret != LDB_SUCCESS) {
				return ldb_module_done(ar->req, NULL, NULL, ret);
			}
			talloc_free(ares);
			return LDB_SUCCESS;
		}

		/*
		 * Otherwise, in the MERGE case, work out if we are
		 * attempting a rename, and if so find the parent the
		 * newly renamed object wants to belong under (which
		 * may not be the parent in it's attached string DN
		 */
		rmd = ar->objs->objects[ar->index_current].meta_data;
		ZERO_STRUCT(omd);
		omd.version = 1;

		/* find existing meta data */
		omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
		if (omd_value) {
			enum ndr_err_code ndr_err;
			ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
						       (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
				NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
				return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
			}

			if (omd.version != 1) {
				return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
			}
		}

		ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");

		instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
		if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
		    && GUID_all_zero(&ar->local_parent_guid)) {
			DEBUG(0, ("Refusing to replicate new version of %s "
				  "as local object has an all-zero parentGUID attribute, "
				  "despite not being an NC root\n",
				  ldb_dn_get_linearized(ar->search_msg->dn)));
			return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
		}

		/*
		 * now we need to check for double renames. We could have a
		 * local rename pending which our replication partner hasn't
		 * received yet. We choose which one wins by looking at the
		 * attribute stamps on the two objects, the newer one wins.
		 *
		 * This also simply applies the correct algorithms for
		 * determining if a change was made to name at all, or
		 * if the object has just been renamed under the same
		 * parent.
		 */
		md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
		md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
		if (!md_local) {
			DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
				 ldb_dn_get_linearized(ar->search_msg->dn)));
			return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
		}

		/*
		 * if there is no name attribute given then we have to assume the
		 *  object we've received has the older name
		 */
		if (replmd_replPropertyMetaData1_new_should_be_taken(
			    ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
			    md_local, md_remote)) {
			struct GUID_txt_buf p_guid_local;
			struct GUID_txt_buf p_guid_remote;
			msg = ar->objs->objects[ar->index_current].msg;

			/* Merge on the existing object, with rename */

			DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
				 "as incoming object changing to %s under %s\n",
				 ldb_dn_get_linearized(ar->search_msg->dn),
				 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
				 ldb_dn_get_linearized(msg->dn),
				 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
						 &p_guid_remote)));
			ret = replmd_replicated_apply_search_for_parent(ar);
		} else {
			struct GUID_txt_buf p_guid_local;
			struct GUID_txt_buf p_guid_remote;
			msg = ar->objs->objects[ar->index_current].msg;

			/*
			 * Merge on the existing object, force no
			 * rename (code below just to explain why in
			 * the DEBUG() logs)
			 */

			if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
				   ldb_dn_get_linearized(msg->dn)) == 0) {
				if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
				    GUID_equal(&ar->local_parent_guid,
					       ar->objs->objects[ar->index_current].parent_guid)
				    == false) {
					DEBUG(4,(__location__ ": Keeping object %s at under %s "
						 "despite incoming object changing parent to %s\n",
						 ldb_dn_get_linearized(ar->search_msg->dn),
						 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
						 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
								 &p_guid_remote)));
				}
			} else {
				DEBUG(4,(__location__ ": Keeping object %s at under %s "
					 " and rejecting older rename to %s under %s\n",
					 ldb_dn_get_linearized(ar->search_msg->dn),
					 GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
					 ldb_dn_get_linearized(msg->dn),
					 GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
							 &p_guid_remote)));
			}
			/*
			 * This assignment ensures that the strcmp()
			 * and GUID_equal() calls in
			 * replmd_replicated_apply_merge() avoids the
			 * rename call
			 */
			ar->objs->objects[ar->index_current].parent_guid =
				&ar->local_parent_guid;

			msg->dn = ar->search_msg->dn;
			ret = replmd_replicated_apply_merge(ar);
		}
		if (ret != LDB_SUCCESS) {
			return ldb_module_done(ar->req, NULL, NULL, ret);
		}
	}
	}

	talloc_free(ares);
	return LDB_SUCCESS;
}