From 875d0111b45c3415cda50a7b4ec6ddf70d24b621 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 6 Sep 2016 16:43:53 +0200 Subject: [PATCH] librpc: add dcerpc_ncacn_pull_pkt_auth() helper function Signed-off-by: Stefan Metzmacher Reviewed-by: Andreas Schneider --- librpc/rpc/dcerpc_util.c | 141 +++++++++++++++++++++++++++++++++++++++ librpc/rpc/rpc_common.h | 11 +++ librpc/wscript_build | 2 +- 3 files changed, 153 insertions(+), 1 deletion(-) diff --git a/librpc/rpc/dcerpc_util.c b/librpc/rpc/dcerpc_util.c index 6f032878c05..8013a610cf4 100644 --- a/librpc/rpc/dcerpc_util.c +++ b/librpc/rpc/dcerpc_util.c @@ -28,6 +28,7 @@ #include "librpc/gen_ndr/ndr_dcerpc.h" #include "rpc_common.h" #include "lib/util/bitmap.h" +#include "auth/gensec/gensec.h" /* we need to be able to get/set the fragment length without doing a full decode */ @@ -360,6 +361,146 @@ NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, return NT_STATUS_OK; } +NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, + struct gensec_security *gensec, + TALLOC_CTX *mem_ctx, + enum dcerpc_pkt_type ptype, + uint8_t required_flags, + uint8_t optional_flags, + uint8_t payload_offset, + DATA_BLOB *payload_and_verifier, + DATA_BLOB *raw_packet, + const struct ncacn_packet *pkt) +{ + NTSTATUS status; + struct dcerpc_auth auth; + uint32_t auth_length; + + if (auth_state == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + status = dcerpc_verify_ncacn_packet_header(pkt, ptype, + payload_and_verifier->length, + required_flags, optional_flags); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + switch (auth_state->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + case DCERPC_AUTH_LEVEL_INTEGRITY: + case DCERPC_AUTH_LEVEL_PACKET: + break; + + case DCERPC_AUTH_LEVEL_CONNECT: + if (pkt->auth_length != 0) { + break; + } + return NT_STATUS_OK; + case DCERPC_AUTH_LEVEL_NONE: + if (pkt->auth_length != 0) { + return NT_STATUS_ACCESS_DENIED; + } + return NT_STATUS_OK; + + default: + return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL; + } + + if (pkt->auth_length == 0) { + return NT_STATUS_RPC_PROTOCOL_ERROR; + } + + if (gensec == NULL) { + return NT_STATUS_INTERNAL_ERROR; + } + + status = dcerpc_pull_auth_trailer(pkt, mem_ctx, + payload_and_verifier, + &auth, &auth_length, false); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (payload_and_verifier->length < auth_length) { + /* + * should be checked in dcerpc_pull_auth_trailer() + */ + return NT_STATUS_INTERNAL_ERROR; + } + + payload_and_verifier->length -= auth_length; + + if (payload_and_verifier->length < auth.auth_pad_length) { + /* + * should be checked in dcerpc_pull_auth_trailer() + */ + return NT_STATUS_INTERNAL_ERROR; + } + + 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_context_id != auth_state->auth_context_id) { + return NT_STATUS_ACCESS_DENIED; + } + + /* check signature or unseal the packet */ + switch (auth_state->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + status = gensec_unseal_packet(gensec, + raw_packet->data + payload_offset, + payload_and_verifier->length, + raw_packet->data, + raw_packet->length - + auth.credentials.length, + &auth.credentials); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_RPC_SEC_PKG_ERROR; + } + memcpy(payload_and_verifier->data, + raw_packet->data + payload_offset, + payload_and_verifier->length); + break; + + case DCERPC_AUTH_LEVEL_INTEGRITY: + case DCERPC_AUTH_LEVEL_PACKET: + status = gensec_check_packet(gensec, + payload_and_verifier->data, + payload_and_verifier->length, + raw_packet->data, + raw_packet->length - + auth.credentials.length, + &auth.credentials); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_RPC_SEC_PKG_ERROR; + } + break; + + case DCERPC_AUTH_LEVEL_CONNECT: + /* for now we ignore possible signatures here */ + break; + + default: + return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL; + } + + /* + * remove the indicated amount of padding + * + * A possible overflow is checked above. + */ + payload_and_verifier->length -= auth.auth_pad_length; + + return NT_STATUS_OK; +} + struct dcerpc_read_ncacn_packet_state { #if 0 struct { diff --git a/librpc/rpc/rpc_common.h b/librpc/rpc/rpc_common.h index 1b10b7ea735..2f44ee0ea3f 100644 --- a/librpc/rpc/rpc_common.h +++ b/librpc/rpc/rpc_common.h @@ -36,6 +36,7 @@ struct epm_floor; struct epm_tower; struct tevent_context; struct tstream_context; +struct gensec_security; enum dcerpc_transport_t { NCA_UNKNOWN, NCACN_NP, NCACN_IP_TCP, NCACN_IP_UDP, NCACN_VNS_IPC, @@ -202,6 +203,16 @@ NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt, size_t max_auth_info, uint8_t required_flags, uint8_t optional_flags); +NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state, + struct gensec_security *gensec, + TALLOC_CTX *mem_ctx, + enum dcerpc_pkt_type ptype, + uint8_t required_flags, + uint8_t optional_flags, + uint8_t payload_offset, + DATA_BLOB *payload_and_verifier, + DATA_BLOB *raw_packet, + const struct ncacn_packet *pkt); struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct tstream_context *stream); diff --git a/librpc/wscript_build b/librpc/wscript_build index 6c2dff5fc18..1c7cc0aa951 100644 --- a/librpc/wscript_build +++ b/librpc/wscript_build @@ -715,7 +715,7 @@ bld.SAMBA_LIBRARY('ndr', bld.SAMBA_LIBRARY('dcerpc-binding', source='rpc/dcerpc_error.c rpc/binding.c rpc/dcerpc_util.c rpc/binding_handle.c', - deps='ndr tevent NDR_DCERPC LIBTSOCKET tevent-util', + deps='ndr tevent NDR_DCERPC LIBTSOCKET tevent-util gensec', pc_files=[], public_headers='rpc/rpc_common.h', vnum='0.0.1')