s4:rpc_server: fix DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN negotiation to match Windows
authorStefan Metzmacher <metze@samba.org>
Wed, 21 Nov 2018 08:39:36 +0000 (09:39 +0100)
committerJeremy Allison <jra@samba.org>
Sat, 12 Jan 2019 02:13:40 +0000 (03:13 +0100)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=7113
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11892

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
selftest/knownfail.d/test_krb5_hdr_sign_delayed [deleted file]
source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_server.h
source4/rpc_server/dcesrv_auth.c

diff --git a/selftest/knownfail.d/test_krb5_hdr_sign_delayed b/selftest/knownfail.d/test_krb5_hdr_sign_delayed
deleted file mode 100644 (file)
index 62231cb..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-^samba.tests.dcerpc.raw_protocol.*.TestDCERPC_BIND.test_krb5_hdr_sign_delayed1
-^samba.tests.dcerpc.raw_protocol.*.TestDCERPC_BIND.test_krb5_hdr_sign_delayed2
index 6a41173..b34585d 100644 (file)
@@ -599,6 +599,12 @@ static NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
        p->max_xmit_frag = 5840;
        p->max_total_request_size = DCERPC_NCACN_REQUEST_DEFAULT_MAX_SIZE;
 
+       p->support_hdr_signing = lpcfg_parm_bool(dce_ctx->lp_ctx,
+                                                NULL,
+                                                "dcesrv",
+                                                "header signing",
+                                                true);
+
        auth = dcesrv_auth_create(p);
        if (auth == NULL) {
                talloc_free(p);
@@ -1787,8 +1793,7 @@ static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
 static NTSTATUS dcesrv_check_verification_trailer(struct dcesrv_call_state *call)
 {
        TALLOC_CTX *frame = talloc_stackframe();
-       const struct dcesrv_auth *auth = call->auth_state;
-       const uint32_t bitmask1 = auth->client_hdr_signing ?
+       const uint32_t bitmask1 = call->conn->client_hdr_signing ?
                DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING : 0;
        const struct dcerpc_sec_vt_pcontext pcontext = {
                .abstract_syntax = call->context->iface->syntax_id,
index 8e404c0..44bf6e6 100644 (file)
@@ -203,8 +203,6 @@ struct dcesrv_auth {
        struct gensec_security *gensec_security;
        struct auth_session_info *session_info;
        NTSTATUS (*session_key_fn)(struct dcesrv_auth *, DATA_BLOB *session_key);
-       bool client_hdr_signing;
-       bool hdr_signing;
        bool auth_started;
        bool auth_finished;
        bool auth_invalid;
@@ -290,6 +288,9 @@ struct dcesrv_connection {
 
        /* the current authentication state */
        struct dcesrv_auth *default_auth_state;
+       bool client_hdr_signing;
+       bool support_hdr_signing;
+       bool negotiated_hdr_signing;
 
        /*
         * remember which pdu types are allowed
index 98827ff..192d90b 100644 (file)
 #include "param/param.h"
 #include "librpc/rpc/rpc_common.h"
 
+static NTSTATUS dcesrv_auth_negotiate_hdr_signing(struct dcesrv_call_state *call,
+                                                 struct ncacn_packet *pkt)
+{
+       struct dcesrv_connection *dce_conn = call->conn;
+       struct dcesrv_auth *auth = call->auth_state;
+
+       if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
+               return NT_STATUS_OK;
+       }
+
+       if (dce_conn->client_hdr_signing) {
+               if (dce_conn->negotiated_hdr_signing && pkt != NULL) {
+                       pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
+               }
+               return NT_STATUS_OK;
+       }
+
+       dce_conn->client_hdr_signing = true;
+       dce_conn->negotiated_hdr_signing = dce_conn->support_hdr_signing;
+
+       if (!dce_conn->negotiated_hdr_signing) {
+               return NT_STATUS_OK;
+       }
+
+       if (pkt != NULL) {
+               pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
+       }
+
+       if (auth->gensec_security == NULL) {
+               return NT_STATUS_OK;
+       }
+
+       gensec_want_feature(auth->gensec_security,
+                           GENSEC_FEATURE_SIGN_PKT_HEADER);
+
+       return NT_STATUS_OK;
+}
+
 static bool dcesrv_auth_prepare_gensec(struct dcesrv_call_state *call)
 {
        struct cli_credentials *server_credentials = NULL;
        struct dcesrv_connection *dce_conn = call->conn;
        struct dcesrv_auth *auth = call->auth_state;
-       bool want_header_signing = false;
        NTSTATUS status;
 
        if (auth->auth_started) {
@@ -180,28 +217,9 @@ static bool dcesrv_auth_prepare_gensec(struct dcesrv_call_state *call)
                return false;
        }
 
-       if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
-               auth->client_hdr_signing = true;
-               want_header_signing = true;
-       }
-
-       if (want_header_signing) {
-               want_header_signing = gensec_have_feature(auth->gensec_security,
-                                               GENSEC_FEATURE_SIGN_PKT_HEADER);
-       }
-
-       if (want_header_signing) {
-               want_header_signing = lpcfg_parm_bool(dce_conn->dce_ctx->lp_ctx,
-                                                     NULL,
-                                                     "dcesrv",
-                                                     "header signing",
-                                                     true);
-       }
-
-       if (want_header_signing) {
+       if (dce_conn->negotiated_hdr_signing) {
                gensec_want_feature(auth->gensec_security,
                                    GENSEC_FEATURE_SIGN_PKT_HEADER);
-               auth->hdr_signing = true;
        }
 
        return true;
@@ -341,6 +359,12 @@ NTSTATUS dcesrv_auth_prepare_bind_ack(struct dcesrv_call_state *call, struct nca
 {
        struct dcesrv_connection *dce_conn = call->conn;
        struct dcesrv_auth *auth = call->auth_state;
+       NTSTATUS status;
+
+       status = dcesrv_auth_negotiate_hdr_signing(call, pkt);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
        dce_conn->allow_alter = true;
 
@@ -354,10 +378,6 @@ NTSTATUS dcesrv_auth_prepare_bind_ack(struct dcesrv_call_state *call, struct nca
                return NT_STATUS_INTERNAL_ERROR;
        }
 
-       if (auth->hdr_signing) {
-               pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
-       }
-
        call->_out_auth_info = (struct dcerpc_auth) {
                .auth_type = auth->auth_type,
                .auth_level = auth->auth_level,
@@ -486,6 +506,12 @@ bool dcesrv_auth_alter(struct dcesrv_call_state *call)
 NTSTATUS dcesrv_auth_prepare_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
 {
        struct dcesrv_auth *auth = call->auth_state;
+       NTSTATUS status;
+
+       status = dcesrv_auth_negotiate_hdr_signing(call, pkt);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
        /* on a pure interface change there is no auth_info structure
           setup */