CVE-2015-5370: s4:librpc/rpc: avoid using dcecli_security->auth_info and use per...
[samba.git] / source4 / librpc / rpc / dcerpc_auth.c
index 443c7587e72500d991e2af138908aba71683ad8c..15a843b4ef5a9c86159643b1a90096d6218e3422 100644 (file)
@@ -124,7 +124,8 @@ _PUBLIC_ NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
 
 struct bind_auth_state {
        struct dcerpc_pipe *pipe;
-       DATA_BLOB credentials;
+       struct dcerpc_auth out_auth_info;
+       struct dcerpc_auth in_auth_info;
        bool more_processing;   /* Is there anything more to do after the
                                 * first bind itself received? */
 };
@@ -141,6 +142,12 @@ static void bind_auth_next_step(struct composite_context *c)
        state = talloc_get_type(c->private_data, struct bind_auth_state);
        sec = &state->pipe->conn->security_state;
 
+       state->out_auth_info = (struct dcerpc_auth) {
+               .auth_type = sec->auth_type,
+               .auth_level = sec->auth_level,
+               .auth_context_id = sec->auth_context_id,
+       };
+
        /* The status value here, from GENSEC is vital to the security
         * of the system.  Even if the other end accepts, if GENSEC
         * claims 'MORE_PROCESSING_REQUIRED' then you must keep
@@ -156,16 +163,14 @@ static void bind_auth_next_step(struct composite_context *c)
 
        c->status = gensec_update_ev(sec->generic_state, state,
                                  state->pipe->conn->event_ctx,
-                                 sec->auth_info->credentials,
-                                 &state->credentials);
+                                 state->in_auth_info.credentials,
+                                 &state->out_auth_info.credentials);
        if (state->pipe->timed_out) {
                composite_error(c, NT_STATUS_IO_TIMEOUT);
                return;
        }
        state->pipe->inhibit_timeout_processing = false;
 
-       data_blob_free(&sec->auth_info->credentials);
-
        if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                more_processing = true;
                c->status = NT_STATUS_OK;
@@ -173,18 +178,21 @@ static void bind_auth_next_step(struct composite_context *c)
 
        if (!composite_is_ok(c)) return;
 
-       if (state->credentials.length == 0) {
+       if (state->out_auth_info.credentials.length == 0) {
                composite_done(c);
                return;
        }
 
-       sec->auth_info->credentials = state->credentials;
+       state->in_auth_info = (struct dcerpc_auth) {
+               .auth_type = DCERPC_AUTH_TYPE_NONE,
+       };
+       sec->tmp_auth_info.in = &state->in_auth_info;
+       sec->tmp_auth_info.mem = state;
+       sec->tmp_auth_info.out = &state->out_auth_info;
 
        if (!more_processing) {
                /* NO reply expected, so just send it */
                c->status = dcerpc_auth3(state->pipe, state);
-               data_blob_free(&state->credentials);
-               sec->auth_info->credentials = data_blob(NULL, 0);
                if (!composite_is_ok(c)) return;
 
                composite_done(c);
@@ -197,8 +205,6 @@ static void bind_auth_next_step(struct composite_context *c)
                                           state->pipe,
                                           &state->pipe->syntax,
                                           &state->pipe->transfer_syntax);
-       data_blob_free(&state->credentials);
-       sec->auth_info->credentials = data_blob(NULL, 0);
        if (composite_nomem(subreq, c)) return;
        tevent_req_set_callback(subreq, bind_auth_recv_alter, c);
 }
@@ -209,6 +215,11 @@ static void bind_auth_recv_alter(struct tevent_req *subreq)
        struct composite_context *c =
                tevent_req_callback_data(subreq,
                struct composite_context);
