CVE-2016-2118: s4:rpc_server: make it possible to define a min_auth_level on a presen...
[samba.git] / source4 / rpc_server / dcerpc_server.c
index df0ffc882c29007b052da09161506baaeaeaa6ec..264b101e8400bcbbe427b43206433fe673fdea3d 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);