NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
struct gensec_security *gensec,
+ bool check_pkt_auth_fields,
TALLOC_CTX *mem_ctx,
enum dcerpc_pkt_type ptype,
uint8_t required_flags,
return NT_STATUS_INTERNAL_ERROR;
}
- if (auth.auth_type != auth_state->auth_type) {
- return NT_STATUS_ACCESS_DENIED;
- }
+ if (check_pkt_auth_fields) {
+ if (auth.auth_type != auth_state->auth_type) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
- if (auth.auth_level != auth_state->auth_level) {
- return NT_STATUS_ACCESS_DENIED;
- }
+ if (auth.auth_level != auth_state->auth_level) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
- if (auth.auth_context_id != auth_state->auth_context_id) {
- return NT_STATUS_ACCESS_DENIED;
+ if (auth.auth_context_id != auth_state->auth_context_id) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
}
/* check signature or unseal the packet */
return false;
}
+ if (auth->auth_invalid) {
+ return false;
+ }
+
/* We can't work without an existing gensec state */
if (auth->gensec_security == NULL) {
return false;
return false;
}
+ if (auth->auth_invalid) {
+ return false;
+ }
+
if (call->in_auth_info.auth_type != auth->auth_type) {
return false;
}
.auth_level = auth->auth_level,
.auth_context_id = auth->auth_context_id,
};
+ bool check_pkt_auth_fields;
NTSTATUS status;
if (!auth->auth_started) {
return false;
}
+ if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
+ /*
+ * The caller most likely checked this
+ * already, but we better double check.
+ */
+ check_pkt_auth_fields = true;
+ } else {
+ /*
+ * The caller already found first fragment
+ * and is passing the auth_state of it.
+ * A server is supposed to use the
+ * setting of the first fragment and
+ * completely ignore the values
+ * on the remaining fragments
+ */
+ check_pkt_auth_fields = false;
+ }
+
status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
auth->gensec_security,
+ check_pkt_auth_fields,
call,
pkt->ptype,
required_flags,
struct ndr_pull *pull;
NTSTATUS status;
+ if (auth->auth_invalid) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
if (!auth->auth_finished) {
return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
}
enum dcerpc_AuthType auth_type = 0;
enum dcerpc_AuthLevel auth_level = 0;
uint32_t auth_context_id = 0;
+ bool auth_invalid = false;
call = talloc_zero(dce_conn, struct dcesrv_call_state);
if (!call) {
if (call->auth_state == NULL) {
struct dcesrv_auth *a = NULL;
+ bool check_type_level = true;
auth_type = dcerpc_get_auth_type(&blob);
auth_level = dcerpc_get_auth_level(&blob);
auth_context_id = dcerpc_get_auth_context_id(&blob);
if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
+ if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
+ check_type_level = false;
+ }
dce_conn->default_auth_level_connect = NULL;
if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
dce_conn->got_explicit_auth_level_connect = true;
for (a = dce_conn->auth_states; a != NULL; a = a->next) {
num_auth_ctx++;
- if (a->auth_type != auth_type) {
+ if (a->auth_context_id != auth_context_id) {
continue;
}
- if (a->auth_finished && a->auth_level != auth_level) {
- continue;
+
+ if (a->auth_type != auth_type) {
+ auth_invalid = true;
}
- if (a->auth_context_id != auth_context_id) {
- continue;
+ if (a->auth_level != auth_level) {
+ auth_invalid = true;
+ }
+
+ if (check_type_level && auth_invalid) {
+ a->auth_invalid = true;
}
DLIST_PROMOTE(dce_conn->auth_states, a);
/*
* This can never be valid.
*/
+ auth_invalid = true;
a->auth_invalid = true;
}
call->auth_state = a;
}
/* only one request is possible in the fragmented list */
if (dce_conn->incoming_fragmented_call_list != NULL) {
+ call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
+
+ existing = dcesrv_find_fragmented_call(dce_conn,
+ call->pkt.call_id);
+ if (existing != NULL && call->auth_state != existing->auth_state) {
+ call->context = dcesrv_find_context(call->conn,
+ call->pkt.u.request.context_id);
+
+ if (call->pkt.auth_length != 0 && existing->context == call->context) {
+ call->fault_code = DCERPC_FAULT_SEC_PKG_ERROR;
+ }
+ }
if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
/*
* Without DCERPC_PFC_FLAG_CONC_MPX
* This is important to get the
* call_id and context_id right.
*/
+ dce_conn->incoming_fragmented_call_list->fault_code = call->fault_code;
TALLOC_FREE(call);
call = dce_conn->incoming_fragmented_call_list;
}
- return dcesrv_fault_disconnect0(call,
- DCERPC_NCA_S_PROTO_ERROR);
+ if (existing != NULL) {
+ call->context = existing->context;
+ }
+ return dcesrv_fault_disconnect0(call, call->fault_code);
}
if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_PENDING_CANCEL) {
return dcesrv_fault_disconnect(call,
DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
}
} else {
- const struct dcerpc_request *nr = &call->pkt.u.request;
- const struct dcerpc_request *er = NULL;
int cmp;
existing = dcesrv_find_fragmented_call(dce_conn,
call->pkt.call_id);
if (existing == NULL) {
+ if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
+ /*
+ * Without DCERPC_PFC_FLAG_CONC_MPX
+ * we need to return the FAULT on the
+ * already existing call.
+ *
+ * This is important to get the
+ * call_id and context_id right.
+ */
+ if (dce_conn->incoming_fragmented_call_list != NULL) {
+ TALLOC_FREE(call);
+ call = dce_conn->incoming_fragmented_call_list;
+ }
+ return dcesrv_fault_disconnect0(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ if (dce_conn->incoming_fragmented_call_list != NULL) {
+ return dcesrv_fault_disconnect0(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+ call->context = dcesrv_find_context(call->conn,
+ call->pkt.u.request.context_id);
+ if (call->context == NULL) {
+ return dcesrv_fault_with_flags(call, DCERPC_NCA_S_UNKNOWN_IF,
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+ }
+ if (auth_invalid) {
+ return dcesrv_fault_disconnect0(call,
+ DCERPC_FAULT_ACCESS_DENIED);
+ }
return dcesrv_fault_disconnect0(call,
DCERPC_NCA_S_PROTO_ERROR);
}
- er = &existing->pkt.u.request;
if (call->pkt.ptype != existing->pkt.ptype) {
/* trying to play silly buggers are we? */
return dcesrv_fault_disconnect(existing,
DCERPC_NCA_S_PROTO_ERROR);
}
- if (nr->context_id != er->context_id) {
- return dcesrv_fault_disconnect(existing,
- DCERPC_NCA_S_PROTO_ERROR);
- }
- if (nr->opnum != er->opnum) {
- return dcesrv_fault_disconnect(existing,
- DCERPC_NCA_S_PROTO_ERROR);
- }
+ call->auth_state = existing->auth_state;
+ call->context = existing->context;
}
}
+++ /dev/null
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_all_111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_alone
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_all_111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_context_111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_level_111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_auth_MPX_middle_auth_type_111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_firstSame111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_firstSameNone
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_firstSameNone111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_lastSameNone
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_MPX_first1_lastSameNone111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_firstSame2
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNext111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNext2
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNextNone
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastNextNone111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSame111
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSame2
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSameNone
-^samba.tests.dcerpc.raw_protocol.samba.tests.dcerpc.raw_protocol.TestDCERPC_BIND.test_ntlmssp_multi_auth_first1_lastSameNone111