+       struct bind_auth_state *state = talloc_get_type(c->private_data,
+                                                       struct bind_auth_state);
+       struct dcecli_security *sec = &state->pipe->conn->security_state;
+
+       ZERO_STRUCT(sec->tmp_auth_info);
 
        c->status = dcerpc_alter_context_recv(subreq);
        TALLOC_FREE(subreq);
@@ -225,14 +236,15 @@ static void bind_auth_recv_bindreply(struct tevent_req *subreq)
                struct composite_context);
        struct bind_auth_state *state = talloc_get_type(c->private_data,
                                                        struct bind_auth_state);
+       struct dcecli_security *sec = &state->pipe->conn->security_state;
+
+       ZERO_STRUCT(sec->tmp_auth_info);
 
        c->status = dcerpc_bind_recv(subreq);
        TALLOC_FREE(subreq);
        if (!composite_is_ok(c)) return;
 
        if (state->pipe->conn->flags & DCERPC_HEADER_SIGNING) {
-               struct dcecli_security *sec = &state->pipe->conn->security_state;
-
                gensec_want_feature(sec->generic_state, GENSEC_FEATURE_SIGN_PKT_HEADER);
        }
 
@@ -362,15 +374,11 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
         */
        sec->auth_context_id = 1;
 
-       sec->auth_info = talloc(p, struct dcerpc_auth);
-       if (composite_nomem(sec->auth_info, c)) return c;
-
-       sec->auth_info->auth_type = sec->auth_type;
-       sec->auth_info->auth_level = sec->auth_level,
-       sec->auth_info->auth_pad_length = 0;
-       sec->auth_info->auth_reserved = 0;
-       sec->auth_info->auth_context_id = sec->auth_context_id;
-       sec->auth_info->credentials = data_blob(NULL, 0);
+       state->out_auth_info = (struct dcerpc_auth) {
+               .auth_type = sec->auth_type,
+               .auth_level = sec->auth_level,
+               .auth_context_id = sec->auth_context_id,
+       };
 
        /* The status value here, from GENSEC is vital to the security
         * of the system.  Even if the other end accepts, if GENSEC
@@ -386,8 +394,8 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
        state->pipe->timed_out = false;
        c->status = gensec_update_ev(sec->generic_state, state,
                                  p->conn->event_ctx,
-                                 sec->auth_info->credentials,
-                                 &state->credentials);
+                                 data_blob_null,
+                                 &state->out_auth_info.credentials);
        if (state->pipe->timed_out) {
                composite_error(c, NT_STATUS_IO_TIMEOUT);
                return c;
@@ -403,25 +411,28 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
        state->more_processing = NT_STATUS_EQUAL(c->status,
                                                 NT_STATUS_MORE_PROCESSING_REQUIRED);
 
-       if (state->credentials.length == 0) {
+       if (state->out_auth_info.credentials.length == 0) {
                composite_done(c);
                return c;
        }
 
-       sec->auth_info->credentials = state->credentials;
-
        if (gensec_have_feature(sec->generic_state, GENSEC_FEATURE_SIGN_PKT_HEADER)) {
-               if (auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
+               if (sec->auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
                        state->pipe->conn->flags |= DCERPC_PROPOSE_HEADER_SIGNING;
                }
        }
 
+       state->in_auth_info = (struct dcerpc_auth) {
+               .auth_type = DCERPC_AUTH_TYPE_NONE,
+       };
+       sec->tmp_auth_info.in = &state->in_auth_info;
+       sec->tmp_auth_info.mem = state;
+       sec->tmp_auth_info.out = &state->out_auth_info;
+
        /* The first request always is a dcerpc_bind. The subsequent ones
         * depend on gensec results */
        subreq = dcerpc_bind_send(state, p->conn->event_ctx, p,
                                  &syntax, &transfer_syntax);
-       data_blob_free(&state->credentials);
-       sec->auth_info->credentials = data_blob(NULL, 0);
        if (composite_nomem(subreq, c)) return c;
        tevent_req_set_callback(subreq, bind_auth_recv_bindreply, c);