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 <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> BUG: https://bugzilla.samba.org/show_bug.cgi?id=11953 Autobuild-User(master): Andrew Bartlett <abart...@samba.org> Autobuild-Date(master): Tue Jun 7 14:33:39 CEST 2016 on sn-devel-144 commit c4afb1d3bd82018e6b29f1018218c36c12f95a82 Author: Andrew Bartlett <abart...@samba.org> Date: Thu Jun 2 15:31:15 2016 +1200 selftest: Add a reverse variation to ReplicateMoveObject3 Signed-off-by: Andrew Bartlett <abart...@samba.org> Reviewed-by: Garming Samba <garm...@catalyst.net.nz> commit 889f33d47f6c753265e27b69ffd22d12dbb6d96f Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> commit 374a01119dac8d1b04f8d43caf6e119be654e2dc Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> commit a8430d15a57d3bae986a55e831bac0c216115b65 Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz commit 225cef98518541ccae07bc7f4e9a7b10bde1856d Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz commit 9dcc62eb781fdc05070bc12c43081e086963e4ad Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz commit 5fee4aa90787237d7a7af11febdc45277a896976 Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz commit f0aa1d8b8074deebc186243a4813c528cd73869d Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz commit b28d8d42783bad1415afdca01dd9c70e092d7360 Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> commit dae543e04e43dad05c90659b94b78e5e69cce709 Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> commit f709261c7398f1df5266e227ebe5a36e6ce6e9be Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz commit 0b525fe862ea993fe34f239482a06acb9f901877 Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> commit 8f1557a2c43e287c07723c16be78e1d858f4111d Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Garming Sam <garm...@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