CVE-2016-2118: s4:rpc_server: make use of "allow dcerpc auth level connect"
authorStefan Metzmacher <metze@samba.org>
Thu, 10 Mar 2016 01:46:59 +0000 (02:46 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 12 Apr 2016 17:25:27 +0000 (19:25 +0200)
With this option turned off we only allow DCERPC_AUTH_LEVEL_{NONE,INTEGRITY,PRIVACY},
this means the reject any request with AUTH_LEVEL_CONNECT with ACCESS_DENIED.

We sadly need to keep this enabled by default for now.

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 264b101e8400bcbbe427b43206433fe673fdea3d..9250f8411adc000bb1dd6572ec860c57910f1cae 100644 (file)
@@ -512,9 +512,29 @@ static int dcesrv_connection_context_destructor(struct dcesrv_connection_context
 
 static void dcesrv_prepare_context_auth(struct dcesrv_call_state *dce_call)
 {
+       struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+       const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
+       enum dcerpc_transport_t transport =
+               dcerpc_binding_get_transport(endpoint->ep_description);
        struct dcesrv_connection_context *context = dce_call->context;
+       const struct dcesrv_interface *iface = context->iface;
 
        context->min_auth_level = DCERPC_AUTH_LEVEL_NONE;
+
+       if (transport == NCALRPC) {
+               context->allow_connect = true;
+               return;
+       }
+
+       /*
+        * allow overwrite per interface
+        * allow dcerpc auth level connect:<interface>
+        */
+       context->allow_connect = lpcfg_allow_dcerpc_auth_level_connect(lp_ctx);
+       context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
+                                       "allow dcerpc auth level connect",
+                                       iface->name,
+                                       context->allow_connect);
 }
 
 NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_state *dce_call,
@@ -539,6 +559,66 @@ NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_cal
        return NT_STATUS_OK;
 }
 
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_call_state *dce_call,
+                                                      const struct dcesrv_interface *iface)
+{
+       struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+       const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
+       enum dcerpc_transport_t transport =
+               dcerpc_binding_get_transport(endpoint->ep_description);
+       struct dcesrv_connection_context *context = dce_call->context;
+
+       if (context == NULL) {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       if (transport == NCALRPC) {
+               context->allow_connect = true;
+               return NT_STATUS_OK;
+       }
+
+       /*
+        * allow overwrite per interface
+        * allow dcerpc auth level connect:<interface>
+        */
+       context->allow_connect = false;
+       context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
+                                       "allow dcerpc auth level connect",
+                                       iface->name,
+                                       context->allow_connect);
+       return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *dce_call,
+                                                     const struct dcesrv_interface *iface)
+{
+       struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+       const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
+       enum dcerpc_transport_t transport =
+               dcerpc_binding_get_transport(endpoint->ep_description);
+       struct dcesrv_connection_context *context = dce_call->context;
+
+       if (context == NULL) {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       if (transport == NCALRPC) {
+               context->allow_connect = true;
+               return NT_STATUS_OK;
+       }
+
+       /*
+        * allow overwrite per interface
+        * allow dcerpc auth level connect:<interface>
+        */
+       context->allow_connect = true;
+       context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
+                                       "allow dcerpc auth level connect",
+                                       iface->name,
+                                       context->allow_connect);
+       return NT_STATUS_OK;
+}
+
 /*
   handle a bind request
 */
@@ -1040,6 +1120,30 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
                auth_level = call->conn->auth_state.auth_info->auth_level;
        }
 
+       switch (auth_level) {
+       case DCERPC_AUTH_LEVEL_NONE:
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+               break;
+       default:
+               if (!context->allow_connect) {
+                       char *addr;
+
+                       addr = tsocket_address_string(call->conn->remote_address,
+                                                     call);
+
+                       DEBUG(2, ("%s: restrict auth_level_connect access "
+                                 "to [%s] with auth[type=0x%x,level=0x%x] "
+                                 "on [%s] from [%s]\n",
+                                 __func__, context->iface->name,
+                                 auth_type, auth_level,
+                                 derpc_transport_string_by_transport(transport),
+                                 addr));
+                       return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
+               }
+               break;
+       }
+
        if (auth_level < context->min_auth_level) {
                char *addr;
 
index 26c5c72be3158822791cc34ddd8494796d649b80..e6ddf6573314ffa0c3a7cc14839f8be77611a07c 100644 (file)
@@ -178,6 +178,7 @@ struct dcesrv_connection_context {
         * the minimum required auth level for this interface
         */
        enum dcerpc_AuthLevel min_auth_level;
+       bool allow_connect;
 };
 
 
@@ -428,5 +429,9 @@ _PUBLIC_ NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_call_sta
                                                          const struct dcesrv_interface *iface);
 _PUBLIC_ NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_call_state *dce_call,
                                                        const struct dcesrv_interface *iface);
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_call_state *dce_call,
+                                                      const struct dcesrv_interface *iface);
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *dce_call,
+                                                     const struct dcesrv_interface *iface);
 
 #endif /* SAMBA_DCERPC_SERVER_H */