2 Unix SMB/CIFS implementation.
4 dcerpc binding handle functions
6 Copyright (C) Stefan Metzmacher 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "librpc/rpc/dcerpc.h"
26 #include "rpc_common.h"
28 struct dcerpc_binding_handle {
30 const struct dcerpc_binding_handle_ops *ops;
32 const struct GUID *object;
33 const struct ndr_interface_table *table;
34 struct tevent_context *sync_ev;
37 static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
42 struct dcerpc_binding_handle *_dcerpc_binding_handle_create(TALLOC_CTX *mem_ctx,
43 const struct dcerpc_binding_handle_ops *ops,
44 const struct GUID *object,
45 const struct ndr_interface_table *table,
51 struct dcerpc_binding_handle *h;
52 void **ppstate = (void **)pstate;
55 h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
60 h->location = location;
64 state = talloc_zero_size(h, psize);
69 talloc_set_name_const(state, type);
71 h->private_data = state;
73 talloc_set_destructor(h, dcerpc_binding_handle_destructor);
79 void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
81 return h->private_data;
84 void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
85 struct tevent_context *ev)
90 bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
92 return h->ops->is_connected(h);
95 uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
98 return h->ops->set_timeout(h, timeout);
101 void dcerpc_binding_handle_auth_info(struct dcerpc_binding_handle *h,
102 enum dcerpc_AuthType *auth_type,
103 enum dcerpc_AuthLevel *auth_level)
105 enum dcerpc_AuthType _auth_type;
106 enum dcerpc_AuthLevel _auth_level;
108 if (auth_type == NULL) {
109 auth_type = &_auth_type;
112 if (auth_level == NULL) {
113 auth_level = &_auth_level;
116 *auth_type = DCERPC_AUTH_TYPE_NONE;
117 *auth_level = DCERPC_AUTH_LEVEL_NONE;
119 if (h->ops->auth_info == NULL) {
123 h->ops->auth_info(h, auth_type, auth_level);
126 struct dcerpc_binding_handle_raw_call_state {
127 const struct dcerpc_binding_handle_ops *ops;
128 struct tevent_context *ev;
129 struct tevent_req *subreq;
132 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
134 struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
135 struct tevent_context *ev,
136 struct dcerpc_binding_handle *h,
137 const struct GUID *object,
140 const uint8_t *in_data,
143 struct tevent_req *req;
144 struct dcerpc_binding_handle_raw_call_state *state;
146 req = tevent_req_create(mem_ctx, &state,
147 struct dcerpc_binding_handle_raw_call_state);
154 if (h->object != NULL) {
156 * If an object is set on the binding handle,
157 * per request object passing is not allowed.
159 if (object != NULL) {
160 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
161 return tevent_req_post(req, ev);
165 * We use the object from the binding handle
170 if (state->ops->raw_call_in_send == NULL) {
171 if (in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
172 tevent_req_nterror(req, NT_STATUS_RPC_CANNOT_SUPPORT);
173 return tevent_req_post(req, ev);
177 state->subreq = state->ops->raw_call_send(state, ev, h,
179 in_flags, in_data, in_length);
180 if (tevent_req_nomem(state->subreq, req)) {
181 return tevent_req_post(req, ev);
183 tevent_req_set_callback(state->subreq,
184 dcerpc_binding_handle_raw_call_done,
190 static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
192 struct tevent_req *req =
193 tevent_req_callback_data(subreq,
196 if (tevent_req_is_in_progress(subreq)) {
197 tevent_req_notify_callback(req);
201 tevent_req_done(req);
204 NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
210 struct dcerpc_binding_handle_raw_call_state *state =
212 struct dcerpc_binding_handle_raw_call_state);
215 if (!tevent_req_is_in_progress(req)) {
216 if (tevent_req_is_nterror(req, &error)) {
217 tevent_req_received(req);
222 error = state->ops->raw_call_recv(state->subreq,
227 if (!NT_STATUS_IS_OK(error)) {
228 tevent_req_received(req);
232 if (tevent_req_is_in_progress(state->subreq)) {
236 tevent_req_received(req);
240 NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
241 const struct GUID *object,
244 const uint8_t *in_data,
251 TALLOC_CTX *frame = talloc_stackframe();
252 struct tevent_context *ev;
253 struct tevent_req *subreq;
254 NTSTATUS status = NT_STATUS_NO_MEMORY;
257 * TODO: allow only one sync call
263 ev = samba_tevent_context_init(frame);
269 if (in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
271 return NT_STATUS_INVALID_PARAMETER_MIX;
274 subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
279 if (subreq == NULL) {
283 if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
287 status = dcerpc_binding_handle_raw_call_recv(subreq,
297 struct dcerpc_binding_handle_raw_call_in_state {
298 const struct dcerpc_binding_handle_ops *ops;
299 struct tevent_context *ev;
300 struct tevent_req *subreq;
303 static void dcerpc_binding_handle_raw_call_in_done(struct tevent_req *subreq);
305 struct tevent_req *dcerpc_binding_handle_raw_call_in_send(TALLOC_CTX *mem_ctx,
306 struct tevent_context *ev,
307 struct tevent_req *raw_call_req,
309 const uint8_t *in_data,
312 struct dcerpc_binding_handle_raw_call_state *raw_call_state =
313 tevent_req_data(raw_call_req,
314 struct dcerpc_binding_handle_raw_call_state);
315 struct tevent_req *req;
316 struct dcerpc_binding_handle_raw_call_in_state *state;
318 req = tevent_req_create(mem_ctx, &state,
319 struct dcerpc_binding_handle_raw_call_in_state);
323 state->ops = raw_call_state->ops;
326 if (state->ev != raw_call_state->ev) {
327 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
328 return tevent_req_post(req, ev);
331 if (state->ops->raw_call_in_send == NULL) {
332 tevent_req_nterror(req, NT_STATUS_RPC_CANNOT_SUPPORT);
333 return tevent_req_post(req, ev);
336 state->subreq = state->ops->raw_call_in_send(state, ev,
337 raw_call_state->subreq,
341 if (tevent_req_nomem(state->subreq, req)) {
342 return tevent_req_post(req, ev);
345 tevent_req_set_callback(state->subreq,
346 dcerpc_binding_handle_raw_call_in_done,
351 static void dcerpc_binding_handle_raw_call_in_done(struct tevent_req *subreq)
353 struct tevent_req *req =
354 tevent_req_callback_data(subreq,
357 if (tevent_req_is_in_progress(subreq)) {
358 tevent_req_notify_callback(req);
362 tevent_req_done(req);
365 NTSTATUS dcerpc_binding_handle_raw_call_in_recv(struct tevent_req *req)
367 struct dcerpc_binding_handle_raw_call_in_state *state =
369 struct dcerpc_binding_handle_raw_call_in_state);
372 if (!tevent_req_is_in_progress(req)) {
373 if (tevent_req_is_nterror(req, &error)) {
374 tevent_req_received(req);
379 error = state->ops->raw_call_in_recv(state->subreq);
380 if (!NT_STATUS_IS_OK(error)) {
381 tevent_req_received(req);
385 if (tevent_req_is_in_progress(state->subreq)) {
389 tevent_req_received(req);
393 struct dcerpc_binding_handle_disconnect_state {
394 const struct dcerpc_binding_handle_ops *ops;
397 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
399 struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
400 struct tevent_context *ev,
401 struct dcerpc_binding_handle *h)
403 struct tevent_req *req;
404 struct dcerpc_binding_handle_disconnect_state *state;
405 struct tevent_req *subreq;
407 req = tevent_req_create(mem_ctx, &state,
408 struct dcerpc_binding_handle_disconnect_state);
415 subreq = state->ops->disconnect_send(state, ev, h);
416 if (tevent_req_nomem(subreq, req)) {
417 return tevent_req_post(req, ev);
419 tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
424 static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
426 struct tevent_req *req = tevent_req_callback_data(subreq,
428 struct dcerpc_binding_handle_disconnect_state *state =
430 struct dcerpc_binding_handle_disconnect_state);
433 error = state->ops->disconnect_recv(subreq);
435 if (tevent_req_nterror(req, error)) {
439 tevent_req_done(req);
442 NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
446 if (tevent_req_is_nterror(req, &error)) {
447 tevent_req_received(req);
451 tevent_req_received(req);
455 struct dcerpc_binding_handle_call_params_state {
456 struct tevent_context *ev;
457 struct dcerpc_binding_handle *h;
458 const struct ndr_interface_call *call;
459 struct dcerpc_binding_handle_call_params *params;
461 struct ndr_push *push;
463 struct tevent_req *subreq;
465 struct ndr_pull *pull;
466 uint32_t pull_missing;
468 struct dcerpc_pipe_handle *ph;
469 struct dcerpc_pipe_handle_connection *pc;
470 const struct ndr_interface_call_pipe *call_pipe;
471 uint32_t in_pipe_idx;
472 uint32_t out_pipe_idx;
475 static void dcerpc_binding_handle_call_params_cleanup(struct tevent_req *req);
476 static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq);
477 static void dcerpc_binding_handle_call_params_next_pipe(struct tevent_req *req);
478 static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq);
479 static void dcerpc_binding_handle_call_params_response(struct tevent_req *req);
480 static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req);
481 static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p);
483 struct tevent_req *dcerpc_binding_handle_call_params_send(TALLOC_CTX *mem_ctx,
484 struct tevent_context *ev,
485 struct dcerpc_binding_handle *h,
486 const struct GUID *object,
487 const struct ndr_interface_table *table,
489 struct dcerpc_binding_handle_call_params *params)
491 struct tevent_req *req;
492 struct dcerpc_binding_handle_call_params_state *state;
493 enum ndr_err_code ndr_err;
495 req = tevent_req_create(mem_ctx, &state,
496 struct dcerpc_binding_handle_call_params_state);
501 if (table != h->table) {
502 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
503 return tevent_req_post(req, ev);
506 if (opnum >= table->num_calls) {
507 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
508 return tevent_req_post(req, ev);
513 state->call = &table->calls[opnum];
514 state->params = params;
516 if (params->in.num_pipes != state->call->in_pipes.num_pipes) {
517 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
518 return tevent_req_post(req, ev);
521 if (params->out.num_pipes != state->call->out_pipes.num_pipes) {
522 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
523 return tevent_req_post(req, ev);
526 tevent_req_defer_callback(req, ev);
528 /* setup for a ndr_push_* call */
529 state->push = ndr_push_init_ctx(state);
530 if (tevent_req_nomem(state->push, req)) {
531 return tevent_req_post(req, ev);
534 if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
535 state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
538 if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
539 state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
540 state->in_flags |= LIBNDR_FLAG_BIGENDIAN;
543 if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
544 state->push->flags |= LIBNDR_FLAG_NDR64;
547 if (h->ops->do_ndr_print) {
548 h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
549 state->params->r_ptr, state->call);
552 /* push the structure into a blob */
553 ndr_err = state->call->ndr_push(state->push, NDR_IN, state->params->r_ptr);
554 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
556 error = ndr_map_error2ntstatus(ndr_err);
557 if (h->ops->ndr_push_failed) {
558 h->ops->ndr_push_failed(h, error,
559 state->params->r_ptr,
562 tevent_req_nterror(req, error);
563 return tevent_req_post(req, ev);
566 /* retrieve the blob */
567 state->request = ndr_push_blob(state->push);
569 if (h->ops->ndr_validate_in) {
571 error = h->ops->ndr_validate_in(h, state,
574 if (!NT_STATUS_IS_OK(error)) {
575 tevent_req_nterror(req, error);
576 return tevent_req_post(req, ev);
580 if (params->in.num_pipes != 0) {
581 state->in_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
584 * push alignment for the next pipe chunk
586 ndr_err = ndr_push_align(state->push, 5);
587 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
589 error = ndr_map_error2ntstatus(ndr_err);
590 tevent_req_nterror(req, error);
591 return tevent_req_post(req, ev);
595 if (params->out.num_pipes != 0) {
597 * even if we only have output pipes we need to indicate that
598 * we want to get incomplete results
600 state->in_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
603 if (state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
604 dcerpc_binding_handle_call_params_pipe_setup(req);
605 if (!tevent_req_is_in_progress(req)) {
606 return tevent_req_post(req, ev);
610 /* retrieve the blob - including possible pipe chunk alignment */
611 state->request = ndr_push_blob(state->push);
613 state->subreq = dcerpc_binding_handle_raw_call_send(state, ev,
617 state->request.length);
618 if (tevent_req_nomem(state->subreq, req)) {
619 return tevent_req_post(req, ev);
621 tevent_req_set_callback(state->subreq,
622 dcerpc_binding_handle_call_params_done,
625 if (!(state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
627 * we didn't ask for any pipes
629 * Indicate that all pipes are done.
631 state->in_pipe_idx = UINT32_MAX;
632 state->out_pipe_idx = UINT32_MAX;
637 * If the subreq is already finished, the backend
638 * may not support LIBNDR_FLAG_INCOMPLETE_BUFFER
640 if (!tevent_req_is_in_progress(state->subreq)) {
644 dcerpc_binding_handle_call_params_next_pipe(req);
645 if (!tevent_req_is_in_progress(req)) {
646 return tevent_req_post(req, ev);
649 if (state->params->in.num_pipes == 0) {
650 struct tevent_req *subreq;
653 * We have only out pipes,
654 * so indicate that we're done with sending in_data.
656 state->in_pipe_idx = UINT32_MAX;
657 state->in_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
658 subreq = dcerpc_binding_handle_raw_call_in_send(state, ev,
663 if (tevent_req_nomem(subreq, req)) {
664 return tevent_req_post(req, ev);
666 tevent_req_set_callback(subreq,
667 dcerpc_binding_handle_call_params_in_done,
675 static void dcerpc_binding_handle_call_params_cleanup(struct tevent_req *req)
677 struct dcerpc_binding_handle_call_params_state *state =
679 struct dcerpc_binding_handle_call_params_state);
681 dcerpc_pipe_handle_connection_disconnect(state->pc);
683 state->call_pipe = NULL;
685 tevent_req_post(req, state->ev);
688 static void dcerpc_binding_handle_call_params_in_done(struct tevent_req *subreq)
690 struct tevent_req *req = tevent_req_callback_data(subreq,
694 error = dcerpc_binding_handle_raw_call_in_recv(subreq);
696 if (tevent_req_nterror(req, error)) {
697 dcerpc_binding_handle_call_params_cleanup(req);
706 static void dcerpc_binding_handle_call_params_next_pipe(struct tevent_req *req)
708 struct dcerpc_binding_handle_call_params_state *state =
710 struct dcerpc_binding_handle_call_params_state);
711 struct dcerpc_binding_handle_call_params *params = state->params;
714 dcerpc_pipe_handle_connection_disconnect(state->pc);
716 state->call_pipe = NULL;
718 if (state->in_pipe_idx < params->in.num_pipes) {
719 uint32_t idx = state->in_pipe_idx++;
721 state->pc = params->in.pipes[idx];
722 state->call_pipe = &state->call->in_pipes.pipes[idx];
724 ok = dcerpc_pipe_handle_connection_push_connect(state->pc,
725 state->call_pipe->chunk_struct_name,
726 state->call_pipe->chunk_struct_size,
729 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
730 dcerpc_binding_handle_call_params_cleanup(req);
736 state->in_pipe_idx = UINT32_MAX;
738 if (state->out_pipe_idx < params->out.num_pipes) {
739 uint32_t idx = state->out_pipe_idx++;
741 state->pc = params->out.pipes[idx];
742 state->call_pipe = &state->call->out_pipes.pipes[idx];
744 ok = dcerpc_pipe_handle_connection_pull_connect(state->pc,
745 state->call_pipe->chunk_struct_name,
746 state->call_pipe->chunk_struct_size,
749 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
750 dcerpc_binding_handle_call_params_cleanup(req);
756 state->out_pipe_idx = UINT32_MAX;
758 if (state->pull == NULL) {
762 if (state->pull->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
766 dcerpc_binding_handle_call_params_response(req);
769 static void dcerpc_binding_handle_call_params_done(struct tevent_req *subreq)
771 struct tevent_req *req = tevent_req_callback_data(subreq,
773 struct dcerpc_binding_handle_call_params_state *state =
775 struct dcerpc_binding_handle_call_params_state);
776 struct dcerpc_binding_handle *h = state->h;
778 uint32_t out_flags = 0;
779 enum ndr_err_code ndr_err;
781 error = dcerpc_binding_handle_raw_call_recv(subreq, state,
782 &state->response.data,
783 &state->response.length,
786 if (!NT_STATUS_IS_OK(error)) {
787 TALLOC_FREE(state->subreq);
788 tevent_req_nterror(req, error);
789 dcerpc_binding_handle_call_params_cleanup(req);
793 if (!(out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
794 TALLOC_FREE(state->subreq);
797 if (state->in_pipe_idx != UINT32_MAX) {
799 * we haven't send all data yet,
800 * this is a protocol error
802 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
803 dcerpc_binding_handle_call_params_cleanup(req);
807 if (state->pull == NULL) {
808 state->pull = ndr_pull_init_blob(&state->response, state);
809 if (tevent_req_nomem(state->pull, req)) {
810 dcerpc_binding_handle_call_params_cleanup(req);
813 state->pull->flags = state->push->flags;
815 if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
816 state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
818 state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
821 if (out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
822 state->pull->flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
825 if (!(out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
826 state->pull->flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
829 ndr_err = ndr_pull_append(state->pull,
831 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
832 error = ndr_map_error2ntstatus(ndr_err);
833 tevent_req_nterror(req, error);
834 dcerpc_binding_handle_call_params_cleanup(req);
837 state->pull_missing -= MIN(state->pull_missing, state->response.length);
838 data_blob_free(&state->response);
841 if (state->out_pipe_idx != UINT32_MAX) {
842 dcerpc_binding_handle_call_params_pipe_notify(state->ph);
846 dcerpc_binding_handle_call_params_response(req);
849 static void dcerpc_binding_handle_call_params_response(struct tevent_req *req)
851 struct dcerpc_binding_handle_call_params_state *state =
853 struct dcerpc_binding_handle_call_params_state);
854 struct dcerpc_binding_handle *h = state->h;
856 enum ndr_err_code ndr_err;
858 state->pull->current_mem_ctx = state->params->r_mem;
860 /* pull the structure from the blob */
861 ndr_err = state->call->ndr_pull(state->pull, NDR_OUT,
862 state->params->r_ptr);
863 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
864 error = ndr_map_error2ntstatus(ndr_err);
865 if (h->ops->ndr_pull_failed) {
866 h->ops->ndr_pull_failed(h, error,
870 tevent_req_nterror(req, error);
871 dcerpc_binding_handle_call_params_cleanup(req);
875 if (h->ops->do_ndr_print) {
876 h->ops->do_ndr_print(h, NDR_OUT,
877 state->params->r_ptr, state->call);
880 if (h->ops->ndr_validate_out) {
881 error = h->ops->ndr_validate_out(h,
883 state->params->r_ptr,
885 if (!NT_STATUS_IS_OK(error)) {
886 tevent_req_nterror(req, error);
887 dcerpc_binding_handle_call_params_cleanup(req);
892 tevent_req_done(req);
895 NTSTATUS dcerpc_binding_handle_call_params_recv(struct tevent_req *req)
897 return tevent_req_simple_recv_ntstatus(req);
900 struct dcerpc_binding_handle_call_params_pipe {
901 struct tevent_req *call_req;
902 struct tevent_req *pull_req;
905 struct dcerpc_binding_handle_call_params_push_state {
906 struct tevent_context *ev;
907 struct dcerpc_pipe_handle *p;
908 struct ndr_push *push;
909 DATA_BLOB chunk_blob;
913 static int dcerpc_binding_handle_call_params_push_state_destructor(
914 struct dcerpc_binding_handle_call_params_push_state *state)
916 struct dcerpc_binding_handle_call_params_pipe *pp =
917 dcerpc_pipe_handle_data(state->p,
918 struct dcerpc_binding_handle_call_params_pipe);
920 if (!state->is_last_chunk) {
924 dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
928 static void dcerpc_binding_handle_call_params_push_done(struct tevent_req *subreq);
930 static struct tevent_req *dcerpc_binding_handle_call_params_push_send(TALLOC_CTX *mem_ctx,
931 struct tevent_context *ev,
932 struct dcerpc_pipe_handle *p,
933 const void *chunk_ptr)
935 struct dcerpc_binding_handle_call_params_pipe *pp =
936 dcerpc_pipe_handle_data(p,
937 struct dcerpc_binding_handle_call_params_pipe);
938 struct dcerpc_binding_handle_call_params_state *call_state =
939 tevent_req_data(pp->call_req,
940 struct dcerpc_binding_handle_call_params_state);
941 struct tevent_req *req;
942 struct dcerpc_binding_handle_call_params_push_state *state;
943 struct tevent_req *subreq;
944 enum ndr_err_code ndr_err;
945 const uint32_t *count = NULL;
946 bool is_last_pipe = false;
948 req = tevent_req_create(mem_ctx, &state,
949 struct dcerpc_binding_handle_call_params_push_state);
955 state->is_last_chunk = true;
957 tevent_req_defer_callback(req, state->ev);
959 talloc_set_destructor(state,
960 dcerpc_binding_handle_call_params_push_state_destructor);
962 /* setup for a ndr_push_* call */
963 state->push = ndr_push_init_ctx(state);
964 if (tevent_req_nomem(state->push, req)) {
965 return tevent_req_post(req, ev);
968 state->push->flags = call_state->push->flags;
970 /* push the structure into a blob */
971 ndr_err = call_state->call_pipe->ndr_push(state->push,
972 NDR_SCALARS|NDR_BUFFERS,
974 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
976 error = ndr_map_error2ntstatus(ndr_err);
977 tevent_req_nterror(req, error);
978 return tevent_req_post(req, ev);
982 * Note: the first struct member is always
985 count = (const uint32_t *)chunk_ptr;
987 state->is_last_chunk = false;
989 state->is_last_chunk = true;
992 if (call_state->in_pipe_idx >= call_state->params->in.num_pipes) {
996 if (is_last_pipe && state->is_last_chunk) {
997 call_state->in_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
1000 * push alignment for the next pipe chunk
1002 ndr_err = ndr_push_align(state->push, 5);
1003 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1005 error = ndr_map_error2ntstatus(ndr_err);
1006 tevent_req_nterror(req, error);
1007 return tevent_req_post(req, ev);
1011 /* retrieve the blob - including possible alignment for the next chunk */
1012 state->chunk_blob = ndr_push_blob(state->push);
1014 subreq = dcerpc_binding_handle_raw_call_in_send(state, ev,
1016 call_state->in_flags,
1017 state->chunk_blob.data,
1018 state->chunk_blob.length);
1019 if (tevent_req_nomem(subreq, req)) {
1020 return tevent_req_post(req, ev);
1022 tevent_req_set_callback(subreq,
1023 dcerpc_binding_handle_call_params_push_done,
1029 static void dcerpc_binding_handle_call_params_push_done(struct tevent_req *subreq)
1031 struct tevent_req *req =
1032 tevent_req_callback_data(subreq,
1034 struct dcerpc_binding_handle_call_params_push_state *state =
1035 tevent_req_data(req,
1036 struct dcerpc_binding_handle_call_params_push_state);
1039 status = dcerpc_binding_handle_raw_call_in_recv(subreq);
1040 TALLOC_FREE(subreq);
1041 TALLOC_FREE(state->push);
1042 if (tevent_req_nterror(req, status)) {
1046 tevent_req_done(req);
1049 static NTSTATUS dcerpc_binding_handle_call_params_push_recv(struct tevent_req *req)
1051 return tevent_req_simple_recv_ntstatus(req);
1054 struct dcerpc_binding_handle_call_params_pull_state {
1055 struct tevent_context *ev;
1056 struct dcerpc_pipe_handle *p;
1062 static int dcerpc_binding_handle_call_params_pull_state_destructor(
1063 struct dcerpc_binding_handle_call_params_pull_state *state)
1065 struct dcerpc_binding_handle_call_params_pipe *pp =
1066 dcerpc_pipe_handle_data(state->p,
1067 struct dcerpc_binding_handle_call_params_pipe);
1069 pp->pull_req = NULL;
1071 if (!state->is_last_chunk) {
1075 dcerpc_binding_handle_call_params_next_pipe(pp->call_req);
1079 static void dcerpc_binding_handle_call_params_pull_notify(struct tevent_req *req);
1081 static struct tevent_req *dcerpc_binding_handle_call_params_pull_send(TALLOC_CTX *mem_ctx,
1082 struct tevent_context *ev,
1083 struct dcerpc_pipe_handle *p,
1087 struct dcerpc_binding_handle_call_params_pipe *pp =
1088 dcerpc_pipe_handle_data(p,
1089 struct dcerpc_binding_handle_call_params_pipe);
1090 struct tevent_req *req;
1091 struct dcerpc_binding_handle_call_params_pull_state *state;
1093 req = tevent_req_create(mem_ctx, &state,
1094 struct dcerpc_binding_handle_call_params_pull_state);
1100 state->chunk_mem = chunk_mem;
1101 state->chunk_ptr = chunk_ptr;
1102 state->is_last_chunk = true;
1104 if (talloc_total_blocks(chunk_mem) != 1) {
1106 * As we typically only have autogenerated callers
1107 * of this function, we can enforce that chunk_mem
1108 * doesn't have any talloc children yet.
1110 * This makes the error handling in the
1111 * NDR_ERR_INCOMPLETE_BUFFER case simpler.
1113 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1114 return tevent_req_post(req, ev);
1117 tevent_req_defer_callback(req, state->ev);
1119 talloc_set_destructor(state,
1120 dcerpc_binding_handle_call_params_pull_state_destructor);
1123 dcerpc_binding_handle_call_params_pull_notify(req);
1124 if (!tevent_req_is_in_progress(req)) {
1125 return tevent_req_post(req, ev);
1131 static void dcerpc_binding_handle_call_params_pull_notify(struct tevent_req *req)
1133 struct dcerpc_binding_handle_call_params_pull_state *state =
1134 tevent_req_data(req,
1135 struct dcerpc_binding_handle_call_params_pull_state);
1136 struct dcerpc_binding_handle_call_params_pipe *pp =
1137 dcerpc_pipe_handle_data(state->p,
1138 struct dcerpc_binding_handle_call_params_pipe);
1139 struct dcerpc_binding_handle_call_params_state *call_state =
1140 tevent_req_data(pp->call_req,
1141 struct dcerpc_binding_handle_call_params_state);
1142 enum ndr_err_code ndr_err;
1143 struct ndr_pull *pipe_pull = NULL;
1144 const uint32_t *count = NULL;
1146 if (call_state->pull == NULL) {
1150 if (call_state->pull->data_size == 0) {
1154 if (call_state->pull_missing > 0) {
1159 * setup a shallow copy subcontext, which we might destroy
1161 ndr_err = ndr_pull_subcontext_start(call_state->pull, &pipe_pull,
1163 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1165 error = ndr_map_error2ntstatus(ndr_err);
1166 tevent_req_nterror(req, error);
1170 /* pull the structure from the subcontext */
1171 pipe_pull->current_mem_ctx = state->chunk_mem;
1172 ndr_err = call_state->call_pipe->ndr_pull(pipe_pull,
1173 NDR_SCALARS|NDR_BUFFERS,
1175 if (ndr_err == NDR_ERR_INCOMPLETE_BUFFER) {
1176 call_state->pull_missing = pipe_pull->relative_highest_offset;
1177 TALLOC_FREE(pipe_pull);
1178 talloc_free_children(state->chunk_mem);
1181 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1183 error = ndr_map_error2ntstatus(ndr_err);
1184 tevent_req_nterror(req, error);
1188 ndr_err = ndr_pull_subcontext_end(call_state->pull, pipe_pull,
1190 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1192 error = ndr_map_error2ntstatus(ndr_err);
1193 tevent_req_nterror(req, error);
1196 TALLOC_FREE(pipe_pull);
1198 ndr_err = ndr_pull_pop(call_state->pull);
1199 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1201 error = ndr_map_error2ntstatus(ndr_err);
1202 tevent_req_nterror(req, error);
1207 * Note: the first struct member is always
1210 count = (const uint32_t *)state->chunk_ptr;
1213 state->is_last_chunk = false;
1214 tevent_req_done(req);
1218 state->is_last_chunk = true;
1219 tevent_req_done(req);
1223 static NTSTATUS dcerpc_binding_handle_call_params_pull_recv(struct tevent_req *req)
1225 return tevent_req_simple_recv_ntstatus(req);
1228 static struct dcerpc_pipe_handle_ops dcerpc_binding_handle_call_params_pipe_ops = {
1229 .name = "dcerpc_binding_handle_call_params_pipe",
1231 .chunk_push_send = dcerpc_binding_handle_call_params_push_send,
1232 .chunk_push_recv = dcerpc_binding_handle_call_params_push_recv,
1234 .chunk_pull_send = dcerpc_binding_handle_call_params_pull_send,
1235 .chunk_pull_recv = dcerpc_binding_handle_call_params_pull_recv,
1238 static void dcerpc_binding_handle_call_params_pipe_setup(struct tevent_req *call_req)
1240 struct dcerpc_binding_handle_call_params_state *call_state =
1241 tevent_req_data(call_req,
1242 struct dcerpc_binding_handle_call_params_state);
1243 struct dcerpc_binding_handle_call_params_pipe *pp;
1245 call_state->ph = dcerpc_pipe_handle_create(call_state,
1246 &dcerpc_binding_handle_call_params_pipe_ops,
1248 struct dcerpc_binding_handle_call_params_pipe);
1249 if (tevent_req_nomem(call_state->ph, call_req)) {
1253 pp->call_req = call_req;
1256 static void dcerpc_binding_handle_call_params_pipe_notify(struct dcerpc_pipe_handle *p)
1258 struct dcerpc_binding_handle_call_params_pipe *pp =
1259 dcerpc_pipe_handle_data(p,
1260 struct dcerpc_binding_handle_call_params_pipe);
1262 if (pp->pull_req == NULL) {
1266 dcerpc_binding_handle_call_params_pull_notify(pp->pull_req);
1269 struct dcerpc_binding_handle_call_state {
1270 struct dcerpc_binding_handle_call_params params;
1273 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
1275 struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
1276 struct tevent_context *ev,
1277 struct dcerpc_binding_handle *h,
1278 const struct GUID *object,
1279 const struct ndr_interface_table *table,
1284 struct tevent_req *req;
1285 struct dcerpc_binding_handle_call_state *state;
1286 struct tevent_req *subreq;
1288 req = tevent_req_create(mem_ctx, &state,
1289 struct dcerpc_binding_handle_call_state);
1294 state->params.r_mem = r_mem;
1295 state->params.r_ptr = r_ptr;
1297 subreq = dcerpc_binding_handle_call_params_send(state, ev, h,
1298 object, table, opnum,
1300 if (tevent_req_nomem(subreq, req)) {
1301 return tevent_req_post(req, ev);
1303 tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
1308 static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
1310 struct tevent_req *req = tevent_req_callback_data(subreq,
1314 error = dcerpc_binding_handle_call_params_recv(subreq);
1315 TALLOC_FREE(subreq);
1316 if (tevent_req_nterror(req, error)) {
1320 tevent_req_done(req);
1323 NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
1325 return tevent_req_simple_recv_ntstatus(req);
1328 NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
1329 const struct GUID *object,
1330 const struct ndr_interface_table *table,
1335 TALLOC_CTX *frame = talloc_stackframe();
1336 struct tevent_context *ev;
1337 struct tevent_req *subreq;
1338 struct dcerpc_binding_handle_call_params params;
1339 NTSTATUS status = NT_STATUS_NO_MEMORY;
1342 * TODO: allow only one sync call
1348 ev = samba_tevent_context_init(frame);
1354 ZERO_STRUCT(params);
1355 params.r_mem = r_mem;
1356 params.r_ptr = r_ptr;
1358 subreq = dcerpc_binding_handle_call_params_send(frame, ev, h,
1359 object, table, opnum,
1361 if (subreq == NULL) {
1365 if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
1369 status = dcerpc_binding_handle_call_params_recv(subreq);