From 74ec26c1ca13a6203512a61d362388667e4b633a Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Tue, 4 Apr 2017 13:11:16 +1200 Subject: [PATCH 01/16] whitespace: Remove some whitespace Signed-off-by: Garming Sam --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 1 + source4/dsdb/samdb/ldb_modules/samldb.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index d9b414d..a922f9b 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3238,6 +3238,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) ret = ldb_module_send_referral(req, referral); talloc_free(ac); return ret; + } if (ret != LDB_SUCCESS) { diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 2c47ff1..48edc28 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -2850,12 +2850,12 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) if (ret != LDB_SUCCESS) { return ret; } - dns_hostname = talloc_strdup(ac, + dns_hostname = talloc_strdup(ac, ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL)); if (dns_hostname == NULL) { return ldb_module_oom(ac->module); } - + talloc_free(msg); ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, -- 1.9.1 From 892efd418449c81be4656e4b704ee220427c5b05 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Tue, 4 Apr 2017 12:21:34 +1200 Subject: [PATCH 02/16] winbindd: Make some debugging clearer Signed-off-by: Garming Sam --- source3/winbindd/winbindd_pam.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index 8139cbe..8ba1305 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1391,7 +1391,7 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, */ DEBUG(3, ("This is the third problem for this " "particular call, adding DC to the " - "negative cache list\n")); + "negative cache list: %s %s\n", domain->name, domain->dcname)); add_failed_connection_entry(domain->name, domain->dcname, result); @@ -1501,7 +1501,7 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) { DEBUG(3,("winbind_samlogon_retry_loop: sam_network_logon(ex) " - "returned NT_STATUS_IO_TIMEOUT after the retry." + "returned NT_STATUS_IO_TIMEOUT after the retry. " "Killing connections to domain %s\n", domainname)); invalidate_cm_connection(domain); -- 1.9.1 From 65232f82fe8a375ae8ce6e4e0895cfa5538a0ae5 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 29 Mar 2017 10:32:39 +1300 Subject: [PATCH 03/16] samba_dnsupdate: Remove extra argument from debug Signed-off-by: Garming Sam --- source4/scripting/bin/samba_dnsupdate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/scripting/bin/samba_dnsupdate b/source4/scripting/bin/samba_dnsupdate index 0687703..f9e835b 100755 --- a/source4/scripting/bin/samba_dnsupdate +++ b/source4/scripting/bin/samba_dnsupdate @@ -560,7 +560,7 @@ def call_samba_tool(d, op="add", zone=None): sys.exit(1) error_count = error_count + 1 if opts.verbose: - print("Failed 'samba-tool dns' based update: %s : %s" % (str(d), estr)) + print("Failed 'samba-tool dns' based update: %s" % (str(d))) except Exception, estr: if opts.fail_immediately: sys.exit(1) -- 1.9.1 From 6307f3dc87509ba0b463f85a80002ce4817e1437 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Tue, 4 Apr 2017 12:18:42 +1200 Subject: [PATCH 04/16] drsuapi.idl: Expose GetNCChanges req8 like req10 Signed-off-by: Garming Sam --- librpc/idl/drsuapi.idl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librpc/idl/drsuapi.idl b/librpc/idl/drsuapi.idl index d08054f..2eb1d65 100644 --- a/librpc/idl/drsuapi.idl +++ b/librpc/idl/drsuapi.idl @@ -561,7 +561,7 @@ interface drsuapi [size_is(num_attids)] drsuapi_DsAttributeId attids[]; } drsuapi_DsPartialAttributeSet; - typedef struct { + typedef [public] struct { GUID destination_dsa_guid; GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context; -- 1.9.1 From b0e2e0c73c63bef346903e43d9d5c4d8044ec122 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Tue, 4 Apr 2017 13:13:16 +1200 Subject: [PATCH 05/16] replmd: Send RODC referrals preferably to the PDC The Windows protocol test suites check that a particular DC is used when sending referrals. Signed-off-by: Garming Sam BUG: https://bugzilla.samba.org/show_bug.cgi?id=12008 --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 67 ++++++++++++++++--------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index a922f9b..44ec1d4 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -41,6 +41,7 @@ #include "dsdb/common/proto.h" #include "dsdb/common/util.h" #include "../libds/common/flags.h" +#include "librpc/gen_ndr/irpc.h" #include "librpc/gen_ndr/ndr_misc.h" #include "librpc/gen_ndr/ndr_drsuapi.h" #include "librpc/gen_ndr/ndr_drsblobs.h" @@ -3153,6 +3154,47 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, } +static int send_rodc_referral(struct ldb_request *req, + struct ldb_context *ldb, + struct ldb_dn *dn) +{ + char *referral = NULL; + struct loadparm_context *lp_ctx = NULL; + struct ldb_dn *fsmo_role_dn = NULL; + struct ldb_dn *role_owner_dn = NULL; + const char *domain = NULL; + WERROR werr; + + lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), + struct loadparm_context); + + werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER, + &fsmo_role_dn, &role_owner_dn); + + if (W_ERROR_IS_OK(werr)) { + struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn); + if (server_dn != NULL) { + ldb_dn_remove_child_components(server_dn, 1); + domain = samdb_dn_to_dnshostname(ldb, req, + server_dn); + } + } + + if (domain == NULL) { + domain = lpcfg_dnsdomain(lp_ctx); + } + + referral = talloc_asprintf(req, "ldap://%s/%s", + domain, + ldb_dn_get_linearized(dn)); + if (referral == NULL) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + return ldb_module_send_referral(req, referral); +} + static int replmd_modify(struct ldb_module *module, struct ldb_request *req) { @@ -3225,17 +3267,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) msg, &ac->seq_num, t, is_schema_nc, &is_urgent, &rodc); if (rodc && (ret == LDB_ERR_REFERRAL)) { - struct loadparm_context *lp_ctx; - char *referral; - - lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), - struct loadparm_context); - - referral = talloc_asprintf(req, - "ldap://%s/%s", - lpcfg_dnsdomain(lp_ctx), - ldb_dn_get_linearized(msg->dn)); - ret = ldb_module_send_referral(req, referral); + ret = send_rodc_referral(req, ldb, msg->dn); talloc_free(ac); return ret; @@ -3498,18 +3530,7 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are msg, &ac->seq_num, t, is_schema_nc, &is_urgent, &rodc); if (rodc && (ret == LDB_ERR_REFERRAL)) { - struct ldb_dn *olddn = ac->req->op.rename.olddn; - struct loadparm_context *lp_ctx; - char *referral; - - lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), - struct loadparm_context); - - referral = talloc_asprintf(req, - "ldap://%s/%s", - lpcfg_dnsdomain(lp_ctx), - ldb_dn_get_linearized(olddn)); - ret = ldb_module_send_referral(req, referral); + ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn); talloc_free(ares); return ldb_module_done(req, NULL, NULL, ret); } -- 1.9.1 From 6ea96bb7f01579383b4dca2a799fcea62d2fd2b8 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Tue, 14 Mar 2017 10:36:13 +1300 Subject: [PATCH 06/16] selftest: Add ldap rodc python test Signed-off-by: Garming Sam Pair-programmed-with: Douglas Bagnall BUG: https://bugzilla.samba.org/show_bug.cgi?id=12008 --- selftest/knownfail | 3 + source4/dsdb/tests/python/rodc.py | 208 ++++++++++++++++++++++++++++++++++++++ source4/selftest/tests.py | 6 ++ 3 files changed, 217 insertions(+) create mode 100755 source4/dsdb/tests/python/rodc.py diff --git a/selftest/knownfail b/selftest/knownfail index 07b4cdb..c91d227 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -317,3 +317,6 @@ # rap password tests don't function in the ad_dc_ntvfs:local environment # ^samba.tests.auth_log_pass_change.samba.tests.auth_log_pass_change.AuthLogPassChangeTests.test_rap_change_password\(ad_dc_ntvfs:local\) +^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_add.* +^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_delete.* +^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_modify_nonreplicated.* diff --git a/source4/dsdb/tests/python/rodc.py b/source4/dsdb/tests/python/rodc.py new file mode 100755 index 0000000..8fd9354 --- /dev/null +++ b/source4/dsdb/tests/python/rodc.py @@ -0,0 +1,208 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import optparse +import sys +import os +import base64 +import random +import re +import uuid + +sys.path.insert(0, "bin/python") +import samba +from samba.tests.subunitrun import SubunitOptions, TestProgram + +import samba.getopt as options + +from samba.auth import system_session +import ldb +from samba.samdb import SamDB +from samba.ndr import ndr_pack, ndr_unpack +from samba.dcerpc import drsblobs + +import time + + +class RodcTestException(Exception): + pass + + +class RodcTests(samba.tests.TestCase): + + def setUp(self): + super(RodcTests, self).setUp() + self.samdb = SamDB(HOST, credentials=CREDS, + session_info=system_session(LP), lp=LP) + + self.base_dn = self.samdb.domain_dn() + + root = self.samdb.search(base='', scope=ldb.SCOPE_BASE, + attrs=['dsServiceName']) + self.service = root[0]['dsServiceName'][0] + self.tag = uuid.uuid4().hex + + def test_add_replicated_objects(self): + for o in ( + { + 'dn': "ou=%s1,%s" % (self.tag, self.base_dn), + "objectclass": "organizationalUnit" + }, + { + 'dn': "cn=%s2,%s" % (self.tag, self.base_dn), + "objectclass": "user" + }, + { + 'dn': "cn=%s3,%s" % (self.tag, self.base_dn), + "objectclass": "group" + }, + { + 'dn': "cn=%s4,%s" % (self.tag, self.service), + "objectclass": "NTDSConnection", + 'enabledConnection': 'TRUE', + 'fromServer': self.base_dn, + 'options': '0' + }, + ): + try: + self.samdb.add(o) + self.fail("Failed to fail to add %s" % o['dn']) + except ldb.LdbError as (ecode, emsg): + if ecode != ldb.ERR_REFERRAL: + print emsg + self.fail("Adding %s: ldb error: %s %s, wanted referral" % + (o['dn'], ecode, emsg)) + else: + m = re.search(r'(ldap://[^>]+)>', emsg) + if m is None: + self.fail("referral seems not to refer to anything") + address = m.group(1) + + try: + tmpdb = SamDB(address, credentials=CREDS, + session_info=system_session(LP), lp=LP) + tmpdb.add(o) + except ldb.LdbError, e: + self.fail("couldn't modify referred location %s" % + address) + + def test_modify_replicated_attributes(self): + # some timestamp ones + dn = 'CN=Guest,CN=Users,' + self.base_dn + value = 'hallooo' + for attr in ['carLicense', 'middleName']: + m = ldb.Message() + m.dn = ldb.Dn(self.samdb, dn) + m[attr] = ldb.MessageElement(value, + ldb.FLAG_MOD_REPLACE, + attr) + try: + self.samdb.modify(m) + self.fail("Failed to fail to modify %s %s" % (dn, attr)) + except ldb.LdbError as (ecode, emsg): + if ecode != ldb.ERR_REFERRAL: + self.fail("Failed to REFER when trying to modify %s %s" % + (dn, attr)) + + def test_modify_nonreplicated_attributes(self): + # some timestamp ones + dn = 'CN=Guest,CN=Users,' + self.base_dn + value = '123456789' + for attr in ['badPwdCount', 'lastLogon', 'lastLogoff']: + m = ldb.Message() + m.dn = ldb.Dn(self.samdb, dn) + m[attr] = ldb.MessageElement(value, + ldb.FLAG_MOD_REPLACE, + attr) + # Windows refers these ones even though they are non-replicated + try: + self.samdb.modify(m) + self.fail("Failed to fail to modify %s %s" % (dn, attr)) + except ldb.LdbError as (ecode, emsg): + if ecode != ldb.ERR_REFERRAL: + self.fail("Failed to REFER when trying to modify %s %s" % + (dn, attr)) + + def test_modify_nonreplicated_reps_attributes(self): + # some timestamp ones + dn = self.base_dn + + m = ldb.Message() + m.dn = ldb.Dn(self.samdb, dn) + attr = 'repsFrom' + + res = self.samdb.search(dn, scope=ldb.SCOPE_BASE, + attrs=['repsFrom']) + rep = ndr_unpack(drsblobs.repsFromToBlob, res[0]['repsFrom'][0], + allow_remaining=True) + rep.ctr.result_last_attempt = -1 + value = ndr_pack(rep) + + m[attr] = ldb.MessageElement(value, + ldb.FLAG_MOD_REPLACE, + attr) + try: + self.samdb.modify(m) + self.fail("Failed to fail to modify %s %s" % (dn, attr)) + except ldb.LdbError as (ecode, emsg): + if ecode != ldb.ERR_REFERRAL: + self.fail("Failed to REFER when trying to modify %s %s" % + (dn, attr)) + + def test_delete_special_objects(self): + dn = 'CN=Guest,CN=Users,' + self.base_dn + try: + self.samdb.delete(dn) + self.fail("Failed to fail to delete %s" % (dn)) + except ldb.LdbError as (ecode, emsg): + if ecode != ldb.ERR_REFERRAL: + print ecode, emsg + self.fail("Failed to REFER when trying to delete %s" % dn) + + def test_no_delete_nonexistent_objects(self): + dn = 'CN=does-not-exist-%s,CN=Users,%s' % (self.tag, self.base_dn) + try: + self.samdb.delete(dn) + self.fail("Failed to fail to delete %s" % (dn)) + except ldb.LdbError as (ecode, emsg): + if ecode != ldb.ERR_NO_SUCH_OBJECT: + print ecode, emsg + self.fail("Failed to NO_SUCH_OBJECT when trying to delete " + "%s (which does not exist)" % dn) + + + +def main(): + global HOST, CREDS, LP + parser = optparse.OptionParser("rodc.py [options] ") + + sambaopts = options.SambaOptions(parser) + versionopts = options.VersionOptions(parser) + credopts = options.CredentialsOptions(parser) + subunitopts = SubunitOptions(parser) + + parser.add_option_group(sambaopts) + parser.add_option_group(versionopts) + parser.add_option_group(credopts) + parser.add_option_group(subunitopts) + + opts, args = parser.parse_args() + + LP = sambaopts.get_loadparm() + CREDS = credopts.get_credentials(LP) + + try: + HOST = args[0] + except IndexError: + parser.print_usage() + sys.exit(1) + + if "://" not in HOST: + if os.path.isfile(HOST): + HOST = "tdb://%s" % HOST + else: + HOST = "ldap://%s" % HOST + + TestProgram(module=__name__, opts=subunitopts) + +main() diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 3f7d6fa..052c41b 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -626,6 +626,12 @@ plantestsuite_loadlist("samba4.ldap.sort.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [p plantestsuite_loadlist("samba4.ldap.vlv.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(samba4srcdir, "dsdb/tests/python/vlv.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) plantestsuite_loadlist("samba4.ldap.linked_attributes.python(ad_dc_ntvfs)", "ad_dc_ntvfs:local", [python, os.path.join(samba4srcdir, "dsdb/tests/python/linked_attributes.py"), '$PREFIX_ABS/ad_dc_ntvfs/private/sam.ldb', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) +plantestsuite_loadlist("samba4.ldap.rodc.python(rodc)", "rodc", + [python, + os.path.join(samba4srcdir, "dsdb/tests/python/rodc.py"), + '$SERVER', '-U"$USERNAME%$PASSWORD"', + '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) + for env in ["ad_dc_ntvfs", "fl2000dc", "fl2003dc", "fl2008r2dc"]: plantestsuite_loadlist("samba4.ldap_schema.python(%s)" % env, env, [python, os.path.join(samba4srcdir, "dsdb/tests/python/ldap_schema.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) plantestsuite("samba4.ldap.possibleInferiors.python(%s)" % env, env, [python, os.path.join(samba4srcdir, "dsdb/samdb/ldb_modules/tests/possibleinferiors.py"), "ldap://$SERVER", '-U"$USERNAME%$PASSWORD"', "-W$DOMAIN"]) -- 1.9.1 From 0951a1ae2869acbd8d45913c711d3a33bbe402c6 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Tue, 20 Sep 2016 04:25:34 +0000 Subject: [PATCH 07/16] rodc: Force all RODC add and delete to cause a referral Previously, you could add or delete and cause replication conflicts on an RODC. Modifies are already partly restricted in repl_meta_data and have more specific requirements, so they cannot be handled here. We still differ against Windows for modifies of non-replicated attributes over LDAP. Signed-off-by: Garming Sam Pair-programmed-with: Douglas Bagnall BUG: https://bugzilla.samba.org/show_bug.cgi?id=12008 --- selftest/knownfail | 3 +- source4/dsdb/samdb/ldb_modules/samldb.c | 64 +++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/selftest/knownfail b/selftest/knownfail index c91d227..85467ad 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -317,6 +317,5 @@ # rap password tests don't function in the ad_dc_ntvfs:local environment # ^samba.tests.auth_log_pass_change.samba.tests.auth_log_pass_change.AuthLogPassChangeTests.test_rap_change_password\(ad_dc_ntvfs:local\) -^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_add.* -^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_delete.* +# We currently don't send referrals for LDAP modify of non-replicated attrs ^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_modify_nonreplicated.* diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 48edc28..1efd58c 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -44,6 +44,7 @@ #include "param/param.h" #include "libds/common/flag_mapping.h" #include "system/network.h" +#include "librpc/gen_ndr/irpc.h" struct samldb_ctx; enum samldb_add_type { @@ -3380,6 +3381,52 @@ static int samldb_verify_subnet(struct samldb_ctx *ac) return LDB_SUCCESS; } +static char * +refer_if_rodc(struct ldb_context *ldb, struct ldb_request *req, struct ldb_dn *dn) +{ + if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID) + && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) { + bool rodc = false; + struct loadparm_context *lp_ctx; + char *referral; + int ret; + WERROR err; + + ret = samdb_rodc(ldb, &rodc); + if (ret != LDB_SUCCESS) { + DEBUG(4, (__location__ ": unable to tell if we are an RODC\n")); + } else if (rodc) { + const char *domain = NULL; + struct ldb_dn *fsmo_role_dn; + struct ldb_dn *role_owner_dn; + ldb_set_errstring(ldb, "RODC modify is forbidden!"); + lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), + struct loadparm_context); + + err = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER, + &fsmo_role_dn, &role_owner_dn); + if (W_ERROR_IS_OK(err)) { + struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn); + if (server_dn != NULL) { + ldb_dn_remove_child_components(server_dn, 1); + + domain = samdb_dn_to_dnshostname(ldb, req, + server_dn); + } + } + if (domain == NULL) { + domain = lpcfg_dnsdomain(lp_ctx); + } + referral = talloc_asprintf(req, + "ldap://%s/%s", + domain, + ldb_dn_get_linearized(dn)); + return referral; + } + } + return NULL; +} + /* add */ static int samldb_add(struct ldb_module *module, struct ldb_request *req) @@ -3388,6 +3435,7 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) struct samldb_ctx *ac; struct ldb_message_element *el; int ret; + char *referral = NULL; ldb = ldb_module_get_ctx(module); ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n"); @@ -3397,6 +3445,12 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); } + referral = refer_if_rodc(ldb, req, req->op.add.message->dn); + if (referral != NULL) { + ret = ldb_module_send_referral(req, referral); + return ret; + } + el = ldb_msg_find_element(req->op.add.message, "userParameters"); if (el != NULL && ldb_req_is_untrusted(req)) { const char *reason = "samldb_add: " @@ -3831,13 +3885,23 @@ static int samldb_prim_group_users_check(struct samldb_ctx *ac) static int samldb_delete(struct ldb_module *module, struct ldb_request *req) { struct samldb_ctx *ac; + char *referral = NULL; int ret; + struct ldb_context *ldb; if (ldb_dn_is_special(req->op.del.dn)) { /* do not manipulate our control entries */ return ldb_next_request(module, req); } + ldb = ldb_module_get_ctx(module); + + referral = refer_if_rodc(ldb, req, req->op.del.dn); + if (referral != NULL) { + ret = ldb_module_send_referral(req, referral); + return ret; + } + ac = samldb_ctx_init(module, req); if (ac == NULL) { return ldb_operr(ldb_module_get_ctx(module)); -- 1.9.1 From 3c9ca7ce47529e2f445474344d3adc6ce9469398 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Fri, 17 Mar 2017 16:09:06 +1300 Subject: [PATCH 08/16] drepl: Add partial attribute set in the case of repl secret Against Windows, the call will always fail without it. Signed-off-by: Garming Sam --- source4/dsdb/repl/drepl_out_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c index ac0b947..d526f45 100644 --- a/source4/dsdb/repl/drepl_out_helpers.c +++ b/source4/dsdb/repl/drepl_out_helpers.c @@ -498,7 +498,7 @@ static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req) return; } replica_flags &= ~DRSUAPI_DRS_WRIT_REP; - } else if (partition->rodc_replica) { + } else if (partition->rodc_replica || state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) { bool for_schema = false; if (ldb_dn_compare_base(schema_dn, partition->dn) == 0) { for_schema = true; -- 1.9.1 From ddc31c548697b31c4b3fde5a0a5b4a95af6370c8 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Fri, 24 Mar 2017 10:24:21 +1300 Subject: [PATCH 09/16] rodc: Allow local RODC changes with version 0 These changes will get clobbered by RWDCs through replication. This behaviour is required for lockoutTime to enforce the password lockout locally on the RODC (and is consistent with Windows). Signed-off-by: Garming Sam --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 14 ++++++++++++-- source4/dsdb/samdb/samdb.h | 6 ++++++ source4/setup/schema_samba4.ldif | 2 ++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 44ec1d4..851b4ad 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -235,7 +235,6 @@ static bool replmd_check_urgent_attribute(const struct ldb_message_element *el) return false; } - static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar); /* @@ -1506,6 +1505,7 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, md1 = &omd->ctr.ctr1.array[i]; md1->version++; md1->attid = attid; + if (md1->attid == DRSUAPI_ATTID_isDeleted) { const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn); const char* rdn; @@ -1532,6 +1532,15 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, md1->originating_usn = *seq_num; md1->local_usn = *seq_num; + if (ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE) != NULL) { + /* Force version to 0 to be overriden later via replication */ + bool am_rodc = false; + int ret = samdb_rodc(ldb, &am_rodc); + if (ret == LDB_SUCCESS && am_rodc) { + md1->version = 0; + } + } + return LDB_SUCCESS; } @@ -1837,7 +1846,8 @@ static int replmd_update_rpmd(struct ldb_module *module, /*if we are RODC and this is a DRSR update then its ok*/ if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID) - && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) { + && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA) + && !ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) { unsigned instanceType; ret = samdb_rodc(ldb, rodc); diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 1e427d0..5dce37e 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -183,6 +183,12 @@ struct dsdb_control_password_user_account_control { /* passed when we want to thoroughly delete linked attributes */ #define DSDB_CONTROL_REPLMD_VANISH_LINKS "1.3.6.1.4.1.7165.4.3.29" +/* + * lockoutTime is a replicated attribute, but must be modified before + * connectivity occurs to allow password lockouts. + */ +#define DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE "1.3.6.1.4.1.7165.4.3.31" + #define DSDB_EXTENDED_REPLICATED_OBJECTS_OID "1.3.6.1.4.1.7165.4.4.1" struct dsdb_extended_replicated_object { struct ldb_message *msg; diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif index 0189fb5..d8bc2d9 100644 --- a/source4/setup/schema_samba4.ldif +++ b/source4/setup/schema_samba4.ldif @@ -222,6 +222,8 @@ #Allocated: DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID 1.3.6.1.4.1.7165.4.3.28 #Allocated: DSDB_CONTROL_REPLMD_VANISH_LINKS 1.3.6.1.4.1.7165.4.3.29 #Allocated: LDB_CONTROL_RECALCULATE_RDN_OID 1.3.6.1.4.1.7165.4.3.30 +#Allocated: DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE 1.3.6.1.4.1.7165.4.3.31 + # Extended 1.3.6.1.4.1.7165.4.4.x #Allocated: DSDB_EXTENDED_REPLICATED_OBJECTS_OID 1.3.6.1.4.1.7165.4.4.1 -- 1.9.1 From ea892e63fd3440b5f41d9ef69c4be64b7f4e8851 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Thu, 30 Mar 2017 15:50:01 +1300 Subject: [PATCH 10/16] replmd: Reduce calls to ldb_request_get_control Signed-off-by: Garming Sam --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 41 ++++++++++++++++--------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 851b4ad..4f077c0 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1367,6 +1367,7 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, const struct GUID *our_invocation_id, NTTIME now, bool is_schema_nc, + bool is_forced_rodc, struct ldb_request *req) { uint32_t i; @@ -1532,13 +1533,9 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, md1->originating_usn = *seq_num; md1->local_usn = *seq_num; - if (ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE) != NULL) { + if (is_forced_rodc) { /* Force version to 0 to be overriden later via replication */ - bool am_rodc = false; - int ret = samdb_rodc(ldb, &am_rodc); - if (ret == LDB_SUCCESS && am_rodc) { - md1->version = 0; - } + md1->version = 0; } return LDB_SUCCESS; @@ -1561,7 +1558,8 @@ static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb, struct replPropertyMetaDataBlob *omd, struct replmd_replicated_request *ar, NTTIME now, - bool is_schema_nc) + bool is_schema_nc, + bool is_forced_rodc) { const char *rdn_name = ldb_dn_get_rdn_name(msg->dn); const struct dsdb_attribute *rdn_attr = @@ -1592,7 +1590,8 @@ static int replmd_update_rpmd_rdn_attr(struct ldb_context *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); + now, is_schema_nc, is_forced_rodc, + ar->req); } @@ -1639,6 +1638,7 @@ static int replmd_update_rpmd(struct ldb_module *module, bool rmd_is_provided; bool rmd_is_just_resorted = false; const char *not_rename_attrs[4 + msg->num_elements]; + bool is_forced_rodc = false; if (rename_attrs) { attrs = rename_attrs; @@ -1655,6 +1655,17 @@ static int replmd_update_rpmd(struct ldb_module *module, ldb = ldb_module_get_ctx(module); + ret = samdb_rodc(ldb, rodc); + if (ret != LDB_SUCCESS) { + DEBUG(4, (__location__ ": unable to tell if we are an RODC\n")); + *rodc = false; + } + + if (*rodc && + ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) { + is_forced_rodc = true; + } + our_invocation_id = samdb_ntds_invocation_id(ldb); if (!our_invocation_id) { /* this happens during an initial vampire while @@ -1791,6 +1802,7 @@ static int replmd_update_rpmd(struct ldb_module *module, &omd, schema, seq_num, our_invocation_id, now, is_schema_nc, + is_forced_rodc, req); if (ret != LDB_SUCCESS) { return ret; @@ -1847,13 +1859,10 @@ static int replmd_update_rpmd(struct ldb_module *module, /*if we are RODC and this is a DRSR update then its ok*/ if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID) && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA) - && !ldb_request_get_control(req, DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE)) { + && !is_forced_rodc) { unsigned instanceType; - ret = samdb_rodc(ldb, rodc); - if (ret != LDB_SUCCESS) { - DEBUG(4, (__location__ ": unable to tell if we are an RODC\n")); - } else if (*rodc) { + if (*rodc) { ldb_set_errstring(ldb, "RODC modify is forbidden!"); return LDB_ERR_REFERRAL; } @@ -4953,7 +4962,8 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar) 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); + md, ar, now, is_schema_nc, + false); 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); @@ -5683,7 +5693,8 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) if (renamed) { ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn, - &nmd, ar, now, is_schema_nc); + &nmd, ar, now, is_schema_nc, + false); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb)); return replmd_replicated_request_error(ar, ret); -- 1.9.1 From 964412ad245709099bda189b08ab32875bdb6341 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Tue, 28 Mar 2017 14:34:01 +1300 Subject: [PATCH 11/16] password-lockout: Allow RODC to ensure lockout and lockout reset Prior to this, the modification of lockoutTime triggered referrals. Signed-off-by: Garming Sam --- source4/auth/sam.c | 79 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 13 deletions(-) diff --git a/source4/auth/sam.c b/source4/auth/sam.c index 7df23d5..4499ffc 100644 --- a/source4/auth/sam.c +++ b/source4/auth/sam.c @@ -702,13 +702,36 @@ NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx, } if (msg_mod != NULL) { - ret = dsdb_modify(sam_ctx, msg_mod, 0); + struct ldb_request *req; + + ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx, + msg_mod, + NULL, + NULL, + ldb_op_default_callback, + NULL); if (ret != LDB_SUCCESS) { - DEBUG(0, ("Failed to update badPwdCount, badPasswordTime or set lockoutTime on %s: %s\n", - ldb_dn_get_linearized(msg_mod->dn), ldb_errstring(sam_ctx))); - TALLOC_FREE(mem_ctx); - return NT_STATUS_INTERNAL_ERROR; + goto done; + } + + ret = ldb_request_add_control(req, + DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE, + false, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(req); + goto done; } + + ret = dsdb_autotransaction_request(sam_ctx, req); + talloc_free(req); + } + +done: + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Failed to update badPwdCount, badPasswordTime or set lockoutTime on %s: %s\n", + ldb_dn_get_linearized(msg_mod->dn), ldb_errstring(sam_ctx))); + TALLOC_FREE(mem_ctx); + return NT_STATUS_INTERNAL_ERROR; } TALLOC_FREE(mem_ctx); @@ -920,17 +943,47 @@ NTSTATUS authsam_logon_success_accounting(struct ldb_context *sam_ctx, } if (msg_mod->num_elements > 0) { - ret = dsdb_replace(sam_ctx, msg_mod, 0); + unsigned int i; + struct ldb_request *req; + + /* mark all the message elements as LDB_FLAG_MOD_REPLACE */ + for (i=0;inum_elements;i++) { + msg_mod->elements[i].flags = LDB_FLAG_MOD_REPLACE; + } + + ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx, + msg_mod, + NULL, + NULL, + ldb_op_default_callback, + NULL); if (ret != LDB_SUCCESS) { - DEBUG(0, ("Failed to set badPwdCount and lockoutTime " - "to 0 and/or lastlogon to now (%lld) " - "%s: %s\n", (long long int)now, - ldb_dn_get_linearized(msg_mod->dn), - ldb_errstring(sam_ctx))); - TALLOC_FREE(mem_ctx); - return NT_STATUS_INTERNAL_ERROR; + goto done; + } + + ret = ldb_request_add_control(req, + DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE, + false, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(req); + goto done; } + + ret = dsdb_autotransaction_request(sam_ctx, req); + talloc_free(req); } + +done: + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Failed to set badPwdCount and lockoutTime " + "to 0 and/or lastlogon to now (%lld) " + "%s: %s\n", (long long int)now, + ldb_dn_get_linearized(msg_mod->dn), + ldb_errstring(sam_ctx))); + TALLOC_FREE(mem_ctx); + return NT_STATUS_INTERNAL_ERROR; + } + TALLOC_FREE(mem_ctx); return NT_STATUS_OK; } -- 1.9.1 From f357c2bffbfca4896af2d8bfc27cfded02188c5c Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Tue, 28 Mar 2017 14:29:26 +1300 Subject: [PATCH 12/16] join.py: Allow RODC to have push replication at join Normally DsAddEntry connects to DRSUAPI, however not in the RODC case. This meant that it never called DsReplicaUpdateRefs and so never got push-replication after join. Signed-off-by: Garming Sam --- python/samba/join.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/samba/join.py b/python/samba/join.py index 88b8d4b..6a92435 100644 --- a/python/samba/join.py +++ b/python/samba/join.py @@ -964,8 +964,10 @@ class dc_join(object): if not ctx.RODC: r.options |= drsuapi.DRSUAPI_DRS_WRIT_REP - if ctx.drsuapi: - ctx.drsuapi.DsReplicaUpdateRefs(ctx.drsuapi_handle, 1, r) + if ctx.drsuapi is None: + ctx.drsuapi_connect() + + ctx.drsuapi.DsReplicaUpdateRefs(ctx.drsuapi_handle, 1, r) def join_finalise(ctx): """Finalise the join, mark us synchronised and setup secrets db.""" -- 1.9.1 From 4bd27c461d249ad2c94cc75209d5f0119d1a7ae1 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 29 Mar 2017 13:16:48 +1300 Subject: [PATCH 13/16] rodc/dns: Do not put a trailing dot at end of a DNS record This causes RESOLV_WRAPPER to not detect the record correctly (while also creating inconsistent and possibly breaking records). Signed-off-by: Garming Sam --- source4/dsdb/dns/dns_update.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/source4/dsdb/dns/dns_update.c b/source4/dsdb/dns/dns_update.c index 0591e34..959223d 100644 --- a/source4/dsdb/dns/dns_update.c +++ b/source4/dsdb/dns/dns_update.c @@ -531,36 +531,35 @@ static NTSTATUS dnsupdate_dnsupdate_RODC(struct irpc_message *msg, return NT_STATUS_OK; } - for (i=0; ir->in.dns_names->count; i++) { struct NL_DNS_NAME_INFO *n = &r->in.dns_names->names[i]; switch (n->type) { case NlDnsLdapAtSite: - dprintf(st->fd, "SRV _ldap._tcp.%s._sites.%s. %s %u\n", + dprintf(st->fd, "SRV _ldap._tcp.%s._sites.%s %s %u\n", site, dnsdomain, hostname, n->port); break; case NlDnsGcAtSite: - dprintf(st->fd, "SRV _ldap._tcp.%s._sites.gc._msdcs.%s. %s %u\n", + dprintf(st->fd, "SRV _ldap._tcp.%s._sites.gc._msdcs.%s %s %u\n", site, dnsdomain, hostname, n->port); break; case NlDnsDsaCname: - dprintf(st->fd, "CNAME %s._msdcs.%s. %s\n", + dprintf(st->fd, "CNAME %s._msdcs.%s %s\n", ntdsguid, dnsforest, hostname); break; case NlDnsKdcAtSite: - dprintf(st->fd, "SRV _kerberos._tcp.%s._sites.dc._msdcs.%s. %s %u\n", + dprintf(st->fd, "SRV _kerberos._tcp.%s._sites.dc._msdcs.%s %s %u\n", site, dnsdomain, hostname, n->port); break; case NlDnsDcAtSite: - dprintf(st->fd, "SRV _ldap._tcp.%s._sites.dc._msdcs.%s. %s %u\n", + dprintf(st->fd, "SRV _ldap._tcp.%s._sites.dc._msdcs.%s %s %u\n", site, dnsdomain, hostname, n->port); break; case NlDnsRfc1510KdcAtSite: - dprintf(st->fd, "SRV _kerberos._tcp.%s._sites.%s. %s %u\n", + dprintf(st->fd, "SRV _kerberos._tcp.%s._sites.%s %s %u\n", site, dnsdomain, hostname, n->port); break; case NlDnsGenericGcAtSite: - dprintf(st->fd, "SRV _gc._tcp.%s._sites.%s. %s %u\n", + dprintf(st->fd, "SRV _gc._tcp.%s._sites.%s %s %u\n", site, dnsforest, hostname, n->port); break; } -- 1.9.1 From 9687a756d8f61ce4093e0aee07c1cc87dc077790 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Mon, 3 Apr 2017 15:31:14 +1200 Subject: [PATCH 14/16] dns_update: RODC updates should use lower case realm This is consistent with the standard update list we write. Signed-off-by: Garming Sam --- source4/dsdb/dns/dns_update.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/dsdb/dns/dns_update.c b/source4/dsdb/dns/dns_update.c index 959223d..8962b08 100644 --- a/source4/dsdb/dns/dns_update.c +++ b/source4/dsdb/dns/dns_update.c @@ -515,7 +515,7 @@ static NTSTATUS dnsupdate_dnsupdate_RODC(struct irpc_message *msg, /* find dnsdomain and dnsforest */ - dnsdomain = lpcfg_realm(s->task->lp_ctx); + dnsdomain = lpcfg_dnsdomain(s->task->lp_ctx); dnsforest = dnsdomain; /* find the hostname */ -- 1.9.1 From 271868cfa86176280031d40d61627653efbc13ba Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 29 Mar 2017 11:24:50 +1300 Subject: [PATCH 15/16] drepl_server: Allow refresh of partitions on UpdateRef When we call UpdateRef, the push replication will not begin until the drepl_server has done its periodic refresh. If UpdateRefs is called, we should just send an IRPC message to call the refresh. NOTE: This has the same dependencies and issues as repl_secrets in auth_sam.c in terms of IRPC implementation. Signed-off-by: Garming Sam --- source4/rpc_server/drsuapi/dcesrv_drsuapi.h | 4 ++- source4/rpc_server/drsuapi/getncchanges.c | 4 ++- source4/rpc_server/drsuapi/updaterefs.c | 51 ++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h index d376f7e..38375b5 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h @@ -40,7 +40,9 @@ struct drsuapi_bind_state { /* prototypes of internal functions */ -WERROR drsuapi_UpdateRefs(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx, +WERROR drsuapi_UpdateRefs(struct imessaging_context *msg_ctx, + struct tevent_context *event_ctx, + struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx, struct drsuapi_DsReplicaUpdateRefsRequest1 *req); WERROR dcesrv_drsuapi_DsReplicaUpdateRefs(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct drsuapi_DsReplicaUpdateRefs *r); diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index 3f2ef8d..1f02f2c 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -2933,7 +2933,9 @@ allowed: to send notifies using the GC SPN */ ureq.options |= (req10->replica_flags & DRSUAPI_DRS_REF_GCSPN); - werr = drsuapi_UpdateRefs(b_state, mem_ctx, &ureq); + werr = drsuapi_UpdateRefs(dce_call->msg_ctx, + dce_call->event_ctx, b_state, + mem_ctx, &ureq); if (!W_ERROR_IS_OK(werr)) { DEBUG(0,(__location__ ": Failed UpdateRefs on %s for %s in DsGetNCChanges - %s\n", drs_ObjectIdentifier_to_string(mem_ctx, ncRoot), ureq.dest_dsa_dns_name, diff --git a/source4/rpc_server/drsuapi/updaterefs.c b/source4/rpc_server/drsuapi/updaterefs.c index 6fdbf2e..457f393 100644 --- a/source4/rpc_server/drsuapi/updaterefs.c +++ b/source4/rpc_server/drsuapi/updaterefs.c @@ -27,6 +27,8 @@ #include "rpc_server/drsuapi/dcesrv_drsuapi.h" #include "auth/session.h" #include "librpc/gen_ndr/ndr_drsuapi.h" +#include "librpc/gen_ndr/ndr_irpc_c.h" +#include "lib/messaging/irpc.h" struct repsTo { uint32_t count; @@ -121,6 +123,10 @@ static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, return WERR_OK; } +struct drepl_refresh_state { + struct dreplsrv_refresh r; +}; + /** * @brief Update the references for the given NC and the destination DSA object * @@ -128,6 +134,9 @@ static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, * will validate the request to update reference and then will add/del a repsTo * to the specified server referenced by its DSA GUID in the request. * + * @param[in] msg_ctx Messaging context for sending partition + * refresh in dreplsrv + * * @param[in] b_state A bind_state object * * @param[in] mem_ctx A talloc context for memory allocation @@ -139,7 +148,9 @@ static WERROR uref_del_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, * @return WERR_OK is success, different error * otherwise. */ -WERROR drsuapi_UpdateRefs(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx, +WERROR drsuapi_UpdateRefs(struct imessaging_context *msg_ctx, + struct tevent_context *event_ctx, + struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx, struct drsuapi_DsReplicaUpdateRefsRequest1 *req) { WERROR werr; @@ -147,6 +158,10 @@ WERROR drsuapi_UpdateRefs(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ct struct ldb_dn *dn; struct ldb_dn *nc_root; struct ldb_context *sam_ctx = b_state->sam_ctx_system?b_state->sam_ctx_system:b_state->sam_ctx; + struct dcerpc_binding_handle *irpc_handle; + struct tevent_req *subreq; + struct drepl_refresh_state *state; + DEBUG(4,("DsReplicaUpdateRefs for host '%s' with GUID %s options 0x%08x nc=%s\n", req->dest_dsa_dns_name, GUID_string(mem_ctx, &req->dest_dsa_guid), @@ -201,7 +216,7 @@ WERROR drsuapi_UpdateRefs(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ct if (req->options & DRSUAPI_DRS_ADD_REF) { struct repsFromTo1 dest; struct repsFromTo1OtherInfo oi; - + ZERO_STRUCT(dest); ZERO_STRUCT(oi); @@ -222,9 +237,36 @@ WERROR drsuapi_UpdateRefs(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ct if (ldb_transaction_commit(sam_ctx) != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed to commit transaction on samdb: %s\n", ldb_errstring(sam_ctx))); - return WERR_DS_DRA_INTERNAL_ERROR; + return WERR_DS_DRA_INTERNAL_ERROR; } + state = talloc_zero(mem_ctx, struct drepl_refresh_state); + if (state == NULL) { + return WERR_OK; + } + + irpc_handle = irpc_binding_handle_by_name(mem_ctx, msg_ctx, + "dreplsrv", &ndr_table_irpc); + if (irpc_handle == NULL) { + /* dreplsrv is not running yet */ + TALLOC_FREE(state); + return WERR_OK; + } + + /* + * [Taken from auth_sam_trigger_repl_secret in auth_sam.c] + * + * This seem to rely on the current IRPC implementation, + * which delivers the message in the _send function. + * + * TODO: we need a ONE_WAY IRPC handle and register + * a callback and wait for it to be triggered! + */ + subreq = dcerpc_dreplsrv_refresh_r_send(state, event_ctx, + irpc_handle, &state->r); + TALLOC_FREE(subreq); + TALLOC_FREE(state); + return WERR_OK; failed: @@ -278,7 +320,8 @@ WERROR dcesrv_drsuapi_DsReplicaUpdateRefs(struct dcesrv_call_state *dce_call, TA } } - werr = drsuapi_UpdateRefs(b_state, mem_ctx, req); + werr = drsuapi_UpdateRefs(dce_call->msg_ctx, dce_call->event_ctx, + b_state, mem_ctx, req); #if 0 NDR_PRINT_FUNCTION_DEBUG(drsuapi_DsReplicaUpdateRefs, NDR_BOTH, r); -- 1.9.1 From 87ea46822a1d891ff2befb54c84663323c1959bb Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 29 Mar 2017 15:21:04 +1300 Subject: [PATCH 16/16] updaterefs: Do not open transaction even when unnecessary This can be called during GetNCChanges (a generally read-only call), it is not wise to be blocking the database for no reason. Signed-off-by: Garming Sam --- source4/rpc_server/drsuapi/updaterefs.c | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/source4/rpc_server/drsuapi/updaterefs.c b/source4/rpc_server/drsuapi/updaterefs.c index 457f393..9cf3556 100644 --- a/source4/rpc_server/drsuapi/updaterefs.c +++ b/source4/rpc_server/drsuapi/updaterefs.c @@ -35,6 +35,43 @@ struct repsTo { struct repsFromToBlob *r; }; +static WERROR uref_check_dest(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, + struct ldb_dn *dn, struct GUID *dest_guid, + uint32_t options) +{ + struct repsTo reps; + WERROR werr; + unsigned int i; + bool found = false; + + werr = dsdb_loadreps(sam_ctx, mem_ctx, dn, "repsTo", &reps.r, &reps.count); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + for (i=0; idest_dsa_guid, + req->options); + if (W_ERROR_EQUAL(werr, WERR_DS_DRA_REF_ALREADY_EXISTS) || + W_ERROR_EQUAL(werr, WERR_DS_DRA_REF_NOT_FOUND)) { + if (req->options & DRSUAPI_DRS_GETCHG_CHECK) { + return WERR_OK; + } + return werr; + } + if (ldb_transaction_start(sam_ctx) != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed to start transaction on samdb: %s\n", ldb_errstring(sam_ctx))); -- 1.9.1