added handling of fragmented requests in the rpc server
authorAndrew Tridgell <tridge@samba.org>
Fri, 12 Dec 2003 05:01:41 +0000 (05:01 +0000)
committerAndrew Tridgell <tridge@samba.org>
Fri, 12 Dec 2003 05:01:41 +0000 (05:01 +0000)
now we just need to handle fragmented replies ....
(This used to be commit 14005c95d7c6c68f7da0f1ad7b7d7952a04a125b)

source4/rpc_server/dcerpc_server.c
source4/rpc_server/rpc_echo.c

index f5e7ff858e647a95ad876755c0d4b5dff993ed5f..0ee5fad3fceb24575d52f1fa41572cb238eb41a3 100644 (file)
@@ -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:
index d003f34ce411bd5599aa270d3ada7b13885b36b3..37e7dd5bb8536fb2f73b77c8469c2c48536e6e96 100644 (file)
@@ -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;