summaryrefslogtreecommitdiff
path: root/source4/rpc_server
diff options
context:
space:
mode:
Diffstat (limited to 'source4/rpc_server')
-rw-r--r--source4/rpc_server/dcerpc_server.c56
-rw-r--r--source4/rpc_server/dcerpc_server.h4
-rw-r--r--source4/rpc_server/dcerpc_tcp.c4
3 files changed, 61 insertions, 3 deletions
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 81c9d4cb8f..bde7063dcc 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -100,6 +100,7 @@ NTSTATUS dcesrv_endpoint_connect_ops(struct dcesrv_context *dce,
(*p)->dispatch = NULL;
(*p)->handles = NULL;
(*p)->next_handle = 0;
+ (*p)->partial_input = data_blob(NULL, 0);
/* make sure the endpoint server likes the connection */
status = ops->connect(*p);
@@ -480,6 +481,40 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
/*
+ work out if we have a full packet yet
+*/
+static BOOL dce_full_packet(const DATA_BLOB *data)
+{
+ if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
+ return False;
+ }
+ if (SVAL(data->data, DCERPC_FRAG_LEN_OFFSET) > data->length) {
+ return False;
+ }
+ return True;
+}
+
+/*
+ we might have consumed only part of our input - advance past that part
+*/
+static void dce_partial_advance(struct dcesrv_state *dce, uint32 offset)
+{
+ DATA_BLOB blob;
+
+ if (dce->partial_input.length == offset) {
+ talloc_free(dce->mem_ctx, dce->partial_input.data);
+ dce->partial_input = data_blob(NULL, 0);
+ return;
+ }
+
+ blob = dce->partial_input;
+ dce->partial_input = data_blob_talloc(dce->mem_ctx,
+ blob.data + offset,
+ blob.length - offset);
+ talloc_free(dce->mem_ctx, blob.data);
+}
+
+/*
provide some input to a dcerpc endpoint server. This passes data
from a dcerpc client into the server
*/
@@ -490,12 +525,27 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
NTSTATUS status;
struct dcesrv_call_state *call;
+ dce->partial_input.data = talloc_realloc(dce->mem_ctx,
+ dce->partial_input.data,
+ dce->partial_input.length + data->length);
+ if (!dce->partial_input.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ memcpy(dce->partial_input.data + dce->partial_input.length,
+ data->data, data->length);
+ dce->partial_input.length += data->length;
+
+ if (!dce_full_packet(&dce->partial_input)) {
+ return NT_STATUS_OK;
+ }
+
mem_ctx = talloc_init("dcesrv_input");
if (!mem_ctx) {
return NT_STATUS_NO_MEMORY;
}
call = talloc_p(mem_ctx, struct dcesrv_call_state);
if (!call) {
+ talloc_free(dce->mem_ctx, dce->partial_input.data);
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
@@ -503,18 +553,22 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
call->dce = dce;
call->replies = NULL;
- ndr = ndr_pull_init_blob(data, mem_ctx);
+ ndr = ndr_pull_init_blob(&dce->partial_input, mem_ctx);
if (!ndr) {
+ talloc_free(dce->mem_ctx, dce->partial_input.data);
talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(dce->mem_ctx, dce->partial_input.data);
talloc_destroy(mem_ctx);
return status;
}
+ dce_partial_advance(dce, ndr->offset);
+
/* see if this is a continued packet */
if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
struct dcesrv_call_state *call2 = call;
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index 38340bcf16..b7206163f4 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -53,6 +53,8 @@ struct dcesrv_call_state {
TALLOC_CTX *mem_ctx;
struct dcerpc_packet pkt;
+ DATA_BLOB input;
+
struct dcesrv_call_reply {
struct dcesrv_call_reply *next, *prev;
DATA_BLOB data;
@@ -101,6 +103,8 @@ struct dcesrv_state {
them, but it will do for now */
uint32 next_handle;
struct dcesrv_handle *handles;
+
+ DATA_BLOB partial_input;
};
diff --git a/source4/rpc_server/dcerpc_tcp.c b/source4/rpc_server/dcerpc_tcp.c
index 110789dba6..1f8230eb1c 100644
--- a/source4/rpc_server/dcerpc_tcp.c
+++ b/source4/rpc_server/dcerpc_tcp.c
@@ -38,7 +38,7 @@ static void dcerpc_write_handler(struct event_context *ev, struct fd_event *fde,
DATA_BLOB blob;
NTSTATUS status;
- blob = data_blob(NULL, 0x4000);
+ blob = data_blob(NULL, 3);
if (!blob.data) {
smb_panic("out of memory in rpc write handler");
}
@@ -63,7 +63,7 @@ static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde,
DATA_BLOB blob;
ssize_t ret;
- blob = data_blob(NULL, 0x4000);
+ blob = data_blob(NULL, 3);
if (!blob.data) {
smb_panic("out of memory in rpc read handler");
}