diff options
-rw-r--r-- | source4/libcli/raw/rawdcerpc.c | 32 | ||||
-rw-r--r-- | source4/libcli/rpc/dcerpc.c | 57 | ||||
-rw-r--r-- | source4/libcli/rpc/dcerpc.h | 2 | ||||
-rw-r--r-- | source4/torture/rpc/echo.c | 7 | ||||
-rw-r--r-- | source4/torture/torture.c | 3 |
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 = |