[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Tue Jun 7 12:34:04 UTC 2016


The branch, master has been updated
       via  1a87c9b repl: Avoid use-after-free when working with the working_schema
       via  c4afb1d selftest: Add a reverse variation to ReplicateMoveObject3
       via  889f33d selftest: Assert replPropertyMetaData values before and after replication
       via  374a011 dsdb: Fix rename and RDN handling for replPropertyMetaData
       via  a8430d1 dsdb: Fix incorrect sorting of replPropertyMetaData with RDN last
       via  225cef9 dsdb: Show initial replicated modify as well as resolved modify in repl_meta_data
       via  9dcc62e selftest: Add more tests to cover attribute changes vs DN renames
       via  5fee4aa dsdb: Use replmd_replPropertyMetaData1_new_should_be_taken in replmd_replicated_apply_search_callback()
       via  f0aa1d8 dsdb: Use replmd_replPropertyMetaData1_new_should_be_taken in replmd_replicated_apply_merge()
       via  b28d8d4 dsdb: Use replmd_replPropertyMetaData1_new_should_be_taken in replmd_replicated_handle_rename()
       via  dae543e dsdb: Use replmd_replPropertyMetaData1_new_should_be_taken in replmd_op_possible_conflict_callback()
       via  f709261 dsdb: Add new helper function replmd_replPropertyMetaData1_new_should_be_taken()
       via  0b525fe selftest: Do not scan the full DB to confirm a specific DN in dbcheck
       via  8f1557a selftest: Run the krb5.kdc test on a more selective basis
      from  fa2a94a selftest: These replication tests are now OK after we fixed all the replication bugs

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


- Log -----------------------------------------------------------------
commit 1a87c9b5994662de8bcd7c080dafb792dedb9f46
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Jun 7 16:41:15 2016 +1200

    repl: Avoid use-after-free when working with the working_schema
    
    The original schema must live as long as the working_schema
    as the working_schema starts as a shallow-copy of schema.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11953
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Tue Jun  7 14:33:39 CEST 2016 on sn-devel-144

commit c4afb1d3bd82018e6b29f1018218c36c12f95a82
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Jun 2 15:31:15 2016 +1200

    selftest: Add a reverse variation to ReplicateMoveObject3
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Samba <garming at catalyst.net.nz>

commit 889f33d47f6c753265e27b69ffd22d12dbb6d96f
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri May 13 11:41:53 2016 +1200

    selftest: Assert replPropertyMetaData values before and after replication
    
    This covers renames, addition of attributes, and the delete.
    
    We also confirm the results via DRS.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 374a01119dac8d1b04f8d43caf6e119be654e2dc
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed May 25 14:49:31 2016 +1200

    dsdb: Fix rename and RDN handling for replPropertyMetaData
    
    This matches Windows 2012R2, which both has the RDN not sorted last and has it updated with the local
    invocation_id and a local version.
    
    The RDN attribute, unlike name, is not replicated over DRS, so the impact for interopability extends only to
    the incorrect RDN values that we were finding with dbcheck (values that did not match the name values).
    
    Finally, we always force the RDN to match the name attribute, which avoids issues
    in dbcheck where these diverge.  As such, we can finally remove dbcheck as a
    flapping test, last re-added in e4bab3a8282d263eb2391bc7e8a6fd64ae068935
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit a8430d15a57d3bae986a55e831bac0c216115b65
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri May 13 23:12:47 2016 +1200

    dsdb: Fix incorrect sorting of replPropertyMetaData with RDN last
    
    Per tests against Windows 2012R2 the RDN is not sorted last and is
    instead sorted normally with all the other elements.
    
    The RDN attribute, unlike name, is not replicated over DRS, so this
    has no interopability impact.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit 225cef98518541ccae07bc7f4e9a7b10bde1856d
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri May 13 11:40:55 2016 +1200

    dsdb: Show initial replicated modify as well as resolved modify in repl_meta_data
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit 9dcc62eb781fdc05070bc12c43081e086963e4ad
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue May 10 16:40:51 2016 +1200

    selftest: Add more tests to cover attribute changes vs DN renames
    
    This covers a bug where unrelated attribute changes would reverse a rename
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit 5fee4aa90787237d7a7af11febdc45277a896976
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed May 4 10:42:41 2016 +1200

    dsdb: Use replmd_replPropertyMetaData1_new_should_be_taken in replmd_replicated_apply_search_callback()
    
    This is the primary handler for renames
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit f0aa1d8b8074deebc186243a4813c528cd73869d
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed May 4 10:42:05 2016 +1200

    dsdb: Use replmd_replPropertyMetaData1_new_should_be_taken in replmd_replicated_apply_merge()
    
    This is the main handler for attribute conflicts
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit b28d8d42783bad1415afdca01dd9c70e092d7360
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed May 4 10:41:48 2016 +1200

    dsdb: Use replmd_replPropertyMetaData1_new_should_be_taken in replmd_replicated_handle_rename()
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit dae543e04e43dad05c90659b94b78e5e69cce709
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed May 4 10:41:15 2016 +1200

    dsdb: Use replmd_replPropertyMetaData1_new_should_be_taken in replmd_op_possible_conflict_callback()
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit f709261c7398f1df5266e227ebe5a36e6ce6e9be
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed May 4 10:00:21 2016 +1200

    dsdb: Add new helper function replmd_replPropertyMetaData1_new_should_be_taken()
    
    This will allow the test for "name" and the actual DN to be consistent,
    and so avoids dbcheck errors when CN and name do not match the DN
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz

commit 0b525fe862ea993fe34f239482a06acb9f901877
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Jun 7 13:54:28 2016 +1200

    selftest: Do not scan the full DB to confirm a specific DN in dbcheck
    
    This avoids a full DB scan and therefore reduces the test time taken
    when we just modified the cn=administrator record.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

commit 8f1557a2c43e287c07723c16be78e1d858f4111d
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Jun 7 13:51:09 2016 +1200

    selftest: Run the krb5.kdc test on a more selective basis
    
    The previous tests would take 20mins, the new set of tests take around 7 mins and still cover
    the important combinations, given that it is the same KDC code in each environment
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Garming Sam <garming at catalyst.net.nz>

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

Summary of changes:
 python/samba/dbchecker.py                          |   15 +-
 selftest/flapping                                  |    1 -
 source4/dsdb/repl/drepl_out_helpers.c              |    2 +-
 source4/dsdb/repl/replicated_objects.c             |   86 +-
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c    |  330 ++--
 ...xpected-replpropertymetadata-after-dbcheck.ldif |   14 +-
 ...pected-replpropertymetadata-after-dbcheck2.ldif |   12 +-
 ...pected-replpropertymetadata-after-dbcheck3.ldif |   14 +-
 ...ected-replpropertymetadata-before-dbcheck2.ldif |   12 +-
 source4/selftest/tests.py                          |   45 +-
 source4/torture/drs/python/repl_move.py            | 1729 +++++++++++++++++++-
 testprogs/blackbox/dbcheck-oldrelease.sh           |    2 +-
 12 files changed, 2006 insertions(+), 256 deletions(-)


Changeset truncated at 500 lines:

diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
index 75eff51..e652f86 100644
--- a/python/samba/dbchecker.py
+++ b/python/samba/dbchecker.py
@@ -1161,7 +1161,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
         # Sort the array, except for the last element.  This strange
         # construction, creating a new list, due to bugs in samba's
         # array handling in IDL generated objects.
-        ctr.array = sorted(ctr.array[:-1], key=lambda o: o.attid) + [ctr.array[-1]]
+        ctr.array = sorted(ctr.array[:], key=lambda o: o.attid)
         # Now walk it in reverse, so we see the low (and so incorrect,
         # the correct values are above 0x80000000) values first and
         # remove the 'second' value we see.
@@ -1215,9 +1215,8 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                     fix = True
                     o.attid = correct_attid
             if fix:
-                # Sort the array, except for the last element (we changed
-                # the value so must re-sort)
-                new_list[:-1] = sorted(new_list[:-1], key=lambda o: o.attid)
+                # Sort the array, (we changed the value so must re-sort)
+                new_list[:] = sorted(new_list[:], key=lambda o: o.attid)
 
         # If we did not already need to fix it, then ask about sorting
         if not fix:
@@ -1461,7 +1460,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
 
                 if len(set_attrs_from_md) < len(list_attid_from_md) \
                    or len(wrong_attids) > 0 \
-                   or sorted(list_attid_from_md[:-1]) != list_attid_from_md[:-1]:
+                   or sorted(list_attid_from_md) != list_attid_from_md:
                     error_count +=1
                     self.err_replmetadata_incorrect_attid(dn, attrname, obj[attrname], wrong_attids)
 
@@ -1469,12 +1468,6 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                     # Here we check that the first attid is 0
                     # (objectClass) and that the last on is the RDN
                     # from the DN.
-                    rdn_attid = self.samdb_schema.get_attid_from_lDAPDisplayName(dn.get_rdn_name())
-                    if list_attid_from_md[-1] != rdn_attid:
-                        error_count += 1
-                        self.report("ERROR: Not fixing incorrect final attributeID in '%s' on '%s', it should match the RDN %s" %
-                                    (attrname, str(dn), dn.get_rdn_name()))
-
                     if list_attid_from_md[0] != 0:
                         error_count += 1
                         self.report("ERROR: Not fixing incorrect inital attributeID in '%s' on '%s', it should be objectClass" %
diff --git a/selftest/flapping b/selftest/flapping
index 66cd305..e5995ef 100644
--- a/selftest/flapping
+++ b/selftest/flapping
@@ -25,7 +25,6 @@
 ^samba3.raw.acls.inheritance\(ad_dc\) # Seems to flap - succeeds on sn-devel, fails on Fedora 16
 ^samba3.raw.samba3checkfsp.samba3checkfsp\(ad_dc\) # Seems to flap - succeeds on sn-devel, fails on Fedora 16
 ^samba3.raw.samba3closeerr.samba3closeerr\(ad_dc\) # Seems to flap - succeeds on sn-devel, fails on Fedora 16
-^samba4.blackbox.dbcheck\( # flakey on sn-devel
 ^samba4.smb2.create.mkdir-dup\(ad_dc_ntvfs\) # This test (for bug 11486) involves a race, not always protected against in the NTVFS file server
 ^samba4.winbind.struct.domain_info.ad_member # flakey on sn-devel-104 and sn-devel-144
 #
diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c
index 6493c1e..64816ad 100644
--- a/source4/dsdb/repl/drepl_out_helpers.c
+++ b/source4/dsdb/repl/drepl_out_helpers.c
@@ -709,7 +709,7 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req
 		return;
 	}
 
-	schema = dsdb_get_schema(service->samdb, NULL);
+	schema = dsdb_get_schema(service->samdb, state);
 	if (!schema) {
 		DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
 		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c
index 674074c..919dd46 100644
--- a/source4/dsdb/repl/replicated_objects.c
+++ b/source4/dsdb/repl/replicated_objects.c
@@ -357,13 +357,9 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 	NTTIME whenChanged = 0;
 	time_t whenChanged_t;
 	const char *whenChanged_s;
-	struct drsuapi_DsReplicaAttribute *name_a = NULL;
-	struct drsuapi_DsReplicaMetaData *name_d = NULL;
-	struct replPropertyMetaData1 *rdn_m = NULL;
 	struct dom_sid *sid = NULL;
 	uint32_t rid = 0;
 	uint32_t attr_count;
-	int ret;
 
 	if (!in->object.identifier) {
 		return WERR_FOOBAR;
@@ -394,7 +390,7 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 
 	msg->num_elements	= in->object.attribute_ctr.num_attributes;
 	msg->elements		= talloc_array(msg, struct ldb_message_element,
-					       msg->num_elements + 1); /* +1 because of the RDN attribute */
+					       msg->num_elements);
 	W_ERROR_HAVE_NO_MEMORY(msg->elements);
 
 	md = talloc(mem_ctx, struct replPropertyMetaDataBlob);
@@ -406,7 +402,7 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 	md->ctr.ctr1.reserved	= 0;
 	md->ctr.ctr1.array	= talloc_array(mem_ctx,
 					       struct replPropertyMetaData1,
-					       md->ctr.ctr1.count + 1); /* +1 because of the RDN attribute */
+					       md->ctr.ctr1.count);
 	W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array);
 
 	for (i=0, attr_count=0; i < in->meta_data_ctr->count; i++, attr_count++) {
@@ -485,73 +481,35 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 		m->originating_usn		= d->originating_usn;
 		m->local_usn			= 0;
 
-		if (d->originating_change_time > whenChanged) {
-			whenChanged = d->originating_change_time;
-		}
-
 		if (a->attid == DRSUAPI_ATTID_name) {
-			name_a = a;
-			name_d = d;
-		}
-	}
-
-	msg->num_elements = attr_count;
-	md->ctr.ctr1.count = attr_count;
-	if (name_a) {
-		rdn_m = &md->ctr.ctr1.array[md->ctr.ctr1.count];
-	}
-
-	if (rdn_m) {
-		struct ldb_message_element *el;
-		const char *rdn_name = NULL;
-		const struct ldb_val *rdn_value = NULL;
-		const struct dsdb_attribute *rdn_attr = NULL;
-		uint32_t rdn_attid;
-
-		/*
-		 * We only need the schema calls for the RDN in this
-		 * codepath, and by doing this we avoid needing to
-		 * have the dsdb_attribute_by_lDAPDisplayName accessor
-		 * working during the schema load.
-		 */
-		rdn_name	= ldb_dn_get_rdn_name(msg->dn);
-		rdn_attr	= dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
-		if (!rdn_attr) {
-			return WERR_FOOBAR;
-		}
-		rdn_attid	= rdn_attr->attributeID_id;
-		rdn_value	= ldb_dn_get_rdn_val(msg->dn);
-
-		el = ldb_msg_find_element(msg, rdn_attr->lDAPDisplayName);
-		if (!el) {
-			ret = ldb_msg_add_value(msg, rdn_attr->lDAPDisplayName, rdn_value, NULL);
-			if (ret != LDB_SUCCESS) {
+			const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
+			if (rdn_val == NULL) {
+				DEBUG(0, ("Unxpectedly unable to get RDN from %s for validation",
+					  ldb_dn_get_linearized(msg->dn)));
 				return WERR_FOOBAR;
 			}
-		} else {
-			if (el->num_values != 1) {
-				DEBUG(0,(__location__ ": Unexpected num_values=%u\n",
-					 el->num_values));
-				return WERR_FOOBAR;				
+			if (e->num_values != 1) {
+				DEBUG(0, ("Unxpectedly got wrong number of attribute values (got %u, expected 1) when checking RDN against name of %s",
+					  e->num_values,
+					  ldb_dn_get_linearized(msg->dn)));
+				return WERR_FOOBAR;
 			}
-			if (!ldb_val_equal_exact(&el->values[0], rdn_value)) {
-				DEBUG(0,(__location__ ": RDN value changed? '%*.*s' '%*.*s'\n",
-					 (int)el->values[0].length, (int)el->values[0].length, el->values[0].data,
-					 (int)rdn_value->length, (int)rdn_value->length, rdn_value->data));
-				return WERR_FOOBAR;				
+			if (data_blob_cmp(rdn_val,
+					  &e->values[0]) != 0) {
+				DEBUG(0, ("Unxpectedly got mismatching RDN values when checking RDN against name of %s",
+					  ldb_dn_get_linearized(msg->dn)));
+				return WERR_FOOBAR;
 			}
 		}
-
-		rdn_m->attid				= rdn_attid;
-		rdn_m->version				= name_d->version;
-		rdn_m->originating_change_time		= name_d->originating_change_time;
-		rdn_m->originating_invocation_id	= name_d->originating_invocation_id;
-		rdn_m->originating_usn			= name_d->originating_usn;
-		rdn_m->local_usn			= 0;
-		md->ctr.ctr1.count++;
+		if (d->originating_change_time > whenChanged) {
+			whenChanged = d->originating_change_time;
+		}
 
 	}
 
+	msg->num_elements = attr_count;
+	md->ctr.ctr1.count = attr_count;
+
 	if (instanceType_e == NULL) {
 		return WERR_FOOBAR;
 	}
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index f1d3958..0d37820 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -690,24 +690,6 @@ static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMeta
 	}
 
 	/*
-	 * the rdn attribute should be at the end!
-	 * so we need to return a value greater than zero
-	 * which means m1 is greater than m2
-	 */
-	if (attid_1 == *rdn_attid) {
-		return 1;
-	}
-
-	/*
-	 * the rdn attribute should be at the end!
-	 * so we need to return a value less than zero
-	 * which means m2 is greater than m1
-	 */
-	if (attid_2 == *rdn_attid) {
-		return -1;
-	}
-
-	/*
 	 * See above regarding this being an unsigned comparison.
 	 * Otherwise when the high bit is set on non-standard
 	 * attributes, they would end up first, before objectClass
@@ -718,7 +700,6 @@ static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMeta
 
 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
 						  struct replPropertyMetaDataCtr1 *ctr1,
-						  const struct dsdb_attribute *rdn_sa,
 						  struct ldb_dn *dn)
 {
 	if (ctr1->count == 0) {
@@ -741,34 +722,12 @@ static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
 
 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
 							   struct replPropertyMetaDataCtr1 *ctr1,
-							   const struct dsdb_schema *schema,
 							   struct ldb_dn *dn)
 {
-	const char *rdn_name;
-	const struct dsdb_attribute *rdn_sa;
-
-	rdn_name = ldb_dn_get_rdn_name(dn);
-	if (!rdn_name) {
-		ldb_debug_set(ldb, LDB_DEBUG_FATAL,
-			      __location__ ": No rDN for %s?\n",
-			      ldb_dn_get_linearized(dn));
-		return LDB_ERR_INVALID_DN_SYNTAX;
-	}
-
-	rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
-	if (rdn_sa == NULL) {
-		ldb_debug_set(ldb, LDB_DEBUG_FATAL,
-			      __location__ ": No sa found for rDN %s for %s\n",
-			      rdn_name, ldb_dn_get_linearized(dn));
-		return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE;
-	}
-
-	DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
-		 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
-
-	LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id,
+	/* Note this is O(n^2) for the almost-sorted case, which this is */
+	LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
 			   replmd_replPropertyMetaData1_attid_sort);
-	return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, rdn_sa, dn);
+	return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
 }
 
 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
