summaryrefslogtreecommitdiff
path: root/librpc/rpc
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2016-09-06 17:17:36 +0200
committerAndreas Schneider <asn@cryptomilk.org>2016-10-26 11:20:15 +0200
commit857b96cafcbd609338f33bcc17036f278063d067 (patch)
tree28a606769e4ececdad839e6419cb96e390a50603 /librpc/rpc
parent875d0111b45c3415cda50a7b4ec6ddf70d24b621 (diff)
downloadsamba-857b96cafcbd609338f33bcc17036f278063d067.tar.gz
librpc: add dcerpc_ncacn_push_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.c202
-rw-r--r--librpc/rpc/rpc_common.h8
2 files changed, 210 insertions, 0 deletions
diff --git a/librpc/rpc/dcerpc_util.c b/librpc/rpc/dcerpc_util.c
index 8013a610cf4..3319587917f 100644
--- a/librpc/rpc/dcerpc_util.c
+++ b/librpc/rpc/dcerpc_util.c
@@ -501,6 +501,208 @@ NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
return NT_STATUS_OK;
}
+NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
+ struct gensec_security *gensec,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *raw_packet,
+ size_t sig_size,
+ uint8_t payload_offset,
+ const DATA_BLOB *payload,
+ const struct ncacn_packet *pkt)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ struct ndr_push *ndr = NULL;
+ uint32_t payload_length;
+ uint32_t whole_length;
+ DATA_BLOB blob = data_blob_null;
+ DATA_BLOB sig = data_blob_null;
+ struct dcerpc_auth _out_auth_info;
+ struct dcerpc_auth *out_auth_info = NULL;
+
+ *raw_packet = data_blob_null;
+
+ if (auth_state == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ switch (auth_state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ if (sig_size == 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (gensec == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ _out_auth_info = (struct dcerpc_auth) {
+ .auth_type = auth_state->auth_type,
+ .auth_level = auth_state->auth_level,
+ .auth_context_id = auth_state->auth_context_id,
+ };
+ out_auth_info = &_out_auth_info;
+ break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ /*
+ * TODO: let the gensec mech decide if it wants to generate a
+ * signature that might be needed for schannel...
+ */
+ if (sig_size != 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (gensec == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_NONE:
+ if (sig_size != 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ break;
+
+ default:
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ ndr = ndr_push_init_ctx(frame);
+ if (ndr == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
+ ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+
+ if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
+ ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
+ }
+
+ ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (out_auth_info != NULL) {
+ /*
+ * pad to 16 byte multiple in the payload portion of the
+ * packet. This matches what w2k3 does. Note that we can't use
+ * ndr_push_align() as that is relative to the start of the
+ * whole packet, whereas w2k8 wants it relative to the start
+ * of the stub.
+ */
+ out_auth_info->auth_pad_length =
+ DCERPC_AUTH_PAD_LENGTH(payload->length);
+ ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ payload_length = payload->length +
+ out_auth_info->auth_pad_length;
+
+ ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
+ out_auth_info);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ whole_length = ndr->offset;
+
+ ndr_err = ndr_push_zero(ndr, sig_size);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ } else {
+ payload_length = payload->length;
+ whole_length = ndr->offset;
+ }
+
+ /* extract the whole packet as a blob */
+ blob = ndr_push_blob(ndr);
+
+ /*
+ * Setup the frag and auth length in the packet buffer.
+ * This is needed if the GENSEC mech does AEAD signing
+ * of the packet headers. The signature itself will be
+ * appended later.
+ */
+ dcerpc_set_frag_length(&blob, blob.length);
+ dcerpc_set_auth_length(&blob, sig_size);
+
+ /* sign or seal the packet */
+ switch (auth_state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ status = gensec_seal_packet(gensec,
+ frame,
+ blob.data + payload_offset,
+ payload_length,
+ blob.data,
+ whole_length,
+ &sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ status = gensec_sign_packet(gensec,
+ frame,
+ blob.data + payload_offset,
+ payload_length,
+ blob.data,
+ whole_length,
+ &sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ case DCERPC_AUTH_LEVEL_NONE:
+ break;
+
+ default:
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (sig.length != sig_size) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_RPC_SEC_PKG_ERROR;
+ }
+
+ if (sig_size != 0) {
+ memcpy(blob.data + whole_length, sig.data, sig_size);
+ }
+
+ *raw_packet = blob;
+ talloc_steal(mem_ctx, raw_packet->data);
+ TALLOC_FREE(frame);
+ 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 2f44ee0ea3f..9bc7d86dc72 100644
--- a/librpc/rpc/rpc_common.h
+++ b/librpc/rpc/rpc_common.h
@@ -213,6 +213,14 @@ NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
DATA_BLOB *payload_and_verifier,
DATA_BLOB *raw_packet,
const struct ncacn_packet *pkt);
+NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
+ struct gensec_security *gensec,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *raw_packet,
+ size_t sig_size,
+ uint8_t payload_offset,
+ const DATA_BLOB *payload,
+ 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);