From d8cbe76b868eb6f2b3876fa540e0847bd2d4f9d7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 4 Nov 2003 03:38:46 +0000 Subject: added support for fragmented sends (This used to be commit f51a216136b7cc7d4d07d4acb80e0a710d82841a) --- source4/libcli/raw/rawdcerpc.c | 32 ++++++++++++++++++++++++ source4/libcli/rpc/dcerpc.c | 57 ++++++++++++++++++++++++++++++++++++------ source4/libcli/rpc/dcerpc.h | 2 ++ 3 files changed, 83 insertions(+), 8 deletions(-) (limited to 'source4/libcli') diff --git a/source4/libcli/raw/rawdcerpc.c b/source4/libcli/raw/rawdcerpc.c index d548129ab1..a6cd75eeaa 100644 --- a/source4/libcli/raw/rawdcerpc.c +++ b/source4/libcli/raw/rawdcerpc.c @@ -218,3 +218,35 @@ NTSTATUS dcerpc_raw_packet_secondary(struct dcerpc_pipe *p, return status; } + + +/* + send an initial pdu in a multi-pdu sequence +*/ +NTSTATUS dcerpc_raw_packet_initial(struct dcerpc_pipe *p, + TALLOC_CTX *mem_ctx, + DATA_BLOB *blob) +{ + union smb_write io; + NTSTATUS status; + + io.generic.level = RAW_WRITE_WRITEX; + io.writex.in.fnum = p->fnum; + io.writex.in.offset = 0; + io.writex.in.wmode = PIPE_START_MESSAGE; + io.writex.in.remaining = blob->length; + io.writex.in.count = blob->length; + io.writex.in.data = blob->data; + + status = smb_raw_write(p->tree, &io); + if (NT_STATUS_IS_OK(status)) { + return status; + } + + /* make sure it accepted it all */ + if (io.writex.out.nwritten != blob->length) { + return NT_STATUS_UNSUCCESSFUL; + } + + return status; +} diff --git a/source4/libcli/rpc/dcerpc.c b/source4/libcli/rpc/dcerpc.c index d4f21f969a..7d6888dde7 100644 --- a/source4/libcli/rpc/dcerpc.c +++ b/source4/libcli/rpc/dcerpc.c @@ -186,11 +186,11 @@ static NTSTATUS dcerpc_pull_response(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_hdr *hdr, struct dcerpc_response *pkt) { - uint32 alloc_hint, stub_len; + uint32 stub_len; BLOB_CHECK_BOUNDS(blob, *offset, 8); - alloc_hint = IVAL(blob->data, (*offset) + 0); + pkt->alloc_hint = IVAL(blob->data, (*offset) + 0); pkt->context_id = SVAL(blob->data, (*offset) + 4); pkt->cancel_count = CVAL(blob->data, (*offset) + 6); @@ -382,9 +382,7 @@ static NTSTATUS dcerpc_push_request(DATA_BLOB *blob, uint32 *offset, struct dcerpc_hdr *hdr, struct dcerpc_request *pkt) { - uint32 alloc_hint = 8 + pkt->stub_data.length + pkt->auth_verifier.length; - - SIVAL(blob->data, (*offset) + 0, alloc_hint); + SIVAL(blob->data, (*offset) + 0, pkt->alloc_hint); SSVAL(blob->data, (*offset) + 4, pkt->context_id); SSVAL(blob->data, (*offset) + 6, pkt->opnum); @@ -621,24 +619,67 @@ NTSTATUS cli_dcerpc_request(struct dcerpc_pipe *p, struct dcerpc_packet pkt; NTSTATUS status; DATA_BLOB blob_in, blob_out, payload; + uint32 remaining, chunk_size; init_dcerpc_hdr(&pkt.hdr); + remaining = stub_data_in->length; + + /* we can write a full max_recv_frag size, minus the dcerpc + request header size */ + chunk_size = p->srv_max_recv_frag - 24; + pkt.hdr.ptype = DCERPC_PKT_REQUEST; - pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; pkt.hdr.call_id = p->call_id++; pkt.hdr.auth_length = 0; - + pkt.in.request.alloc_hint = remaining; pkt.in.request.context_id = 0; pkt.in.request.opnum = opnum; - pkt.in.request.stub_data = *stub_data_in; pkt.in.request.auth_verifier = data_blob(NULL, 0); + /* we send a series of pdus without waiting for a reply until + the last pdu */ + while (remaining > chunk_size) { + if (remaining == stub_data_in->length) { + pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST; + } else { + pkt.hdr.pfc_flags = 0; + } + + pkt.in.request.stub_data.data = stub_data_in->data + + (stub_data_in->length - remaining); + pkt.in.request.stub_data.length = chunk_size; + + status = dcerpc_push(&blob_in, mem_ctx, &pkt); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = dcerpc_raw_packet_initial(p, mem_ctx, &blob_in); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + remaining -= chunk_size; + } + + /* now we send a pdu with LAST_FRAG sent and get the first + part of the reply */ + if (remaining == stub_data_in->length) { + pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; + } else { + pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_LAST; + } + pkt.in.request.stub_data.data = stub_data_in->data + + (stub_data_in->length - remaining); + pkt.in.request.stub_data.length = remaining; + status = dcerpc_push(&blob_in, mem_ctx, &pkt); if (!NT_STATUS_IS_OK(status)) { return status; } + /* send the pdu and get the initial response pdu */ status = dcerpc_raw_packet(p, mem_ctx, &blob_in, &blob_out); status = dcerpc_pull(&blob_out, mem_ctx, &pkt); diff --git a/source4/libcli/rpc/dcerpc.h b/source4/libcli/rpc/dcerpc.h index 7f24f46b91..09ddc3625c 100644 --- a/source4/libcli/rpc/dcerpc.h +++ b/source4/libcli/rpc/dcerpc.h @@ -86,6 +86,7 @@ struct dcerpc_packet { } bind; struct dcerpc_request { + uint32 alloc_hint; uint16 context_id; uint16 opnum; DATA_BLOB stub_data; @@ -114,6 +115,7 @@ struct dcerpc_packet { } bind_nak; struct dcerpc_response { + uint32 alloc_hint; uint16 context_id; uint8 cancel_count; DATA_BLOB stub_data; -- cgit