librpc: add dcerpc_ncacn_pull_pkt_auth() helper function
authorStefan Metzmacher <metze@samba.org>
Tue, 6 Sep 2016 14:43:53 +0000 (16:43 +0200)
committerAndreas Schneider <asn@cryptomilk.org>
Wed, 26 Oct 2016 09:20:15 +0000 (11:20 +0200)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
librpc/rpc/dcerpc_util.c
librpc/rpc/rpc_common.h
librpc/wscript_build

index 6f032878c05952323ba02f53f627a599cc9f4d70..8013a610cf4d160dd9a1613b4fc7e3eb10900f53 100644 (file)
@@ -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 {
index 1b10b7ea7351fd4152e24aab41d34fbb48af4f73..2f44ee0ea3f6e74c9dc0f8796bd2a148b155d045 100644 (file)
@@ -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);
index 6c2dff5fc188ab7d9348715141084b477fef6383..1c7cc0aa9517ce2f349c2c2ac9a04be4ec96a01d 100644 (file)
@@ -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')