]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
CVE-2015-5370: s4:librpc/rpc: send a dcerpc_sec_verification_trailer if needed
authorStefan Metzmacher <metze@samba.org>
Wed, 8 Jul 2015 14:25:48 +0000 (16:25 +0200)
committerStefan Metzmacher <metze@samba.org>
Wed, 30 Mar 2016 02:10:04 +0000 (04:10 +0200)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11344

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

index 31b14f1377d5b48558b3225b24518beb6e29458c..fecc0f29a5d77e338a6d9553b3bb91855a6f2bc4 100644 (file)
@@ -65,6 +65,8 @@ struct rpc_request {
        DATA_BLOB request_data;
        bool ignore_timeout;
        bool wait_for_sync;
+       bool verify_bitmask1;
+       bool verify_pcontext;
 
        struct {
                void (*callback)(struct rpc_request *);
@@ -1545,6 +1547,13 @@ static void dcerpc_request_recv_data(struct dcecli_connection *c,
                return;
        }
 
+       if (req->verify_bitmask1) {
+               req->p->conn->security_state.verified_bitmask1 = true;
+       }
+       if (req->verify_pcontext) {
+               req->p->verified_pcontext = true;
+       }
+
        if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
                req->flags |= DCERPC_PULL_BIGENDIAN;
        } else {
@@ -1569,6 +1578,8 @@ req_done:
        }
 }
 
+static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
+
 /*
   perform the send side of a async dcerpc request
 */
@@ -1579,6 +1590,7 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
                                               DATA_BLOB *stub_data)
 {
        struct rpc_request *req;
+       NTSTATUS status;
 
        req = talloc_zero(mem_ctx, struct rpc_request);
        if (req == NULL) {
@@ -1601,6 +1613,12 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
        req->request_data.length = stub_data->length;
        req->request_data.data = stub_data->data;
 
+       status = dcerpc_request_prepare_vt(req);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(req);
+               return NULL;
+       }
+
        DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
        talloc_set_destructor(req, dcerpc_req_dequeue);
 
@@ -1615,6 +1633,124 @@ static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
        return req;
 }
 
+static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
+{
+       struct dcecli_security *sec = &req->p->conn->security_state;
+       struct dcerpc_sec_verification_trailer *t;
+       struct dcerpc_sec_vt *c = NULL;
+       struct ndr_push *ndr = NULL;
+       enum ndr_err_code ndr_err;
+
+       if (sec->auth_info == NULL) {
+               return NT_STATUS_OK;
+       }
+
+       if (sec->auth_info->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
+               return NT_STATUS_OK;
+       }
+
+       t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
+       if (t == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (!sec->verified_bitmask1) {
+               t->commands = talloc_realloc(t, t->commands,
+                                            struct dcerpc_sec_vt,
+                                            t->count.count + 1);
+               if (t->commands == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               c = &t->commands[t->count.count++];
+               ZERO_STRUCTP(c);
+
+               c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
+               if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
+                       c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
+               }
+               req->verify_bitmask1 = true;
+       }
+
+       if (!req->p->verified_pcontext) {
+               t->commands = talloc_realloc(t, t->commands,
+                                            struct dcerpc_sec_vt,
+                                            t->count.count + 1);
+               if (t->commands == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               c = &t->commands[t->count.count++];
+               ZERO_STRUCTP(c);
+
+               c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
+               c->u.pcontext.abstract_syntax = req->p->syntax;
+               c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
+
+               req->verify_pcontext = true;
+       }
+
+       if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
+               t->commands = talloc_realloc(t, t->commands,
+                                            struct dcerpc_sec_vt,
+                                            t->count.count + 1);
+               if (t->commands == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               c = &t->commands[t->count.count++];
+               ZERO_STRUCTP(c);
+
+               c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
+               c->u.header2.ptype = DCERPC_PKT_REQUEST;
+               if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
+                       c->u.header2.drep[0] = 0;
+               } else {
+                       c->u.header2.drep[0] = DCERPC_DREP_LE;
+               }
+               c->u.header2.drep[1] = 0;
+               c->u.header2.drep[2] = 0;
+               c->u.header2.drep[3] = 0;
+               c->u.header2.call_id = req->call_id;
+               c->u.header2.context_id = req->p->context_id;
+               c->u.header2.opnum = req->opnum;
+       }
+
+       if (t->count.count == 0) {
+               TALLOC_FREE(t);
+               return NT_STATUS_OK;
+       }
+
+       c = &t->commands[t->count.count - 1];
+       c->command |= DCERPC_SEC_VT_COMMAND_END;
+
+       if (DEBUGLEVEL >= 10) {
+               NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
+       }
+
+       ndr = ndr_push_init_ctx(req);
+       if (ndr == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /*
+        * for now we just copy and append
+        */
+
+       ndr_err = ndr_push_bytes(ndr, req->request_data.data,
+                                req->request_data.length);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return ndr_map_error2ntstatus(ndr_err);
+       }
+
+       ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
+                                               NDR_SCALARS | NDR_BUFFERS,
+                                               t);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               return ndr_map_error2ntstatus(ndr_err);
+       }
+       req->request_data = ndr_push_blob(ndr);
+
+       return NT_STATUS_OK;
+}
+
 /*
   Send a request using the transport
 */
index a7d16947707588ad0b2108a33f9cca9cf9c7a5b4..8b2aebede45c7dd28b2138bb890d9ead08b823c6 100644 (file)
@@ -51,6 +51,9 @@ struct dcecli_security {
 
        /* get the session key */
        NTSTATUS (*session_key)(struct dcecli_connection *, DATA_BLOB *);
+
+       bool verified_bitmask1;
+
 };
 
 /*
@@ -126,6 +129,8 @@ struct dcerpc_pipe {
         */
        bool inhibit_timeout_processing;
        bool timed_out;
+
+       bool verified_pcontext;
 };
 
 /* default timeout for all rpc requests, in seconds */