diff options
author | Stefan Metzmacher <metze@samba.org> | 2016-09-06 17:17:36 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2016-10-26 11:20:15 +0200 |
commit | 857b96cafcbd609338f33bcc17036f278063d067 (patch) | |
tree | 28a606769e4ececdad839e6419cb96e390a50603 /librpc/rpc | |
parent | 875d0111b45c3415cda50a7b4ec6ddf70d24b621 (diff) | |
download | samba-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.c | 202 | ||||
-rw-r--r-- | librpc/rpc/rpc_common.h | 8 |
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); |