From 51aa7bd3115d2962bc2f6f8c1ea2fa80998d119f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 14 Jul 2015 09:12:18 +0200 Subject: [PATCH] CVE-2016-2118: s4:rpc_server: make it possible to define a min_auth_level on a presentation context MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit BUG: https://bugzilla.samba.org/show_bug.cgi?id=11616 Signed-off-by: Stefan Metzmacher Reviewed-by: Günther Deschner --- source4/rpc_server/dcerpc_server.c | 60 ++++++++++++++++++++++++++++++ source4/rpc_server/dcerpc_server.h | 9 +++++ 2 files changed, 69 insertions(+) diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index df0ffc882c2..264b101e840 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -510,6 +510,35 @@ static int dcesrv_connection_context_destructor(struct dcesrv_connection_context return 0; } +static void dcesrv_prepare_context_auth(struct dcesrv_call_state *dce_call) +{ + struct dcesrv_connection_context *context = dce_call->context; + + context->min_auth_level = DCERPC_AUTH_LEVEL_NONE; +} + +NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + if (dce_call->context == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_INTEGRITY; + return NT_STATUS_OK; +} + +NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + if (dce_call->context == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + dce_call->context->min_auth_level = DCERPC_AUTH_LEVEL_PRIVACY; + return NT_STATUS_OK; +} + /* handle a bind request */ @@ -597,6 +626,8 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) call->context = context; talloc_set_destructor(context, dcesrv_connection_context_destructor); + dcesrv_prepare_context_auth(call); + status = iface->bind(call, iface, if_version); if (!NT_STATUS_IS_OK(status)) { char *uuid_str = GUID_string(call, &uuid); @@ -781,6 +812,8 @@ static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_ call->context = context; talloc_set_destructor(context, dcesrv_connection_context_destructor); + dcesrv_prepare_context_auth(call); + status = iface->bind(call, iface, if_version); if (!NT_STATUS_IS_OK(status)) { /* we don't want to trigger the iface->unbind() hook */ @@ -982,9 +1015,14 @@ done: */ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) { + const struct dcesrv_endpoint *endpoint = call->conn->endpoint; + enum dcerpc_transport_t transport = + dcerpc_binding_get_transport(endpoint->ep_description); struct ndr_pull *pull; NTSTATUS status; struct dcesrv_connection_context *context; + uint32_t auth_type = DCERPC_AUTH_TYPE_NONE; + uint32_t auth_level = DCERPC_AUTH_LEVEL_NONE; /* if authenticated, and the mech we use can't do async replies, don't use them... */ if (call->conn->auth_state.gensec_security && @@ -997,6 +1035,28 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) return dcesrv_fault(call, DCERPC_FAULT_UNK_IF); } + if (call->conn->auth_state.auth_info != NULL) { + auth_type = call->conn->auth_state.auth_info->auth_type; + auth_level = call->conn->auth_state.auth_info->auth_level; + } + + if (auth_level < context->min_auth_level) { + char *addr; + + addr = tsocket_address_string(call->conn->remote_address, call); + + DEBUG(2, ("%s: restrict access by min_auth_level[0x%x] " + "to [%s] with auth[type=0x%x,level=0x%x] " + "on [%s] from [%s]\n", + __func__, + context->min_auth_level, + context->iface->name, + auth_type, auth_level, + derpc_transport_string_by_transport(transport), + addr)); + return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED); + } + pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call); NT_STATUS_HAVE_NO_MEMORY(pull); diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h index 9f5cfaba5b5..26c5c72be31 100644 --- a/source4/rpc_server/dcerpc_server.h +++ b/source4/rpc_server/dcerpc_server.h @@ -173,6 +173,11 @@ struct dcesrv_connection_context { /* private data for the interface implementation */ void *private_data; + + /* + * the minimum required auth level for this interface + */ + enum dcerpc_AuthLevel min_auth_level; }; @@ -419,5 +424,9 @@ _PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call); */ _PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call); +_PUBLIC_ NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface); +_PUBLIC_ NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface); #endif /* SAMBA_DCERPC_SERVER_H */ -- 2.25.1