2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "librpc/rpc/rpc_common.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "libcli/smb/tstream_smbXcli_np.h"
39 enum rpc_request_state {
46 handle for an async dcerpc request
49 struct rpc_request *next, *prev;
50 struct dcerpc_pipe *p;
53 enum rpc_request_state state;
58 /* this is used to distinguish bind and alter_context requests
59 from normal requests */
60 void (*recv_handler)(struct rpc_request *conn,
61 DATA_BLOB *blob, struct ncacn_packet *pkt);
63 const struct GUID *object;
65 DATA_BLOB request_data;
70 void (*callback)(struct rpc_request *);
75 _PUBLIC_ NTSTATUS dcerpc_init(void)
80 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
81 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
83 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
84 struct dcerpc_pipe *p,
85 const struct GUID *object,
87 DATA_BLOB *stub_data);
88 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
90 DATA_BLOB *stub_data);
91 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
95 ndr_push_flags_fn_t ndr_push,
96 ndr_pull_flags_fn_t ndr_pull);
97 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
98 struct ndr_pull *pull_in,
101 ndr_push_flags_fn_t ndr_push,
102 ndr_pull_flags_fn_t ndr_pull,
103 ndr_print_function_t ndr_print);
104 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
105 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
107 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
109 /* destroy a dcerpc connection */
110 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
113 conn->free_skipped = true;
116 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
121 /* initialise a dcerpc connection.
122 the event context is optional
124 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
125 struct tevent_context *ev)
127 struct dcecli_connection *c;
129 c = talloc_zero(mem_ctx, struct dcecli_connection);
136 if (c->event_ctx == NULL) {
142 c->security_state.auth_info = NULL;
143 c->security_state.session_key = dcerpc_generic_session_key;
144 c->security_state.generic_state = NULL;
145 c->binding_string = NULL;
148 * Windows uses 5840 for ncacn_ip_tcp,
149 * so we also use it (for every transport)
150 * by default. But we give the transport
151 * the chance to overwrite it.
153 c->srv_max_xmit_frag = 5840;
154 c->srv_max_recv_frag = 5840;
157 c->io_trigger = tevent_create_immediate(c);
158 if (c->io_trigger == NULL) {
163 talloc_set_destructor(c, dcerpc_connection_destructor);
168 struct dcerpc_bh_state {
169 struct dcerpc_pipe *p;
172 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
174 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
175 struct dcerpc_bh_state);
185 if (hs->p->conn->dead) {
192 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
195 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
196 struct dcerpc_bh_state);
200 return DCERPC_REQUEST_TIMEOUT;
203 old = hs->p->request_timeout;
204 hs->p->request_timeout = timeout;
209 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
210 enum dcerpc_AuthType *auth_type,
211 enum dcerpc_AuthLevel *auth_level)
213 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
214 struct dcerpc_bh_state);
220 if (hs->p->conn == NULL) {
224 if (hs->p->conn->security_state.auth_info == NULL) {
228 *auth_type = hs->p->conn->security_state.auth_info->auth_type;
229 *auth_level = hs->p->conn->security_state.auth_info->auth_level;
232 struct dcerpc_bh_raw_call_state {
233 struct tevent_context *ev;
234 struct dcerpc_binding_handle *h;
240 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
242 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
243 struct tevent_context *ev,
244 struct dcerpc_binding_handle *h,
245 const struct GUID *object,
248 const uint8_t *in_data,
251 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
252 struct dcerpc_bh_state);
253 struct tevent_req *req;
254 struct dcerpc_bh_raw_call_state *state;
256 struct rpc_request *subreq;
258 req = tevent_req_create(mem_ctx, &state,
259 struct dcerpc_bh_raw_call_state);
265 state->in_data.data = discard_const_p(uint8_t, in_data);
266 state->in_data.length = in_length;
268 ok = dcerpc_bh_is_connected(h);
270 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
271 return tevent_req_post(req, ev);
274 subreq = dcerpc_request_send(state,
279 if (tevent_req_nomem(subreq, req)) {
280 return tevent_req_post(req, ev);
282 subreq->async.callback = dcerpc_bh_raw_call_done;
283 subreq->async.private_data = req;
288 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
290 struct tevent_req *req =
291 talloc_get_type_abort(subreq->async.private_data,
293 struct dcerpc_bh_raw_call_state *state =
295 struct dcerpc_bh_raw_call_state);
299 state->out_flags = 0;
300 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
301 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
304 fault_code = subreq->fault_code;
306 status = dcerpc_request_recv(subreq, state, &state->out_data);
307 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
308 status = dcerpc_fault_to_nt_status(fault_code);
312 * We trigger the callback in the next event run
313 * because the code in this file might trigger
314 * multiple request callbacks from within a single
317 * In order to avoid segfaults from within
318 * dcerpc_connection_dead() we call
319 * tevent_req_defer_callback().
321 tevent_req_defer_callback(req, state->ev);
323 if (!NT_STATUS_IS_OK(status)) {
324 tevent_req_nterror(req, status);
328 tevent_req_done(req);
331 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
337 struct dcerpc_bh_raw_call_state *state =
339 struct dcerpc_bh_raw_call_state);
342 if (tevent_req_is_nterror(req, &status)) {
343 tevent_req_received(req);
347 *out_data = talloc_move(mem_ctx, &state->out_data.data);
348 *out_length = state->out_data.length;
349 *out_flags = state->out_flags;
350 tevent_req_received(req);
354 struct dcerpc_bh_disconnect_state {
358 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
359 struct tevent_context *ev,
360 struct dcerpc_binding_handle *h)
362 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
363 struct dcerpc_bh_state);
364 struct tevent_req *req;
365 struct dcerpc_bh_disconnect_state *state;
368 req = tevent_req_create(mem_ctx, &state,
369 struct dcerpc_bh_disconnect_state);
374 ok = dcerpc_bh_is_connected(h);
376 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
377 return tevent_req_post(req, ev);
380 /* TODO: do a real disconnect ... */
383 tevent_req_done(req);
384 return tevent_req_post(req, ev);
387 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
391 if (tevent_req_is_nterror(req, &status)) {
392 tevent_req_received(req);
396 tevent_req_received(req);
400 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
402 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
403 struct dcerpc_bh_state);
405 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
412 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
414 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
415 struct dcerpc_bh_state);
417 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
424 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
426 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
427 struct dcerpc_bh_state);
429 if (hs->p->conn->flags & DCERPC_NDR64) {
436 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
438 const void *_struct_ptr,
439 const struct ndr_interface_call *call)
441 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
442 struct dcerpc_bh_state);
443 void *struct_ptr = discard_const(_struct_ptr);
445 if (ndr_flags & NDR_IN) {
446 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
447 ndr_print_function_debug(call->ndr_print,
453 if (ndr_flags & NDR_OUT) {
454 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
455 ndr_print_function_debug(call->ndr_print,
463 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
465 const void *struct_ptr,
466 const struct ndr_interface_call *call)
468 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
469 call->name, nt_errstr(error)));
472 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
474 const DATA_BLOB *blob,
475 const struct ndr_interface_call *call)
477 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
478 struct dcerpc_bh_state);
479 const uint32_t num_examples = 20;
482 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
483 call->name, nt_errstr(error)));
485 if (hs->p->conn->packet_log_dir == NULL) return;
487 for (i=0;i<num_examples;i++) {
489 asprintf(&name, "%s/rpclog/%s-out.%d",
490 hs->p->conn->packet_log_dir,
495 if (!file_exist(name)) {
496 if (file_save(name, blob->data, blob->length)) {
497 DEBUG(10,("Logged rpc packet to %s\n", name));
506 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
508 const DATA_BLOB *blob,
509 const struct ndr_interface_call *call)
511 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
512 struct dcerpc_bh_state);
514 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
517 status = dcerpc_ndr_validate_in(hs->p->conn,
523 if (!NT_STATUS_IS_OK(status)) {
524 DEBUG(0,("Validation [in] failed for %s - %s\n",
525 call->name, nt_errstr(status)));
530 DEBUG(10,("rpc request data:\n"));
531 dump_data(10, blob->data, blob->length);
536 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
537 struct ndr_pull *pull_in,
538 const void *_struct_ptr,
539 const struct ndr_interface_call *call)
541 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
542 struct dcerpc_bh_state);
543 void *struct_ptr = discard_const(_struct_ptr);
545 DEBUG(10,("rpc reply data:\n"));
546 dump_data(10, pull_in->data, pull_in->data_size);
548 if (pull_in->offset != pull_in->data_size) {
549 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
550 pull_in->data_size - pull_in->offset,
551 pull_in->offset, pull_in->offset,
553 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
554 but it turns out that early versions of NT
555 (specifically NT3.1) add junk onto the end of rpc
556 packets, so if we want to interoperate at all with
557 those versions then we need to ignore this error */
560 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
563 status = dcerpc_ndr_validate_out(hs->p->conn,
570 if (!NT_STATUS_IS_OK(status)) {
571 DEBUG(2,("Validation [out] failed for %s - %s\n",
572 call->name, nt_errstr(status)));
580 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
582 .is_connected = dcerpc_bh_is_connected,
583 .set_timeout = dcerpc_bh_set_timeout,
584 .auth_info = dcerpc_bh_auth_info,
585 .raw_call_send = dcerpc_bh_raw_call_send,
586 .raw_call_recv = dcerpc_bh_raw_call_recv,
587 .disconnect_send = dcerpc_bh_disconnect_send,
588 .disconnect_recv = dcerpc_bh_disconnect_recv,
590 .push_bigendian = dcerpc_bh_push_bigendian,
591 .ref_alloc = dcerpc_bh_ref_alloc,
592 .use_ndr64 = dcerpc_bh_use_ndr64,
593 .do_ndr_print = dcerpc_bh_do_ndr_print,
594 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
595 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
596 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
597 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
600 /* initialise a dcerpc pipe. */
601 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
603 struct dcerpc_binding_handle *h;
604 struct dcerpc_bh_state *hs;
606 h = dcerpc_binding_handle_create(p,
611 struct dcerpc_bh_state,
618 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
623 /* initialise a dcerpc pipe. */
624 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
626 struct dcerpc_pipe *p;
628 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
633 p->conn = dcerpc_connection_init(p, ev);
634 if (p->conn == NULL) {
639 p->last_fault_code = 0;
641 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
644 ZERO_STRUCT(p->syntax);
645 ZERO_STRUCT(p->transfer_syntax);
648 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
651 p->binding_handle = dcerpc_pipe_binding_handle(p);
652 if (p->binding_handle == NULL) {
662 choose the next call id to use
664 static uint32_t next_call_id(struct dcecli_connection *c)
667 if (c->call_id == 0) {
674 setup for a ndr pull, also setting up any flags from the binding string
676 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
677 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
679 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
681 if (ndr == NULL) return ndr;
683 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
684 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
687 if (c->flags & DCERPC_NDR_REF_ALLOC) {
688 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
691 if (c->flags & DCERPC_NDR64) {
692 ndr->flags |= LIBNDR_FLAG_NDR64;
699 parse a data blob into a ncacn_packet structure. This handles both
700 input and output packets
702 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
703 struct ncacn_packet *pkt)
705 struct ndr_pull *ndr;
706 enum ndr_err_code ndr_err;
708 ndr = ndr_pull_init_blob(blob, mem_ctx);
710 return NT_STATUS_NO_MEMORY;
713 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
714 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
717 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
718 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
721 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
723 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
724 return ndr_map_error2ntstatus(ndr_err);
727 if (pkt->frag_length != blob->length) {
728 return NT_STATUS_RPC_PROTOCOL_ERROR;
735 parse the authentication information on a dcerpc response packet
737 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
738 DATA_BLOB *raw_packet,
739 struct ncacn_packet *pkt)
742 struct dcerpc_auth auth;
743 uint32_t auth_length;
745 if (!c->security_state.auth_info ||
746 !c->security_state.generic_state) {
750 switch (c->security_state.auth_info->auth_level) {
751 case DCERPC_AUTH_LEVEL_PRIVACY:
752 case DCERPC_AUTH_LEVEL_INTEGRITY:
755 case DCERPC_AUTH_LEVEL_CONNECT:
756 if (pkt->auth_length != 0) {
760 case DCERPC_AUTH_LEVEL_NONE:
761 if (pkt->auth_length != 0) {
762 return NT_STATUS_INVALID_NETWORK_RESPONSE;
767 return NT_STATUS_INVALID_LEVEL;
770 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
771 &pkt->u.response.stub_and_verifier,
772 &auth, &auth_length, false);
773 NT_STATUS_NOT_OK_RETURN(status);
775 pkt->u.response.stub_and_verifier.length -= auth_length;
777 /* check signature or unseal the packet */
778 switch (c->security_state.auth_info->auth_level) {
779 case DCERPC_AUTH_LEVEL_PRIVACY:
780 status = gensec_unseal_packet(c->security_state.generic_state,
781 raw_packet->data + DCERPC_REQUEST_LENGTH,
782 pkt->u.response.stub_and_verifier.length,
784 raw_packet->length - auth.credentials.length,
786 memcpy(pkt->u.response.stub_and_verifier.data,
787 raw_packet->data + DCERPC_REQUEST_LENGTH,
788 pkt->u.response.stub_and_verifier.length);
791 case DCERPC_AUTH_LEVEL_INTEGRITY:
792 status = gensec_check_packet(c->security_state.generic_state,
793 pkt->u.response.stub_and_verifier.data,
794 pkt->u.response.stub_and_verifier.length,
796 raw_packet->length - auth.credentials.length,
800 case DCERPC_AUTH_LEVEL_CONNECT:
801 /* for now we ignore possible signatures here */
802 status = NT_STATUS_OK;
806 status = NT_STATUS_INVALID_LEVEL;
810 /* remove the indicated amount of padding */
811 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
812 return NT_STATUS_INFO_LENGTH_MISMATCH;
814 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
821 push a dcerpc request packet into a blob, possibly signing it.
823 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
824 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
826 struct ncacn_packet *pkt)
829 struct ndr_push *ndr;
831 size_t payload_length;
832 enum ndr_err_code ndr_err;
833 size_t hdr_size = DCERPC_REQUEST_LENGTH;
835 /* non-signed packets are simpler */
837 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
840 switch (c->security_state.auth_info->auth_level) {
841 case DCERPC_AUTH_LEVEL_PRIVACY:
842 case DCERPC_AUTH_LEVEL_INTEGRITY:
845 case DCERPC_AUTH_LEVEL_CONNECT:
846 /* TODO: let the gensec mech decide if it wants to generate a signature */
847 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
849 case DCERPC_AUTH_LEVEL_NONE:
850 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
853 return NT_STATUS_INVALID_LEVEL;
856 ndr = ndr_push_init_ctx(mem_ctx);
858 return NT_STATUS_NO_MEMORY;
861 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
862 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
865 if (c->flags & DCERPC_NDR64) {
866 ndr->flags |= LIBNDR_FLAG_NDR64;
869 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
870 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
874 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
875 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
876 return ndr_map_error2ntstatus(ndr_err);
879 /* pad to 16 byte multiple in the payload portion of the
880 packet. This matches what w2k3 does. Note that we can't use
881 ndr_push_align() as that is relative to the start of the
882 whole packet, whereas w2k8 wants it relative to the start
884 c->security_state.auth_info->auth_pad_length =
885 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
886 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
887 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
888 return ndr_map_error2ntstatus(ndr_err);
891 payload_length = pkt->u.request.stub_and_verifier.length +
892 c->security_state.auth_info->auth_pad_length;
894 /* we start without signature, it will appended later */
895 c->security_state.auth_info->credentials = data_blob(NULL,0);
897 /* add the auth verifier */
898 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
899 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
900 return ndr_map_error2ntstatus(ndr_err);
903 /* extract the whole packet as a blob */
904 *blob = ndr_push_blob(ndr);
907 * Setup the frag and auth length in the packet buffer.
908 * This is needed if the GENSEC mech does AEAD signing
909 * of the packet headers. The signature itself will be
912 dcerpc_set_frag_length(blob, blob->length + sig_size);
913 dcerpc_set_auth_length(blob, sig_size);
915 /* sign or seal the packet */
916 switch (c->security_state.auth_info->auth_level) {
917 case DCERPC_AUTH_LEVEL_PRIVACY:
918 status = gensec_seal_packet(c->security_state.generic_state,
920 blob->data + hdr_size,
925 if (!NT_STATUS_IS_OK(status)) {
930 case DCERPC_AUTH_LEVEL_INTEGRITY:
931 status = gensec_sign_packet(c->security_state.generic_state,
933 blob->data + hdr_size,
938 if (!NT_STATUS_IS_OK(status)) {
944 status = NT_STATUS_INVALID_LEVEL;
948 if (creds2.length != sig_size) {
949 /* this means the sig_size estimate for the signature
950 was incorrect. We have to correct the packet
951 sizes. That means we could go over the max fragment
953 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
954 (unsigned) creds2.length,
956 (unsigned) c->security_state.auth_info->auth_pad_length,
957 (unsigned) pkt->u.request.stub_and_verifier.length));
958 dcerpc_set_frag_length(blob, blob->length + creds2.length);
959 dcerpc_set_auth_length(blob, creds2.length);
962 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
963 return NT_STATUS_NO_MEMORY;
971 fill in the fixed values in a dcerpc header
973 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
976 pkt->rpc_vers_minor = 0;
977 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
980 pkt->drep[0] = DCERPC_DREP_LE;
988 map a bind nak reason to a NTSTATUS
990 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
993 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
994 return NT_STATUS_REVISION_MISMATCH;
995 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
996 return NT_STATUS_INVALID_PARAMETER;
1000 return NT_STATUS_UNSUCCESSFUL;
1003 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
1006 return NT_STATUS_RPC_PROTOCOL_ERROR;
1009 switch (ack->reason) {
1010 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
1011 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1012 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
1013 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1017 return NT_STATUS_UNSUCCESSFUL;
1021 remove requests from the pending or queued queues
1023 static int dcerpc_req_dequeue(struct rpc_request *req)
1025 switch (req->state) {
1026 case RPC_REQUEST_QUEUED:
1027 DLIST_REMOVE(req->p->conn->request_queue, req);
1029 case RPC_REQUEST_PENDING:
1030 DLIST_REMOVE(req->p->conn->pending, req);
1032 case RPC_REQUEST_DONE:
1040 mark the dcerpc connection dead. All outstanding requests get an error
1042 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1044 if (conn->dead) return;
1048 TALLOC_FREE(conn->io_trigger);
1049 conn->io_trigger_pending = false;
1051 dcerpc_shutdown_pipe(conn, status);
1053 /* all pending requests get the error */
1054 while (conn->pending) {
1055 struct rpc_request *req = conn->pending;
1056 dcerpc_req_dequeue(req);
1057 req->state = RPC_REQUEST_DONE;
1058 req->status = status;
1059 if (req->async.callback) {
1060 req->async.callback(req);
1064 /* all requests, which are not shipped */
1065 while (conn->request_queue) {
1066 struct rpc_request *req = conn->request_queue;
1067 dcerpc_req_dequeue(req);
1068 req->state = RPC_REQUEST_DONE;
1069 req->status = status;
1070 if (req->async.callback) {
1071 req->async.callback(req);
1075 talloc_set_destructor(conn, NULL);
1076 if (conn->free_skipped) {
1082 forward declarations of the recv_data handlers for the types of
1083 packets we need to handle
1085 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1086 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1089 receive a dcerpc reply from the transport. Here we work out what
1090 type of reply it is (normal request, bind or alter context) and
1091 dispatch to the appropriate handler
1093 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1095 struct ncacn_packet pkt;
1101 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1102 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1105 /* the transport may be telling us of a severe error, such as
1107 if (!NT_STATUS_IS_OK(status)) {
1108 data_blob_free(blob);
1109 dcerpc_connection_dead(conn, status);
1113 /* parse the basic packet to work out what type of response this is */
1114 status = ncacn_pull(conn, blob, blob->data, &pkt);
1115 if (!NT_STATUS_IS_OK(status)) {
1116 data_blob_free(blob);
1117 dcerpc_connection_dead(conn, status);
1121 dcerpc_request_recv_data(conn, blob, &pkt);
1125 handle timeouts of individual dcerpc requests
1127 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1128 struct timeval t, void *private_data)
1130 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1132 if (req->ignore_timeout) {
1133 dcerpc_req_dequeue(req);
1134 req->state = RPC_REQUEST_DONE;
1135 req->status = NT_STATUS_IO_TIMEOUT;
1136 if (req->async.callback) {
1137 req->async.callback(req);
1142 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1145 struct dcerpc_bind_state {
1146 struct tevent_context *ev;
1147 struct dcerpc_pipe *p;
1150 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1151 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1152 DATA_BLOB *raw_packet,
1153 struct ncacn_packet *pkt);
1155 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1156 struct tevent_context *ev,
1157 struct dcerpc_pipe *p,
1158 const struct ndr_syntax_id *syntax,
1159 const struct ndr_syntax_id *transfer_syntax)
1161 struct tevent_req *req;
1162 struct dcerpc_bind_state *state;
1163 struct ncacn_packet pkt;
1166 struct rpc_request *subreq;
1168 req = tevent_req_create(mem_ctx, &state,
1169 struct dcerpc_bind_state);
1177 p->syntax = *syntax;
1178 p->transfer_syntax = *transfer_syntax;
1180 init_ncacn_hdr(p->conn, &pkt);
1182 pkt.ptype = DCERPC_PKT_BIND;
1183 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1184 pkt.call_id = p->conn->call_id;
1185 pkt.auth_length = 0;
1187 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1188 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1191 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1192 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1195 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1196 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1197 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1198 pkt.u.bind.num_contexts = 1;
1199 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1200 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1201 return tevent_req_post(req, ev);
1203 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1204 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1205 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1206 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1207 pkt.u.bind.auth_info = data_blob(NULL, 0);
1209 /* construct the NDR form of the packet */
1210 status = ncacn_push_auth(&blob, state, &pkt,
1211 p->conn->security_state.auth_info);
1212 if (tevent_req_nterror(req, status)) {
1213 return tevent_req_post(req, ev);
1217 * we allocate a dcerpc_request so we can be in the same
1218 * request queue as normal requests
1220 subreq = talloc_zero(state, struct rpc_request);
1221 if (tevent_req_nomem(subreq, req)) {
1222 return tevent_req_post(req, ev);
1225 subreq->state = RPC_REQUEST_PENDING;
1226 subreq->call_id = pkt.call_id;
1227 subreq->async.private_data = req;
1228 subreq->async.callback = dcerpc_bind_fail_handler;
1230 subreq->recv_handler = dcerpc_bind_recv_handler;
1231 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1232 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1234 status = dcerpc_send_request(p->conn, &blob, true);
1235 if (tevent_req_nterror(req, status)) {
1236 return tevent_req_post(req, ev);
1239 tevent_add_timer(ev, subreq,
1240 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1241 dcerpc_timeout_handler, subreq);
1246 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1248 struct tevent_req *req =
1249 talloc_get_type_abort(subreq->async.private_data,
1251 struct dcerpc_bind_state *state =
1252 tevent_req_data(req,
1253 struct dcerpc_bind_state);
1254 NTSTATUS status = subreq->status;
1256 TALLOC_FREE(subreq);
1259 * We trigger the callback in the next event run
1260 * because the code in this file might trigger
1261 * multiple request callbacks from within a single
1264 * In order to avoid segfaults from within
1265 * dcerpc_connection_dead() we call
1266 * tevent_req_defer_callback().
1268 tevent_req_defer_callback(req, state->ev);
1270 tevent_req_nterror(req, status);
1273 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1274 DATA_BLOB *raw_packet,
1275 struct ncacn_packet *pkt)
1277 struct tevent_req *req =
1278 talloc_get_type_abort(subreq->async.private_data,
1280 struct dcerpc_bind_state *state =
1281 tevent_req_data(req,
1282 struct dcerpc_bind_state);
1283 struct dcecli_connection *conn = state->p->conn;
1287 * Note that pkt is allocated under raw_packet->data,
1288 * while raw_packet->data is a child of subreq.
1290 talloc_steal(state, raw_packet->data);
1291 TALLOC_FREE(subreq);
1294 * We trigger the callback in the next event run
1295 * because the code in this file might trigger
1296 * multiple request callbacks from within a single
1299 * In order to avoid segfaults from within
1300 * dcerpc_connection_dead() we call
1301 * tevent_req_defer_callback().
1303 tevent_req_defer_callback(req, state->ev);
1305 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1306 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1308 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1309 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1311 tevent_req_nterror(req, status);
1315 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1316 (pkt->u.bind_ack.num_results == 0) ||
1317 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1318 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1319 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1324 * DCE-RPC 1.1 (c706) specifies
1325 * CONST_MUST_RCV_FRAG_SIZE as 1432
1327 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1328 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1329 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1332 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1333 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1334 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1337 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1338 pkt->u.bind_ack.max_xmit_frag);
1339 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1340 pkt->u.bind_ack.max_recv_frag);
1342 if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1343 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1344 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1347 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1348 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1349 conn->flags |= DCERPC_HEADER_SIGNING;
1352 /* the bind_ack might contain a reply set of credentials */
1353 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1354 uint32_t auth_length;
1356 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1357 conn->security_state.auth_info, &auth_length, true);
1358 if (tevent_req_nterror(req, status)) {
1363 state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1365 tevent_req_done(req);
1368 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1370 return tevent_req_simple_recv_ntstatus(req);
1374 perform a continued bind (and auth3)
1376 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1377 TALLOC_CTX *mem_ctx)
1379 struct ncacn_packet pkt;
1383 init_ncacn_hdr(p->conn, &pkt);
1385 pkt.ptype = DCERPC_PKT_AUTH3;
1386 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1387 pkt.call_id = next_call_id(p->conn);
1388 pkt.auth_length = 0;
1389 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1391 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1392 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1395 /* construct the NDR form of the packet */
1396 status = ncacn_push_auth(&blob, mem_ctx,
1398 p->conn->security_state.auth_info);
1399 if (!NT_STATUS_IS_OK(status)) {
1403 /* send it on its way */
1404 status = dcerpc_send_request(p->conn, &blob, false);
1405 if (!NT_STATUS_IS_OK(status)) {
1409 return NT_STATUS_OK;
1414 process a fragment received from the transport layer during a
1417 This function frees the data
1419 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1420 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1422 struct rpc_request *req;
1423 unsigned int length;
1424 NTSTATUS status = NT_STATUS_OK;
1427 if this is an authenticated connection then parse and check
1428 the auth info. We have to do this before finding the
1429 matching packet, as the request structure might have been
1430 removed due to a timeout, but if it has been we still need
1431 to run the auth routines so that we don't get the sign/seal
1432 info out of step with the server
1434 if (c->security_state.auth_info && c->security_state.generic_state &&
1435 pkt->ptype == DCERPC_PKT_RESPONSE) {
1436 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1439 /* find the matching request */
1440 for (req=c->pending;req;req=req->next) {
1441 if (pkt->call_id == req->call_id) break;
1445 /* useful for testing certain vendors RPC servers */
1446 if (req == NULL && c->pending && pkt->call_id == 0) {
1447 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1453 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1454 data_blob_free(raw_packet);
1458 talloc_steal(req, raw_packet->data);
1460 if (req->recv_handler != NULL) {
1461 dcerpc_req_dequeue(req);
1462 req->state = RPC_REQUEST_DONE;
1465 * We have to look at shipping further requests before calling
1466 * the async function, that one might close the pipe
1468 dcerpc_schedule_io_trigger(c);
1470 req->recv_handler(req, raw_packet, pkt);
1474 if (pkt->ptype == DCERPC_PKT_FAULT) {
1475 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1476 req->fault_code = pkt->u.fault.status;
1477 req->status = NT_STATUS_NET_WRITE_FAULT;
1481 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1482 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1484 req->fault_code = DCERPC_FAULT_OTHER;
1485 req->status = NT_STATUS_NET_WRITE_FAULT;
1489 /* now check the status from the auth routines, and if it failed then fail
1490 this request accordingly */
1491 if (!NT_STATUS_IS_OK(status)) {
1492 req->status = status;
1496 length = pkt->u.response.stub_and_verifier.length;
1499 req->payload.data = talloc_realloc(req,
1502 req->payload.length + length);
1503 if (!req->payload.data) {
1504 req->status = NT_STATUS_NO_MEMORY;
1507 memcpy(req->payload.data+req->payload.length,
1508 pkt->u.response.stub_and_verifier.data, length);
1509 req->payload.length += length;
1512 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1513 data_blob_free(raw_packet);
1514 dcerpc_send_read(c);
1518 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1519 req->flags |= DCERPC_PULL_BIGENDIAN;
1521 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1525 data_blob_free(raw_packet);
1527 /* we've got the full payload */
1528 dcerpc_req_dequeue(req);
1529 req->state = RPC_REQUEST_DONE;
1532 * We have to look at shipping further requests before calling
1533 * the async function, that one might close the pipe
1535 dcerpc_schedule_io_trigger(c);
1537 if (req->async.callback) {
1538 req->async.callback(req);
1543 perform the send side of a async dcerpc request
1545 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1546 struct dcerpc_pipe *p,
1547 const struct GUID *object,
1549 DATA_BLOB *stub_data)
1551 struct rpc_request *req;
1553 req = talloc_zero(mem_ctx, struct rpc_request);
1559 req->call_id = next_call_id(p->conn);
1560 req->state = RPC_REQUEST_QUEUED;
1562 if (object != NULL) {
1563 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1564 if (req->object == NULL) {
1571 req->request_data.length = stub_data->length;
1572 req->request_data.data = stub_data->data;
1574 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1575 talloc_set_destructor(req, dcerpc_req_dequeue);
1577 dcerpc_schedule_io_trigger(p->conn);
1579 if (p->request_timeout) {
1580 tevent_add_timer(p->conn->event_ctx, req,
1581 timeval_current_ofs(p->request_timeout, 0),
1582 dcerpc_timeout_handler, req);
1589 Send a request using the transport
1592 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1594 struct rpc_request *req;
1595 struct dcerpc_pipe *p;
1596 DATA_BLOB *stub_data;
1597 struct ncacn_packet pkt;
1599 uint32_t remaining, chunk_size;
1600 bool first_packet = true;
1601 size_t sig_size = 0;
1602 bool need_async = false;
1603 bool can_async = true;
1605 req = c->request_queue;
1611 stub_data = &req->request_data;
1617 if (c->security_state.auth_info &&
1618 c->security_state.generic_state)
1620 struct gensec_security *gensec = c->security_state.generic_state;
1622 switch (c->security_state.auth_info->auth_level) {
1623 case DCERPC_AUTH_LEVEL_PRIVACY:
1624 case DCERPC_AUTH_LEVEL_INTEGRITY:
1625 can_async = gensec_have_feature(gensec,
1626 GENSEC_FEATURE_ASYNC_REPLIES);
1628 case DCERPC_AUTH_LEVEL_CONNECT:
1629 case DCERPC_AUTH_LEVEL_NONE:
1638 if (need_async && !can_async) {
1639 req->wait_for_sync = true;
1643 DLIST_REMOVE(c->request_queue, req);
1644 DLIST_ADD(c->pending, req);
1645 req->state = RPC_REQUEST_PENDING;
1647 init_ncacn_hdr(p->conn, &pkt);
1649 remaining = stub_data->length;
1651 /* we can write a full max_recv_frag size, minus the dcerpc
1652 request header size */
1653 chunk_size = p->conn->srv_max_recv_frag;
1654 chunk_size -= DCERPC_REQUEST_LENGTH;
1655 if (c->security_state.auth_info &&
1656 c->security_state.generic_state) {
1657 sig_size = gensec_sig_size(c->security_state.generic_state,
1658 p->conn->srv_max_recv_frag);
1660 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1661 chunk_size -= sig_size;
1664 chunk_size -= (chunk_size % 16);
1666 pkt.ptype = DCERPC_PKT_REQUEST;
1667 pkt.call_id = req->call_id;
1668 pkt.auth_length = 0;
1670 pkt.u.request.context_id = p->context_id;
1671 pkt.u.request.opnum = req->opnum;
1674 pkt.u.request.object.object = *req->object;
1675 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1676 chunk_size -= ndr_size_GUID(req->object,0);
1679 /* we send a series of pdus without waiting for a reply */
1680 while (remaining > 0 || first_packet) {
1681 uint32_t chunk = MIN(chunk_size, remaining);
1682 bool last_frag = false;
1683 bool do_trans = false;
1685 first_packet = false;
1686 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1688 if (remaining == stub_data->length) {
1689 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1691 if (chunk == remaining) {
1692 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1696 pkt.u.request.alloc_hint = remaining;
1697 pkt.u.request.stub_and_verifier.data = stub_data->data +
1698 (stub_data->length - remaining);
1699 pkt.u.request.stub_and_verifier.length = chunk;
1701 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1702 if (!NT_STATUS_IS_OK(req->status)) {
1703 req->state = RPC_REQUEST_DONE;
1704 DLIST_REMOVE(p->conn->pending, req);
1708 if (last_frag && !need_async) {
1712 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1713 if (!NT_STATUS_IS_OK(req->status)) {
1714 req->state = RPC_REQUEST_DONE;
1715 DLIST_REMOVE(p->conn->pending, req);
1719 if (last_frag && !do_trans) {
1720 req->status = dcerpc_send_read(p->conn);
1721 if (!NT_STATUS_IS_OK(req->status)) {
1722 req->state = RPC_REQUEST_DONE;
1723 DLIST_REMOVE(p->conn->pending, req);
1732 static void dcerpc_io_trigger(struct tevent_context *ctx,
1733 struct tevent_immediate *im,
1736 struct dcecli_connection *c =
1737 talloc_get_type_abort(private_data,
1738 struct dcecli_connection);
1740 c->io_trigger_pending = false;
1742 dcerpc_schedule_io_trigger(c);
1744 dcerpc_ship_next_request(c);
1747 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1753 if (c->request_queue == NULL) {
1757 if (c->request_queue->wait_for_sync && c->pending) {
1761 if (c->io_trigger_pending) {
1765 c->io_trigger_pending = true;
1767 tevent_schedule_immediate(c->io_trigger,
1774 perform the receive side of a async dcerpc request
1776 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1777 TALLOC_CTX *mem_ctx,
1778 DATA_BLOB *stub_data)
1782 while (req->state != RPC_REQUEST_DONE) {
1783 struct tevent_context *ctx = req->p->conn->event_ctx;
1784 if (tevent_loop_once(ctx) != 0) {
1785 return NT_STATUS_CONNECTION_DISCONNECTED;
1788 *stub_data = req->payload;
1789 status = req->status;
1790 if (stub_data->data) {
1791 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1793 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1794 req->p->last_fault_code = req->fault_code;
1796 talloc_unlink(talloc_parent(req), req);
1801 this is a paranoid NDR validator. For every packet we push onto the wire
1802 we pull it back again, then push it again. Then we compare the raw NDR data
1803 for that to the NDR we initially generated. If they don't match then we know
1804 we must have a bug in either the pull or push side of our code
1806 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1807 TALLOC_CTX *mem_ctx,
1810 ndr_push_flags_fn_t ndr_push,
1811 ndr_pull_flags_fn_t ndr_pull)
1814 struct ndr_pull *pull;
1815 struct ndr_push *push;
1817 enum ndr_err_code ndr_err;
1819 st = talloc_size(mem_ctx, struct_size);
1821 return NT_STATUS_NO_MEMORY;
1824 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1826 return NT_STATUS_NO_MEMORY;
1828 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1830 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1831 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1834 if (c->flags & DCERPC_NDR64) {
1835 pull->flags |= LIBNDR_FLAG_NDR64;
1838 ndr_err = ndr_pull(pull, NDR_IN, st);
1839 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1840 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1841 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1842 "failed input validation pull - %s",
1844 return ndr_map_error2ntstatus(ndr_err);
1847 push = ndr_push_init_ctx(mem_ctx);
1849 return NT_STATUS_NO_MEMORY;
1852 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1853 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1856 if (c->flags & DCERPC_NDR64) {
1857 push->flags |= LIBNDR_FLAG_NDR64;
1860 ndr_err = ndr_push(push, NDR_IN, st);
1861 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1862 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1863 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1864 "failed input validation push - %s",
1866 return ndr_map_error2ntstatus(ndr_err);
1869 blob2 = ndr_push_blob(push);
1871 if (data_blob_cmp(&blob, &blob2) != 0) {
1872 DEBUG(3,("original:\n"));
1873 dump_data(3, blob.data, blob.length);
1874 DEBUG(3,("secondary:\n"));
1875 dump_data(3, blob2.data, blob2.length);
1876 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1877 "failed input validation blobs doesn't match");
1878 return ndr_map_error2ntstatus(ndr_err);
1881 return NT_STATUS_OK;
1885 this is a paranoid NDR input validator. For every packet we pull
1886 from the wire we push it back again then pull and push it
1887 again. Then we compare the raw NDR data for that to the NDR we
1888 initially generated. If they don't match then we know we must have a
1889 bug in either the pull or push side of our code
1891 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1892 struct ndr_pull *pull_in,
1895 ndr_push_flags_fn_t ndr_push,
1896 ndr_pull_flags_fn_t ndr_pull,
1897 ndr_print_function_t ndr_print)
1900 struct ndr_pull *pull;
1901 struct ndr_push *push;
1902 DATA_BLOB blob, blob2;
1903 TALLOC_CTX *mem_ctx = pull_in;
1905 enum ndr_err_code ndr_err;
1907 st = talloc_size(mem_ctx, struct_size);
1909 return NT_STATUS_NO_MEMORY;
1911 memcpy(st, struct_ptr, struct_size);
1913 push = ndr_push_init_ctx(mem_ctx);
1915 return NT_STATUS_NO_MEMORY;
1918 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1919 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1920 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1921 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1922 "failed output validation push - %s",
1924 return ndr_map_error2ntstatus(ndr_err);
1927 blob = ndr_push_blob(push);
1929 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1931 return NT_STATUS_NO_MEMORY;
1934 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1935 ndr_err = ndr_pull(pull, NDR_OUT, st);
1936 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1937 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1938 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1939 "failed output validation pull - %s",
1941 return ndr_map_error2ntstatus(ndr_err);
1944 push = ndr_push_init_ctx(mem_ctx);
1946 return NT_STATUS_NO_MEMORY;
1949 ndr_err = ndr_push(push, NDR_OUT, st);
1950 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1951 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1952 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1953 "failed output validation push2 - %s",
1955 return ndr_map_error2ntstatus(ndr_err);
1958 blob2 = ndr_push_blob(push);
1960 if (data_blob_cmp(&blob, &blob2) != 0) {
1961 DEBUG(3,("original:\n"));
1962 dump_data(3, blob.data, blob.length);
1963 DEBUG(3,("secondary:\n"));
1964 dump_data(3, blob2.data, blob2.length);
1965 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1966 "failed output validation blobs doesn't match");
1967 return ndr_map_error2ntstatus(ndr_err);
1970 /* this checks the printed forms of the two structures, which effectively
1971 tests all of the value() attributes */
1972 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1973 NDR_OUT, struct_ptr);
1974 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1976 if (strcmp(s1, s2) != 0) {
1978 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1980 /* this is sometimes useful */
1981 printf("VALIDATE ERROR\n");
1982 file_save("wire.dat", s1, strlen(s1));
1983 file_save("gen.dat", s2, strlen(s2));
1984 system("diff -u wire.dat gen.dat");
1986 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1987 "failed output validation strings doesn't match");
1988 return ndr_map_error2ntstatus(ndr_err);
1991 return NT_STATUS_OK;
1995 a useful function for retrieving the server name we connected to
1997 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1999 return p->conn ? p->conn->server_name : NULL;
2004 get the dcerpc auth_level for a open connection
2006 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2010 if (c->flags & DCERPC_SEAL) {
2011 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2012 } else if (c->flags & DCERPC_SIGN) {
2013 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2014 } else if (c->flags & DCERPC_CONNECT) {
2015 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2017 auth_level = DCERPC_AUTH_LEVEL_NONE;
2022 struct dcerpc_alter_context_state {
2023 struct tevent_context *ev;
2024 struct dcerpc_pipe *p;
2027 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2028 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2029 DATA_BLOB *raw_packet,
2030 struct ncacn_packet *pkt);
2032 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2033 struct tevent_context *ev,
2034 struct dcerpc_pipe *p,
2035 const struct ndr_syntax_id *syntax,
2036 const struct ndr_syntax_id *transfer_syntax)
2038 struct tevent_req *req;
2039 struct dcerpc_alter_context_state *state;
2040 struct ncacn_packet pkt;
2043 struct rpc_request *subreq;
2045 req = tevent_req_create(mem_ctx, &state,
2046 struct dcerpc_alter_context_state);
2054 p->syntax = *syntax;
2055 p->transfer_syntax = *transfer_syntax;
2057 init_ncacn_hdr(p->conn, &pkt);
2059 pkt.ptype = DCERPC_PKT_ALTER;
2060 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2061 pkt.call_id = p->conn->call_id;
2062 pkt.auth_length = 0;
2064 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
2065 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2068 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2069 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2070 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
2071 pkt.u.alter.num_contexts = 1;
2072 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2073 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2074 return tevent_req_post(req, ev);
2076 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2077 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2078 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2079 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2080 pkt.u.alter.auth_info = data_blob(NULL, 0);
2082 /* construct the NDR form of the packet */
2083 status = ncacn_push_auth(&blob, state, &pkt,
2084 p->conn->security_state.auth_info);
2085 if (tevent_req_nterror(req, status)) {
2086 return tevent_req_post(req, ev);
2090 * we allocate a dcerpc_request so we can be in the same
2091 * request queue as normal requests
2093 subreq = talloc_zero(state, struct rpc_request);
2094 if (tevent_req_nomem(subreq, req)) {
2095 return tevent_req_post(req, ev);
2098 subreq->state = RPC_REQUEST_PENDING;
2099 subreq->call_id = pkt.call_id;
2100 subreq->async.private_data = req;
2101 subreq->async.callback = dcerpc_alter_context_fail_handler;
2103 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2104 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2105 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2107 status = dcerpc_send_request(p->conn, &blob, true);
2108 if (tevent_req_nterror(req, status)) {
2109 return tevent_req_post(req, ev);
2112 tevent_add_timer(ev, subreq,
2113 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2114 dcerpc_timeout_handler, subreq);
2119 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2121 struct tevent_req *req =
2122 talloc_get_type_abort(subreq->async.private_data,
2124 struct dcerpc_alter_context_state *state =
2125 tevent_req_data(req,
2126 struct dcerpc_alter_context_state);
2127 NTSTATUS status = subreq->status;
2129 TALLOC_FREE(subreq);
2132 * We trigger the callback in the next event run
2133 * because the code in this file might trigger
2134 * multiple request callbacks from within a single
2137 * In order to avoid segfaults from within
2138 * dcerpc_connection_dead() we call
2139 * tevent_req_defer_callback().
2141 tevent_req_defer_callback(req, state->ev);
2143 tevent_req_nterror(req, status);
2146 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2147 DATA_BLOB *raw_packet,
2148 struct ncacn_packet *pkt)
2150 struct tevent_req *req =
2151 talloc_get_type_abort(subreq->async.private_data,
2153 struct dcerpc_alter_context_state *state =
2154 tevent_req_data(req,
2155 struct dcerpc_alter_context_state);
2156 struct dcecli_connection *conn = state->p->conn;
2160 * Note that pkt is allocated under raw_packet->data,
2161 * while raw_packet->data is a child of subreq.
2163 talloc_steal(state, raw_packet->data);
2164 TALLOC_FREE(subreq);
2167 * We trigger the callback in the next event run
2168 * because the code in this file might trigger
2169 * multiple request callbacks from within a single
2172 * In order to avoid segfaults from within
2173 * dcerpc_connection_dead() we call
2174 * tevent_req_defer_callback().
2176 tevent_req_defer_callback(req, state->ev);
2178 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2179 pkt->u.alter_resp.num_results == 1 &&
2180 pkt->u.alter_resp.ctx_list[0].result != 0) {
2181 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2182 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2183 pkt->u.alter_resp.ctx_list[0].reason,
2184 nt_errstr(status)));
2185 tevent_req_nterror(req, status);
2189 if (pkt->ptype == DCERPC_PKT_FAULT) {
2190 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2191 dcerpc_errstr(state, pkt->u.fault.status)));
2192 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2193 state->p->last_fault_code = pkt->u.fault.status;
2194 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2196 state->p->last_fault_code = pkt->u.fault.status;
2197 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2202 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2203 pkt->u.alter_resp.num_results == 0 ||
2204 pkt->u.alter_resp.ctx_list[0].result != 0) {
2205 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2206 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2210 /* the alter_resp might contain a reply set of credentials */
2211 if (conn->security_state.auth_info &&
2212 pkt->u.alter_resp.auth_info.length) {
2213 uint32_t auth_length;
2215 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2216 conn->security_state.auth_info, &auth_length, true);
2217 if (tevent_req_nterror(req, status)) {
2222 tevent_req_done(req);
2225 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2227 return tevent_req_simple_recv_ntstatus(req);
2231 send a dcerpc alter_context request
2233 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2234 TALLOC_CTX *mem_ctx,
2235 const struct ndr_syntax_id *syntax,
2236 const struct ndr_syntax_id *transfer_syntax)
2238 struct tevent_req *subreq;
2239 struct tevent_context *ev = p->conn->event_ctx;
2242 /* TODO: create a new event context here */
2244 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2245 p, syntax, transfer_syntax);
2246 if (subreq == NULL) {
2247 return NT_STATUS_NO_MEMORY;
2250 ok = tevent_req_poll(subreq, ev);
2253 status = map_nt_error_from_unix_common(errno);
2257 return dcerpc_alter_context_recv(subreq);
2260 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2262 if (c->transport.stream == NULL) {
2266 tevent_queue_stop(c->transport.write_queue);
2267 TALLOC_FREE(c->transport.read_subreq);
2268 TALLOC_FREE(c->transport.stream);
2270 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2271 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2274 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2275 status = NT_STATUS_END_OF_FILE;
2278 dcerpc_recv_data(c, NULL, status);
2283 shutdown SMB pipe connection
2285 struct dcerpc_shutdown_pipe_state {
2286 struct dcecli_connection *c;
2290 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2292 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2294 struct dcerpc_shutdown_pipe_state *state;
2295 struct tevent_req *subreq;
2297 if (c->transport.stream == NULL) {
2298 return NT_STATUS_OK;
2301 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2302 if (state == NULL) {
2303 return NT_STATUS_NO_MEMORY;
2306 state->status = status;
2308 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2309 if (subreq == NULL) {
2310 return NT_STATUS_NO_MEMORY;
2312 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2317 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2319 struct dcerpc_shutdown_pipe_state *state =
2320 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2321 struct dcecli_connection *c = state->c;
2322 NTSTATUS status = state->status;
2326 * here we ignore the return values...
2328 tstream_disconnect_recv(subreq, &error);
2329 TALLOC_FREE(subreq);
2333 dcerpc_transport_dead(c, status);
2338 struct dcerpc_send_read_state {
2339 struct dcecli_connection *p;
2342 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2344 struct dcecli_connection *p = state->p;
2346 p->transport.read_subreq = NULL;
2351 static void dcerpc_send_read_done(struct tevent_req *subreq);
2353 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2355 struct dcerpc_send_read_state *state;
2357 if (p->transport.read_subreq != NULL) {
2358 p->transport.pending_reads++;
2359 return NT_STATUS_OK;
2362 state = talloc_zero(p, struct dcerpc_send_read_state);
2363 if (state == NULL) {
2364 return NT_STATUS_NO_MEMORY;
2368 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2370 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2372 p->transport.stream);
2373 if (p->transport.read_subreq == NULL) {
2374 return NT_STATUS_NO_MEMORY;
2376 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2378 return NT_STATUS_OK;
2381 static void dcerpc_send_read_done(struct tevent_req *subreq)
2383 struct dcerpc_send_read_state *state =
2384 tevent_req_callback_data(subreq,
2385 struct dcerpc_send_read_state);
2386 struct dcecli_connection *p = state->p;
2388 struct ncacn_packet *pkt;
2391 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2393 TALLOC_FREE(subreq);
2394 if (!NT_STATUS_IS_OK(status)) {
2396 dcerpc_transport_dead(p, status);
2401 * here we steal into thet connection context,
2402 * but p->transport.recv_data() will steal or free it again
2404 talloc_steal(p, blob.data);
2407 if (p->transport.pending_reads > 0) {
2408 p->transport.pending_reads--;
2410 status = dcerpc_send_read(p);
2411 if (!NT_STATUS_IS_OK(status)) {
2412 dcerpc_transport_dead(p, status);
2417 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2420 struct dcerpc_send_request_state {
2421 struct dcecli_connection *p;
2426 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2428 struct dcecli_connection *p = state->p;
2430 p->transport.read_subreq = NULL;
2435 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2436 static void dcerpc_send_request_done(struct tevent_req *subreq);
2438 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2441 struct dcerpc_send_request_state *state;
2442 struct tevent_req *subreq;
2443 bool use_trans = trigger_read;
2445 if (p->transport.stream == NULL) {
2446 return NT_STATUS_CONNECTION_DISCONNECTED;
2449 state = talloc_zero(p, struct dcerpc_send_request_state);
2450 if (state == NULL) {
2451 return NT_STATUS_NO_MEMORY;
2455 state->blob = data_blob_talloc(state, data->data, data->length);
2456 if (state->blob.data == NULL) {
2458 return NT_STATUS_NO_MEMORY;
2460 state->iov.iov_base = (void *)state->blob.data;
2461 state->iov.iov_len = state->blob.length;
2463 if (p->transport.read_subreq != NULL) {
2467 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2473 * we need to block reads until our write is
2474 * the next in the write queue.
2476 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2477 p->transport.write_queue);
2478 if (p->transport.read_subreq == NULL) {
2480 return NT_STATUS_NO_MEMORY;
2482 tevent_req_set_callback(p->transport.read_subreq,
2483 dcerpc_send_request_wait_done,
2486 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2488 trigger_read = false;
2491 subreq = tstream_writev_queue_send(state, p->event_ctx,
2492 p->transport.stream,
2493 p->transport.write_queue,
2495 if (subreq == NULL) {
2497 return NT_STATUS_NO_MEMORY;
2499 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2502 dcerpc_send_read(p);
2505 return NT_STATUS_OK;
2508 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2510 struct dcerpc_send_request_state *state =
2511 tevent_req_callback_data(subreq,
2512 struct dcerpc_send_request_state);
2513 struct dcecli_connection *p = state->p;
2517 p->transport.read_subreq = NULL;
2518 talloc_set_destructor(state, NULL);
2520 ok = tevent_queue_wait_recv(subreq);
2523 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2527 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2528 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2529 if (!NT_STATUS_IS_OK(status)) {
2531 dcerpc_transport_dead(p, status);
2536 /* we free subreq after tstream_cli_np_use_trans */
2537 TALLOC_FREE(subreq);
2539 dcerpc_send_read(p);
2542 static void dcerpc_send_request_done(struct tevent_req *subreq)
2544 struct dcerpc_send_request_state *state =
2545 tevent_req_callback_data(subreq,
2546 struct dcerpc_send_request_state);
2550 ret = tstream_writev_queue_recv(subreq, &error);
2551 TALLOC_FREE(subreq);
2553 struct dcecli_connection *p = state->p;
2554 NTSTATUS status = map_nt_error_from_unix_common(error);
2557 dcerpc_transport_dead(p, status);