@@ -1083,9 +1042,9 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req)
 	nmd.ctr.ctr1.count = ni;
 
 	/*
-	 * sort meta data array, and move the rdn attribute entry to the end
+	 * sort meta data array
 	 */
-	ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, ac->schema, msg->dn);
+	ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
 	if (ret != LDB_SUCCESS) {
 		ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
 		talloc_free(ac);
@@ -1367,6 +1326,52 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb,
 	return LDB_SUCCESS;
 }
 
+/*
+ * Bump the replPropertyMetaData version on an attribute, and if it
+ * has changed (or forced by leaving rdn_old NULL), update the value
+ * in the entry.
+ *
+ * This is important, as calling a modify operation may not change the
+ * version number if the values appear unchanged, but a rename between
+ * parents bumps this value.
+ *
+ */
+static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
+				       struct ldb_message *msg,
+				       const struct ldb_val *rdn_new,
+				       const struct ldb_val *rdn_old,
+				       struct replPropertyMetaDataBlob *omd,
+				       struct replmd_replicated_request *ar,
+				       NTTIME now,
+				       bool is_schema_nc)
+{
+	struct ldb_message_element new_el = {
+		.flags = LDB_FLAG_MOD_REPLACE,
+		.name = ldb_dn_get_rdn_name(msg->dn),
+		.num_values = 1,
+		.values = discard_const_p(struct ldb_val, rdn_new)
+	};
+	struct ldb_message_element old_el = {
+		.flags = LDB_FLAG_MOD_REPLACE,
+		.name = ldb_dn_get_rdn_name(msg->dn),
+		.num_values = rdn_old ? 1 : 0,
+		.values = discard_const_p(struct ldb_val, rdn_old)
+	};
+
+	if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
+		int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
+		if (ret != LDB_SUCCESS) {
+			return ldb_oom(ldb);
+		}
+	}
+
+	return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
+					  omd, ar->schema, &ar->seq_num,
+					  &ar->our_invocation_id,
+					  now, is_schema_nc, ar->req);
+
+}
+
 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
 {
 	uint32_t count = omd.ctr.ctr1.count;
@@ -1618,7 +1623,7 @@ static int replmd_update_rpmd(struct ldb_module *module,
 			return LDB_ERR_OPERATIONS_ERROR;
 		}
 
-		ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, schema, msg->dn);
+		ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
 		if (ret != LDB_SUCCESS) {
 			ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
 			return ret;
@@ -3583,6 +3588,47 @@ static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *
 				      new_m->originating_change_time);
 }
 
