CVE-2015-5370: s3:rpc_server: ensure that the message ordering doesn't violate the...
authorJeremy Allison <jra@samba.org>
Tue, 7 Jul 2015 07:15:39 +0000 (09:15 +0200)
committerStefan Metzmacher <metze@samba.org>
Wed, 30 Mar 2016 02:39:48 +0000 (04:39 +0200)
The first pdu is always a BIND.

REQUEST pdus are only allowed once the authentication
is finished.

A simple anonymous authentication is finished after the BIND.
Real authentication may need additional ALTER or AUTH3 exchanges.

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11344

Signed-off-by: Jeremy Allison <jra@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Günther Deschner <gd@samba.org>
source3/rpc_server/rpc_handles.c
source3/rpc_server/rpc_pipes.h
source3/rpc_server/srv_pipe.c

index 4e2edc6db963db6adf4dcfb0a6e5819677bf99bf..62b545c55c9ccc7d665cbd960ffe73aac40e81e0 100644 (file)
@@ -69,6 +69,7 @@ int make_base_pipes_struct(TALLOC_CTX *mem_ctx,
        p->msg_ctx = msg_ctx;
        p->transport = transport;
        p->endian = endian;
+       p->allow_bind = true;
 
        p->remote_address = tsocket_address_copy(remote_address, p);
        if (p->remote_address == NULL) {
index 14b870532c828422f3fd64f3acc48b0947a5f20c..d44ee92bd5c0b137151530b98220a877eea4af4b 100644 (file)
@@ -130,6 +130,13 @@ struct pipes_struct {
 
        bool pipe_bound;
 
+       /*
+        * States we can be in.
+        */
+       bool allow_alter;
+       bool allow_bind;
+       bool allow_auth3;
+
        /*
         * Set the DCERPC_FAULT to return.
         */
index 96bf212b705c2f6ba026aa0f90a343e5770d630f..3b36a2a62136d7308698f582d226891c13f9d1c0 100644 (file)
@@ -282,6 +282,9 @@ static bool setup_bind_nak(struct pipes_struct *p, struct ncacn_packet *pkt)
        p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE;
        p->auth.auth_type = DCERPC_AUTH_TYPE_NONE;
        p->pipe_bound = False;
+       p->allow_bind = false;
+       p->allow_alter = false;
+       p->allow_auth3 = false;
 
        return True;
 }
@@ -636,11 +639,11 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
        DATA_BLOB auth_blob = data_blob_null;
        const struct ndr_interface_table *table;
 
-       /* No rebinds on a bound pipe - use alter context. */
-       if (p->pipe_bound) {
-               DEBUG(2,("Rejecting bind request on bound rpc connection\n"));
+       if (!p->allow_bind) {
+               DEBUG(2,("Pipe not in allow bind state\n"));
                return setup_bind_nak(p, pkt);
        }
+       p->allow_bind = false;
 
        if (pkt->u.bind.num_contexts == 0) {
                DEBUG(0, ("api_pipe_bind_req: no rpc contexts around\n"));
@@ -722,7 +725,6 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
                bind_ack_ctx.reason.value = 0;
                bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0];
        } else {
-               p->pipe_bound = False;
                /* Rejection reason: abstract syntax not supported */
                bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
                bind_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX;
@@ -751,7 +753,6 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
        } else {
                p->auth.auth_type = DCERPC_AUTH_TYPE_NONE;
                p->auth.auth_level = DCERPC_AUTH_LEVEL_NONE;
-               p->pipe_bound = True;
        }
 
        ZERO_STRUCT(u.bind_ack);
@@ -838,6 +839,22 @@ static bool api_pipe_bind_req(struct pipes_struct *p,
        p->out_data.current_pdu_sent = 0;
 
        TALLOC_FREE(auth_blob.data);
+
+       if (bind_ack_ctx.result == 0) {
+               p->allow_alter = true;
+               p->allow_auth3 = true;
+               if (p->auth.auth_type == DCERPC_AUTH_TYPE_NONE) {
+                       status = pipe_auth_verify_final(p);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(0, ("pipe_auth_verify_final failed: %s\n",
+                                         nt_errstr(status)));
+                               goto err_exit;
+                       }
+               }
+       } else {
+               goto err_exit;
+       }
+
        return True;
 
   err_exit:
@@ -860,6 +877,11 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt)
 
        DEBUG(5, ("api_pipe_bind_auth3: decode request. %d\n", __LINE__));
 
+       if (!p->allow_auth3) {
+               DEBUG(1, ("Pipe not in allow auth3 state.\n"));
+               goto err;
+       }
+
        /* We can only finish if the pipe is unbound for now */
        if (p->pipe_bound) {
                DEBUG(0, (__location__ ": Pipe already bound, "
@@ -934,6 +956,10 @@ bool api_pipe_bind_auth3(struct pipes_struct *p, struct ncacn_packet *pkt)
 
 err:
        p->pipe_bound = false;
+       p->allow_bind = false;
+       p->allow_alter = false;
+       p->allow_auth3 = false;
+
        TALLOC_FREE(p->auth.auth_ctx);
        return false;
 }
@@ -957,6 +983,11 @@ static bool api_pipe_alter_context(struct pipes_struct *p,
 
        DEBUG(5,("api_pipe_alter_context: make response. %d\n", __LINE__));
 
+       if (!p->allow_alter) {
+               DEBUG(1, ("Pipe not in allow alter state.\n"));
+               goto err_exit;
+       }
+
        if (pkt->u.bind.assoc_group_id != 0) {
                assoc_gid = pkt->u.bind.assoc_group_id;
        } else {
@@ -982,7 +1013,6 @@ static bool api_pipe_alter_context(struct pipes_struct *p,
                bind_ack_ctx.reason.value = 0;
                bind_ack_ctx.syntax = pkt->u.bind.ctx_list[0].transfer_syntaxes[0];
        } else {
-               p->pipe_bound = False;
                /* Rejection reason: abstract syntax not supported */
                bind_ack_ctx.result = DCERPC_BIND_PROVIDER_REJECT;
                bind_ack_ctx.reason.value = DCERPC_BIND_REASON_ASYNTAX;
@@ -1383,6 +1413,10 @@ void set_incoming_fault(struct pipes_struct *p)
        p->in_data.pdu.length = 0;
        p->fault_state = DCERPC_FAULT_CANT_PERFORM;
 
+       p->allow_alter = false;
+       p->allow_auth3 = false;
+       p->pipe_bound = false;
+
        DEBUG(10, ("Setting fault state\n"));
 }