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/rpc/dcerpc_util.h"
30 #include "librpc/rpc/dcerpc_pkt_auth.h"
31 #include "librpc/gen_ndr/ndr_misc.h"
32 #include "librpc/gen_ndr/ndr_dcerpc.h"
33 #include "auth/gensec/gensec.h"
34 #include "param/param.h"
35 #include "lib/util/tevent_ntstatus.h"
36 #include "librpc/rpc/rpc_common.h"
37 #include "lib/tsocket/tsocket.h"
38 #include "libcli/smb/tstream_smbXcli_np.h"
41 enum rpc_request_state {
48 handle for an async dcerpc request
51 struct rpc_request *next, *prev;
52 struct dcerpc_pipe *p;
55 enum rpc_request_state state;
60 /* this is used to distinguish bind and alter_context requests
61 from normal requests */
62 void (*recv_handler)(struct rpc_request *conn,
63 DATA_BLOB *blob, struct ncacn_packet *pkt);
65 const struct GUID *object;
67 DATA_BLOB request_data;
74 void (*callback)(struct rpc_request *);
79 _PUBLIC_ NTSTATUS dcerpc_init(void)
84 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
85 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
86 static int dcerpc_req_dequeue(struct rpc_request *req);
88 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
89 struct dcerpc_pipe *p,
90 const struct GUID *object,
92 DATA_BLOB *stub_data);
93 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
95 DATA_BLOB *stub_data);
96 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
100 ndr_push_flags_fn_t ndr_push,
101 ndr_pull_flags_fn_t ndr_pull);
102 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
103 struct ndr_pull *pull_in,
106 ndr_push_flags_fn_t ndr_push,
107 ndr_pull_flags_fn_t ndr_pull,
108 ndr_print_function_t ndr_print);
109 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
110 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
112 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
114 /* destroy a dcerpc connection */
115 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
118 conn->free_skipped = true;
121 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
126 /* initialise a dcerpc connection.
127 the event context is optional
129 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
130 struct tevent_context *ev)
132 struct dcecli_connection *c;
134 c = talloc_zero(mem_ctx, struct dcecli_connection);
141 if (c->event_ctx == NULL) {
147 c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
148 c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
149 c->security_state.auth_context_id = 0;
150 c->security_state.session_key = dcecli_generic_session_key;
151 c->security_state.generic_state = NULL;
154 * Windows uses 5840 for ncacn_ip_tcp,
155 * so we also use it (for every transport)
156 * by default. But we give the transport
157 * the chance to overwrite it.
159 c->srv_max_xmit_frag = 5840;
160 c->srv_max_recv_frag = 5840;
161 c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
164 c->io_trigger = tevent_create_immediate(c);
165 if (c->io_trigger == NULL) {
170 talloc_set_destructor(c, dcerpc_connection_destructor);
175 struct dcerpc_bh_state {
176 struct dcerpc_pipe *p;
179 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
181 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
182 struct dcerpc_bh_state);
192 if (hs->p->conn->dead) {
199 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
202 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
203 struct dcerpc_bh_state);
207 return DCERPC_REQUEST_TIMEOUT;
210 old = hs->p->request_timeout;
211 hs->p->request_timeout = timeout;
216 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
217 enum dcerpc_AuthType *auth_type,
218 enum dcerpc_AuthLevel *auth_level)
220 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
221 struct dcerpc_bh_state);
227 if (hs->p->conn == NULL) {
231 *auth_type = hs->p->conn->security_state.auth_type;
232 *auth_level = hs->p->conn->security_state.auth_level;
235 struct dcerpc_bh_raw_call_state {
236 struct tevent_context *ev;
237 struct dcerpc_binding_handle *h;
241 struct rpc_request *subreq;
244 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
245 static bool dcerpc_bh_raw_call_cancel(struct tevent_req *req);
247 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
248 struct tevent_context *ev,
249 struct dcerpc_binding_handle *h,
250 const struct GUID *object,
253 const uint8_t *in_data,
256 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
257 struct dcerpc_bh_state);
258 struct tevent_req *req;
259 struct dcerpc_bh_raw_call_state *state;
262 req = tevent_req_create(mem_ctx, &state,
263 struct dcerpc_bh_raw_call_state);
269 state->in_data.data = discard_const_p(uint8_t, in_data);
270 state->in_data.length = in_length;
272 ok = dcerpc_bh_is_connected(h);
274 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
275 return tevent_req_post(req, ev);
278 state->subreq = dcerpc_request_send(state,
283 if (tevent_req_nomem(state->subreq, req)) {
284 return tevent_req_post(req, ev);
286 state->subreq->async.callback = dcerpc_bh_raw_call_done;
287 state->subreq->async.private_data = req;
289 tevent_req_set_cancel_fn(req, dcerpc_bh_raw_call_cancel);
294 static bool dcerpc_bh_raw_call_cancel(struct tevent_req *req)
296 struct dcerpc_bh_raw_call_state *state = tevent_req_data(
297 req, struct dcerpc_bh_raw_call_state);
298 struct rpc_request *subreq = state->subreq;
300 switch (subreq->state) {
301 case RPC_REQUEST_DONE:
302 /* Can't cancel a complete request */
304 case RPC_REQUEST_PENDING:
306 /* TODO Send CO_CANCEL PDU */
309 case RPC_REQUEST_QUEUED:
312 * If still queued, just remove from queue and call
315 dcerpc_req_dequeue(subreq);
316 subreq->payload = data_blob_null;
317 subreq->state = RPC_REQUEST_DONE;
318 subreq->status = NT_STATUS_RPC_CALL_CANCELLED;
321 * We have to look at shipping further requests before calling
322 * the async function, that one might close the pipe
324 dcerpc_schedule_io_trigger(subreq->p->conn);
326 if (subreq->async.callback) {
327 subreq->async.callback(subreq);
336 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
338 struct tevent_req *req =
339 talloc_get_type_abort(subreq->async.private_data,
341 struct dcerpc_bh_raw_call_state *state =
343 struct dcerpc_bh_raw_call_state);
347 state->out_flags = 0;
348 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
349 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
352 fault_code = subreq->fault_code;
354 status = dcerpc_request_recv(subreq, state, &state->out_data);
355 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
356 status = dcerpc_fault_to_nt_status(fault_code);
360 * We trigger the callback in the next event run
361 * because the code in this file might trigger
362 * multiple request callbacks from within a single
365 * In order to avoid segfaults from within
366 * dcerpc_connection_dead() we call
367 * tevent_req_defer_callback().
369 tevent_req_defer_callback(req, state->ev);
371 if (!NT_STATUS_IS_OK(status)) {
372 tevent_req_nterror(req, status);
376 tevent_req_done(req);
379 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
385 struct dcerpc_bh_raw_call_state *state =
387 struct dcerpc_bh_raw_call_state);
390 if (tevent_req_is_nterror(req, &status)) {
391 tevent_req_received(req);
395 *out_data = talloc_move(mem_ctx, &state->out_data.data);
396 *out_length = state->out_data.length;
397 *out_flags = state->out_flags;
398 tevent_req_received(req);
402 struct dcerpc_bh_disconnect_state {
406 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
407 struct tevent_context *ev,
408 struct dcerpc_binding_handle *h)
410 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
411 struct dcerpc_bh_state);
412 struct tevent_req *req;
413 struct dcerpc_bh_disconnect_state *state;
416 req = tevent_req_create(mem_ctx, &state,
417 struct dcerpc_bh_disconnect_state);
422 ok = dcerpc_bh_is_connected(h);
424 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
425 return tevent_req_post(req, ev);
428 /* TODO: do a real disconnect ... */
431 tevent_req_done(req);
432 return tevent_req_post(req, ev);
435 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
439 if (tevent_req_is_nterror(req, &status)) {
440 tevent_req_received(req);
444 tevent_req_received(req);
448 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
450 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
451 struct dcerpc_bh_state);
453 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
460 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
462 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
463 struct dcerpc_bh_state);
465 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
472 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
474 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
475 struct dcerpc_bh_state);
477 if (hs->p->conn->flags & DCERPC_NDR64) {
484 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
485 ndr_flags_type ndr_flags,
486 const void *_struct_ptr,
487 const struct ndr_interface_call *call)
489 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
490 struct dcerpc_bh_state);
491 void *struct_ptr = discard_const(_struct_ptr);
492 bool print_in = false;
493 bool print_out = false;
495 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
499 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
503 if (DEBUGLEVEL >= 11) {
508 if (ndr_flags & NDR_IN) {
510 ndr_print_function_debug(call->ndr_print,
516 if (ndr_flags & NDR_OUT) {
518 ndr_print_function_debug(call->ndr_print,
526 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
528 const void *struct_ptr,
529 const struct ndr_interface_call *call)
531 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
532 call->name, nt_errstr(error)));
535 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
537 const DATA_BLOB *blob,
538 const struct ndr_interface_call *call)
540 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
541 struct dcerpc_bh_state);
542 const uint32_t num_examples = 20;
545 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
546 call->name, nt_errstr(error)));
548 if (hs->p->conn->packet_log_dir == NULL) return;
550 for (i=0;i<num_examples;i++) {
554 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
555 hs->p->conn->packet_log_dir,
560 if (!file_exist(name)) {
561 if (file_save(name, blob->data, blob->length)) {
562 DEBUG(10,("Logged rpc packet to %s\n", name));
571 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
573 const DATA_BLOB *blob,
574 const struct ndr_interface_call *call)
576 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
577 struct dcerpc_bh_state);
579 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
582 status = dcerpc_ndr_validate_in(hs->p->conn,
588 if (!NT_STATUS_IS_OK(status)) {
589 DEBUG(0,("Validation [in] failed for %s - %s\n",
590 call->name, nt_errstr(status)));
595 DEBUG(10,("rpc request data:\n"));
596 dump_data(10, blob->data, blob->length);
601 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
602 struct ndr_pull *pull_in,
603 const void *_struct_ptr,
604 const struct ndr_interface_call *call)
606 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
607 struct dcerpc_bh_state);
608 void *struct_ptr = discard_const(_struct_ptr);
610 DEBUG(10,("rpc reply data:\n"));
611 dump_data(10, pull_in->data, pull_in->data_size);
613 if (pull_in->offset != pull_in->data_size) {
614 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
615 pull_in->data_size - pull_in->offset,
616 pull_in->offset, pull_in->offset,
618 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
619 but it turns out that early versions of NT
620 (specifically NT3.1) add junk onto the end of rpc
621 packets, so if we want to interoperate at all with
622 those versions then we need to ignore this error */
625 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
628 status = dcerpc_ndr_validate_out(hs->p->conn,
635 if (!NT_STATUS_IS_OK(status)) {
636 DEBUG(2,("Validation [out] failed for %s - %s\n",
637 call->name, nt_errstr(status)));
645 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
647 .is_connected = dcerpc_bh_is_connected,
648 .set_timeout = dcerpc_bh_set_timeout,
649 .auth_info = dcerpc_bh_auth_info,
650 .raw_call_send = dcerpc_bh_raw_call_send,
651 .raw_call_recv = dcerpc_bh_raw_call_recv,
652 .disconnect_send = dcerpc_bh_disconnect_send,
653 .disconnect_recv = dcerpc_bh_disconnect_recv,
655 .push_bigendian = dcerpc_bh_push_bigendian,
656 .ref_alloc = dcerpc_bh_ref_alloc,
657 .use_ndr64 = dcerpc_bh_use_ndr64,
658 .do_ndr_print = dcerpc_bh_do_ndr_print,
659 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
660 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
661 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
662 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
665 /* initialise a dcerpc pipe. */
666 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p,
667 const struct GUID *object,
668 const struct ndr_interface_table *table)
670 struct dcerpc_binding_handle *h;
671 struct dcerpc_bh_state *hs;
673 h = dcerpc_binding_handle_create(p,
678 struct dcerpc_bh_state,
685 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
690 /* initialise a dcerpc pipe. */
691 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
693 struct dcerpc_pipe *p;
695 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
700 p->conn = dcerpc_connection_init(p, ev);
701 if (p->conn == NULL) {
706 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
709 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
717 choose the next call id to use
719 static uint32_t next_call_id(struct dcecli_connection *c)
722 if (c->call_id == 0) {
729 setup for a ndr pull, also setting up any flags from the binding string
731 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
732 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
734 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
736 if (ndr == NULL) return ndr;
738 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
739 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
742 if (c->flags & DCERPC_NDR_REF_ALLOC) {
743 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
746 if (c->flags & DCERPC_NDR64) {
747 ndr->flags |= LIBNDR_FLAG_NDR64;
754 parse the authentication information on a dcerpc response packet
756 static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c,
758 enum dcerpc_pkt_type ptype,
759 uint8_t required_flags,
760 uint8_t optional_flags,
761 uint8_t payload_offset,
762 DATA_BLOB *payload_and_verifier,
763 DATA_BLOB *raw_packet,
764 const struct ncacn_packet *pkt)
766 const struct dcerpc_auth tmp_auth = {
767 .auth_type = c->security_state.auth_type,
768 .auth_level = c->security_state.auth_level,
769 .auth_context_id = c->security_state.auth_context_id,
773 status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
774 c->security_state.generic_state,
775 true, /* check_pkt_auth_fields */
781 payload_and_verifier,
784 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
785 return NT_STATUS_INVALID_NETWORK_RESPONSE;
787 if (!NT_STATUS_IS_OK(status)) {
796 push a dcerpc request packet into a blob, possibly signing it.
798 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
799 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
801 struct ncacn_packet *pkt)
803 const struct dcerpc_auth tmp_auth = {
804 .auth_type = c->security_state.auth_type,
805 .auth_level = c->security_state.auth_level,
806 .auth_context_id = c->security_state.auth_context_id,
809 uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
811 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
812 payload_offset += 16;
815 status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
816 c->security_state.generic_state,
820 &pkt->u.request.stub_and_verifier,
822 if (!NT_STATUS_IS_OK(status)) {
831 fill in the fixed values in a dcerpc header
833 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
836 pkt->rpc_vers_minor = 0;
837 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
840 pkt->drep[0] = DCERPC_DREP_LE;
848 map a bind nak reason to a NTSTATUS
850 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
853 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
854 return NT_STATUS_REVISION_MISMATCH;
855 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
856 return NT_STATUS_INVALID_PARAMETER;
860 return NT_STATUS_UNSUCCESSFUL;
863 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
866 return NT_STATUS_RPC_PROTOCOL_ERROR;
869 switch (ack->result) {
870 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
872 * We have not asked for this...
874 return NT_STATUS_RPC_PROTOCOL_ERROR;
879 switch (ack->reason.value) {
880 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
881 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
882 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
883 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
887 return NT_STATUS_UNSUCCESSFUL;
891 remove requests from the pending or queued queues
893 static int dcerpc_req_dequeue(struct rpc_request *req)
895 switch (req->state) {
896 case RPC_REQUEST_QUEUED:
897 DLIST_REMOVE(req->p->conn->request_queue, req);
899 case RPC_REQUEST_PENDING:
900 DLIST_REMOVE(req->p->conn->pending, req);
902 case RPC_REQUEST_DONE:
910 mark the dcerpc connection dead. All outstanding requests get an error
912 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
914 if (conn->dead) return;
918 TALLOC_FREE(conn->io_trigger);
919 conn->io_trigger_pending = false;
921 dcerpc_shutdown_pipe(conn, status);
923 /* all pending requests get the error */
924 while (conn->pending) {
925 struct rpc_request *req = conn->pending;
926 dcerpc_req_dequeue(req);
927 req->state = RPC_REQUEST_DONE;
928 req->status = status;
929 if (req->async.callback) {
930 req->async.callback(req);
934 /* all requests, which are not shipped */
935 while (conn->request_queue) {
936 struct rpc_request *req = conn->request_queue;
937 dcerpc_req_dequeue(req);
938 req->state = RPC_REQUEST_DONE;
939 req->status = status;
940 if (req->async.callback) {
941 req->async.callback(req);
945 talloc_set_destructor(conn, NULL);
946 if (conn->free_skipped) {
952 forward declarations of the recv_data handlers for the types of
953 packets we need to handle
955 static void dcerpc_request_recv_data(struct dcecli_connection *c,
956 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
959 receive a dcerpc reply from the transport. Here we work out what
960 type of reply it is (normal request, bind or alter context) and
961 dispatch to the appropriate handler
963 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
965 struct ncacn_packet pkt;
971 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
972 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
975 /* the transport may be telling us of a severe error, such as
977 if (!NT_STATUS_IS_OK(status)) {
978 data_blob_free(blob);
979 dcerpc_connection_dead(conn, status);
983 /* parse the basic packet to work out what type of response this is */
984 status = dcerpc_pull_ncacn_packet(blob->data, blob, &pkt);
985 if (!NT_STATUS_IS_OK(status)) {
986 data_blob_free(blob);
987 dcerpc_connection_dead(conn, status);
991 dcerpc_request_recv_data(conn, blob, &pkt);
995 handle timeouts of individual dcerpc requests
997 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
998 struct timeval t, void *private_data)
1000 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1002 if (req->ignore_timeout) {
1003 dcerpc_req_dequeue(req);
1004 req->state = RPC_REQUEST_DONE;
1005 req->status = NT_STATUS_IO_TIMEOUT;
1006 if (req->async.callback) {
1007 req->async.callback(req);
1012 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1015 struct dcerpc_bind_state {
1016 struct tevent_context *ev;
1017 struct dcerpc_pipe *p;
1020 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1021 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1022 DATA_BLOB *raw_packet,
1023 struct ncacn_packet *pkt);
1025 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1026 struct tevent_context *ev,
1027 struct dcerpc_pipe *p,
1028 const struct ndr_syntax_id *syntax,
1029 const struct ndr_syntax_id *transfer_syntax)
1031 struct tevent_req *req;
1032 struct dcerpc_bind_state *state;
1033 struct ncacn_packet pkt;
1036 struct rpc_request *subreq;
1038 struct ndr_syntax_id bind_time_features;
1040 bind_time_features = dcerpc_construct_bind_time_features(
1041 DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
1042 DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
1044 req = tevent_req_create(mem_ctx, &state,
1045 struct dcerpc_bind_state);
1053 p->syntax = *syntax;
1054 p->transfer_syntax = *transfer_syntax;
1056 flags = dcerpc_binding_get_flags(p->binding);
1058 init_ncacn_hdr(p->conn, &pkt);
1060 pkt.ptype = DCERPC_PKT_BIND;
1061 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1062 pkt.call_id = p->conn->call_id;
1063 pkt.auth_length = 0;
1065 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1066 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1069 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1070 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1073 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1074 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1075 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1076 pkt.u.bind.num_contexts = 2;
1077 pkt.u.bind.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
1078 pkt.u.bind.num_contexts);
1079 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1080 return tevent_req_post(req, ev);
1082 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1083 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1084 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1085 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1086 pkt.u.bind.ctx_list[1].context_id = p->context_id + 1;
1087 pkt.u.bind.ctx_list[1].num_transfer_syntaxes = 1;
1088 pkt.u.bind.ctx_list[1].abstract_syntax = p->syntax;
1089 pkt.u.bind.ctx_list[1].transfer_syntaxes = &bind_time_features;
1090 pkt.u.bind.auth_info = data_blob(NULL, 0);
1092 /* construct the NDR form of the packet */
1093 status = dcerpc_ncacn_push_auth(&blob,
1096 p->conn->security_state.tmp_auth_info.out);
1097 if (tevent_req_nterror(req, status)) {
1098 return tevent_req_post(req, ev);
1102 * we allocate a dcerpc_request so we can be in the same
1103 * request queue as normal requests
1105 subreq = talloc_zero(state, struct rpc_request);
1106 if (tevent_req_nomem(subreq, req)) {
1107 return tevent_req_post(req, ev);
1110 subreq->state = RPC_REQUEST_PENDING;
1111 subreq->call_id = pkt.call_id;
1112 subreq->async.private_data = req;
1113 subreq->async.callback = dcerpc_bind_fail_handler;
1115 subreq->recv_handler = dcerpc_bind_recv_handler;
1116 DLIST_ADD_END(p->conn->pending, subreq);
1117 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1119 status = dcerpc_send_request(p->conn, &blob, true);
1120 if (tevent_req_nterror(req, status)) {
1121 return tevent_req_post(req, ev);
1124 tevent_add_timer(ev, subreq,
1125 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1126 dcerpc_timeout_handler, subreq);
1131 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1133 struct tevent_req *req =
1134 talloc_get_type_abort(subreq->async.private_data,
1136 struct dcerpc_bind_state *state =
1137 tevent_req_data(req,
1138 struct dcerpc_bind_state);
1139 NTSTATUS status = subreq->status;
1141 TALLOC_FREE(subreq);
1144 * We trigger the callback in the next event run
1145 * because the code in this file might trigger
1146 * multiple request callbacks from within a single
1149 * In order to avoid segfaults from within
1150 * dcerpc_connection_dead() we call
1151 * tevent_req_defer_callback().
1153 tevent_req_defer_callback(req, state->ev);
1155 tevent_req_nterror(req, status);
1158 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1159 DATA_BLOB *raw_packet,
1160 struct ncacn_packet *pkt)
1162 struct tevent_req *req =
1163 talloc_get_type_abort(subreq->async.private_data,
1165 struct dcerpc_bind_state *state =
1166 tevent_req_data(req,
1167 struct dcerpc_bind_state);
1168 struct dcecli_connection *conn = state->p->conn;
1169 struct dcecli_security *sec = &conn->security_state;
1170 struct dcerpc_binding *b = NULL;
1175 * Note that pkt is allocated under raw_packet->data,
1176 * while raw_packet->data is a child of subreq.
1178 talloc_steal(state, raw_packet->data);
1179 TALLOC_FREE(subreq);
1182 * We trigger the callback in the next event run
1183 * because the code in this file might trigger
1184 * multiple request callbacks from within a single
1187 * In order to avoid segfaults from within
1188 * dcerpc_connection_dead() we call
1189 * tevent_req_defer_callback().
1191 tevent_req_defer_callback(req, state->ev);
1193 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1194 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1196 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1197 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1199 tevent_req_nterror(req, status);
1203 status = dcerpc_verify_ncacn_packet_header(pkt,
1204 DCERPC_PKT_BIND_ACK,
1205 pkt->u.bind_ack.auth_info.length,
1206 DCERPC_PFC_FLAG_FIRST |
1207 DCERPC_PFC_FLAG_LAST,
1208 DCERPC_PFC_FLAG_CONC_MPX |
1209 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1210 if (!NT_STATUS_IS_OK(status)) {
1211 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1212 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1216 if (pkt->u.bind_ack.num_results < 1) {
1217 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1218 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1222 if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1223 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1224 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1225 pkt->u.bind_ack.ctx_list[0].reason.value,
1226 nt_errstr(status)));
1227 tevent_req_nterror(req, status);
1231 if (pkt->u.bind_ack.num_results >= 2) {
1232 if (pkt->u.bind_ack.ctx_list[1].result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1233 conn->bind_time_features = pkt->u.bind_ack.ctx_list[1].reason.negotiate;
1235 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[1]);
1236 DEBUG(10,("dcerpc: bind_time_feature failed - reason %d - %s\n",
1237 pkt->u.bind_ack.ctx_list[1].reason.value,
1238 nt_errstr(status)));
1239 status = NT_STATUS_OK;
1244 * DCE-RPC 1.1 (c706) specifies
1245 * CONST_MUST_RCV_FRAG_SIZE as 1432
1247 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1248 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1249 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1252 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1253 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1254 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1257 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1258 pkt->u.bind_ack.max_xmit_frag);
1259 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1260 pkt->u.bind_ack.max_recv_frag);
1262 flags = dcerpc_binding_get_flags(state->p->binding);
1264 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1265 if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1266 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1268 conn->flags &= ~DCERPC_CONCURRENT_MULTIPLEX;
1272 if (!(conn->flags & DCERPC_CONCURRENT_MULTIPLEX)) {
1273 struct dcerpc_binding *pb =
1274 discard_const_p(struct dcerpc_binding, state->p->binding);
1276 * clear DCERPC_CONCURRENT_MULTIPLEX
1278 status = dcerpc_binding_set_flags(pb, 0,
1279 DCERPC_CONCURRENT_MULTIPLEX);
1280 if (tevent_req_nterror(req, status)) {
1284 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1285 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1286 conn->flags |= DCERPC_HEADER_SIGNING;
1289 /* the bind_ack might contain a reply set of credentials */
1290 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1291 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1292 &pkt->u.bind_ack.auth_info,
1293 sec->tmp_auth_info.in,
1295 if (tevent_req_nterror(req, status)) {
1301 * We're the owner of the binding, so we're allowed to modify it.
1303 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1304 status = dcerpc_binding_set_assoc_group_id(b,
1305 pkt->u.bind_ack.assoc_group_id);
1306 if (tevent_req_nterror(req, status)) {
1310 tevent_req_done(req);
1313 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1315 return tevent_req_simple_recv_ntstatus(req);
1319 perform a continued bind (and auth3)
1321 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1322 TALLOC_CTX *mem_ctx)
1324 struct ncacn_packet pkt;
1329 flags = dcerpc_binding_get_flags(p->binding);
1331 init_ncacn_hdr(p->conn, &pkt);
1333 pkt.ptype = DCERPC_PKT_AUTH3;
1334 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1335 pkt.call_id = next_call_id(p->conn);
1336 pkt.auth_length = 0;
1337 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1339 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1340 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1343 /* construct the NDR form of the packet */
1344 status = dcerpc_ncacn_push_auth(&blob,
1347 p->conn->security_state.tmp_auth_info.out);
1348 if (!NT_STATUS_IS_OK(status)) {
1352 /* send it on its way */
1353 status = dcerpc_send_request(p->conn, &blob, false);
1354 if (!NT_STATUS_IS_OK(status)) {
1358 return NT_STATUS_OK;
1363 process a fragment received from the transport layer during a
1366 This function frees the data
1368 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1369 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1371 struct rpc_request *req;
1372 unsigned int length;
1373 NTSTATUS status = NT_STATUS_OK;
1376 if this is an authenticated connection then parse and check
1377 the auth info. We have to do this before finding the
1378 matching packet, as the request structure might have been
1379 removed due to a timeout, but if it has been we still need
1380 to run the auth routines so that we don't get the sign/seal
1381 info out of step with the server
1383 switch (pkt->ptype) {
1384 case DCERPC_PKT_RESPONSE:
1385 status = ncacn_pull_pkt_auth(c, raw_packet->data,
1386 DCERPC_PKT_RESPONSE,
1387 0, /* required_flags */
1388 DCERPC_PFC_FLAG_FIRST |
1389 DCERPC_PFC_FLAG_LAST,
1390 DCERPC_REQUEST_LENGTH,
1391 &pkt->u.response.stub_and_verifier,
1398 /* find the matching request */
1399 for (req=c->pending;req;req=req->next) {
1400 if (pkt->call_id == req->call_id) break;
1404 /* useful for testing certain vendors RPC servers */
1405 if (req == NULL && c->pending && pkt->call_id == 0) {
1406 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1412 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1413 data_blob_free(raw_packet);
1417 talloc_steal(req, raw_packet->data);
1419 if (req->recv_handler != NULL) {
1420 dcerpc_req_dequeue(req);
1421 req->state = RPC_REQUEST_DONE;
1424 * We have to look at shipping further requests before calling
1425 * the async function, that one might close the pipe
1427 dcerpc_schedule_io_trigger(c);
1429 req->recv_handler(req, raw_packet, pkt);
1433 if (pkt->ptype == DCERPC_PKT_FAULT) {
1434 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1435 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1436 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
1437 dcerpc_connection_dead(c, status);
1440 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1441 dcerpc_connection_dead(c, status);
1444 req->fault_code = pkt->u.fault.status;
1445 req->status = NT_STATUS_NET_WRITE_FAULT;
1449 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1450 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1452 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1456 /* now check the status from the auth routines, and if it failed then fail
1457 this request accordingly */
1458 if (!NT_STATUS_IS_OK(status)) {
1459 dcerpc_connection_dead(c, status);
1463 length = pkt->u.response.stub_and_verifier.length;
1465 if (req->payload.length + length > c->max_total_response_size) {
1466 DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
1467 (unsigned)req->payload.length + length,
1468 (unsigned)c->max_total_response_size));
1469 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1474 req->payload.data = talloc_realloc(req,
1477 req->payload.length + length);
1478 if (!req->payload.data) {
1479 req->status = NT_STATUS_NO_MEMORY;
1482 memcpy(req->payload.data+req->payload.length,
1483 pkt->u.response.stub_and_verifier.data, length);
1484 req->payload.length += length;
1487 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1488 data_blob_free(raw_packet);
1489 dcerpc_send_read(c);
1493 if (req->verify_bitmask1) {
1494 req->p->conn->security_state.verified_bitmask1 = true;
1496 if (req->verify_pcontext) {
1497 req->p->verified_pcontext = true;
1500 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1501 req->flags |= DCERPC_PULL_BIGENDIAN;
1503 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1507 data_blob_free(raw_packet);
1509 /* we've got the full payload */
1510 dcerpc_req_dequeue(req);
1511 req->state = RPC_REQUEST_DONE;
1514 * We have to look at shipping further requests before calling
1515 * the async function, that one might close the pipe
1517 dcerpc_schedule_io_trigger(c);
1519 if (req->async.callback) {
1520 req->async.callback(req);
1524 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1527 perform the send side of a async dcerpc request
1529 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1530 struct dcerpc_pipe *p,
1531 const struct GUID *object,
1533 DATA_BLOB *stub_data)
1535 struct rpc_request *req;
1538 req = talloc_zero(mem_ctx, struct rpc_request);
1544 req->call_id = next_call_id(p->conn);
1545 req->state = RPC_REQUEST_QUEUED;
1547 if (object != NULL) {
1548 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1549 if (req->object == NULL) {
1556 req->request_data.length = stub_data->length;
1557 req->request_data.data = stub_data->data;
1559 status = dcerpc_request_prepare_vt(req);
1560 if (!NT_STATUS_IS_OK(status)) {
1565 DLIST_ADD_END(p->conn->request_queue, req);
1566 talloc_set_destructor(req, dcerpc_req_dequeue);
1568 dcerpc_schedule_io_trigger(p->conn);
1570 if (p->request_timeout) {
1571 tevent_add_timer(p->conn->event_ctx, req,
1572 timeval_current_ofs(p->request_timeout, 0),
1573 dcerpc_timeout_handler, req);
1579 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1581 struct dcecli_security *sec = &req->p->conn->security_state;
1582 struct dcerpc_sec_verification_trailer *t;
1583 struct dcerpc_sec_vt *c = NULL;
1584 struct ndr_push *ndr = NULL;
1585 enum ndr_err_code ndr_err;
1587 if (sec->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1588 return NT_STATUS_OK;
1591 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1593 return NT_STATUS_NO_MEMORY;
1596 if (!sec->verified_bitmask1) {
1597 t->commands = talloc_realloc(t, t->commands,
1598 struct dcerpc_sec_vt,
1599 t->count.count + 1);
1600 if (t->commands == NULL) {
1601 return NT_STATUS_NO_MEMORY;
1603 c = &t->commands[t->count.count++];
1606 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1607 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1608 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1610 req->verify_bitmask1 = true;
1613 if (!req->p->verified_pcontext) {
1614 t->commands = talloc_realloc(t, t->commands,
1615 struct dcerpc_sec_vt,
1616 t->count.count + 1);
1617 if (t->commands == NULL) {
1618 return NT_STATUS_NO_MEMORY;
1620 c = &t->commands[t->count.count++];
1623 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1624 c->u.pcontext.abstract_syntax = req->p->syntax;
1625 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1627 req->verify_pcontext = true;
1630 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1631 t->commands = talloc_realloc(t, t->commands,
1632 struct dcerpc_sec_vt,
1633 t->count.count + 1);
1634 if (t->commands == NULL) {
1635 return NT_STATUS_NO_MEMORY;
1637 c = &t->commands[t->count.count++];
1640 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1641 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1642 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1643 c->u.header2.drep[0] = 0;
1645 c->u.header2.drep[0] = DCERPC_DREP_LE;
1647 c->u.header2.drep[1] = 0;
1648 c->u.header2.drep[2] = 0;
1649 c->u.header2.drep[3] = 0;
1650 c->u.header2.call_id = req->call_id;
1651 c->u.header2.context_id = req->p->context_id;
1652 c->u.header2.opnum = req->opnum;
1655 if (t->count.count == 0) {
1657 return NT_STATUS_OK;
1660 c = &t->commands[t->count.count - 1];
1661 c->command |= DCERPC_SEC_VT_COMMAND_END;
1663 if (DEBUGLEVEL >= 10) {
1664 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1667 ndr = ndr_push_init_ctx(req);
1669 return NT_STATUS_NO_MEMORY;
1673 * for now we just copy and append
1676 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1677 req->request_data.length);
1678 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1679 return ndr_map_error2ntstatus(ndr_err);
1682 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1683 NDR_SCALARS | NDR_BUFFERS,
1685 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1686 return ndr_map_error2ntstatus(ndr_err);
1688 req->request_data = ndr_push_blob(ndr);
1690 return NT_STATUS_OK;
1694 Send a request using the transport
1697 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1699 struct rpc_request *req;
1700 struct dcerpc_pipe *p;
1701 DATA_BLOB *stub_data;
1702 struct ncacn_packet pkt;
1704 uint32_t remaining, chunk_size;
1705 bool first_packet = true;
1706 size_t sig_size = 0;
1707 bool need_async = false;
1708 bool can_async = true;
1710 req = c->request_queue;
1716 stub_data = &req->request_data;
1722 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1723 can_async = gensec_have_feature(c->security_state.generic_state,
1724 GENSEC_FEATURE_ASYNC_REPLIES);
1727 if (need_async && !can_async) {
1728 req->wait_for_sync = true;
1732 DLIST_REMOVE(c->request_queue, req);
1733 DLIST_ADD(c->pending, req);
1734 req->state = RPC_REQUEST_PENDING;
1736 init_ncacn_hdr(p->conn, &pkt);
1738 remaining = stub_data->length;
1740 /* we can write a full max_recv_frag size, minus the dcerpc
1741 request header size */
1742 chunk_size = p->conn->srv_max_recv_frag;
1743 chunk_size -= DCERPC_REQUEST_LENGTH;
1744 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1745 size_t max_payload = chunk_size;
1747 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1748 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1750 sig_size = gensec_sig_size(c->security_state.generic_state,
1753 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1754 chunk_size -= sig_size;
1757 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1759 pkt.ptype = DCERPC_PKT_REQUEST;
1760 pkt.call_id = req->call_id;
1761 pkt.auth_length = 0;
1763 pkt.u.request.context_id = p->context_id;
1764 pkt.u.request.opnum = req->opnum;
1767 pkt.u.request.object.object = *req->object;
1768 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1769 chunk_size -= ndr_size_GUID(req->object,0);
1772 /* we send a series of pdus without waiting for a reply */
1773 while (remaining > 0 || first_packet) {
1774 uint32_t chunk = MIN(chunk_size, remaining);
1775 bool last_frag = false;
1776 bool do_trans = false;
1778 first_packet = false;
1779 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1781 if (remaining == stub_data->length) {
1782 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1784 if (chunk == remaining) {
1785 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1789 pkt.u.request.alloc_hint = remaining;
1790 pkt.u.request.stub_and_verifier.data = stub_data->data +
1791 (stub_data->length - remaining);
1792 pkt.u.request.stub_and_verifier.length = chunk;
1794 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1795 if (!NT_STATUS_IS_OK(req->status)) {
1796 req->state = RPC_REQUEST_DONE;
1797 DLIST_REMOVE(p->conn->pending, req);
1801 if (last_frag && !need_async) {
1805 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1806 if (!NT_STATUS_IS_OK(req->status)) {
1807 req->state = RPC_REQUEST_DONE;
1808 DLIST_REMOVE(p->conn->pending, req);
1812 if (last_frag && !do_trans) {
1813 req->status = dcerpc_send_read(p->conn);
1814 if (!NT_STATUS_IS_OK(req->status)) {
1815 req->state = RPC_REQUEST_DONE;
1816 DLIST_REMOVE(p->conn->pending, req);
1825 static void dcerpc_io_trigger(struct tevent_context *ctx,
1826 struct tevent_immediate *im,
1829 struct dcecli_connection *c =
1830 talloc_get_type_abort(private_data,
1831 struct dcecli_connection);
1833 c->io_trigger_pending = false;
1835 dcerpc_schedule_io_trigger(c);
1837 dcerpc_ship_next_request(c);
1840 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1846 if (c->request_queue == NULL) {
1850 if (c->request_queue->wait_for_sync && c->pending) {
1854 if (c->io_trigger_pending) {
1858 c->io_trigger_pending = true;
1860 tevent_schedule_immediate(c->io_trigger,
1867 perform the receive side of a async dcerpc request
1869 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1870 TALLOC_CTX *mem_ctx,
1871 DATA_BLOB *stub_data)
1875 while (req->state != RPC_REQUEST_DONE) {
1876 struct tevent_context *ctx = req->p->conn->event_ctx;
1877 if (tevent_loop_once(ctx) != 0) {
1878 return NT_STATUS_CONNECTION_DISCONNECTED;
1881 *stub_data = req->payload;
1882 status = req->status;
1883 if (stub_data->data) {
1884 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1886 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1887 req->p->last_fault_code = req->fault_code;
1889 talloc_unlink(talloc_parent(req), req);
1894 this is a paranoid NDR validator. For every packet we push onto the wire
1895 we pull it back again, then push it again. Then we compare the raw NDR data
1896 for that to the NDR we initially generated. If they don't match then we know
1897 we must have a bug in either the pull or push side of our code
1899 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1900 TALLOC_CTX *mem_ctx,
1903 ndr_push_flags_fn_t ndr_push,
1904 ndr_pull_flags_fn_t ndr_pull)
1907 struct ndr_pull *pull;
1908 struct ndr_push *push;
1910 enum ndr_err_code ndr_err;
1912 st = talloc_size(mem_ctx, struct_size);
1914 return NT_STATUS_NO_MEMORY;
1917 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1919 return NT_STATUS_NO_MEMORY;
1921 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1923 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1924 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1927 if (c->flags & DCERPC_NDR64) {
1928 pull->flags |= LIBNDR_FLAG_NDR64;
1931 ndr_err = ndr_pull(pull, NDR_IN, st);
1932 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1933 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1934 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1935 "failed input validation pull - %s",
1937 return ndr_map_error2ntstatus(ndr_err);
1940 push = ndr_push_init_ctx(mem_ctx);
1942 return NT_STATUS_NO_MEMORY;
1945 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1946 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1949 if (c->flags & DCERPC_NDR64) {
1950 push->flags |= LIBNDR_FLAG_NDR64;
1953 ndr_err = ndr_push(push, NDR_IN, st);
1954 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1955 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1956 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1957 "failed input validation push - %s",
1959 return ndr_map_error2ntstatus(ndr_err);
1962 blob2 = ndr_push_blob(push);
1964 if (data_blob_cmp(&blob, &blob2) != 0) {
1965 DEBUG(3,("original:\n"));
1966 dump_data(3, blob.data, blob.length);
1967 DEBUG(3,("secondary:\n"));
1968 dump_data(3, blob2.data, blob2.length);
1969 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1970 "failed input validation blobs doesn't match");
1971 return ndr_map_error2ntstatus(ndr_err);
1974 return NT_STATUS_OK;
1978 this is a paranoid NDR input validator. For every packet we pull
1979 from the wire we push it back again then pull and push it
1980 again. Then we compare the raw NDR data for that to the NDR we
1981 initially generated. If they don't match then we know we must have a
1982 bug in either the pull or push side of our code
1984 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1985 struct ndr_pull *pull_in,
1988 ndr_push_flags_fn_t ndr_push,
1989 ndr_pull_flags_fn_t ndr_pull,
1990 ndr_print_function_t ndr_print)
1993 struct ndr_pull *pull;
1994 struct ndr_push *push;
1995 DATA_BLOB blob, blob2;
1996 TALLOC_CTX *mem_ctx = pull_in;
1998 enum ndr_err_code ndr_err;
2000 st = talloc_size(mem_ctx, struct_size);
2002 return NT_STATUS_NO_MEMORY;
2004 memcpy(st, struct_ptr, struct_size);
2006 push = ndr_push_init_ctx(mem_ctx);
2008 return NT_STATUS_NO_MEMORY;
2011 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2012 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2013 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2014 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2015 "failed output validation push - %s",
2017 return ndr_map_error2ntstatus(ndr_err);
2020 blob = ndr_push_blob(push);
2022 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2024 return NT_STATUS_NO_MEMORY;
2027 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2028 ndr_err = ndr_pull(pull, NDR_OUT, st);
2029 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2030 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2031 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2032 "failed output validation pull - %s",
2034 return ndr_map_error2ntstatus(ndr_err);
2037 push = ndr_push_init_ctx(mem_ctx);
2039 return NT_STATUS_NO_MEMORY;
2042 ndr_err = ndr_push(push, NDR_OUT, st);
2043 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2044 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2045 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2046 "failed output validation push2 - %s",
2048 return ndr_map_error2ntstatus(ndr_err);
2051 blob2 = ndr_push_blob(push);
2053 if (data_blob_cmp(&blob, &blob2) != 0) {
2054 DEBUG(3,("original:\n"));
2055 dump_data(3, blob.data, blob.length);
2056 DEBUG(3,("secondary:\n"));
2057 dump_data(3, blob2.data, blob2.length);
2058 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2059 "failed output validation blobs doesn't match");
2060 return ndr_map_error2ntstatus(ndr_err);
2063 /* this checks the printed forms of the two structures, which effectively
2064 tests all of the value() attributes */
2065 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2066 NDR_OUT, struct_ptr);
2067 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2069 if (strcmp(s1, s2) != 0) {
2071 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2073 /* this is sometimes useful */
2074 printf("VALIDATE ERROR\n");
2075 file_save("wire.dat", s1, strlen(s1));
2076 file_save("gen.dat", s2, strlen(s2));
2077 system("diff -u wire.dat gen.dat");
2079 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2080 "failed output validation strings doesn't match");
2081 return ndr_map_error2ntstatus(ndr_err);
2084 return NT_STATUS_OK;
2088 a useful function for retrieving the server name we connected to
2090 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2092 return p->conn ? p->conn->server_name : NULL;
2097 get the dcerpc auth_level for a open connection
2099 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2103 if (c->flags & DCERPC_SEAL) {
2104 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2105 } else if (c->flags & DCERPC_SIGN) {
2106 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2107 } else if (c->flags & DCERPC_PACKET) {
2108 auth_level = DCERPC_AUTH_LEVEL_PACKET;
2109 } else if (c->flags & DCERPC_CONNECT) {
2110 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2112 auth_level = DCERPC_AUTH_LEVEL_NONE;
2117 struct dcerpc_alter_context_state {
2118 struct tevent_context *ev;
2119 struct dcerpc_pipe *p;
2122 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2123 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2124 DATA_BLOB *raw_packet,
2125 struct ncacn_packet *pkt);
2127 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2128 struct tevent_context *ev,
2129 struct dcerpc_pipe *p,
2130 const struct ndr_syntax_id *syntax,
2131 const struct ndr_syntax_id *transfer_syntax)
2133 struct tevent_req *req;
2134 struct dcerpc_alter_context_state *state;
2135 struct ncacn_packet pkt;
2138 struct rpc_request *subreq;
2141 req = tevent_req_create(mem_ctx, &state,
2142 struct dcerpc_alter_context_state);
2150 p->syntax = *syntax;
2151 p->transfer_syntax = *transfer_syntax;
2153 flags = dcerpc_binding_get_flags(p->binding);
2155 init_ncacn_hdr(p->conn, &pkt);
2157 pkt.ptype = DCERPC_PKT_ALTER;
2158 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2159 pkt.call_id = p->conn->call_id;
2160 pkt.auth_length = 0;
2162 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2163 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2166 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2167 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2168 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2169 pkt.u.alter.num_contexts = 1;
2170 pkt.u.alter.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
2171 pkt.u.alter.num_contexts);
2172 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2173 return tevent_req_post(req, ev);
2175 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2176 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2177 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2178 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2179 pkt.u.alter.auth_info = data_blob(NULL, 0);
2181 /* construct the NDR form of the packet */
2182 status = dcerpc_ncacn_push_auth(&blob,
2185 p->conn->security_state.tmp_auth_info.out);
2186 if (tevent_req_nterror(req, status)) {
2187 return tevent_req_post(req, ev);
2191 * we allocate a dcerpc_request so we can be in the same
2192 * request queue as normal requests
2194 subreq = talloc_zero(state, struct rpc_request);
2195 if (tevent_req_nomem(subreq, req)) {
2196 return tevent_req_post(req, ev);
2199 subreq->state = RPC_REQUEST_PENDING;
2200 subreq->call_id = pkt.call_id;
2201 subreq->async.private_data = req;
2202 subreq->async.callback = dcerpc_alter_context_fail_handler;
2204 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2205 DLIST_ADD_END(p->conn->pending, subreq);
2206 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2208 status = dcerpc_send_request(p->conn, &blob, true);
2209 if (tevent_req_nterror(req, status)) {
2210 return tevent_req_post(req, ev);
2213 tevent_add_timer(ev, subreq,
2214 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2215 dcerpc_timeout_handler, subreq);
2220 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2222 struct tevent_req *req =
2223 talloc_get_type_abort(subreq->async.private_data,
2225 struct dcerpc_alter_context_state *state =
2226 tevent_req_data(req,
2227 struct dcerpc_alter_context_state);
2228 NTSTATUS status = subreq->status;
2230 TALLOC_FREE(subreq);
2233 * We trigger the callback in the next event run
2234 * because the code in this file might trigger
2235 * multiple request callbacks from within a single
2238 * In order to avoid segfaults from within
2239 * dcerpc_connection_dead() we call
2240 * tevent_req_defer_callback().
2242 tevent_req_defer_callback(req, state->ev);
2244 tevent_req_nterror(req, status);
2247 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2248 DATA_BLOB *raw_packet,
2249 struct ncacn_packet *pkt)
2251 struct tevent_req *req =
2252 talloc_get_type_abort(subreq->async.private_data,
2254 struct dcerpc_alter_context_state *state =
2255 tevent_req_data(req,
2256 struct dcerpc_alter_context_state);
2257 struct dcecli_connection *conn = state->p->conn;
2258 struct dcecli_security *sec = &conn->security_state;
2262 * Note that pkt is allocated under raw_packet->data,
2263 * while raw_packet->data is a child of subreq.
2265 talloc_steal(state, raw_packet->data);
2266 TALLOC_FREE(subreq);
2269 * We trigger the callback in the next event run
2270 * because the code in this file might trigger
2271 * multiple request callbacks from within a single
2274 * In order to avoid segfaults from within
2275 * dcerpc_connection_dead() we call
2276 * tevent_req_defer_callback().
2278 tevent_req_defer_callback(req, state->ev);
2280 if (pkt->ptype == DCERPC_PKT_FAULT) {
2281 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2282 dcerpc_errstr(state, pkt->u.fault.status)));
2283 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2284 state->p->last_fault_code = pkt->u.fault.status;
2285 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2286 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2287 state->p->last_fault_code = pkt->u.fault.status;
2288 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2290 state->p->last_fault_code = pkt->u.fault.status;
2291 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2292 tevent_req_nterror(req, status);
2297 status = dcerpc_verify_ncacn_packet_header(pkt,
2298 DCERPC_PKT_ALTER_RESP,
2299 pkt->u.alter_resp.auth_info.length,
2300 DCERPC_PFC_FLAG_FIRST |
2301 DCERPC_PFC_FLAG_LAST,
2302 DCERPC_PFC_FLAG_CONC_MPX |
2303 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2304 if (!NT_STATUS_IS_OK(status)) {
2305 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2306 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2310 if (pkt->u.alter_resp.num_results != 1) {
2311 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2312 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2316 if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2317 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2318 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2319 pkt->u.alter_resp.ctx_list[0].reason.value,
2320 nt_errstr(status)));
2321 tevent_req_nterror(req, status);
2325 /* the alter_resp might contain a reply set of credentials */
2326 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2327 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2328 &pkt->u.alter_resp.auth_info,
2329 sec->tmp_auth_info.in,
2331 if (tevent_req_nterror(req, status)) {
2336 tevent_req_done(req);
2339 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2341 return tevent_req_simple_recv_ntstatus(req);
2345 send a dcerpc alter_context request
2347 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2348 TALLOC_CTX *mem_ctx,
2349 const struct ndr_syntax_id *syntax,
2350 const struct ndr_syntax_id *transfer_syntax)
2352 struct tevent_req *subreq;
2353 struct tevent_context *ev = p->conn->event_ctx;
2356 /* TODO: create a new event context here */
2358 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2359 p, syntax, transfer_syntax);
2360 if (subreq == NULL) {
2361 return NT_STATUS_NO_MEMORY;
2364 ok = tevent_req_poll(subreq, ev);
2367 status = map_nt_error_from_unix_common(errno);
2371 return dcerpc_alter_context_recv(subreq);
2374 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2376 if (c->transport.stream == NULL) {
2380 tevent_queue_stop(c->transport.write_queue);
2381 TALLOC_FREE(c->transport.read_subreq);
2382 TALLOC_FREE(c->transport.stream);
2384 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2385 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2388 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2389 status = NT_STATUS_END_OF_FILE;
2392 dcerpc_recv_data(c, NULL, status);
2397 shutdown SMB pipe connection
2399 struct dcerpc_shutdown_pipe_state {
2400 struct dcecli_connection *c;
2404 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2406 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2408 struct dcerpc_shutdown_pipe_state *state;
2409 struct tevent_req *subreq;
2411 if (c->transport.stream == NULL) {
2412 return NT_STATUS_OK;
2415 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2416 if (state == NULL) {
2417 return NT_STATUS_NO_MEMORY;
2420 state->status = status;
2422 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2423 if (subreq == NULL) {
2424 return NT_STATUS_NO_MEMORY;
2426 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2431 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2433 struct dcerpc_shutdown_pipe_state *state =
2434 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2435 struct dcecli_connection *c = state->c;
2436 NTSTATUS status = state->status;
2440 * here we ignore the return values...
2442 tstream_disconnect_recv(subreq, &error);
2443 TALLOC_FREE(subreq);
2447 dcerpc_transport_dead(c, status);
2452 struct dcerpc_send_read_state {
2453 struct dcecli_connection *p;
2456 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2458 struct dcecli_connection *p = state->p;
2460 p->transport.read_subreq = NULL;
2465 static void dcerpc_send_read_done(struct tevent_req *subreq);
2467 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2469 struct dcerpc_send_read_state *state;
2471 if (p->transport.read_subreq != NULL) {
2472 p->transport.pending_reads++;
2473 return NT_STATUS_OK;
2476 state = talloc_zero(p, struct dcerpc_send_read_state);
2477 if (state == NULL) {
2478 return NT_STATUS_NO_MEMORY;
2482 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2484 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2486 p->transport.stream);
2487 if (p->transport.read_subreq == NULL) {
2488 return NT_STATUS_NO_MEMORY;
2490 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2492 return NT_STATUS_OK;
2495 static void dcerpc_send_read_done(struct tevent_req *subreq)
2497 struct dcerpc_send_read_state *state =
2498 tevent_req_callback_data(subreq,
2499 struct dcerpc_send_read_state);
2500 struct dcecli_connection *p = state->p;
2502 struct ncacn_packet *pkt;
2505 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2507 TALLOC_FREE(subreq);
2508 if (!NT_STATUS_IS_OK(status)) {
2510 dcerpc_transport_dead(p, status);
2515 * here we steal into thet connection context,
2516 * but p->transport.recv_data() will steal or free it again
2518 talloc_steal(p, blob.data);
2521 if (p->transport.pending_reads > 0) {
2522 p->transport.pending_reads--;
2524 status = dcerpc_send_read(p);
2525 if (!NT_STATUS_IS_OK(status)) {
2526 dcerpc_transport_dead(p, status);
2531 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2534 struct dcerpc_send_request_state {
2535 struct dcecli_connection *p;
2540 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2542 struct dcecli_connection *p = state->p;
2544 p->transport.read_subreq = NULL;
2549 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2550 static void dcerpc_send_request_done(struct tevent_req *subreq);
2552 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2555 struct dcerpc_send_request_state *state;
2556 struct tevent_req *subreq;
2557 bool use_trans = trigger_read;
2559 if (p->transport.stream == NULL) {
2560 return NT_STATUS_CONNECTION_DISCONNECTED;
2563 state = talloc_zero(p, struct dcerpc_send_request_state);
2564 if (state == NULL) {
2565 return NT_STATUS_NO_MEMORY;
2569 state->blob = data_blob_talloc(state, data->data, data->length);
2570 if (state->blob.data == NULL) {
2572 return NT_STATUS_NO_MEMORY;
2574 state->iov.iov_base = (void *)state->blob.data;
2575 state->iov.iov_len = state->blob.length;
2577 if (p->transport.read_subreq != NULL) {
2581 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2587 * we need to block reads until our write is
2588 * the next in the write queue.
2590 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2591 p->transport.write_queue);
2592 if (p->transport.read_subreq == NULL) {
2594 return NT_STATUS_NO_MEMORY;
2596 tevent_req_set_callback(p->transport.read_subreq,
2597 dcerpc_send_request_wait_done,
2600 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2602 trigger_read = false;
2605 subreq = tstream_writev_queue_send(state, p->event_ctx,
2606 p->transport.stream,
2607 p->transport.write_queue,
2609 if (subreq == NULL) {
2611 return NT_STATUS_NO_MEMORY;
2613 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2616 dcerpc_send_read(p);
2619 return NT_STATUS_OK;
2622 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2624 struct dcerpc_send_request_state *state =
2625 tevent_req_callback_data(subreq,
2626 struct dcerpc_send_request_state);
2627 struct dcecli_connection *p = state->p;
2631 p->transport.read_subreq = NULL;
2632 talloc_set_destructor(state, NULL);
2634 ok = tevent_queue_wait_recv(subreq);
2637 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2641 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2642 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2643 if (!NT_STATUS_IS_OK(status)) {
2645 dcerpc_transport_dead(p, status);
2650 /* we free subreq after tstream_cli_np_use_trans */
2651 TALLOC_FREE(subreq);
2653 dcerpc_send_read(p);
2656 static void dcerpc_send_request_done(struct tevent_req *subreq)
2658 struct dcerpc_send_request_state *state =
2659 tevent_req_callback_data(subreq,
2660 struct dcerpc_send_request_state);
2664 ret = tstream_writev_queue_recv(subreq, &error);
2665 TALLOC_FREE(subreq);
2667 struct dcecli_connection *p = state->p;
2668 NTSTATUS status = map_nt_error_from_unix_common(error);
2671 dcerpc_transport_dead(p, status);