summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libcli/raw/rawdcerpc.c32
-rw-r--r--source4/libcli/rpc/dcerpc.c57
-rw-r--r--source4/libcli/rpc/dcerpc.h2
-rw-r--r--source4/torture/rpc/echo.c7
-rw-r--r--source4/torture/torture.c3
5 files changed, 86 insertions, 15 deletions
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;
diff --git a/source4/torture/rpc/echo.c b/source4/torture/rpc/echo.c
index 834eb1f678..1d034c48df 100644
--- a/source4/torture/rpc/echo.c
+++ b/source4/torture/rpc/echo.c
@@ -126,7 +126,7 @@ static BOOL test_sinkdata(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
int i;
NTSTATUS status;
char *data_in;
- int len = 100;
+ int len = 200000;
printf("\nTesting SinkData\n");
@@ -160,11 +160,6 @@ BOOL torture_rpc_echo(int dummy)
return False;
}
- if (!test_sourcedata(p, mem_ctx)) {
- ret = False;
- }
- return ret;
-
if (!test_addone(p, mem_ctx)) {
ret = False;
}
diff --git a/source4/torture/torture.c b/source4/torture/torture.c
index 8dc82242a2..bb5741c54f 100644
--- a/source4/torture/torture.c
+++ b/source4/torture/torture.c
@@ -157,7 +157,8 @@ NTSTATUS torture_rpc_connection(struct dcerpc_pipe **p, const char *pipe_name)
STD_RIGHT_READ_CONTROL_ACCESS |
SA_RIGHT_FILE_WRITE_ATTRIBUTES |
SA_RIGHT_FILE_WRITE_EA |
- GENERIC_RIGHTS_FILE_READ;
+ GENERIC_RIGHTS_FILE_READ |
+ GENERIC_RIGHTS_FILE_WRITE;
open_parms.ntcreatex.in.file_attr = 0;
open_parms.ntcreatex.in.alloc_size = 0;
open_parms.ntcreatex.in.share_access =