}
struct dcerpc_binding_handle_call_params_state {
+ struct tevent_context *ev;
struct dcerpc_binding_handle *h;
const struct ndr_interface_call *call;
struct dcerpc_binding_handle_call_params *params;
uint32_t out_pipe_idx;
};
+static void dcerpc_binding_handle_call_params_cleanup(struct tevent_req *req);
static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq);
static void dcerpc_binding_handle_call_params_next_pipe(struct tevent_req *req);
static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq);
+static void dcerpc_binding_handle_call_params_response(struct tevent_req *req);
static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req);
static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p);
return tevent_req_post(req, ev);
}
+ state->ev = ev;
state->h = h;
state->call = &table->calls[opnum];
state->params = params;
return tevent_req_post(req, ev);
}
+ tevent_req_defer_callback(req, ev);
+
/* setup for a ndr_push_* call */
state->push = ndr_push_init_ctx(state);
if (tevent_req_nomem(state->push, req)) {
return req;
}
+static void dcerpc_binding_handle_call_params_cleanup(struct tevent_req *req)
+{
+ struct dcerpc_binding_handle_call_params_state *state =
+ tevent_req_data(req,
+ struct dcerpc_binding_handle_call_params_state);
+
+ dcerpc_pipe_handle_connection_disconnect(state->pc);
+ state->pc = NULL;
+ state->call_pipe = NULL;
+
+ tevent_req_post(req, state->ev);
+}
+
static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
error = dcerpc_binding_handle_raw_call_in_recv(subreq);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, error)) {
+ dcerpc_binding_handle_call_params_cleanup(req);
return;
}
state->ph);
if (!ok) {
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ dcerpc_binding_handle_call_params_cleanup(req);
return;
}
state->ph);
if (!ok) {
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ dcerpc_binding_handle_call_params_cleanup(req);
return;
}
return;
}
state->out_pipe_idx = UINT32_MAX;
+
+ if (state->pull == NULL) {
+ return;
+ }
+
+ if (state->pull->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
+ return;
+ }
+
+ dcerpc_binding_handle_call_params_response(req);
}
static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq)
if (!NT_STATUS_IS_OK(error)) {
TALLOC_FREE(state->subreq);
tevent_req_nterror(req, error);
+ dcerpc_binding_handle_call_params_cleanup(req);
return;
}
* this is a protocol error
*/
tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ dcerpc_binding_handle_call_params_cleanup(req);
return;
}
if (state->pull == NULL) {
state->pull = ndr_pull_init_blob(&state->response, state);
if (tevent_req_nomem(state->pull, req)) {
+ dcerpc_binding_handle_call_params_cleanup(req);
return;
}
state->pull->flags = state->push->flags;
state->pull->flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
}
- ndr_err = NDR_ERR_UNREAD_BYTES;// ndr_pull_append_blob(state->pull,
- // &state->response);
+ ndr_err = ndr_pull_append(state->pull,
+ &state->response);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
error = ndr_map_error2ntstatus(ndr_err);
- if (h->ops->ndr_pull_failed) {
- h->ops->ndr_pull_failed(h, error,
- &state->response,
- state->call);
- }
tevent_req_nterror(req, error);
+ dcerpc_binding_handle_call_params_cleanup(req);
return;
}
}
return;
}
+ dcerpc_binding_handle_call_params_response(req);
+}
+
+static void dcerpc_binding_handle_call_params_response(struct tevent_req *req)
+{
+ struct dcerpc_binding_handle_call_params_state *state =
+ tevent_req_data(req,
+ struct dcerpc_binding_handle_call_params_state);
+ struct dcerpc_binding_handle *h = state->h;
+ NTSTATUS error;
+ enum ndr_err_code ndr_err;
+
state->pull->current_mem_ctx = state->params->r_mem;
/* pull the structure from the blob */
state->call);
}
tevent_req_nterror(req, error);
+ dcerpc_binding_handle_call_params_cleanup(req);
return;
}
state->call);
if (!NT_STATUS_IS_OK(error)) {
tevent_req_nterror(req, error);
+ dcerpc_binding_handle_call_params_cleanup(req);
return;
}
}
struct dcerpc_binding_handle_call_params_pipe *pp =
dcerpc_pipe_handle_data(state->p,
struct dcerpc_binding_handle_call_params_pipe);
- struct dcerpc_binding_handle_call_params_state *call_state =
- tevent_req_data(pp->call_req,
- struct dcerpc_binding_handle_call_params_state);
- dcerpc_pipe_handle_connection_disconnect(call_state->pc);
- call_state->pc = NULL;
- call_state->call_pipe = NULL;
+ if (!state->is_last_chunk) {
+ return 0;
+ }
+
+ dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
return 0;
}
}
state->ev = ev;
state->p = p;
+ state->is_last_chunk = true;
+
+ tevent_req_defer_callback(req, state->ev);
talloc_set_destructor(state,
dcerpc_binding_handle_call_params_push_state_destructor);
state->push->flags = call_state->push->flags;
- //if (h->ops->do_ndr_print) {
- // h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
- // state->params->r_ptr, state->call);
- //}
-
/* push the structure into a blob */
ndr_err = call_state->call_pipe->ndr_push(state->push,
NDR_SCALARS|NDR_BUFFERS,
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
NTSTATUS error;
error = ndr_map_error2ntstatus(ndr_err);
- //if (h->ops->ndr_push_failed) {
- // h->ops->ndr_push_failed(h, error,
- // state->params->r_ptr,
- // state->call);
- //}
tevent_req_nterror(req, error);
return tevent_req_post(req, ev);
}
struct dcerpc_binding_handle_call_params_push_state *state =
tevent_req_data(req,
struct dcerpc_binding_handle_call_params_push_state);
- struct dcerpc_binding_handle_call_params_pipe *pp =
- dcerpc_pipe_handle_data(state->p,
- struct dcerpc_binding_handle_call_params_pipe);
NTSTATUS status;
status = dcerpc_binding_handle_raw_call_in_recv(subreq);
return;
}
- talloc_set_destructor(state, NULL);
-
- if (!state->is_last_chunk) {
- tevent_req_done(req);
- return;
- }
-
- tevent_req_defer_callback(req, state->ev);
tevent_req_done(req);
- dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
}
static NTSTATUS dcerpc_binding_handle_call_params_push_recv(struct tevent_req *req)
struct dcerpc_pipe_handle *p;
void *chunk_mem;
void *chunk_ptr;
+ bool is_last_chunk;
};
static int dcerpc_binding_handle_call_params_pull_state_destructor(
struct dcerpc_binding_handle_call_params_pipe *pp =
dcerpc_pipe_handle_data(state->p,
struct dcerpc_binding_handle_call_params_pipe);
- struct dcerpc_binding_handle_call_params_state *call_state =
- tevent_req_data(pp->call_req,
- struct dcerpc_binding_handle_call_params_state);
pp->pull_req = NULL;
- dcerpc_pipe_handle_connection_disconnect(call_state->pc);
- call_state->pc = NULL;
- call_state->call_pipe = NULL;
+ if (!state->is_last_chunk) {
+ return 0;
+ }
+
+ dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
return 0;
}
state->p = p;
state->chunk_mem = chunk_mem;
state->chunk_ptr = chunk_ptr;
+ state->is_last_chunk = true;
- dcerpc_binding_handle_call_params_pull_notify(req);
- if (!tevent_req_is_in_progress(req)) {
+ if (talloc_total_blocks(chunk_mem) != 1) {
+ /*
+ * As we typically only have autogenerated callers
+ * of this function, we can enforce that chunk_mem
+ * doesn't have any talloc children yet.
+ *
+ * This makes the error handling in the
+ * NDR_ERR_INCOMPLETE_BUFFER case simpler.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
return tevent_req_post(req, ev);
}
+ tevent_req_defer_callback(req, state->ev);
+
talloc_set_destructor(state,
dcerpc_binding_handle_call_params_pull_state_destructor);
pp->pull_req = req;
+ dcerpc_binding_handle_call_params_pull_notify(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
return req;
}
tevent_req_data(pp->call_req,
struct dcerpc_binding_handle_call_params_state);
enum ndr_err_code ndr_err;
+ struct ndr_pull *pipe_pull = NULL;
const uint32_t *count = NULL;
if (call_state->pull == NULL) {
return;
}
- call_state->pull->current_mem_ctx = state->chunk_mem;
+ /*
+ * setup a shallow copy subcontext, which we might destroy
+ */
+ ndr_err = ndr_pull_subcontext_start(call_state->pull, &pipe_pull,
+ 0xFFFFFFFF, 0);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS error;
+ error = ndr_map_error2ntstatus(ndr_err);
+ tevent_req_nterror(req, error);
+ return;
+ }
- /* pull the structure from the blob */
- ndr_err = call_state->call_pipe->ndr_pull(call_state->pull,
+ /* pull the structure from the subcontext */
+ pipe_pull->current_mem_ctx = state->chunk_mem;
+ ndr_err = call_state->call_pipe->ndr_pull(pipe_pull,
NDR_SCALARS|NDR_BUFFERS,
state->chunk_ptr);
if (ndr_err == NDR_ERR_INCOMPLETE_BUFFER) {
+ TALLOC_FREE(pipe_pull);
+ talloc_free_children(state->chunk_mem);
return;
}
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
NTSTATUS error;
error = ndr_map_error2ntstatus(ndr_err);
- //if (h->ops->ndr_pull_failed) {
- // h->ops->ndr_pull_failed(h, error,
- // &state->response,
- // state->call);
- //}
tevent_req_nterror(req, error);
return;
}
- //if (h->ops->do_ndr_print) {
- // h->ops->do_ndr_print(h, NDR_OUT,
- // state->params->r_ptr, state->call);
- //}
-
- //if (h->ops->ndr_validate_out) {
- // error = h->ops->ndr_validate_out(h,
- // state->pull,
- // state->params->r_ptr,
- // state->call);
- // if (!NT_STATUS_IS_OK(error)) {
- // tevent_req_nterror(req, error);
- // return;
- // }
- //}
-
- //ndr_err = ndr_pull_pop(call_state->pull);
+ ndr_err = ndr_pull_subcontext_end(call_state->pull, pipe_pull,
+ 0xFFFFFFFF, 0);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
NTSTATUS error;
error = ndr_map_error2ntstatus(ndr_err);
tevent_req_nterror(req, error);
return;
}
+ TALLOC_FREE(pipe_pull);
- pp->pull_req = NULL;
- talloc_set_destructor(state, NULL);
+ ndr_err = ndr_pull_pop(call_state->pull);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS error;
+ error = ndr_map_error2ntstatus(ndr_err);
+ tevent_req_nterror(req, error);
+ return;
+ }
/*
* Note: the first struct member is always
count = (const uint32_t *)state->chunk_ptr;
if (*count != 0) {
+ state->is_last_chunk = false;
tevent_req_done(req);
return;
}
- tevent_req_defer_callback(req, state->ev);
+ state->is_last_chunk = true;
tevent_req_done(req);
- dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
}