mirror of
https://github.com/samba-team/samba.git
synced 2025-01-24 02:04:21 +03:00
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>
This commit is contained in:
parent
c0d74ca7af
commit
0ba1b1867c
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user