summaryrefslogtreecommitdiff
path: root/librpc/rpc
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2016-09-06 16:43:53 +0200
committerAndreas Schneider <asn@cryptomilk.org>2016-10-26 11:20:15 +0200
commit875d0111b45c3415cda50a7b4ec6ddf70d24b621 (patch)
tree7ab90ab764050c0e4e283a40db6c4d037239bf0e /librpc/rpc
parent5f17d3bd29955ac5425d24213110d670f08be9b9 (diff)
downloadsamba-875d0111b45c3415cda50a7b4ec6ddf70d24b621.tar.gz
librpc: add dcerpc_ncacn_pull_pkt_auth() helper function
Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org>
Diffstat (limited to 'librpc/rpc')
-rw-r--r--librpc/rpc/dcerpc_util.c141
-rw-r--r--librpc/rpc/rpc_common.h11
2 files changed, 152 insertions, 0 deletions
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);