CVE-2016-2118: s4:rpc_server: make it possible to define a min_auth_level on a presen...
authorStefan Metzmacher <metze@samba.org>
Tue, 14 Jul 2015 07:12:18 +0000 (09:12 +0200)
committerStefan Metzmacher <metze@samba.org>
Wed, 30 Mar 2016 02:08:19 +0000 (04:08 +0200)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11616

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Günther Deschner <gd@samba.org>
source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_server.h

index b1c763b76f7df488a664638386a3dae73dd81e43..5828baad102dd00b42ae2dd01bde26602f992418 100644 (file)
@@ -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);
 
index 8786cd83cc6fd14feb1e6e40e9a911a9f4375140..3e40710665c6112abbc0d01d38508c58b427df52 100644 (file)
@@ -168,6 +168,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;
 };
 
 
@@ -407,5 +412,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 */