The branch, master has been updated via 4f558c9 repl_meta_data: Remove the correct forward link for dn+binary attributes via 056b6b8 repl_meta_data: Add comment with some future improvements via 75d523f repl_meta_data: Always sort the links when upgrading them via 6ee0ace repl_meta_data: Bring replmd_check_upgrade_links() into get_parsed_dns_trusted() via b6902fd python/tests: Add test for generated and duplicate mAPIIDs via ec11d65 samldb: Allow automatic generation of mAPIIDs via 1c16e8a torture/drs: Add a test for dn+binary linked attributes via bfe423a torture/drs: run repl_schema in vampire_2000_dc environment as well via 1983d07 selftest: add vampire_2000_dc environment via 305cdce python/tests: add test for generated and duplicate linkIDs via 373bd43 torture/drs: generate linkID for test rather than specifying via 35be7ee samldb: Allow automatic generation of linkIDs and prevent duplicates from 85d5b43 waf: Do not install the unit test binary for krb5samba
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 4f558c9ad6f9b8a947e33207473579655708eed0 Author: Andrew Bartlett <abart...@samba.org> Date: Mon Oct 12 15:51:37 2015 +1300 repl_meta_data: Remove the correct forward link for dn+binary attributes The previous code assumed that only plain DNs could be linked attributes. We need to look over the list of attribute values and find the value that causes this particular backlink to exist, so we can remove it. We do not know (until we search) of the binary portion, so we must search over all the attribute values at this layer, using the parsed_dn_find() routine used elsewhere in this code. Found attempting to demote an RODC in a clone of a Windows 2012R2 domain, due to the msDS-RevealedUsers attribute. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11139 Signed-off-by: Andrew Bartlett <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Autobuild-User(master): Andrew Bartlett <abart...@samba.org> Autobuild-Date(master): Tue Feb 14 06:14:35 CET 2017 on sn-devel-144 commit 056b6b8e5c5203d642cc2c9cbe2e9c36dff6bc56 Author: Andrew Bartlett <abart...@samba.org> Date: Tue Feb 14 12:11:19 2017 +1300 repl_meta_data: Add comment with some future improvements Signed-off-by: Andrew Bartlett <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> commit 75d523f5792275b8aa357d0f266b0bc9b7a1c935 Author: Andrew Bartlett <abart...@samba.org> Date: Tue Feb 14 12:08:35 2017 +1300 repl_meta_data: Always sort the links when upgrading them This allows us to know that the output of get_parsed_dns_trusted() is sorted, as an upgraded attribute of FL2000 links would not otherwise be sorted in the DB This allows us to delete linked objects that have a forward link from a FL2000 style linked attribute once the DN+Binary patches land. Signed-off-by: Andrew Bartlett <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> commit 6ee0aceae17991d3eb665e9f19399be1a03b1ace Author: Andrew Bartlett <abart...@samba.org> Date: Tue Feb 14 11:59:13 2017 +1300 repl_meta_data: Bring replmd_check_upgrade_links() into get_parsed_dns_trusted() This eliminates a lot of duplicate code and allows us to know that we will have a set of FL2003 style links in the parsed DNs to operate on Signed-off-by: Andrew Bartlett <abart...@samba.org> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> commit b6902fd637f22f2740d1ae1eb5ac73aadc9a0f30 Author: Bob Campbell <bobcampb...@catalyst.net.nz> Date: Wed Feb 8 11:55:32 2017 +1300 python/tests: Add test for generated and duplicate mAPIIDs Signed-off-by: Bob Campbell <bobcampb...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit ec11d65bef7aaea155fb40e87a74210166eca7dd Author: Bob Campbell <bobcampb...@catalyst.net.nz> Date: Wed Feb 8 11:40:32 2017 +1300 samldb: Allow automatic generation of mAPIIDs This allows us to conform to MS-ADTS 3.1.1.2.3.2, where the OID 1.2.840.113556.1.2.49 can be specified as the mAPIID of a new attribute in the schema in order to automatically assign it an unused mAPIID. Signed-off-by: Bob Campbell <bobcampb...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 1c16e8abd28fd05ab169b7a6bc11f102264def3e Author: Bob Campbell <bobcampb...@catalyst.net.nz> Date: Fri Feb 3 10:34:14 2017 +1300 torture/drs: Add a test for dn+binary linked attributes Signed-off-by: Bob Campbell <bobcampb...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=11139 commit bfe423a6607e2b80d1fd946bcaf303c0be2b757b Author: Bob Campbell <bobcampb...@catalyst.net.nz> Date: Fri Feb 3 10:33:54 2017 +1300 torture/drs: run repl_schema in vampire_2000_dc environment as well This will be necessary as linked attributes are handled differently in Windows 2000. We also only check msDS-IntId if we have a functional level of > Windows 2000, as this attribute is not present on lower domain function levels. Signed-off-by: Bob Campbell <bobcampb...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=11139 commit 1983d078f62d1e4f6597ef549f576e72285b25a5 Author: Bob Campbell <bobcampb...@catalyst.net.nz> Date: Wed Feb 8 09:16:41 2017 +1300 selftest: add vampire_2000_dc environment This is the equivalent of vampire_dc, but using a domain functional level of DS_DOMAIN_FUNCTION_2000. Using this functional level is useful for tests involving replication and linked attributes, as they behave differently at it. 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=11139 Pair-programmed-with: Bob Campbell <bobcampb...@catalyst.net.nz> commit 305cdcea8851d389aa7c6b9da69441c2aacee432 Author: Bob Campbell <bobcampb...@catalyst.net.nz> Date: Thu Feb 2 09:46:26 2017 +1300 python/tests: add test for generated and duplicate linkIDs Signed-off-by: Bob Campbell <bobcampb...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=11139 commit 373bd435425f85a0f24f9f14c36f76c51243a077 Author: Bob Campbell <bobcampb...@catalyst.net.nz> Date: Tue Feb 7 15:42:29 2017 +1300 torture/drs: generate linkID for test rather than specifying Signed-off-by: Bob Campbell <bobcampb...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=11139 commit 35be7ee8a49f000282859661fc6522c9d6c05020 Author: Bob Campbell <bobcampb...@catalyst.net.nz> Date: Wed Feb 1 11:54:40 2017 +1300 samldb: Allow automatic generation of linkIDs and prevent duplicates As per MS-ADTS 3.1.1.2.3.1, this allows specifying the OID 1.2.840.113556.1.2.50 as the linkID of a new linked attribute in the schema in order to automatically assign it an unused even linkID. Specifying the attributeID or ldapDisplayName of an existing forward link will now also add the new linked attribute as the backlink of that existing link. This also prevents adding duplicate linkIDs. Previously, we could run into issues when trying to delete backlinks with duplicate linkIDs. Signed-off-by: Bob Campbell <bobcampb...@catalyst.net.nz> Reviewed-by: Garming Sam <garm...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> BUG: https://bugzilla.samba.org/show_bug.cgi?id=11139 ----------------------------------------------------------------------- Summary of changes: selftest/selftest.pl | 7 + selftest/target/Samba.pm | 1 + selftest/target/Samba4.pm | 46 ++- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 257 +++++++++++------ source4/dsdb/samdb/ldb_modules/samldb.c | 290 ++++++++++++++++++- source4/dsdb/tests/python/ldap_schema.py | 361 ++++++++++++++++++++++++ source4/selftest/tests.py | 11 +- source4/torture/drs/python/repl_schema.py | 91 +++++- source4/torture/drs/rpc/msds_intid.c | 2 +- 9 files changed, 944 insertions(+), 122 deletions(-) Changeset truncated at 500 lines: diff --git a/selftest/selftest.pl b/selftest/selftest.pl index bfc8d7f..45e0ae0 100755 --- a/selftest/selftest.pl +++ b/selftest/selftest.pl @@ -811,6 +811,13 @@ my @exported_envvars = ( "VAMPIRE_DC_NETBIOSNAME", "VAMPIRE_DC_NETBIOSALIAS", + # domain controller stuff for FL 2000 Vampired DC + "VAMPIRE_2000_DC_SERVER", + "VAMPIRE_2000_DC_SERVER_IP", + "VAMPIRE_2000_DC_SERVER_IPV6", + "VAMPIRE_2000_DC_NETBIOSNAME", + "VAMPIRE_2000_DC_NETBIOSALIAS", + "PROMOTED_DC_SERVER", "PROMOTED_DC_SERVER_IP", "PROMOTED_DC_SERVER_IPV6", diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm index 24484c9..e5c7f93 100644 --- a/selftest/target/Samba.pm +++ b/selftest/target/Samba.pm @@ -308,6 +308,7 @@ sub get_interface($) $interfaces{"fakednsforwarder1"} = 36; $interfaces{"fakednsforwarder2"} = 37; $interfaces{"s4member_dflt"} = 38; + $interfaces{"vampire2000dc"} = 39; # update lib/socket_wrapper/socket_wrapper.c # #define MAX_WRAPPED_INTERFACES 40 diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index dacdab4..8b5e699 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1246,15 +1246,20 @@ sub provision_promoted_dc($$$) sub provision_vampire_dc($$$) { - my ($self, $prefix, $dcvars) = @_; - print "PROVISIONING VAMPIRE DC...\n"; + my ($self, $prefix, $dcvars, $fl) = @_; + print "PROVISIONING VAMPIRE DC @ FL $fl...\n"; + my $name = "localvampiredc"; + + if ($fl == "2000") { + $name = "vampire2000dc"; + } # We do this so that we don't run the provision. That's the job of 'net vampire'. my $ctx = $self->provision_raw_prepare($prefix, "domain controller", - "localvampiredc", - "SAMBADOMAIN", - "samba.example.com", - "2008", + $name, + $dcvars->{DOMAIN}, + $dcvars->{REALM}, + $fl, $dcvars->{PASSWORD}, $dcvars->{SERVER_IP}, $dcvars->{SERVER_IPV6}); @@ -1299,11 +1304,17 @@ sub provision_vampire_dc($$$) return undef; } - $ret->{VAMPIRE_DC_SERVER} = $ret->{SERVER}; - $ret->{VAMPIRE_DC_SERVER_IP} = $ret->{SERVER_IP}; - $ret->{VAMPIRE_DC_SERVER_IPV6} = $ret->{SERVER_IPV6}; - $ret->{VAMPIRE_DC_NETBIOSNAME} = $ret->{NETBIOSNAME}; - + if ($fl == "2000") { + $ret->{VAMPIRE_2000_DC_SERVER} = $ret->{SERVER}; + $ret->{VAMPIRE_2000_DC_SERVER_IP} = $ret->{SERVER_IP}; + $ret->{VAMPIRE_2000_DC_SERVER_IPV6} = $ret->{SERVER_IPV6}; + $ret->{VAMPIRE_2000_DC_NETBIOSNAME} = $ret->{NETBIOSNAME}; + } else { + $ret->{VAMPIRE_DC_SERVER} = $ret->{SERVER}; + $ret->{VAMPIRE_DC_SERVER_IP} = $ret->{SERVER_IP}; + $ret->{VAMPIRE_DC_SERVER_IPV6} = $ret->{SERVER_IPV6}; + $ret->{VAMPIRE_DC_NETBIOSNAME} = $ret->{NETBIOSNAME}; + } $ret->{DC_SERVER} = $dcvars->{DC_SERVER}; $ret->{DC_SERVER_IP} = $dcvars->{DC_SERVER_IP}; $ret->{DC_SERVER_IPV6} = $dcvars->{DC_SERVER_IPV6}; @@ -2002,6 +2013,11 @@ sub setup_env($$$) return $self->setup_ad_dc_ntvfs("$path/ad_dc_ntvfs"); } elsif ($envname eq "fl2000dc") { return $self->setup_fl2000dc("$path/fl2000dc"); + } elsif ($envname eq "vampire_2000_dc") { + if (not defined($self->{vars}->{fl2000dc})) { + $self->setup_fl2000dc("$path/fl2000dc"); + } + return $self->setup_vampire_dc("$path/vampire_2000_dc", $self->{vars}->{fl2000dc}, "2000"); } elsif ($envname eq "fl2003dc") { if (not defined($self->{vars}->{ad_dc})) { $self->setup_ad_dc("$path/ad_dc"); @@ -2021,7 +2037,7 @@ sub setup_env($$$) if (not defined($self->{vars}->{ad_dc_ntvfs})) { $self->setup_ad_dc_ntvfs("$path/ad_dc_ntvfs"); } - return $self->setup_vampire_dc("$path/vampire_dc", $self->{vars}->{ad_dc_ntvfs}); + return $self->setup_vampire_dc("$path/vampire_dc", $self->{vars}->{ad_dc_ntvfs}, "2008"); } elsif ($envname eq "promoted_dc") { if (not defined($self->{vars}->{ad_dc_ntvfs})) { $self->setup_ad_dc_ntvfs("$path/ad_dc_ntvfs"); @@ -2211,11 +2227,11 @@ sub setup_fl2008r2dc($$$) return $env; } -sub setup_vampire_dc($$$) +sub setup_vampire_dc($$$$) { - my ($self, $path, $dc_vars) = @_; + my ($self, $path, $dc_vars, $fl) = @_; - my $env = $self->provision_vampire_dc($path, $dc_vars); + my $env = $self->provision_vampire_dc($path, $dc_vars, $fl); if (defined $env) { if (not defined($self->check_or_start($env, "single"))) { diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 6e041c7..e3bf032 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -101,8 +101,18 @@ struct replmd_replicated_request { bool isDeleted; }; +struct parsed_dn { + struct dsdb_dn *dsdb_dn; + struct GUID guid; + struct ldb_val *v; +}; + static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar); static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete); +static int replmd_check_upgrade_links(struct ldb_context *ldb, + struct parsed_dn *dns, uint32_t count, + struct ldb_message_element *el, + const char *ldap_oid); enum urgent_situation { REPL_URGENT_ON_CREATE = 1, @@ -862,12 +872,6 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds const struct GUID *invocation_id, uint64_t seq_num, uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted); -struct parsed_dn { - struct dsdb_dn *dsdb_dn; - struct GUID guid; - struct ldb_val *v; -}; - static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_message_element *el, struct parsed_dn **pdn, const char *ldap_oid, struct ldb_request *parent); @@ -2073,6 +2077,9 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, * GUID, even though the GUIDs might not be known. That works because we trust * the database to give us the elements like that if the * replmd_private->sorted_links flag is set. + * + * We also ensure that the links are in the Functional Level 2003 + * linked attributes format. */ static int get_parsed_dns_trusted(struct ldb_module *module, struct replmd_private *replmd_private, @@ -2083,7 +2090,7 @@ static int get_parsed_dns_trusted(struct ldb_module *module, struct ldb_request *parent) { unsigned int i; - + int ret; if (el == NULL) { *pdn = NULL; return LDB_SUCCESS; @@ -2093,19 +2100,41 @@ static int get_parsed_dns_trusted(struct ldb_module *module, /* We need to sort the list. This is the slow old path we want to avoid. */ - return get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid, + ret = get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid, parent); - } - /* Here we get a list of 'struct parsed_dns' without the parsing */ - *pdn = talloc_zero_array(mem_ctx, struct parsed_dn, - el->num_values); - if (!*pdn) { - ldb_module_oom(module); - return LDB_ERR_OPERATIONS_ERROR; + if (ret != LDB_SUCCESS) { + return ret; + } + } else { + /* Here we get a list of 'struct parsed_dns' without the parsing */ + *pdn = talloc_zero_array(mem_ctx, struct parsed_dn, + el->num_values); + if (!*pdn) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (i = 0; i < el->num_values; i++) { + (*pdn)[i].v = &el->values[i]; + } } - for (i = 0; i < el->num_values; i++) { - (*pdn)[i].v = &el->values[i]; + /* + * This upgrades links to FL2003 style, and sorts the result + * if that was needed. + * + * TODO: Add a database feature that asserts we have no FL2000 + * style links to avoid this check or add a feature that + * uses a similar check to find sorted/unsorted links + * for an on-the-fly upgrade. + */ + + ret = replmd_check_upgrade_links(ldb_module_get_ctx(module), + *pdn, el->num_values, + el, + ldap_oid); + if (ret != LDB_SUCCESS) { + return ret; } return LDB_SUCCESS; @@ -2208,10 +2237,10 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d static int replmd_check_upgrade_links(struct ldb_context *ldb, struct parsed_dn *dns, uint32_t count, struct ldb_message_element *el, - const struct GUID *invocation_id, const char *ldap_oid) { uint32_t i; + const struct GUID *invocation_id = NULL; for (i=0; i<count; i++) { NTSTATUS status; uint32_t version; @@ -2243,6 +2272,14 @@ static int replmd_check_upgrade_links(struct ldb_context *ldb, continue; } + if (invocation_id == NULL) { + invocation_id = samdb_ntds_invocation_id(ldb); + if (invocation_id == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + } + + /* it's an old one that needs upgrading */ ret = replmd_update_la_val(el->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, @@ -2251,6 +2288,19 @@ static int replmd_check_upgrade_links(struct ldb_context *ldb, return ret; } } + + /* + * This sort() is critical for the operation of + * get_parsed_dns_trusted() because callers of this function + * expect a sorted list, and FL2000 style links are not + * sorted. In particular, as well as the upgrade case, + * get_parsed_dns_trusted() is called from + * replmd_delete_remove_link() even in FL2000 mode + * + * We do not normally pay the cost of the qsort() due to the + * early return in the RMD_VERSION found case. + */ + TYPESAFE_QSORT(dns, count, parsed_dn_compare); return LDB_SUCCESS; } @@ -2381,9 +2431,14 @@ static int replmd_modify_la_add(struct ldb_module *module, const struct GUID *invocation_id; struct ldb_context *ldb = ldb_module_get_ctx(module); NTTIME now; - unix_to_nt_time(&now, t); + invocation_id = samdb_ntds_invocation_id(ldb); + if (!invocation_id) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + /* get the DNs to be added, fully parsed. * * We need full parsing because they came off the wire and we don't @@ -2407,20 +2462,6 @@ static int replmd_modify_la_add(struct ldb_module *module, return ret; } - invocation_id = samdb_ntds_invocation_id(ldb); - if (!invocation_id) { - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values, - old_el, invocation_id, - schema_attr->syntax->ldap_oid); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ret; - } - max_num_values = old_num_values + el->num_values; if (max_num_values < old_num_values) { DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. " @@ -2597,16 +2638,21 @@ static int replmd_modify_la_delete(struct ldb_module *module, struct parsed_dn *dns, *old_dns; TALLOC_CTX *tmp_ctx = NULL; int ret; - const struct GUID *invocation_id; struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_control *vanish_links_ctrl = NULL; bool vanish_links = false; unsigned int num_to_delete = el->num_values; uint32_t rmd_flags; + const struct GUID *invocation_id; NTTIME now; unix_to_nt_time(&now, t); + invocation_id = samdb_ntds_invocation_id(ldb); + if (!invocation_id) { + return LDB_ERR_OPERATIONS_ERROR; + } + if (old_el == NULL || old_el->num_values == 0) { /* there is nothing to delete... */ if (num_to_delete == 0) { @@ -2637,20 +2683,6 @@ static int replmd_modify_la_delete(struct ldb_module *module, return ret; } - invocation_id = samdb_ntds_invocation_id(ldb); - if (!invocation_id) { - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = replmd_check_upgrade_links(ldb, old_dns, old_el->num_values, - old_el, invocation_id, - schema_attr->syntax->ldap_oid); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ret; - } - if (parent) { vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS); if (vanish_links_ctrl) { @@ -2863,6 +2895,11 @@ static int replmd_modify_la_replace(struct ldb_module *module, unix_to_nt_time(&now, t); + invocation_id = samdb_ntds_invocation_id(ldb); + if (!invocation_id) { + return LDB_ERR_OPERATIONS_ERROR; + } + /* * The replace operation is unlike the replace and delete cases in that * we need to look at every existing link to see whether it is being @@ -2908,13 +2945,8 @@ static int replmd_modify_la_replace(struct ldb_module *module, return ret; } - invocation_id = samdb_ntds_invocation_id(ldb); - if (!invocation_id) { - return LDB_ERR_OPERATIONS_ERROR; - } - ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values, - old_el, invocation_id, ldap_oid); + old_el, ldap_oid); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -3625,7 +3657,9 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are */ static int replmd_delete_remove_link(struct ldb_module *module, const struct dsdb_schema *schema, + struct replmd_private *replmd_private, struct ldb_dn *dn, + struct GUID *guid, struct ldb_message_element *el, const struct dsdb_attribute *sa, struct ldb_request *parent) @@ -3636,14 +3670,19 @@ static int replmd_delete_remove_link(struct ldb_module *module, for (i=0; i<el->num_values; i++) { struct dsdb_dn *dsdb_dn; - NTSTATUS status; int ret; - struct GUID guid2; struct ldb_message *msg; const struct dsdb_attribute *target_attr; struct ldb_message_element *el2; + const char *dn_str; struct ldb_val dn_val; uint32_t dsdb_flags = 0; + const char *attrs[] = { NULL, NULL }; + struct ldb_result *link_res; + struct ldb_message *link_msg; + struct ldb_message_element *link_el; + struct parsed_dn *link_dns; + struct parsed_dn *p = NULL, *unused = NULL; if (dsdb_dn_is_deleted_val(&el->values[i])) { continue; @@ -3655,12 +3694,6 @@ static int replmd_delete_remove_link(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } - status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID"); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } - /* remove the link */ msg = ldb_msg_new(tmp_ctx); if (!msg) { @@ -3676,14 +3709,74 @@ static int replmd_delete_remove_link(struct ldb_module *module, if (target_attr == NULL) { continue; } + attrs[0] = target_attr->lDAPDisplayName; - ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2); + ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, + LDB_FLAG_MOD_DELETE, &el2); if (ret != LDB_SUCCESS) { ldb_module_oom(module); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } - dn_val = data_blob_string_const(ldb_dn_get_linearized(dn)); + + ret = dsdb_module_search_dn(module, tmp_ctx, &link_res, + msg->dn, attrs, + DSDB_FLAG_NEXT_MODULE | + DSDB_SEARCH_SHOW_EXTENDED_DN, + parent); + + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + link_msg = link_res->msgs[0]; + link_el = ldb_msg_find_element(link_msg, + target_attr->lDAPDisplayName); + if (link_el == NULL) { + talloc_free(tmp_ctx); + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + + /* + * This call 'upgrades' the links in link_dns, but we + * do not commit the result back into the database, so + * this is safe to call in FL2000 or on databases that + * have been run at that level in the past. + */ + ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, + link_el, &link_dns, + target_attr->syntax->ldap_oid, parent); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = parsed_dn_find(ldb, link_dns, link_el->num_values, + guid, dn, &p, &unused, + target_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + if (p == NULL) { + ldb_asprintf_errstring(ldb_module_get_ctx(module), + "Failed to find forward link on %s " + "as %s to remove backlink %s on %s", + ldb_dn_get_linearized(msg->dn), + target_attr->lDAPDisplayName, + sa->lDAPDisplayName, + ldb_dn_get_linearized(dn)); + talloc_free(tmp_ctx); + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + + + /* This needs to get the Binary DN, by first searching */ + dn_str = dsdb_dn_get_linearized(tmp_ctx, + p->dsdb_dn); -- Samba Shared Repository