librpc/rpc: add dcerpc_binding_handle_raw_call_in_*
authorStefan Metzmacher <metze@samba.org>
Fri, 30 Aug 2013 09:56:18 +0000 (11:56 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 4 Jun 2019 11:14:55 +0000 (13:14 +0200)
The binding handle backend can support LIBNDR_FLAG_INCOMPLETE_BUFFER
with this change and implement the raw_call_in_send/recv functions
to get more data from the caller. The final chunk clears the
LIBNDR_FLAG_INCOMPLETE_BUFFER flag in the in_flags of raw_call_in_send().

If LIBNDR_FLAG_INCOMPLETE_BUFFER was indicated in the in_flags of raw_call_send()
the backend can deliver partial results to the caller,
in raw_call_recv() by specifying LIBNDR_FLAG_INCOMPLETE_BUFFER in the out_flags.
In that case the caller should not call TALLOC_FREE(subreq)
as there's more to come. The backend continues to delivers results by
raw_call_recv() and clears LIBNDR_FLAG_INCOMPLETE_BUFFER on the last chunk.

This will be used to implement support for DCERPC pipes.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
librpc/rpc/binding_handle.c
librpc/rpc/rpc_common.h

index c42b4e9900cacee5013c55d756d81f5927a9925e..42347f0470a547112f4fb5477bd75fd708af60dd 100644 (file)
@@ -167,6 +167,13 @@ struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
                object = h->object;
        }
 
+       if (state->ops->raw_call_in_send == NULL) {
+               if (in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
+                       tevent_req_nterror(req, NT_STATUS_RPC_CANNOT_SUPPORT);
+                       return tevent_req_post(req, ev);
+               }
+       }
+
        state->subreq = state->ops->raw_call_send(state, ev, h,
                                                  object, opnum,
                                                  in_flags, in_data, in_length);
@@ -259,6 +266,11 @@ NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
                goto fail;
        }
 
+       if (in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
+               talloc_free(frame);
+               return NT_STATUS_INVALID_PARAMETER_MIX;
+       }
+
        subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
                                                     h, object, opnum,
                                                     in_flags,
@@ -282,6 +294,102 @@ fail:
        return status;
 }
 
+struct dcerpc_binding_handle_raw_call_in_state {
+       const struct dcerpc_binding_handle_ops *ops;
+       struct tevent_context *ev;
+       struct tevent_req *subreq;
+};
+
+static void dcerpc_binding_handle_raw_call_in_done(struct tevent_req *subreq);
+
+struct tevent_req *dcerpc_binding_handle_raw_call_in_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct tevent_req *raw_call_req,
+                                               uint32_t in_flags,
+                                               const uint8_t *in_data,
+                                               size_t in_length)
+{
+       struct dcerpc_binding_handle_raw_call_state *raw_call_state =
+               tevent_req_data(raw_call_req,
+               struct dcerpc_binding_handle_raw_call_state);
+       struct tevent_req *req;
+       struct dcerpc_binding_handle_raw_call_in_state *state;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct dcerpc_binding_handle_raw_call_in_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->ops = raw_call_state->ops;
+       state->ev = ev;
+
+       if (state->ev != raw_call_state->ev) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+               return tevent_req_post(req, ev);
+       }
+
+       if (state->ops->raw_call_in_send == NULL) {
+               tevent_req_nterror(req, NT_STATUS_RPC_CANNOT_SUPPORT);
+               return tevent_req_post(req, ev);
+       }
+
+       state->subreq = state->ops->raw_call_in_send(state, ev,
+                                                    raw_call_state->subreq,
+                                                    in_flags,
+                                                    in_data,
+                                                    in_length);
+       if (tevent_req_nomem(state->subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       tevent_req_set_callback(state->subreq,
+                               dcerpc_binding_handle_raw_call_in_done,
+                               req);
+       return req;
+}
+
+static void dcerpc_binding_handle_raw_call_in_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq,
+               struct tevent_req);
+
+       if (tevent_req_is_in_progress(subreq)) {
+               tevent_req_notify_callback(req);
+               return;
+       }
+
+       tevent_req_done(req);
+}
+
+NTSTATUS dcerpc_binding_handle_raw_call_in_recv(struct tevent_req *req)
+{
+       struct dcerpc_binding_handle_raw_call_in_state *state =
+               tevent_req_data(req,
+               struct dcerpc_binding_handle_raw_call_in_state);
+       NTSTATUS error;
+
+       if (!tevent_req_is_in_progress(req)) {
+               if (tevent_req_is_nterror(req, &error)) {
+                       tevent_req_received(req);
+                       return error;
+               }
+       }
+
+       error = state->ops->raw_call_in_recv(state->subreq);
+       if (!NT_STATUS_IS_OK(error)) {
+               tevent_req_received(req);
+               return error;
+       }
+
+       if (tevent_req_is_in_progress(state->subreq)) {
+               return NT_STATUS_OK;
+       }
+
+       tevent_req_received(req);
+       return error;
+}
+
 struct dcerpc_binding_handle_disconnect_state {
        const struct dcerpc_binding_handle_ops *ops;
 };
index 8a8d3be6c3ee263c5d7e06ece562a05561e2b17c..8ea2ee344f107efe24bf4a97b7ded3a8957baf80 100644 (file)
@@ -276,6 +276,13 @@ struct dcerpc_binding_handle_ops {
                                  uint8_t **out_data,
                                  size_t *out_length,
                                  uint32_t *out_flags);
+       struct tevent_req *(*raw_call_in_send)(TALLOC_CTX *mem_ctx,
+                                              struct tevent_context *ev,
+                                              struct tevent_req *raw_call_req,
+                                              uint32_t in_flags,
+                                              const uint8_t *in_data,
+                                              size_t in_length);
+       NTSTATUS (*raw_call_in_recv)(struct tevent_req *req);
 
        struct tevent_req *(*disconnect_send)(TALLOC_CTX *mem_ctx,
                                              struct tevent_context *ev,
@@ -360,6 +367,13 @@ NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
                                        uint8_t **out_data,
                                        size_t *out_length,
                                        uint32_t *out_flags);
+struct tevent_req *dcerpc_binding_handle_raw_call_in_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct tevent_req *raw_call_req,
+                                               uint32_t in_flags,
+                                               const uint8_t *in_data,
+                                               size_t in_length);
+NTSTATUS dcerpc_binding_handle_raw_call_in_recv(struct tevent_req *req);
 
 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
                                                struct tevent_context *ev,