diff options
author | Stefan Metzmacher <metze@samba.org> | 2015-06-26 08:10:46 +0200 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2016-04-12 19:25:30 +0200 |
commit | 0ba1b1867c3ed388358adc6ae0b583fdc7775795 (patch) | |
tree | ad6f2dba5116344ee3b38427a2c72ddf7b3ce78c /source4/rpc_server | |
parent | c0d74ca7af9a9aafe81787bcd540af56e048cca3 (diff) | |
download | samba-0ba1b1867c3ed388358adc6ae0b583fdc7775795.tar.gz |
CVE-2015-5370: s4:rpc_server: ensure that the message ordering doesn't violate the spec
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.
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>
Diffstat (limited to 'source4/rpc_server')
-rw-r--r-- | source4/rpc_server/dcerpc_server.c | 41 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_server.h | 8 | ||||
-rw-r--r-- | source4/rpc_server/dcesrv_auth.c | 12 |
3 files changed, 59 insertions, 2 deletions
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index 435bb72ec64..76adb18bd41 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -408,6 +408,7 @@ _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx, p->msg_ctx = msg_ctx; p->server_id = server_id; p->state_flags = state_flags; + p->allow_bind = true; p->max_recv_frag = 5840; p->max_xmit_frag = 5840; @@ -459,6 +460,11 @@ static void dcesrv_call_disconnect_after(struct dcesrv_call_state *call, return; } + call->conn->allow_bind = false; + call->conn->allow_alter = false; + call->conn->allow_auth3 = false; + call->conn->allow_request = false; + call->terminate_reason = talloc_strdup(call, reason); if (call->terminate_reason == NULL) { call->terminate_reason = __location__; @@ -914,6 +920,10 @@ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call) { NTSTATUS status; + if (!call->conn->allow_auth3) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } + status = dcerpc_verify_ncacn_packet_header(&call->pkt, DCERPC_PKT_AUTH3, call->pkt.u.auth3.auth_info.length, @@ -1099,6 +1109,10 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call) NTSTATUS status; uint32_t context_id; + if (!call->conn->allow_alter) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } + status = dcerpc_verify_ncacn_packet_header(&call->pkt, DCERPC_PKT_ALTER, call->pkt.u.alter.auth_info.length, @@ -1224,6 +1238,10 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call) NTSTATUS status; struct dcesrv_connection_context *context; + if (!call->conn->allow_request) { + return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); + } + /* if authenticated, and the mech we use can't do async replies, don't use them... */ if (call->conn->auth_state.gensec_security && !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) { @@ -1390,9 +1408,22 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, talloc_set_destructor(call, dcesrv_call_dequeue); + if (call->conn->allow_bind) { + /* + * Only one bind is possible per connection + */ + call->conn->allow_bind = false; + return dcesrv_bind(call); + } + /* we have to check the signing here, before combining the pdus */ if (call->pkt.ptype == DCERPC_PKT_REQUEST) { + if (!call->conn->allow_request) { + return dcesrv_fault_disconnect(call, + DCERPC_NCA_S_PROTO_ERROR); + } + status = dcerpc_verify_ncacn_packet_header(&call->pkt, DCERPC_PKT_REQUEST, call->pkt.u.request.stub_and_verifier.length, @@ -1488,7 +1519,8 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, switch (call->pkt.ptype) { case DCERPC_PKT_BIND: - status = dcesrv_bind(call); + status = dcesrv_bind_nak(call, + DCERPC_BIND_NAK_REASON_NOT_SPECIFIED); break; case DCERPC_PKT_AUTH3: status = dcesrv_auth3(call); @@ -1500,7 +1532,7 @@ static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn, status = dcesrv_request(call); break; default: - status = NT_STATUS_INVALID_PARAMETER; + status = dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR); break; } @@ -1674,6 +1706,11 @@ static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, cons srv_conn = talloc_get_type(dce_conn->transport.private_data, struct stream_connection); + dce_conn->allow_bind = false; + dce_conn->allow_auth3 = false; + dce_conn->allow_alter = false; + dce_conn->allow_request = false; + if (dce_conn->pending_call_list == NULL) { char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason); diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h index ad19612de0b..4e621e2b516 100644 --- a/source4/rpc_server/dcerpc_server.h +++ b/source4/rpc_server/dcerpc_server.h @@ -260,6 +260,14 @@ struct dcesrv_connection { /* the current authentication state */ struct dcesrv_auth auth_state; + + /* + * remember which pdu types are allowed + */ + bool allow_bind; + bool allow_auth3; + bool allow_alter; + bool allow_request; }; diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c index 03231a5cfde..f5086ac4d0f 100644 --- a/source4/rpc_server/dcesrv_auth.c +++ b/source4/rpc_server/dcesrv_auth.c @@ -130,7 +130,11 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe NTSTATUS status; bool want_header_signing = false; + dce_conn->allow_alter = true; + dce_conn->allow_auth3 = true; + if (call->pkt.auth_length == 0) { + dce_conn->allow_request = true; return NT_STATUS_OK; } @@ -161,6 +165,7 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); return status; } + dce_conn->allow_request = true; if (!gensec_have_feature(dce_conn->auth_state.gensec_security, GENSEC_FEATURE_SIGN_PKT_HEADER)) @@ -246,6 +251,8 @@ bool dcesrv_auth_auth3(struct dcesrv_call_state *call) DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); return false; } + dce_conn->allow_request = true; + /* Now that we are authenticated, go back to the generic session key... */ dce_conn->auth_state.session_key = dcesrv_generic_session_key; return true; @@ -325,6 +332,7 @@ NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_pack DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); return status; } + dce_conn->allow_request = true; /* Now that we are authenticated, got back to the generic session key... */ dce_conn->auth_state.session_key = dcesrv_generic_session_key; @@ -352,6 +360,10 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) uint32_t auth_length; size_t hdr_size = DCERPC_REQUEST_LENGTH; + if (!dce_conn->allow_request) { + return false; + } + if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security) { if (pkt->auth_length != 0) { |