From 65116adcebe23d3ae42a641515f6001268ed0ef0 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 16 Jul 2010 15:15:48 -0400 Subject: [PATCH] s3-dcerpc: Fix ability to receive Big Endian PDUs --- librpc/rpc/dcerpc_util.c | 5 ++++ source3/include/proto.h | 1 + source3/librpc/rpc/dcerpc.h | 6 +++-- source3/librpc/rpc/dcerpc_helpers.c | 36 ++++++++++++++++++++++++----- source3/rpc_client/cli_pipe.c | 12 +++++----- source3/rpc_server/srv_pipe.c | 6 ++--- source3/rpc_server/srv_pipe_hnd.c | 24 ++++++++++--------- 7 files changed, 62 insertions(+), 28 deletions(-) diff --git a/librpc/rpc/dcerpc_util.c b/librpc/rpc/dcerpc_util.c index a4bc096ddde..c79cfd506a5 100644 --- a/librpc/rpc/dcerpc_util.c +++ b/librpc/rpc/dcerpc_util.c @@ -52,6 +52,11 @@ void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v) } } +uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob) +{ + return blob->data[DCERPC_DREP_OFFSET]; +} + /* pull an dcerpc_auth structure, taking account of any auth padding in the blob at the end of the structure diff --git a/source3/include/proto.h b/source3/include/proto.h index 6f8eebb4591..9471f63195d 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -2937,6 +2937,7 @@ NTSTATUS dcerpc_fault_to_nt_status(uint32_t fault_code); void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v); uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob); void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v); +uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob); NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt, TALLOC_CTX *mem_ctx, DATA_BLOB *pkt_auth_blob, diff --git a/source3/librpc/rpc/dcerpc.h b/source3/librpc/rpc/dcerpc.h index d18920ca0db..bb7bd34de8a 100644 --- a/source3/librpc/rpc/dcerpc.h +++ b/source3/librpc/rpc/dcerpc.h @@ -123,7 +123,8 @@ NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx, DATA_BLOB *blob); NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, - struct ncacn_packet *r); + struct ncacn_packet *r, + bool bigendian); NTSTATUS dcerpc_push_schannel_bind(TALLOC_CTX *mem_ctx, struct NL_AUTH_MESSAGE *r, DATA_BLOB *blob); @@ -136,6 +137,7 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx, DATA_BLOB *blob); NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, - struct dcerpc_auth *r); + struct dcerpc_auth *r, + bool bigendian); #endif /* __DCERPC_H__ */ diff --git a/source3/librpc/rpc/dcerpc_helpers.c b/source3/librpc/rpc/dcerpc_helpers.c index ce48a691ac6..5c92a792e97 100644 --- a/source3/librpc/rpc/dcerpc_helpers.c +++ b/source3/librpc/rpc/dcerpc_helpers.c @@ -92,15 +92,27 @@ NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx, */ NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, - struct ncacn_packet *r) + struct ncacn_packet *r, + bool bigendian) { enum ndr_err_code ndr_err; + struct ndr_pull *ndr; + + ndr = ndr_pull_init_blob(blob, mem_ctx); + if (!ndr) { + return NT_STATUS_NO_MEMORY; + } + if (bigendian) { + ndr->flags |= LIBNDR_FLAG_BIGENDIAN; + } + + ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, r); - ndr_err = ndr_pull_struct_blob(blob, mem_ctx, r, - (ndr_pull_flags_fn_t)ndr_pull_ncacn_packet); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(ndr); return ndr_map_error2ntstatus(ndr_err); } + talloc_free(ndr); if (DEBUGLEVEL >= 10) { NDR_PRINT_DEBUG(ncacn_packet, r); @@ -194,15 +206,27 @@ NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx, */ NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, - struct dcerpc_auth *r) + struct dcerpc_auth *r, + bool bigendian) { enum ndr_err_code ndr_err; + struct ndr_pull *ndr; + + ndr = ndr_pull_init_blob(blob, mem_ctx); + if (!ndr) { + return NT_STATUS_NO_MEMORY; + } + if (bigendian) { + ndr->flags |= LIBNDR_FLAG_BIGENDIAN; + } + + ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, r); - ndr_err = ndr_pull_struct_blob(blob, mem_ctx, r, - (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(ndr); return ndr_map_error2ntstatus(ndr_err); } + talloc_free(ndr); if (DEBUGLEVEL >= 10) { NDR_PRINT_DEBUG(dcerpc_auth, r); diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index c90e06095ca..411b12feef2 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -619,7 +619,7 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli, DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length); - status = dcerpc_pull_dcerpc_auth(cli, &blob, &auth_info); + status = dcerpc_pull_dcerpc_auth(cli, &blob, &auth_info, false); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unmarshall dcerpc_auth.\n")); return status; @@ -749,7 +749,7 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli, + pkt->auth_length); - status = dcerpc_pull_dcerpc_auth(cli, &blob, &auth_info); + status = dcerpc_pull_dcerpc_auth(cli, &blob, &auth_info, false); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("cli_pipe_verify_ntlmssp: failed to unmarshall dcerpc_auth.\n")); return status; @@ -915,7 +915,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx, NTSTATUS ret = NT_STATUS_OK; uint8 ss_padding_len = 0; - ret = dcerpc_pull_ncacn_packet(cli, pdu, pkt); + ret = dcerpc_pull_ncacn_packet(cli, pdu, pkt, false); if (!NT_STATUS_IS_OK(ret)) { return ret; } @@ -2612,7 +2612,7 @@ static NTSTATUS rpc_finish_auth3_bind_send(struct tevent_req *req, status = dcerpc_pull_dcerpc_auth(talloc_tos(), &r->u.bind_ack.auth_info, - &auth); + &auth, false); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to pull dcerpc auth: %s.\n", nt_errstr(status))); @@ -2694,7 +2694,7 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind_send(struct tevent_req *req, DCERPC_AUTH_TRAILER_LENGTH + r->auth_length); - status = dcerpc_pull_dcerpc_auth(state, &auth_blob, &auth_info); + status = dcerpc_pull_dcerpc_auth(state, &auth_blob, &auth_info, false); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to unmarshall dcerpc_auth.\n")); return status; @@ -2778,7 +2778,7 @@ static void rpc_bind_ntlmssp_api_done(struct tevent_req *subreq) status = dcerpc_pull_dcerpc_auth(pkt, &pkt->u.alter_resp.auth_info, - &auth); + &auth, false); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return; diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 6d37ec2bc2b..968553a28de 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -568,7 +568,7 @@ bool api_pipe_bind_auth3(pipes_struct *p, struct ncacn_packet *pkt) status = dcerpc_pull_dcerpc_auth(pkt, &pkt->u.auth3.auth_info, - &auth_info); + &auth_info, p->endian); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to unmarshall dcerpc_auth.\n")); goto err; @@ -1303,7 +1303,7 @@ bool api_pipe_bind_req(pipes_struct *p, struct ncacn_packet *pkt) */ status = dcerpc_pull_dcerpc_auth(pkt, &pkt->u.bind.auth_info, - &auth_info); + &auth_info, p->endian); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n")); goto err_exit; @@ -1524,7 +1524,7 @@ bool api_pipe_alter_context(pipes_struct *p, struct ncacn_packet *pkt) status = dcerpc_pull_dcerpc_auth(pkt, &pkt->u.bind.auth_info, - &auth_info); + &auth_info, p->endian); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Unable to unmarshall dcerpc_auth.\n")); goto err_exit; diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index 3055e1a29c9..51f30cea254 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -406,25 +406,27 @@ static void process_complete_pdu(pipes_struct *p) goto done; } - status = dcerpc_pull_ncacn_packet(pkt, &p->in_data.pdu, pkt); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Failed to unmarshal rpc packet: %s!\n", - nt_errstr(status))); - goto done; - } - - /* Store the call_id */ - p->call_id = pkt->call_id; - /* * Ensure we're using the corrent endianness for both the * RPC header flags and the raw data we will be reading from. */ - if (pkt->drep[0] == DCERPC_DREP_LE) { + if (dcerpc_get_endian_flag(&p->in_data.pdu) & DCERPC_DREP_LE) { p->endian = RPC_LITTLE_ENDIAN; } else { p->endian = RPC_BIG_ENDIAN; } + DEBUG(10, ("PDU is in %s Endian format!\n", p->endian?"Big":"Little")); + + status = dcerpc_pull_ncacn_packet(pkt, &p->in_data.pdu, + pkt, p->endian); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Failed to unmarshal rpc packet: %s!\n", + nt_errstr(status))); + goto done; + } + + /* Store the call_id */ + p->call_id = pkt->call_id; DEBUG(10, ("Processing packet type %d\n", (int)pkt->ptype)); -- 2.34.1