summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-12-12 05:01:41 +0000
committerAndrew Tridgell <tridge@samba.org>2003-12-12 05:01:41 +0000
commitdab0deae833d1180f61e7d4112966990d4c19600 (patch)
treea0d396b8c8687c085271bd5eeeca13c89e3d33ea /source4
parent869df3adbd02f8a151e54c3216155163979b99fe (diff)
downloadsamba-dab0deae833d1180f61e7d4112966990d4c19600.tar.gz
samba-dab0deae833d1180f61e7d4112966990d4c19600.tar.bz2
samba-dab0deae833d1180f61e7d4112966990d4c19600.zip
added handling of fragmented requests in the rpc server
now we just need to handle fragmented replies .... (This used to be commit 14005c95d7c6c68f7da0f1ad7b7d7952a04a125b)
Diffstat (limited to 'source4')
-rw-r--r--source4/rpc_server/dcerpc_server.c71
-rw-r--r--source4/rpc_server/rpc_echo.c4
2 files changed, 67 insertions, 8 deletions
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index f5e7ff858e..0ee5fad3fc 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -37,6 +37,19 @@ static const struct dcesrv_endpoint_ops *find_endpoint(struct server_context *sm
return NULL;
}
+/*
+ find a call that is pending in our call list
+*/
+static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_state *dce, uint16 call_id)
+{
+ struct dcesrv_call_state *c;
+ for (c=dce->call_list;c;c=c->next) {
+ if (c->pkt.call_id == call_id) {
+ return c;
+ }
+ }
+ return NULL;
+}
/*
register an endpoint server
@@ -248,11 +261,6 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
DATA_BLOB stub;
struct dcerpc_packet pkt;
- if (call->pkt.pfc_flags != (DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST)) {
- /* we don't do fragments in the server yet */
- return dcesrv_fault(call, DCERPC_FAULT_TODO);
- }
-
opnum = call->pkt.u.request.opnum;
if (opnum >= call->dce->ndr->num_calls) {
@@ -349,6 +357,7 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
}
call->mem_ctx = mem_ctx;
call->dce = dce;
+ call->data = data_blob(NULL, 0);
ndr = ndr_pull_init_blob(data, mem_ctx);
if (!ndr) {
@@ -362,10 +371,56 @@ NTSTATUS dcesrv_input(struct dcesrv_state *dce, const DATA_BLOB *data)
return status;
}
- /* TODO: at this point we should see if the packet is a
- continuation of an existing call, but I'm too lazy for that
- right now ... maybe tomorrow */
+ /* see if this is a continued packet */
+ if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
+ struct dcesrv_call_state *call2 = call;
+ uint32 alloc_size;
+
+ /* we only allow fragmented requests, no other packet types */
+ if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
+ return dcesrv_fault(call2, DCERPC_FAULT_TODO);
+ }
+
+ /* this is a continuation of an existing call - find the call then
+ tack it on the end */
+ call = dcesrv_find_call(dce, call2->pkt.call_id);
+ if (!call) {
+ return dcesrv_fault(call2, DCERPC_FAULT_TODO);
+ }
+
+ if (call->pkt.ptype != call2->pkt.ptype) {
+ /* trying to play silly buggers are we? */
+ return dcesrv_fault(call2, DCERPC_FAULT_TODO);
+ }
+
+ alloc_size = call->pkt.u.request.stub_and_verifier.length +
+ call2->pkt.u.request.stub_and_verifier.length;
+ if (call->pkt.u.request.alloc_hint > alloc_size) {
+ alloc_size = call->pkt.u.request.alloc_hint;
+ }
+
+ call->pkt.u.request.stub_and_verifier.data =
+ talloc_realloc(call->mem_ctx,
+ call->pkt.u.request.stub_and_verifier.data, alloc_size);
+ if (!call->pkt.u.request.stub_and_verifier.data) {
+ return dcesrv_fault(call2, DCERPC_FAULT_TODO);
+ }
+ memcpy(call->pkt.u.request.stub_and_verifier.data +
+ call->pkt.u.request.stub_and_verifier.length,
+ call2->pkt.u.request.stub_and_verifier.data,
+ call2->pkt.u.request.stub_and_verifier.length);
+ call->pkt.u.request.stub_and_verifier.length +=
+ call2->pkt.u.request.stub_and_verifier.length;
+
+ call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
+ }
+ /* this may not be the last pdu in the chain - if its isn't then
+ just put it on the call_list and wait for the rest */
+ if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
+ DLIST_ADD_END(dce->call_list, call, struct dcesrv_call_state *);
+ return NT_STATUS_OK;
+ }
switch (call->pkt.ptype) {
case DCERPC_PKT_BIND:
diff --git a/source4/rpc_server/rpc_echo.c b/source4/rpc_server/rpc_echo.c
index d003f34ce4..37e7dd5bb8 100644
--- a/source4/rpc_server/rpc_echo.c
+++ b/source4/rpc_server/rpc_echo.c
@@ -31,6 +31,10 @@ static NTSTATUS echo_AddOne(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struc
static NTSTATUS echo_EchoData(struct dcesrv_state *dce, TALLOC_CTX *mem_ctx, struct echo_EchoData *r)
{
+ r->out.out_data = talloc(mem_ctx, r->in.len);
+ if (!r->out.out_data) {
+ return NT_STATUS_NO_MEMORY;
+ }
memcpy(r->out.out_data, r->in.in_data, r->in.len);
return NT_STATUS_OK;