From bc56157aecce9f4d0df2ea15d18096c09af38ac7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Jul 2024 18:01:24 +0200 Subject: [PATCH 1/8] dcesrv_core: public dcesrv_call_disconnect_after() Signed-off-by: Stefan Metzmacher --- librpc/rpc/dcesrv_core.c | 4 ++-- librpc/rpc/dcesrv_core.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/librpc/rpc/dcesrv_core.c b/librpc/rpc/dcesrv_core.c index c0a4150e3b3c..f291247e1e28 100644 --- a/librpc/rpc/dcesrv_core.c +++ b/librpc/rpc/dcesrv_core.c @@ -768,8 +768,8 @@ static void dcesrv_call_set_list(struct dcesrv_call_state *call, } } -static void dcesrv_call_disconnect_after(struct dcesrv_call_state *call, - const char *reason) +void dcesrv_call_disconnect_after(struct dcesrv_call_state *call, + const char *reason) { struct dcesrv_auth *a = NULL; diff --git a/librpc/rpc/dcesrv_core.h b/librpc/rpc/dcesrv_core.h index 3758c8d7de2e..384ab08a608f 100644 --- a/librpc/rpc/dcesrv_core.h +++ b/librpc/rpc/dcesrv_core.h @@ -564,6 +564,9 @@ NTSTATUS dcesrv_auth_session_key(struct dcesrv_call_state *call, NTSTATUS dcesrv_transport_session_key(struct dcesrv_call_state *call, DATA_BLOB *session_key); +void dcesrv_call_disconnect_after(struct dcesrv_call_state *call, + const char *reason); + /* a useful macro for generating a RPC fault in the backend code */ #define DCESRV_FAULT(code) do { \ dce_call->fault_code = code; \ -- 2.34.1 From 0dd68a20c133837e9c7b40fcc4e216e066482261 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Jul 2024 18:02:57 +0200 Subject: [PATCH 2/8] dcesrv_fault_with_flags => DCERPC_FAULT_ACCESS_DENIED => dcesrv_call_disconnect_after --- librpc/rpc/dcesrv_reply.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/librpc/rpc/dcesrv_reply.c b/librpc/rpc/dcesrv_reply.c index 4890169c98b0..59a6790d5aa4 100644 --- a/librpc/rpc/dcesrv_reply.c +++ b/librpc/rpc/dcesrv_reply.c @@ -102,6 +102,11 @@ NTSTATUS dcesrv_fault_with_flags(struct dcesrv_call_state *call, return NT_STATUS_OK; } + if (fault_code == DCERPC_FAULT_ACCESS_DENIED) { + dcesrv_call_disconnect_after(call, + "DCERPC_FAULT_ACCESS_DENIED"); + } + /* setup a fault */ dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)); pkt.auth_length = 0; -- 2.34.1 From b136fba38ebb85bdd9d03884246a5dcca5a45526 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Jul 2024 18:04:56 +0200 Subject: [PATCH 3/8] smb2_ioctl_named_pipe: make use of nt_status_np_pipe() We should return NT_STATUS_PIPE_DISCONNECTED or NT_STATUS_PIPE_BROKEN in the same way SMB2 read/write do it. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15680 Signed-off-by: Stefan Metzmacher --- source3/smbd/smb2_ioctl_named_pipe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source3/smbd/smb2_ioctl_named_pipe.c b/source3/smbd/smb2_ioctl_named_pipe.c index f9e3dec049c0..4c1967cca67a 100644 --- a/source3/smbd/smb2_ioctl_named_pipe.c +++ b/source3/smbd/smb2_ioctl_named_pipe.c @@ -123,6 +123,7 @@ static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq) TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { + status = nt_status_np_pipe(status); tevent_req_nterror(req, status); return; } @@ -173,6 +174,7 @@ static void smbd_smb2_ioctl_pipe_read_done(struct tevent_req *subreq) TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { + status = nt_status_np_pipe(status); tevent_req_nterror(req, status); return; } -- 2.34.1 From 46b68a82eb0c0706f8a50ad7a0348129bd49d4ba Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Jul 2024 18:11:49 +0200 Subject: [PATCH 4/8] py_dcerpc_interface_init_helper dcerpc_secondary_auth_connection --- source4/librpc/rpc/pyrpc_util.c | 67 +++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 8 deletions(-) diff --git a/source4/librpc/rpc/pyrpc_util.c b/source4/librpc/rpc/pyrpc_util.c index 43c29af0e76a..5b11cab1aeec 100644 --- a/source4/librpc/rpc/pyrpc_util.c +++ b/source4/librpc/rpc/pyrpc_util.c @@ -160,6 +160,8 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py struct dcerpc_pipe *base_pipe; PyObject *py_base; PyTypeObject *ClientConnection_Type; + struct loadparm_context *lp_ctx = NULL; + struct cli_credentials *credentials = NULL; py_base = PyImport_ImportModule("samba.dcerpc.base"); if (py_base == NULL) { @@ -204,16 +206,65 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py return NULL; } - status = dcerpc_secondary_context(base_pipe, &ret->pipe, table); - if (!NT_STATUS_IS_OK(status)) { - PyErr_SetNTSTATUS(status); - Py_DECREF(ret); - Py_DECREF(py_base); - Py_DECREF(ClientConnection_Type); - return NULL; + if (py_lp_ctx != Py_None) { + lp_ctx = lpcfg_from_py_object(ret->ev, py_lp_ctx); + if (lp_ctx == NULL) { + PyErr_SetString(PyExc_TypeError, "Expected loadparm context"); + Py_DECREF(ret); + return NULL; + } + } + + if (py_credentials != Py_None) { + credentials = cli_credentials_from_py_object(py_credentials); + if (credentials == NULL) { + PyErr_SetString(PyExc_TypeError, "Expected credentials"); + Py_DECREF(ret); + return NULL; + } + } + + if (credentials != NULL && lp_ctx != NULL) { + struct dcerpc_binding *binding = NULL; + + status = dcerpc_parse_binding(ret->mem_ctx, + binding_string, + &binding); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + Py_DECREF(ret); + Py_DECREF(py_base); + Py_DECREF(ClientConnection_Type); + return NULL; + } + + status = dcerpc_secondary_auth_connection(base_pipe, + binding, + table, + credentials, + lp_ctx, + ret->mem_ctx, + &ret->pipe); + // TALLOC_FREE(binding); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + Py_DECREF(ret); + Py_DECREF(py_base); + Py_DECREF(ClientConnection_Type); + return NULL; + } + } else { + status = dcerpc_secondary_context(base_pipe, &ret->pipe, table); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + Py_DECREF(ret); + Py_DECREF(py_base); + Py_DECREF(ClientConnection_Type); + return NULL; + } + ret->pipe = talloc_steal(ret->mem_ctx, ret->pipe); } - ret->pipe = talloc_steal(ret->mem_ctx, ret->pipe); Py_XDECREF(ClientConnection_Type); Py_XDECREF(py_base); } else { -- 2.34.1 From 16289009b461d8210dca36dc166a27cef9bdfb73 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Jul 2024 18:12:31 +0200 Subject: [PATCH 5/8] OpenPolicyFallback based on in_revision_info is not None caller fallback --- python/samba/lsa_utils.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/python/samba/lsa_utils.py b/python/samba/lsa_utils.py index 043e65f3341b..5eaf23af2bad 100644 --- a/python/samba/lsa_utils.py +++ b/python/samba/lsa_utils.py @@ -48,7 +48,7 @@ def OpenPolicyFallback( attr.sec_qos = qos - try: + if in_revision_info is not None: out_version, out_rev_info, policy = conn.OpenPolicy3( system_name, attr, @@ -56,16 +56,13 @@ def OpenPolicyFallback( in_version, in_revision_info ) - except NTSTATUSError as e: - if e.args[0] == NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE: - out_version = 1 - out_rev_info = lsa.revision_info1() - out_rev_info.revision = 1 - out_rev_info.supported_features = 0 - - policy = conn.OpenPolicy2(system_name, attr, access_mask) - else: - raise + else: + out_version = 1 + out_rev_info = lsa.revision_info1() + out_rev_info.revision = 1 + out_rev_info.supported_features = 0 + + policy = conn.OpenPolicy2(system_name, attr, access_mask) return out_version, out_rev_info, policy -- 2.34.1 From 791a51440c90ad485064886d2d10ab58311f280b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Jul 2024 18:13:56 +0200 Subject: [PATCH 6/8] python/samba/netcmd/domain/trust.py OpenPolicyFallback 3 => 2 --- python/samba/netcmd/domain/trust.py | 66 +++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/python/samba/netcmd/domain/trust.py b/python/samba/netcmd/domain/trust.py index 0784fa5e2822..a2e15d3550f9 100644 --- a/python/samba/netcmd/domain/trust.py +++ b/python/samba/netcmd/domain/trust.py @@ -52,10 +52,12 @@ class DomainTrustCommand(Command): self.local_server = None self.local_binding_string = None self.local_creds = None + self._last_local_lsa = None self.remote_server = None self.remote_binding_string = None self.remote_creds = None + self._last_remote_lsa = None def _uint32(self, v): return ctypes.c_uint32(v).value @@ -125,8 +127,13 @@ class DomainTrustCommand(Command): self.local_creds = local_creds return self.local_server - def new_local_lsa_connection(self): - return lsa.lsarpc(self.local_binding_string, self.local_lp, self.local_creds) + def new_local_lsa_connection(self, basis_connection=None): + conn = lsa.lsarpc(self.local_binding_string, self.local_lp, + self.local_creds, + basis_connection=basis_connection) + if basis_connection is None: + self._last_local_lsa = conn + return conn def new_local_netlogon_connection(self): return netlogon.netlogon(self.local_binding_string, self.local_lp, self.local_creds) @@ -203,8 +210,12 @@ class DomainTrustCommand(Command): self.remote_creds = remote_creds return self.remote_server - def new_remote_lsa_connection(self): - return lsa.lsarpc(self.remote_binding_string, self.local_lp, self.remote_creds) + def new_remote_lsa_connection(self, basis_connection=None): + conn = lsa.lsarpc(self.remote_binding_string, self.local_lp, + self.remote_creds, basis_connection=basis_connection) + if basis_connection is None: + self._last_remote_lsa = conn + return conn def new_remote_netlogon_connection(self): return netlogon.netlogon(self.remote_binding_string, self.local_lp, self.remote_creds) @@ -217,17 +228,40 @@ class DomainTrustCommand(Command): lsa.LSA_FEATURE_TDO_AUTH_INFO_AES_CIPHER ) - out_version, out_revision_info1, policy = OpenPolicyFallback( - conn, - b''.decode('utf-8'), - in_version, - in_revision_info1, - policy_access - ) + try: + out_version, out_revision_info1, policy = OpenPolicyFallback( + conn, + b''.decode('utf-8'), + in_version, + in_revision_info1, + policy_access + ) + except NTSTATUSError as e: + if e.args[0] != ntstatus.NT_STATUS_ACCESS_DENIED: + raise + if self._last_local_lsa is conn: + new_conn_fn = self.new_local_lsa_connection + self._last_local_lsa = None + if self._last_remote_lsa is conn: + new_conn_fn = self.new_remote_lsa_connection + self._last_remote_lsa = None + + in_revision_info1 = None + + if in_revision_info1 is None: + conn = new_conn_fn(basis_connection=conn) + + out_version, out_revision_info1, policy = OpenPolicyFallback( + conn, + b''.decode('utf-8'), + in_version, + in_revision_info1, + policy_access + ) info = conn.QueryInfoPolicy2(policy, lsa.LSA_POLICY_INFO_DNS) - return (policy, out_version, out_revision_info1, info) + return (conn, policy, out_version, out_revision_info1, info) def get_netlogon_dc_unc(self, conn, server, domain): try: @@ -515,6 +549,7 @@ class cmd_domain_trust_show(DomainTrustCommand): try: local_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION ( + local_lsa, local_policy, local_version, local_revision_info1, @@ -656,6 +691,7 @@ class cmd_domain_trust_modify(DomainTrustCommand): try: local_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION ( + local_lsa, local_policy, local_version, local_revision_info1, @@ -914,6 +950,7 @@ class cmd_domain_trust_create(DomainTrustCommand): try: ( + local_lsa, local_policy, local_version, local_revision_info1, @@ -939,6 +976,7 @@ class cmd_domain_trust_create(DomainTrustCommand): try: ( + remote_lsa, remote_policy, remote_version, remote_revision_info1, @@ -1303,6 +1341,7 @@ class cmd_domain_trust_delete(DomainTrustCommand): try: ( + local_lsa, local_policy, local_version, local_revision_info1, @@ -1344,6 +1383,7 @@ class cmd_domain_trust_delete(DomainTrustCommand): try: ( + remote_lsa, remote_policy, remote_version, remote_revision_info1, @@ -1456,6 +1496,7 @@ class cmd_domain_trust_validate(DomainTrustCommand): try: ( + local_lsa, local_policy, local_version, local_revision_info1, @@ -1896,6 +1937,7 @@ class cmd_domain_trust_namespaces(DomainTrustCommand): try: ( + local_lsa, local_policy, local_version, local_revision_info1, -- 2.34.1 From 747032021a725196c56b71a8a7275d884c465f91 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Jul 2024 18:14:28 +0200 Subject: [PATCH 7/8] HACK dcerpc_lsa_open_policy_fallback only 2 --- source3/rpc_client/cli_lsarpc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c index 73b4872a2c4a..61469411a37c 100644 --- a/source3/rpc_client/cli_lsarpc.c +++ b/source3/rpc_client/cli_lsarpc.c @@ -179,6 +179,7 @@ NTSTATUS dcerpc_lsa_open_policy_fallback(struct dcerpc_binding_handle *h, { NTSTATUS status; + goto policy2; status = dcerpc_lsa_open_policy3(h, mem_ctx, srv_name_slash, @@ -188,7 +189,10 @@ NTSTATUS dcerpc_lsa_open_policy_fallback(struct dcerpc_binding_handle *h, out_revision_info, pol, result); - if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) || + NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) + { +policy2: *out_version = 1; *out_revision_info = (union lsa_revision_info) { .info1 = { -- 2.34.1 From c35251cbf55b7f6d73734f567aafdf78f1958b78 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 17 Jul 2024 18:14:46 +0200 Subject: [PATCH 8/8] HACK dcesrv_lsa_OpenPolicy3 simulate windows <= 2016 --- source4/rpc_server/lsa/lsa_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/rpc_server/lsa/lsa_init.c b/source4/rpc_server/lsa/lsa_init.c index bc5dadd5bd69..76dddd700de9 100644 --- a/source4/rpc_server/lsa/lsa_init.c +++ b/source4/rpc_server/lsa/lsa_init.c @@ -232,7 +232,7 @@ NTSTATUS dcesrv_lsa_OpenPolicy3(struct dcesrv_call_state *dce_call, struct dcesrv_handle *handle = NULL; NTSTATUS status; - if (transport != NCACN_NP && transport != NCALRPC) { + if (transport != NCALRPC) { DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } -- 2.34.1