+static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
+							     struct replPropertyMetaData1 *cur_m,
+							     struct replPropertyMetaData1 *new_m)
+{
+	bool cmp;
+
+	/*
+	 * If the new replPropertyMetaData entry for this attribute is
+	 * not provided (this happens in the case where we look for
+	 * ATTID_name, but the name was not changed), then the local
+	 * state is clearly still current, as the remote
+	 * server didn't send it due to being older the high watermark
+	 * USN we sent.
+	 */
+	if (new_m == NULL) {
+		return false;
+	}
+
+	if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
+		/*
+		 * if we compare equal then do an
+		 * update. This is used when a client
+		 * asks for a FULL_SYNC, and can be
+		 * used to recover a corrupt
+		 * replica.
+		 *
+		 * This call is a bit tricky, what we
+		 * are doing it turning the 'is_newer'
+		 * call into a 'not is older' by
+		 * swapping cur_m and new_m, and negating the
+		 * outcome.
+		 */
+		cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
+							     cur_m);
+	} else {
+		cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
+							    new_m);
+	}
+	return cmp;
+}
+
 
 /*
   form a conflict DN
@@ -3857,18 +3903,31 @@ static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct
 
 	rmd = ar->objs->objects[ar->index_current].meta_data;
 
-	/* we decide which is newer based on the RPMD on the name
-	   attribute.  See [MS-DRSR] ResolveNameConflict */
+	/*
+	 * we decide which is newer based on the RPMD on the name
+	 * attribute.  See [MS-DRSR] ResolveNameConflict.
+	 *
+	 * We expect omd_name to be present, as this is from a local
+	 * search, but while rmd_name should have been given to us by
+	 * the remote server, if it is missing we just prefer the
+	 * local name in
+	 * replmd_replPropertyMetaData1_new_should_be_taken()
+	 */
 	rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
 	omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
