diff --git a/python/samba/drs_utils.py b/python/samba/drs_utils.py index 6e2cfea9ab2..49837492b7d 100644 --- a/python/samba/drs_utils.py +++ b/python/samba/drs_utils.py @@ -147,12 +147,16 @@ def drs_DsBind(drs): class drs_Replicate(object): '''DRS replication calls''' - def __init__(self, binding_string, lp, creds, samdb): + def __init__(self, binding_string, lp, creds, samdb, invocation_id): self.drs = drsuapi.drsuapi(binding_string, lp, creds) (self.drs_handle, self.supported_extensions) = drs_DsBind(self.drs) self.net = Net(creds=creds, lp=lp) self.samdb = samdb - self.replication_state = self.net.replicate_init(self.samdb, lp, self.drs) + if not isinstance(invocation_id, misc.GUID): + raise RuntimeError("Must supply GUID for invocation_id") + if invocation_id == misc.GUID("00000000-0000-0000-0000-000000000000"): + raise RuntimeError("Must not set GUID 00000000-0000-0000-0000-000000000000 as invocation_id") + self.replication_state = self.net.replicate_init(self.samdb, lp, self.drs, invocation_id) def drs_get_rodc_partial_attribute_set(self): '''get a list of attributes for RODC replication''' diff --git a/python/samba/join.py b/python/samba/join.py index 15db67fbb4a..2379d5f214d 100644 --- a/python/samba/join.py +++ b/python/samba/join.py @@ -799,7 +799,7 @@ class dc_join(object): binding_options += ",print" repl = drs_utils.drs_Replicate( "ncacn_ip_tcp:%s[%s]" % (ctx.server, binding_options), - ctx.lp, repl_creds, ctx.local_samdb) + ctx.lp, repl_creds, ctx.local_samdb, ctx.invocation_id) repl.replicate(ctx.schema_dn, source_dsa_invocation_id, destination_dsa_guid, schema=True, rodc=ctx.RODC, diff --git a/python/samba/netcmd/drs.py b/python/samba/netcmd/drs.py index de78ac71c78..36dc48e2c23 100644 --- a/python/samba/netcmd/drs.py +++ b/python/samba/netcmd/drs.py @@ -258,11 +258,13 @@ def drs_local_replicate(self, SOURCE_DC, NC): source_dsa_invocation_id = misc.GUID(self.samdb.get_invocation_id()) + dest_dsa_invocation_id = misc.GUID(self.local_samdb.get_invocation_id()) destination_dsa_guid = self.ntds_guid self.samdb.transaction_start() repl = drs_utils.drs_Replicate("ncacn_ip_tcp:%s[seal]" % self.server, self.lp, - self.creds, self.local_samdb) + self.creds, self.local_samdb, dest_dsa_invocation_id) + try: repl.replicate(NC, source_dsa_invocation_id, destination_dsa_guid) except Exception, e: diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 7a243c3d376..55bd73e4249 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -1302,6 +1302,7 @@ const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb) /* see if we have a cached copy */ invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id"); if (invocation_id) { + SMB_ASSERT(!GUID_all_zero(invocation_id)); return invocation_id; } @@ -1362,6 +1363,7 @@ bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *in goto failed; } + SMB_ASSERT(!GUID_all_zero(invocation_id_in)); *invocation_id_new = *invocation_id_in; /* cache the domain_sid in the ldb */ diff --git a/source4/dsdb/pydsdb.c b/source4/dsdb/pydsdb.c index 99e239e60c8..c9e80c2f1bd 100644 --- a/source4/dsdb/pydsdb.c +++ b/source4/dsdb/pydsdb.c @@ -727,6 +727,11 @@ static PyObject *py_dsdb_set_ntds_invocation_id(PyObject *self, PyObject *args) PyErr_LDB_OR_RAISE(py_ldb, ldb); GUID_from_string(PyString_AsString(py_guid), &guid); + if (GUID_all_zero(&guid)) { + PyErr_SetString(PyExc_RuntimeError, "set_ntds_invocation_id rejected due to all-zero invocation ID"); + return NULL; + } + ret = samdb_set_ntds_invocation_id(ldb, &guid); if (!ret) { PyErr_SetString(PyExc_RuntimeError, "set_ntds_invocation_id failed"); diff --git a/source4/libnet/py_net.c b/source4/libnet/py_net.c index acb0a377591..7981aad0225 100644 --- a/source4/libnet/py_net.c +++ b/source4/libnet/py_net.c @@ -22,6 +22,7 @@ #include #include "includes.h" #include +#include #include "libnet.h" #include "auth/credentials/pycredentials.h" #include "libcli/security/security.h" @@ -33,6 +34,7 @@ #include "libcli/finddc.h" #include "dsdb/samdb/samdb.h" #include "py_net.h" +#include "librpc/rpc/pyrpc_util.h" void initnet(void); @@ -363,16 +365,17 @@ struct replicate_state { */ static PyObject *py_net_replicate_init(py_net_Object *self, PyObject *args, PyObject *kwargs) { - const char *kwnames[] = { "samdb", "lp", "drspipe", NULL }; - PyObject *py_ldb, *py_lp, *py_drspipe; + const char *kwnames[] = { "samdb", "lp", "drspipe", "invocation_id", NULL }; + PyObject *py_ldb, *py_lp, *py_drspipe, *py_invocation_id; struct ldb_context *samdb; struct loadparm_context *lp; struct replicate_state *s; NTSTATUS status; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOO", + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOOO", discard_const_p(char *, kwnames), - &py_ldb, &py_lp, &py_drspipe)) { + &py_ldb, &py_lp, &py_drspipe, + &py_invocation_id)) { return NULL; } @@ -392,6 +395,12 @@ static PyObject *py_net_replicate_init(py_net_Object *self, PyObject *args, PyOb talloc_free(s); return NULL; } + if (!py_check_dcerpc_type(py_invocation_id, "samba.dcerpc.misc", "GUID")) { + + talloc_free(s); + return NULL; + } + s->dest_dsa.invocation_id = *pytalloc_get_type(py_invocation_id, struct GUID); s->drs_pipe = (dcerpc_InterfaceObject *)(py_drspipe);