-	if (!rmd_name || !omd_name) {
-		DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
+	if (!omd_name) {
+		DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
 			 ldb_dn_get_linearized(conflict_dn)));
 		goto failed;
 	}
 
-	rename_incoming_record = !(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) &&
-		!replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
+	/*
+	 * Should we preserve the current record, and so rename the
+	 * incoming record to be a conflict?
+	 */
+	rename_incoming_record
+		= !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
+								    omd_name, rmd_name);
 
 	if (rename_incoming_record) {
 		struct GUID guid;
@@ -4018,12 +4077,19 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
 	unsigned int i;
 	int ret;
 	bool remote_isDeleted = false;
-	const struct dsdb_attribute *rdn_sa;
-	const char *rdn_name;
+	bool is_schema_nc;
+	NTTIME now;
+	time_t t = time(NULL);
+	const struct ldb_val *rdn_val;
+	struct replmd_private *replmd_private =
+		talloc_get_type(ldb_module_get_private(ar->module),
+				struct replmd_private);
+	unix_to_nt_time(&now, t);
 
 	ldb = ldb_module_get_ctx(ar->module);
 	msg = ar->objs->objects[ar->index_current].msg;
 	md = ar->objs->objects[ar->index_current].meta_data;
+	is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
 
 	ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
 	if (ret != LDB_SUCCESS) {
@@ -4087,23 +4153,20 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
 						     "isDeleted", false);
 
 	/*
-	 * the meta data array is already sorted by the caller
+	 * the meta data array is already sorted by the caller, except
+	 * for the RDN, which needs to be added.
 	 */
 
-	rdn_name = ldb_dn_get_rdn_name(msg->dn);
-	if (rdn_name == NULL) {
-		ldb_asprintf_errstring(ldb, __location__ ": No rDN for %s?\n", ldb_dn_get_linearized(msg->dn));
-		return replmd_replicated_request_error(ar, LDB_ERR_INVALID_DN_SYNTAX);
-	}
 
-	rdn_sa = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
-	if (rdn_sa == NULL) {
-		ldb_asprintf_errstring(ldb, ": No schema attribute found for rDN %s for %s\n",
-				       rdn_name, ldb_dn_get_linearized(msg->dn));
-		return replmd_replicated_request_error(ar, LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE);
+	rdn_val = ldb_dn_get_rdn_val(msg->dn);
+	ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
+				     md, ar, now, is_schema_nc);
+	if (ret != LDB_SUCCESS) {
+		ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
+		return replmd_replicated_request_error(ar, ret);
 	}
 
-	ret = replmd_replPropertyMetaDataCtr1_verify(ldb, &md->ctr.ctr1, rdn_sa, msg->dn);
+	ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
 	if (ret != LDB_SUCCESS) {
 		ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
 		return replmd_replicated_request_error(ar, ret);
@@ -4392,6 +4455,11 @@ static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
 
 	ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
 				 DSDB_FLAG_NEXT_MODULE, ar->req);
+	if (ret == LDB_SUCCESS) {
+		talloc_free(tmp_ctx);
+		*renamed = true;
+		return ret;


-- 
Samba Shared Repository



More information about the samba-cvs mailing list