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;
66 bool request_data_allocated;
67 struct tevent_req *stub_subreq;
73 bool incomplete_request_data;
77 void (*callback)(struct rpc_request *);
82 _PUBLIC_ NTSTATUS dcerpc_init(void)
87 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
88 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
90 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
91 struct dcerpc_pipe *p,
92 const struct GUID *object,
94 DATA_BLOB *stub_data);
95 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
97 DATA_BLOB *stub_data);
98 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
102 ndr_push_flags_fn_t ndr_push,
103 ndr_pull_flags_fn_t ndr_pull);
104 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
105 struct ndr_pull *pull_in,
108 ndr_push_flags_fn_t ndr_push,
109 ndr_pull_flags_fn_t ndr_pull,
110 ndr_print_function_t ndr_print);
111 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
112 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
114 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
116 /* destroy a dcerpc connection */
117 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
120 conn->free_skipped = true;
123 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
128 /* initialise a dcerpc connection.
129 the event context is optional
131 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
132 struct tevent_context *ev)
134 struct dcecli_connection *c;
136 c = talloc_zero(mem_ctx, struct dcecli_connection);
143 if (c->event_ctx == NULL) {
149 c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
150 c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
151 c->security_state.auth_context_id = 0;
152 c->security_state.session_key = dcerpc_generic_session_key;
153 c->security_state.generic_state = NULL;
156 * Windows uses 5840 for ncacn_ip_tcp,
157 * so we also use it (for every transport)
158 * by default. But we give the transport
159 * the chance to overwrite it.
161 c->srv_max_xmit_frag = 5840;
162 c->srv_max_recv_frag = 5840;
163 c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
166 c->io_trigger = tevent_create_immediate(c);
167 if (c->io_trigger == NULL) {
172 talloc_set_destructor(c, dcerpc_connection_destructor);
177 struct dcerpc_bh_state {
178 struct dcerpc_pipe *p;
181 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
183 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
184 struct dcerpc_bh_state);
194 if (hs->p->conn->dead) {
201 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
204 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
205 struct dcerpc_bh_state);
209 return DCERPC_REQUEST_TIMEOUT;
212 old = hs->p->request_timeout;
213 hs->p->request_timeout = timeout;
218 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
219 enum dcerpc_AuthType *auth_type,
220 enum dcerpc_AuthLevel *auth_level)
222 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
223 struct dcerpc_bh_state);
229 if (hs->p->conn == NULL) {
233 *auth_type = hs->p->conn->security_state.auth_type;
234 *auth_level = hs->p->conn->security_state.auth_level;
237 struct dcerpc_bh_raw_call_state {
238 struct tevent_context *ev;
239 struct dcerpc_binding_handle *h;
244 struct rpc_request *subreq;
247 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
249 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
250 struct tevent_context *ev,
251 struct dcerpc_binding_handle *h,
252 const struct GUID *object,
255 const uint8_t *in_data,
258 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
259 struct dcerpc_bh_state);
260 struct tevent_req *req;
261 struct dcerpc_bh_raw_call_state *state;
264 req = tevent_req_create(mem_ctx, &state,
265 struct dcerpc_bh_raw_call_state);
271 state->in_flags = in_flags;
272 state->in_data.data = discard_const_p(uint8_t, in_data);
273 state->in_data.length = in_length;
275 ok = dcerpc_bh_is_connected(h);
277 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
278 return tevent_req_post(req, ev);
281 state->subreq = dcerpc_request_send(state,
286 if (tevent_req_nomem(state->subreq, req)) {
287 return tevent_req_post(req, ev);
289 state->subreq->async.callback = dcerpc_bh_raw_call_done;
290 state->subreq->async.private_data = req;
292 if (state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
293 state->subreq->incomplete_request_data = true;
299 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
301 struct tevent_req *req =
302 talloc_get_type_abort(subreq->async.private_data,
304 struct dcerpc_bh_raw_call_state *state =
306 struct dcerpc_bh_raw_call_state);
310 state->out_flags = 0;
311 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
312 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
315 if (subreq->state == RPC_REQUEST_PENDING) {
316 state->out_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
318 state->subreq = NULL;
319 state->out_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
322 fault_code = subreq->fault_code;
324 status = dcerpc_request_recv(subreq, state, &state->out_data);
325 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
326 status = dcerpc_fault_to_nt_status(fault_code);
330 * We trigger the callback in the next event run
331 * because the code in this file might trigger
332 * multiple request callbacks from within a single
335 * In order to avoid segfaults from within
336 * dcerpc_connection_dead() we call
337 * tevent_req_defer_callback().
339 tevent_req_defer_callback(req, state->ev);
341 if (!NT_STATUS_IS_OK(status)) {
342 tevent_req_nterror(req, status);
346 if (state->out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
347 tevent_req_notify_callback(req);
351 tevent_req_done(req);
354 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
360 struct dcerpc_bh_raw_call_state *state =
362 struct dcerpc_bh_raw_call_state);
365 if (tevent_req_is_nterror(req, &status)) {
366 tevent_req_received(req);
370 *out_data = talloc_move(mem_ctx, &state->out_data.data);
371 *out_length = state->out_data.length;
372 *out_flags = state->out_flags;
373 if (!(state->out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
374 tevent_req_received(req);
379 struct dcerpc_bh_raw_call_in_state {
383 static struct tevent_req *dcerpc_bh_raw_call_in_send(TALLOC_CTX *mem_ctx,
384 struct tevent_context *ev,
385 struct tevent_req *raw_call_req,
387 const uint8_t *in_data,
390 struct dcerpc_bh_raw_call_state *raw_call_state = NULL;
391 struct tevent_req *req;
392 struct dcerpc_bh_raw_call_in_state *state;
394 req = tevent_req_create(mem_ctx, &state,
395 struct dcerpc_bh_raw_call_in_state);
400 if (!tevent_req_is_in_progress(raw_call_req)) {
401 tevent_req_nterror(req, NT_STATUS_RPC_CALL_FAILED);
402 return tevent_req_post(req, ev);
405 raw_call_state = tevent_req_data(raw_call_req,
406 struct dcerpc_bh_raw_call_state);
409 struct rpc_request *subreq;
414 static NTSTATUS dcerpc_bh_raw_call_in__recv(struct tevent_req *req)
419 struct dcerpc_bh_disconnect_state {
423 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
424 struct tevent_context *ev,
425 struct dcerpc_binding_handle *h)
427 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
428 struct dcerpc_bh_state);
429 struct tevent_req *req;
430 struct dcerpc_bh_disconnect_state *state;
433 req = tevent_req_create(mem_ctx, &state,
434 struct dcerpc_bh_disconnect_state);
439 ok = dcerpc_bh_is_connected(h);
441 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
442 return tevent_req_post(req, ev);
445 /* TODO: do a real disconnect ... */
448 tevent_req_done(req);
449 return tevent_req_post(req, ev);
452 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
456 if (tevent_req_is_nterror(req, &status)) {
457 tevent_req_received(req);
461 tevent_req_received(req);
465 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
467 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
468 struct dcerpc_bh_state);
470 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
477 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
479 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
480 struct dcerpc_bh_state);
482 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
489 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
491 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
492 struct dcerpc_bh_state);
494 if (hs->p->conn->flags & DCERPC_NDR64) {
501 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
503 const void *_struct_ptr,
504 const struct ndr_interface_call *call)
506 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
507 struct dcerpc_bh_state);
508 void *struct_ptr = discard_const(_struct_ptr);
509 bool print_in = false;
510 bool print_out = false;
512 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
516 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
520 if (DEBUGLEVEL >= 11) {
525 if (ndr_flags & NDR_IN) {
527 ndr_print_function_debug(call->ndr_print,
533 if (ndr_flags & NDR_OUT) {
535 ndr_print_function_debug(call->ndr_print,
543 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
545 const void *struct_ptr,
546 const struct ndr_interface_call *call)
548 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
549 call->name, nt_errstr(error)));
552 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
554 const DATA_BLOB *blob,
555 const struct ndr_interface_call *call)
557 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
558 struct dcerpc_bh_state);
559 const uint32_t num_examples = 20;
562 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
563 call->name, nt_errstr(error)));
565 if (hs->p->conn->packet_log_dir == NULL) return;
567 for (i=0;i<num_examples;i++) {
571 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
572 hs->p->conn->packet_log_dir,
577 if (!file_exist(name)) {
578 if (file_save(name, blob->data, blob->length)) {
579 DEBUG(10,("Logged rpc packet to %s\n", name));
588 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
590 const DATA_BLOB *blob,
591 const struct ndr_interface_call *call)
593 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
594 struct dcerpc_bh_state);
596 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
599 status = dcerpc_ndr_validate_in(hs->p->conn,
605 if (!NT_STATUS_IS_OK(status)) {
606 DEBUG(0,("Validation [in] failed for %s - %s\n",
607 call->name, nt_errstr(status)));
612 DEBUG(10,("rpc request data:\n"));
613 dump_data(10, blob->data, blob->length);
618 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
619 struct ndr_pull *pull_in,
620 const void *_struct_ptr,
621 const struct ndr_interface_call *call)
623 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
624 struct dcerpc_bh_state);
625 void *struct_ptr = discard_const(_struct_ptr);
627 DEBUG(10,("rpc reply data:\n"));
628 dump_data(10, pull_in->data, pull_in->data_size);
630 if (pull_in->offset != pull_in->data_size) {
631 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
632 pull_in->data_size - pull_in->offset,
633 pull_in->offset, pull_in->offset,
635 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
636 but it turns out that early versions of NT
637 (specifically NT3.1) add junk onto the end of rpc
638 packets, so if we want to interoperate at all with
639 those versions then we need to ignore this error */
642 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
645 status = dcerpc_ndr_validate_out(hs->p->conn,
652 if (!NT_STATUS_IS_OK(status)) {
653 DEBUG(2,("Validation [out] failed for %s - %s\n",
654 call->name, nt_errstr(status)));
662 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
664 .is_connected = dcerpc_bh_is_connected,
665 .set_timeout = dcerpc_bh_set_timeout,
666 .auth_info = dcerpc_bh_auth_info,
667 .raw_call_send = dcerpc_bh_raw_call_send,
668 .raw_call_recv = dcerpc_bh_raw_call_recv,
669 .disconnect_send = dcerpc_bh_disconnect_send,
670 .disconnect_recv = dcerpc_bh_disconnect_recv,
672 .push_bigendian = dcerpc_bh_push_bigendian,
673 .ref_alloc = dcerpc_bh_ref_alloc,
674 .use_ndr64 = dcerpc_bh_use_ndr64,
675 .do_ndr_print = dcerpc_bh_do_ndr_print,
676 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
677 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
678 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
679 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
682 /* initialise a dcerpc pipe. */
683 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p,
684 const struct GUID *object,
685 const struct ndr_interface_table *table)
687 struct dcerpc_binding_handle *h;
688 struct dcerpc_bh_state *hs;
690 h = dcerpc_binding_handle_create(p,
695 struct dcerpc_bh_state,
702 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
707 /* initialise a dcerpc pipe. */
708 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
710 struct dcerpc_pipe *p;
712 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
717 p->conn = dcerpc_connection_init(p, ev);
718 if (p->conn == NULL) {
723 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
726 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
734 choose the next call id to use
736 static uint32_t next_call_id(struct dcecli_connection *c)
739 if (c->call_id == 0) {
746 setup for a ndr pull, also setting up any flags from the binding string
748 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
749 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
751 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
753 if (ndr == NULL) return ndr;
755 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
756 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
759 if (c->flags & DCERPC_NDR_REF_ALLOC) {
760 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
763 if (c->flags & DCERPC_NDR64) {
764 ndr->flags |= LIBNDR_FLAG_NDR64;
771 parse the authentication information on a dcerpc response packet
773 static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c,
775 enum dcerpc_pkt_type ptype,
776 uint8_t required_flags,
777 uint8_t optional_flags,
778 uint8_t payload_offset,
779 DATA_BLOB *payload_and_verifier,
780 DATA_BLOB *raw_packet,
781 const struct ncacn_packet *pkt)
783 const struct dcerpc_auth tmp_auth = {
784 .auth_type = c->security_state.auth_type,
785 .auth_level = c->security_state.auth_level,
786 .auth_context_id = c->security_state.auth_context_id,
790 status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
791 c->security_state.generic_state,
797 payload_and_verifier,
800 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
801 return NT_STATUS_INVALID_NETWORK_RESPONSE;
803 if (!NT_STATUS_IS_OK(status)) {
812 push a dcerpc request packet into a blob, possibly signing it.
814 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
815 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
817 struct ncacn_packet *pkt)
819 const struct dcerpc_auth tmp_auth = {
820 .auth_type = c->security_state.auth_type,
821 .auth_level = c->security_state.auth_level,
822 .auth_context_id = c->security_state.auth_context_id,
825 uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
827 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
828 payload_offset += 16;
831 status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
832 c->security_state.generic_state,
836 &pkt->u.request.stub_and_verifier,
838 if (!NT_STATUS_IS_OK(status)) {
847 fill in the fixed values in a dcerpc header
849 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
852 pkt->rpc_vers_minor = 0;
853 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
856 pkt->drep[0] = DCERPC_DREP_LE;
864 map a bind nak reason to a NTSTATUS
866 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
869 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
870 return NT_STATUS_REVISION_MISMATCH;
871 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
872 return NT_STATUS_INVALID_PARAMETER;
876 return NT_STATUS_UNSUCCESSFUL;
879 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
882 return NT_STATUS_RPC_PROTOCOL_ERROR;
885 switch (ack->result) {
886 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
888 * We have not asked for this...
890 return NT_STATUS_RPC_PROTOCOL_ERROR;
895 switch (ack->reason.value) {
896 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
897 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
898 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
899 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
903 return NT_STATUS_UNSUCCESSFUL;
907 remove requests from the pending or queued queues
909 static int dcerpc_req_dequeue(struct rpc_request *req)
911 switch (req->state) {
912 case RPC_REQUEST_QUEUED:
913 DLIST_REMOVE(req->p->conn->request_queue, req);
915 case RPC_REQUEST_PENDING:
916 DLIST_REMOVE(req->p->conn->pending, req);
918 case RPC_REQUEST_DONE:
926 mark the dcerpc connection dead. All outstanding requests get an error
928 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
930 if (conn->dead) return;
934 TALLOC_FREE(conn->io_trigger);
935 conn->io_trigger_pending = false;
937 dcerpc_shutdown_pipe(conn, status);
939 /* all pending requests get the error */
940 while (conn->pending) {
941 struct rpc_request *req = conn->pending;
942 dcerpc_req_dequeue(req);
943 req->state = RPC_REQUEST_DONE;
944 req->status = status;
945 if (req->async.callback) {
946 req->async.callback(req);
950 /* all requests, which are not shipped */
951 while (conn->request_queue) {
952 struct rpc_request *req = conn->request_queue;
953 dcerpc_req_dequeue(req);
954 req->state = RPC_REQUEST_DONE;
955 req->status = status;
956 if (req->async.callback) {
957 req->async.callback(req);
961 talloc_set_destructor(conn, NULL);
962 if (conn->free_skipped) {
968 forward declarations of the recv_data handlers for the types of
969 packets we need to handle
971 static void dcerpc_request_recv_data(struct dcecli_connection *c,
972 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
975 receive a dcerpc reply from the transport. Here we work out what
976 type of reply it is (normal request, bind or alter context) and
977 dispatch to the appropriate handler
979 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
981 struct ncacn_packet pkt;
987 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
988 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
991 /* the transport may be telling us of a severe error, such as
993 if (!NT_STATUS_IS_OK(status)) {
994 data_blob_free(blob);
995 dcerpc_connection_dead(conn, status);
999 /* parse the basic packet to work out what type of response this is */
1000 status = dcerpc_pull_ncacn_packet(blob->data, blob, &pkt);
1001 if (!NT_STATUS_IS_OK(status)) {
1002 data_blob_free(blob);
1003 dcerpc_connection_dead(conn, status);
1007 dcerpc_request_recv_data(conn, blob, &pkt);
1011 handle timeouts of individual dcerpc requests
1013 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1014 struct timeval t, void *private_data)
1016 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1018 if (req->ignore_timeout) {
1019 dcerpc_req_dequeue(req);
1020 req->state = RPC_REQUEST_DONE;
1021 req->status = NT_STATUS_IO_TIMEOUT;
1022 if (req->async.callback) {
1023 req->async.callback(req);
1028 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1031 struct dcerpc_bind_state {
1032 struct tevent_context *ev;
1033 struct dcerpc_pipe *p;
1036 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1037 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1038 DATA_BLOB *raw_packet,
1039 struct ncacn_packet *pkt);
1041 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1042 struct tevent_context *ev,
1043 struct dcerpc_pipe *p,
1044 const struct ndr_syntax_id *syntax,
1045 const struct ndr_syntax_id *transfer_syntax)
1047 struct tevent_req *req;
1048 struct dcerpc_bind_state *state;
1049 struct ncacn_packet pkt;
1052 struct rpc_request *subreq;
1054 struct ndr_syntax_id bind_time_features;
1056 bind_time_features = dcerpc_construct_bind_time_features(
1057 DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
1058 DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
1060 req = tevent_req_create(mem_ctx, &state,
1061 struct dcerpc_bind_state);
1069 p->syntax = *syntax;
1070 p->transfer_syntax = *transfer_syntax;
1072 flags = dcerpc_binding_get_flags(p->binding);
1074 init_ncacn_hdr(p->conn, &pkt);
1076 pkt.ptype = DCERPC_PKT_BIND;
1077 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1078 pkt.call_id = p->conn->call_id;
1079 pkt.auth_length = 0;
1081 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1082 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1085 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1086 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1089 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1090 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1091 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1092 pkt.u.bind.num_contexts = 2;
1093 pkt.u.bind.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
1094 pkt.u.bind.num_contexts);
1095 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1096 return tevent_req_post(req, ev);
1098 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1099 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1100 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1101 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1102 pkt.u.bind.ctx_list[1].context_id = p->context_id + 1;
1103 pkt.u.bind.ctx_list[1].num_transfer_syntaxes = 1;
1104 pkt.u.bind.ctx_list[1].abstract_syntax = p->syntax;
1105 pkt.u.bind.ctx_list[1].transfer_syntaxes = &bind_time_features;
1106 pkt.u.bind.auth_info = data_blob(NULL, 0);
1108 /* construct the NDR form of the packet */
1109 status = ncacn_push_auth(&blob, state, &pkt,
1110 p->conn->security_state.tmp_auth_info.out);
1111 if (tevent_req_nterror(req, status)) {
1112 return tevent_req_post(req, ev);
1116 * we allocate a dcerpc_request so we can be in the same
1117 * request queue as normal requests
1119 subreq = talloc_zero(state, struct rpc_request);
1120 if (tevent_req_nomem(subreq, req)) {
1121 return tevent_req_post(req, ev);
1124 subreq->state = RPC_REQUEST_PENDING;
1125 subreq->call_id = pkt.call_id;
1126 subreq->async.private_data = req;
1127 subreq->async.callback = dcerpc_bind_fail_handler;
1129 subreq->recv_handler = dcerpc_bind_recv_handler;
1130 DLIST_ADD_END(p->conn->pending, subreq);
1131 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1133 status = dcerpc_send_request(p->conn, &blob, true);
1134 if (tevent_req_nterror(req, status)) {
1135 return tevent_req_post(req, ev);
1138 tevent_add_timer(ev, subreq,
1139 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1140 dcerpc_timeout_handler, subreq);
1145 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1147 struct tevent_req *req =
1148 talloc_get_type_abort(subreq->async.private_data,
1150 struct dcerpc_bind_state *state =
1151 tevent_req_data(req,
1152 struct dcerpc_bind_state);
1153 NTSTATUS status = subreq->status;
1155 TALLOC_FREE(subreq);
1158 * We trigger the callback in the next event run
1159 * because the code in this file might trigger
1160 * multiple request callbacks from within a single
1163 * In order to avoid segfaults from within
1164 * dcerpc_connection_dead() we call
1165 * tevent_req_defer_callback().
1167 tevent_req_defer_callback(req, state->ev);
1169 tevent_req_nterror(req, status);
1172 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1173 DATA_BLOB *raw_packet,
1174 struct ncacn_packet *pkt)
1176 struct tevent_req *req =
1177 talloc_get_type_abort(subreq->async.private_data,
1179 struct dcerpc_bind_state *state =
1180 tevent_req_data(req,
1181 struct dcerpc_bind_state);
1182 struct dcecli_connection *conn = state->p->conn;
1183 struct dcecli_security *sec = &conn->security_state;
1184 struct dcerpc_binding *b = NULL;
1189 * Note that pkt is allocated under raw_packet->data,
1190 * while raw_packet->data is a child of subreq.
1192 talloc_steal(state, raw_packet->data);
1193 TALLOC_FREE(subreq);
1196 * We trigger the callback in the next event run
1197 * because the code in this file might trigger
1198 * multiple request callbacks from within a single
1201 * In order to avoid segfaults from within
1202 * dcerpc_connection_dead() we call
1203 * tevent_req_defer_callback().
1205 tevent_req_defer_callback(req, state->ev);
1207 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1208 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1210 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1211 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1213 tevent_req_nterror(req, status);
1217 status = dcerpc_verify_ncacn_packet_header(pkt,
1218 DCERPC_PKT_BIND_ACK,
1219 pkt->u.bind_ack.auth_info.length,
1220 DCERPC_PFC_FLAG_FIRST |
1221 DCERPC_PFC_FLAG_LAST,
1222 DCERPC_PFC_FLAG_CONC_MPX |
1223 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1224 if (!NT_STATUS_IS_OK(status)) {
1225 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1226 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1230 if (pkt->u.bind_ack.num_results < 1) {
1231 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1232 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1236 if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1237 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1238 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1239 pkt->u.bind_ack.ctx_list[0].reason.value,
1240 nt_errstr(status)));
1241 tevent_req_nterror(req, status);
1245 if (pkt->u.bind_ack.num_results >= 2) {
1246 if (pkt->u.bind_ack.ctx_list[1].result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1247 conn->bind_time_features = pkt->u.bind_ack.ctx_list[1].reason.negotiate;
1249 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[1]);
1250 DEBUG(10,("dcerpc: bind_time_feature failed - reason %d - %s\n",
1251 pkt->u.bind_ack.ctx_list[1].reason.value,
1252 nt_errstr(status)));
1253 status = NT_STATUS_OK;
1258 * DCE-RPC 1.1 (c706) specifies
1259 * CONST_MUST_RCV_FRAG_SIZE as 1432
1261 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1262 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1263 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1266 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1267 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1268 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1271 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1272 pkt->u.bind_ack.max_xmit_frag);
1273 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1274 pkt->u.bind_ack.max_recv_frag);
1276 flags = dcerpc_binding_get_flags(state->p->binding);
1278 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1279 if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1280 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1282 conn->flags &= ~DCERPC_CONCURRENT_MULTIPLEX;
1286 if (!(conn->flags & DCERPC_CONCURRENT_MULTIPLEX)) {
1287 struct dcerpc_binding *pb =
1288 discard_const_p(struct dcerpc_binding, state->p->binding);
1290 * clear DCERPC_CONCURRENT_MULTIPLEX
1292 status = dcerpc_binding_set_flags(pb, 0,
1293 DCERPC_CONCURRENT_MULTIPLEX);
1294 if (tevent_req_nterror(req, status)) {
1298 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1299 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1300 conn->flags |= DCERPC_HEADER_SIGNING;
1303 /* the bind_ack might contain a reply set of credentials */
1304 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1305 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1306 &pkt->u.bind_ack.auth_info,
1307 sec->tmp_auth_info.in,
1309 if (tevent_req_nterror(req, status)) {
1315 * We're the owner of the binding, so we're allowed to modify it.
1317 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1318 status = dcerpc_binding_set_assoc_group_id(b,
1319 pkt->u.bind_ack.assoc_group_id);
1320 if (tevent_req_nterror(req, status)) {
1324 tevent_req_done(req);
1327 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1329 return tevent_req_simple_recv_ntstatus(req);
1333 perform a continued bind (and auth3)
1335 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1336 TALLOC_CTX *mem_ctx)
1338 struct ncacn_packet pkt;
1343 flags = dcerpc_binding_get_flags(p->binding);
1345 init_ncacn_hdr(p->conn, &pkt);
1347 pkt.ptype = DCERPC_PKT_AUTH3;
1348 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1349 pkt.call_id = next_call_id(p->conn);
1350 pkt.auth_length = 0;
1351 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1353 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1354 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1357 /* construct the NDR form of the packet */
1358 status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1359 p->conn->security_state.tmp_auth_info.out);
1360 if (!NT_STATUS_IS_OK(status)) {
1364 /* send it on its way */
1365 status = dcerpc_send_request(p->conn, &blob, false);
1366 if (!NT_STATUS_IS_OK(status)) {
1370 return NT_STATUS_OK;
1375 process a fragment received from the transport layer during a
1378 This function frees the data
1380 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1381 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1383 struct rpc_request *req;
1384 unsigned int length;
1385 NTSTATUS status = NT_STATUS_OK;
1388 if this is an authenticated connection then parse and check
1389 the auth info. We have to do this before finding the
1390 matching packet, as the request structure might have been
1391 removed due to a timeout, but if it has been we still need
1392 to run the auth routines so that we don't get the sign/seal
1393 info out of step with the server
1395 switch (pkt->ptype) {
1396 case DCERPC_PKT_RESPONSE:
1397 status = ncacn_pull_pkt_auth(c, raw_packet->data,
1398 DCERPC_PKT_RESPONSE,
1399 0, /* required_flags */
1400 DCERPC_PFC_FLAG_FIRST |
1401 DCERPC_PFC_FLAG_LAST,
1402 DCERPC_REQUEST_LENGTH,
1403 &pkt->u.response.stub_and_verifier,
1410 /* find the matching request */
1411 for (req=c->pending;req;req=req->next) {
1412 if (pkt->call_id == req->call_id) break;
1416 /* useful for testing certain vendors RPC servers */
1417 if (req == NULL && c->pending && pkt->call_id == 0) {
1418 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1424 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1425 data_blob_free(raw_packet);
1429 talloc_steal(req, raw_packet->data);
1431 if (req->recv_handler != NULL) {
1432 dcerpc_req_dequeue(req);
1433 req->state = RPC_REQUEST_DONE;
1436 * We have to look at shipping further requests before calling
1437 * the async function, that one might close the pipe
1439 dcerpc_schedule_io_trigger(c);
1441 req->recv_handler(req, raw_packet, pkt);
1445 if (pkt->ptype == DCERPC_PKT_FAULT) {
1446 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1447 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1448 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
1449 dcerpc_connection_dead(c, status);
1452 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1453 dcerpc_connection_dead(c, status);
1456 req->fault_code = pkt->u.fault.status;
1457 req->status = NT_STATUS_NET_WRITE_FAULT;
1461 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1462 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1464 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1468 /* now check the status from the auth routines, and if it failed then fail
1469 this request accordingly */
1470 if (!NT_STATUS_IS_OK(status)) {
1471 dcerpc_connection_dead(c, status);
1475 if (req->state != RPC_REQUEST_PENDING) {
1476 req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
1480 if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1481 if (req->first_pdu_done) {
1482 req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
1485 req->first_pdu_done = true;
1487 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1488 req->flags |= DCERPC_PULL_BIGENDIAN;
1490 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1494 if (!req->first_pdu_done) {
1495 req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
1499 length = pkt->u.response.stub_and_verifier.length;
1501 if (req->payload.length + length > c->max_total_response_size) {
1502 DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
1503 (unsigned)req->payload.length + length,
1504 (unsigned)c->max_total_response_size));
1505 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1510 req->payload.data = talloc_realloc(req,
1513 req->payload.length + length);
1514 if (!req->payload.data) {
1515 req->status = NT_STATUS_NO_MEMORY;
1518 memcpy(req->payload.data+req->payload.length,
1519 pkt->u.response.stub_and_verifier.data, length);
1520 req->payload.length += length;
1523 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1524 data_blob_free(raw_packet);
1526 req->status = dcerpc_send_read(c);
1527 if (!NT_STATUS_IS_OK(req->status)) {
1531 if (!req->incomplete_request_data) {
1535 if (req->async.callback) {
1536 req->async.callback(req);
1541 if (req->verify_bitmask1) {
1542 req->p->conn->security_state.verified_bitmask1 = true;
1544 if (req->verify_pcontext) {
1545 req->p->verified_pcontext = true;
1548 req->incomplete_request_data = false;
1551 data_blob_free(raw_packet);
1553 /* we've got the full payload */
1554 dcerpc_req_dequeue(req);
1555 req->state = RPC_REQUEST_DONE;
1558 * We have to look at shipping further requests before calling
1559 * the async function, that one might close the pipe
1561 dcerpc_schedule_io_trigger(c);
1563 if (req->async.callback) {
1564 req->async.callback(req);
1568 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1571 perform the send side of a async dcerpc request
1573 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1574 struct dcerpc_pipe *p,
1575 const struct GUID *object,
1577 DATA_BLOB *stub_data)
1579 struct rpc_request *req;
1582 req = talloc_zero(mem_ctx, struct rpc_request);
1588 req->call_id = next_call_id(p->conn);
1589 req->state = RPC_REQUEST_QUEUED;
1591 if (object != NULL) {
1592 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1593 if (req->object == NULL) {
1600 req->request_data.length = stub_data->length;
1601 req->request_data.data = stub_data->data;
1603 status = dcerpc_request_prepare_vt(req);
1604 if (!NT_STATUS_IS_OK(status)) {
1609 DLIST_ADD_END(p->conn->request_queue, req);
1610 talloc_set_destructor(req, dcerpc_req_dequeue);
1612 dcerpc_schedule_io_trigger(p->conn);
1614 if (p->request_timeout) {
1615 tevent_add_timer(p->conn->event_ctx, req,
1616 timeval_current_ofs(p->request_timeout, 0),
1617 dcerpc_timeout_handler, req);
1623 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1625 struct dcecli_security *sec = &req->p->conn->security_state;
1626 struct dcerpc_sec_verification_trailer *t;
1627 struct dcerpc_sec_vt *c = NULL;
1628 struct ndr_push *ndr = NULL;
1629 enum ndr_err_code ndr_err;
1631 if (sec->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1632 return NT_STATUS_OK;
1635 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1637 return NT_STATUS_NO_MEMORY;
1640 if (!sec->verified_bitmask1) {
1641 t->commands = talloc_realloc(t, t->commands,
1642 struct dcerpc_sec_vt,
1643 t->count.count + 1);
1644 if (t->commands == NULL) {
1645 return NT_STATUS_NO_MEMORY;
1647 c = &t->commands[t->count.count++];
1650 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1651 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1652 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1654 req->verify_bitmask1 = true;
1657 if (!req->p->verified_pcontext) {
1658 t->commands = talloc_realloc(t, t->commands,
1659 struct dcerpc_sec_vt,
1660 t->count.count + 1);
1661 if (t->commands == NULL) {
1662 return NT_STATUS_NO_MEMORY;
1664 c = &t->commands[t->count.count++];
1667 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1668 c->u.pcontext.abstract_syntax = req->p->syntax;
1669 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1671 req->verify_pcontext = true;
1674 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1675 t->commands = talloc_realloc(t, t->commands,
1676 struct dcerpc_sec_vt,
1677 t->count.count + 1);
1678 if (t->commands == NULL) {
1679 return NT_STATUS_NO_MEMORY;
1681 c = &t->commands[t->count.count++];
1684 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1685 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1686 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1687 c->u.header2.drep[0] = 0;
1689 c->u.header2.drep[0] = DCERPC_DREP_LE;
1691 c->u.header2.drep[1] = 0;
1692 c->u.header2.drep[2] = 0;
1693 c->u.header2.drep[3] = 0;
1694 c->u.header2.call_id = req->call_id;
1695 c->u.header2.context_id = req->p->context_id;
1696 c->u.header2.opnum = req->opnum;
1699 if (t->count.count == 0) {
1701 return NT_STATUS_OK;
1704 c = &t->commands[t->count.count - 1];
1705 c->command |= DCERPC_SEC_VT_COMMAND_END;
1707 if (DEBUGLEVEL >= 10) {
1708 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1711 ndr = ndr_push_init_ctx(req);
1713 return NT_STATUS_NO_MEMORY;
1717 * for now we just copy and append
1720 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1721 req->request_data.length);
1722 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1723 return ndr_map_error2ntstatus(ndr_err);
1726 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1727 NDR_SCALARS | NDR_BUFFERS,
1729 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1730 return ndr_map_error2ntstatus(ndr_err);
1732 req->request_data = ndr_push_blob(ndr);
1734 return NT_STATUS_OK;
1738 Send a request using the transport
1741 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1743 struct rpc_request *req;
1744 struct dcerpc_pipe *p;
1745 DATA_BLOB *stub_data;
1746 struct ncacn_packet pkt;
1748 uint32_t remaining, chunk_size;
1749 size_t sig_size = 0;
1750 bool need_async = false;
1751 bool can_async = true;
1753 req = c->request_queue;
1759 stub_data = &req->request_data;
1765 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1766 can_async = gensec_have_feature(c->security_state.generic_state,
1767 GENSEC_FEATURE_ASYNC_REPLIES);
1770 if (need_async && !can_async) {
1771 req->wait_for_sync = true;
1775 init_ncacn_hdr(p->conn, &pkt);
1777 remaining = stub_data->length;
1779 /* we can write a full max_recv_frag size, minus the dcerpc
1780 request header size */
1781 chunk_size = p->conn->srv_max_recv_frag;
1782 chunk_size -= DCERPC_REQUEST_LENGTH;
1783 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1784 size_t max_payload = chunk_size;
1786 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1787 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1789 sig_size = gensec_sig_size(c->security_state.generic_state,
1792 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1793 chunk_size -= sig_size;
1796 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1798 pkt.ptype = DCERPC_PKT_REQUEST;
1799 pkt.call_id = req->call_id;
1800 pkt.auth_length = 0;
1802 pkt.u.request.context_id = p->context_id;
1803 pkt.u.request.opnum = req->opnum;
1806 pkt.u.request.object.object = *req->object;
1807 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1808 chunk_size -= ndr_size_GUID(req->object,0);
1811 /* we send a series of pdus without waiting for a reply */
1812 while (remaining > 0 || !req->first_pdu_done) {
1813 uint32_t chunk = MIN(chunk_size, remaining);
1814 bool last_frag = false;
1815 bool do_trans = false;
1817 if ((chunk == remaining) && !req->incomplete_request_data) {
1821 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1823 if (!req->first_pdu_done) {
1824 req->first_pdu_done = true;
1825 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1828 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1831 pkt.u.request.alloc_hint = remaining;
1832 pkt.u.request.stub_and_verifier.data = stub_data->data +
1833 (stub_data->length - remaining);
1834 pkt.u.request.stub_and_verifier.length = chunk;
1836 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1837 if (!NT_STATUS_IS_OK(req->status)) {
1838 req->state = RPC_REQUEST_DONE;
1839 DLIST_REMOVE(c->request_queue, req);
1843 if (last_frag && !need_async) {
1847 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1848 if (!NT_STATUS_IS_OK(req->status)) {
1849 req->state = RPC_REQUEST_DONE;
1850 DLIST_REMOVE(c->request_queue, req);
1854 if (last_frag && !do_trans) {
1855 req->status = dcerpc_send_read(p->conn);
1856 if (!NT_STATUS_IS_OK(req->status)) {
1857 req->state = RPC_REQUEST_DONE;
1858 DLIST_REMOVE(c->request_queue, req);
1867 if (req->request_data_allocated) {
1868 data_blob_free(&req->request_data);
1870 req->request_data_allocated = false;
1871 req->request_data = data_blob_null;
1873 if (!req->incomplete_request_data) {
1874 DLIST_REMOVE(c->request_queue, req);
1875 DLIST_ADD(c->pending, req);
1876 req->state = RPC_REQUEST_PENDING;
1878 * we reuse first_pdu_done for the receive side
1880 req->first_pdu_done = false;
1883 if (req->stub_subreq == NULL) {
1887 tevent_req_done(req->stub_subreq);
1893 static void dcerpc_io_trigger(struct tevent_context *ctx,
1894 struct tevent_immediate *im,
1897 struct dcecli_connection *c =
1898 talloc_get_type_abort(private_data,
1899 struct dcecli_connection);
1901 c->io_trigger_pending = false;
1903 dcerpc_schedule_io_trigger(c);
1905 dcerpc_ship_next_request(c);
1908 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1914 if (c->request_queue == NULL) {
1918 if (c->request_queue->wait_for_sync && c->pending) {
1922 if (c->io_trigger_pending) {
1926 c->io_trigger_pending = true;
1928 tevent_schedule_immediate(c->io_trigger,
1935 perform the receive side of a async dcerpc request
1937 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1938 TALLOC_CTX *mem_ctx,
1939 DATA_BLOB *stub_data)
1943 *stub_data = req->payload;
1944 req->payload = data_blob_null;
1945 status = req->status;
1946 if (stub_data->data) {
1947 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1949 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1950 req->p->last_fault_code = req->fault_code;
1952 if (req->state == RPC_REQUEST_PENDING) {
1953 if (NT_STATUS_IS_OK(status)) {
1957 talloc_unlink(talloc_parent(req), req);
1962 this is a paranoid NDR validator. For every packet we push onto the wire
1963 we pull it back again, then push it again. Then we compare the raw NDR data
1964 for that to the NDR we initially generated. If they don't match then we know
1965 we must have a bug in either the pull or push side of our code
1967 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1968 TALLOC_CTX *mem_ctx,
1971 ndr_push_flags_fn_t ndr_push,
1972 ndr_pull_flags_fn_t ndr_pull)
1975 struct ndr_pull *pull;
1976 struct ndr_push *push;
1978 enum ndr_err_code ndr_err;
1980 st = talloc_size(mem_ctx, struct_size);
1982 return NT_STATUS_NO_MEMORY;
1985 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1987 return NT_STATUS_NO_MEMORY;
1989 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1991 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1992 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1995 if (c->flags & DCERPC_NDR64) {
1996 pull->flags |= LIBNDR_FLAG_NDR64;
1999 ndr_err = ndr_pull(pull, NDR_IN, st);
2000 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2001 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2002 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2003 "failed input validation pull - %s",
2005 return ndr_map_error2ntstatus(ndr_err);
2008 push = ndr_push_init_ctx(mem_ctx);
2010 return NT_STATUS_NO_MEMORY;
2013 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2014 push->flags |= LIBNDR_FLAG_BIGENDIAN;
2017 if (c->flags & DCERPC_NDR64) {
2018 push->flags |= LIBNDR_FLAG_NDR64;
2021 ndr_err = ndr_push(push, NDR_IN, st);
2022 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2023 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2024 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2025 "failed input validation push - %s",
2027 return ndr_map_error2ntstatus(ndr_err);
2030 blob2 = ndr_push_blob(push);
2032 if (data_blob_cmp(&blob, &blob2) != 0) {
2033 DEBUG(3,("original:\n"));
2034 dump_data(3, blob.data, blob.length);
2035 DEBUG(3,("secondary:\n"));
2036 dump_data(3, blob2.data, blob2.length);
2037 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2038 "failed input validation blobs doesn't match");
2039 return ndr_map_error2ntstatus(ndr_err);
2042 return NT_STATUS_OK;
2046 this is a paranoid NDR input validator. For every packet we pull
2047 from the wire we push it back again then pull and push it
2048 again. Then we compare the raw NDR data for that to the NDR we
2049 initially generated. If they don't match then we know we must have a
2050 bug in either the pull or push side of our code
2052 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
2053 struct ndr_pull *pull_in,
2056 ndr_push_flags_fn_t ndr_push,
2057 ndr_pull_flags_fn_t ndr_pull,
2058 ndr_print_function_t ndr_print)
2061 struct ndr_pull *pull;
2062 struct ndr_push *push;
2063 DATA_BLOB blob, blob2;
2064 TALLOC_CTX *mem_ctx = pull_in;
2066 enum ndr_err_code ndr_err;
2068 st = talloc_size(mem_ctx, struct_size);
2070 return NT_STATUS_NO_MEMORY;
2072 memcpy(st, struct_ptr, struct_size);
2074 push = ndr_push_init_ctx(mem_ctx);
2076 return NT_STATUS_NO_MEMORY;
2079 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2080 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2081 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2082 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2083 "failed output validation push - %s",
2085 return ndr_map_error2ntstatus(ndr_err);
2088 blob = ndr_push_blob(push);
2090 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2092 return NT_STATUS_NO_MEMORY;
2095 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2096 ndr_err = ndr_pull(pull, NDR_OUT, st);
2097 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2098 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2099 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2100 "failed output validation pull - %s",
2102 return ndr_map_error2ntstatus(ndr_err);
2105 push = ndr_push_init_ctx(mem_ctx);
2107 return NT_STATUS_NO_MEMORY;
2110 ndr_err = ndr_push(push, NDR_OUT, st);
2111 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2112 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2113 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2114 "failed output validation push2 - %s",
2116 return ndr_map_error2ntstatus(ndr_err);
2119 blob2 = ndr_push_blob(push);
2121 if (data_blob_cmp(&blob, &blob2) != 0) {
2122 DEBUG(3,("original:\n"));
2123 dump_data(3, blob.data, blob.length);
2124 DEBUG(3,("secondary:\n"));
2125 dump_data(3, blob2.data, blob2.length);
2126 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2127 "failed output validation blobs doesn't match");
2128 return ndr_map_error2ntstatus(ndr_err);
2131 /* this checks the printed forms of the two structures, which effectively
2132 tests all of the value() attributes */
2133 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2134 NDR_OUT, struct_ptr);
2135 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2137 if (strcmp(s1, s2) != 0) {
2139 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2141 /* this is sometimes useful */
2142 printf("VALIDATE ERROR\n");
2143 file_save("wire.dat", s1, strlen(s1));
2144 file_save("gen.dat", s2, strlen(s2));
2145 system("diff -u wire.dat gen.dat");
2147 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2148 "failed output validation strings doesn't match");
2149 return ndr_map_error2ntstatus(ndr_err);
2152 return NT_STATUS_OK;
2156 a useful function for retrieving the server name we connected to
2158 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2160 return p->conn ? p->conn->server_name : NULL;
2165 get the dcerpc auth_level for a open connection
2167 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2171 if (c->flags & DCERPC_SEAL) {
2172 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2173 } else if (c->flags & DCERPC_SIGN) {
2174 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2175 } else if (c->flags & DCERPC_PACKET) {
2176 auth_level = DCERPC_AUTH_LEVEL_PACKET;
2177 } else if (c->flags & DCERPC_CONNECT) {
2178 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2180 auth_level = DCERPC_AUTH_LEVEL_NONE;
2185 struct dcerpc_alter_context_state {
2186 struct tevent_context *ev;
2187 struct dcerpc_pipe *p;
2190 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2191 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2192 DATA_BLOB *raw_packet,
2193 struct ncacn_packet *pkt);
2195 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2196 struct tevent_context *ev,
2197 struct dcerpc_pipe *p,
2198 const struct ndr_syntax_id *syntax,
2199 const struct ndr_syntax_id *transfer_syntax)
2201 struct tevent_req *req;
2202 struct dcerpc_alter_context_state *state;
2203 struct ncacn_packet pkt;
2206 struct rpc_request *subreq;
2209 req = tevent_req_create(mem_ctx, &state,
2210 struct dcerpc_alter_context_state);
2218 p->syntax = *syntax;
2219 p->transfer_syntax = *transfer_syntax;
2221 flags = dcerpc_binding_get_flags(p->binding);
2223 init_ncacn_hdr(p->conn, &pkt);
2225 pkt.ptype = DCERPC_PKT_ALTER;
2226 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2227 pkt.call_id = p->conn->call_id;
2228 pkt.auth_length = 0;
2230 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2231 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2234 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2235 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2236 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2237 pkt.u.alter.num_contexts = 1;
2238 pkt.u.alter.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
2239 pkt.u.alter.num_contexts);
2240 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2241 return tevent_req_post(req, ev);
2243 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2244 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2245 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2246 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2247 pkt.u.alter.auth_info = data_blob(NULL, 0);
2249 /* construct the NDR form of the packet */
2250 status = ncacn_push_auth(&blob, state, &pkt,
2251 p->conn->security_state.tmp_auth_info.out);
2252 if (tevent_req_nterror(req, status)) {
2253 return tevent_req_post(req, ev);
2257 * we allocate a dcerpc_request so we can be in the same
2258 * request queue as normal requests
2260 subreq = talloc_zero(state, struct rpc_request);
2261 if (tevent_req_nomem(subreq, req)) {
2262 return tevent_req_post(req, ev);
2265 subreq->state = RPC_REQUEST_PENDING;
2266 subreq->call_id = pkt.call_id;
2267 subreq->async.private_data = req;
2268 subreq->async.callback = dcerpc_alter_context_fail_handler;
2270 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2271 DLIST_ADD_END(p->conn->pending, subreq);
2272 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2274 status = dcerpc_send_request(p->conn, &blob, true);
2275 if (tevent_req_nterror(req, status)) {
2276 return tevent_req_post(req, ev);
2279 tevent_add_timer(ev, subreq,
2280 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2281 dcerpc_timeout_handler, subreq);
2286 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2288 struct tevent_req *req =
2289 talloc_get_type_abort(subreq->async.private_data,
2291 struct dcerpc_alter_context_state *state =
2292 tevent_req_data(req,
2293 struct dcerpc_alter_context_state);
2294 NTSTATUS status = subreq->status;
2296 TALLOC_FREE(subreq);
2299 * We trigger the callback in the next event run
2300 * because the code in this file might trigger
2301 * multiple request callbacks from within a single
2304 * In order to avoid segfaults from within
2305 * dcerpc_connection_dead() we call
2306 * tevent_req_defer_callback().
2308 tevent_req_defer_callback(req, state->ev);
2310 tevent_req_nterror(req, status);
2313 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2314 DATA_BLOB *raw_packet,
2315 struct ncacn_packet *pkt)
2317 struct tevent_req *req =
2318 talloc_get_type_abort(subreq->async.private_data,
2320 struct dcerpc_alter_context_state *state =
2321 tevent_req_data(req,
2322 struct dcerpc_alter_context_state);
2323 struct dcecli_connection *conn = state->p->conn;
2324 struct dcecli_security *sec = &conn->security_state;
2328 * Note that pkt is allocated under raw_packet->data,
2329 * while raw_packet->data is a child of subreq.
2331 talloc_steal(state, raw_packet->data);
2332 TALLOC_FREE(subreq);
2335 * We trigger the callback in the next event run
2336 * because the code in this file might trigger
2337 * multiple request callbacks from within a single
2340 * In order to avoid segfaults from within
2341 * dcerpc_connection_dead() we call
2342 * tevent_req_defer_callback().
2344 tevent_req_defer_callback(req, state->ev);
2346 if (pkt->ptype == DCERPC_PKT_FAULT) {
2347 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2348 dcerpc_errstr(state, pkt->u.fault.status)));
2349 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2350 state->p->last_fault_code = pkt->u.fault.status;
2351 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2352 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2353 state->p->last_fault_code = pkt->u.fault.status;
2354 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2356 state->p->last_fault_code = pkt->u.fault.status;
2357 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2358 tevent_req_nterror(req, status);
2363 status = dcerpc_verify_ncacn_packet_header(pkt,
2364 DCERPC_PKT_ALTER_RESP,
2365 pkt->u.alter_resp.auth_info.length,
2366 DCERPC_PFC_FLAG_FIRST |
2367 DCERPC_PFC_FLAG_LAST,
2368 DCERPC_PFC_FLAG_CONC_MPX |
2369 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2370 if (!NT_STATUS_IS_OK(status)) {
2371 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2372 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2376 if (pkt->u.alter_resp.num_results != 1) {
2377 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2378 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2382 if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2383 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2384 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2385 pkt->u.alter_resp.ctx_list[0].reason.value,
2386 nt_errstr(status)));
2387 tevent_req_nterror(req, status);
2391 /* the alter_resp might contain a reply set of credentials */
2392 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2393 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2394 &pkt->u.alter_resp.auth_info,
2395 sec->tmp_auth_info.in,
2397 if (tevent_req_nterror(req, status)) {
2402 tevent_req_done(req);
2405 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2407 return tevent_req_simple_recv_ntstatus(req);
2411 send a dcerpc alter_context request
2413 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2414 TALLOC_CTX *mem_ctx,
2415 const struct ndr_syntax_id *syntax,
2416 const struct ndr_syntax_id *transfer_syntax)
2418 struct tevent_req *subreq;
2419 struct tevent_context *ev = p->conn->event_ctx;
2422 /* TODO: create a new event context here */
2424 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2425 p, syntax, transfer_syntax);
2426 if (subreq == NULL) {
2427 return NT_STATUS_NO_MEMORY;
2430 ok = tevent_req_poll(subreq, ev);
2433 status = map_nt_error_from_unix_common(errno);
2437 return dcerpc_alter_context_recv(subreq);
2440 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2442 if (c->transport.stream == NULL) {
2446 tevent_queue_stop(c->transport.write_queue);
2447 TALLOC_FREE(c->transport.read_subreq);
2448 TALLOC_FREE(c->transport.stream);
2450 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2451 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2454 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2455 status = NT_STATUS_END_OF_FILE;
2458 dcerpc_recv_data(c, NULL, status);
2463 shutdown SMB pipe connection
2465 struct dcerpc_shutdown_pipe_state {
2466 struct dcecli_connection *c;
2470 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2472 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2474 struct dcerpc_shutdown_pipe_state *state;
2475 struct tevent_req *subreq;
2477 if (c->transport.stream == NULL) {
2478 return NT_STATUS_OK;
2481 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2482 if (state == NULL) {
2483 return NT_STATUS_NO_MEMORY;
2486 state->status = status;
2488 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2489 if (subreq == NULL) {
2490 return NT_STATUS_NO_MEMORY;
2492 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2497 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2499 struct dcerpc_shutdown_pipe_state *state =
2500 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2501 struct dcecli_connection *c = state->c;
2502 NTSTATUS status = state->status;
2506 * here we ignore the return values...
2508 tstream_disconnect_recv(subreq, &error);
2509 TALLOC_FREE(subreq);
2513 dcerpc_transport_dead(c, status);
2518 struct dcerpc_send_read_state {
2519 struct dcecli_connection *p;
2522 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2524 struct dcecli_connection *p = state->p;
2526 p->transport.read_subreq = NULL;
2531 static void dcerpc_send_read_done(struct tevent_req *subreq);
2533 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2535 struct dcerpc_send_read_state *state;
2537 if (p->transport.read_subreq != NULL) {
2538 p->transport.pending_reads++;
2539 return NT_STATUS_OK;
2542 state = talloc_zero(p, struct dcerpc_send_read_state);
2543 if (state == NULL) {
2544 return NT_STATUS_NO_MEMORY;
2548 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2550 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2552 p->transport.stream);
2553 if (p->transport.read_subreq == NULL) {
2554 return NT_STATUS_NO_MEMORY;
2556 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2558 return NT_STATUS_OK;
2561 static void dcerpc_send_read_done(struct tevent_req *subreq)
2563 struct dcerpc_send_read_state *state =
2564 tevent_req_callback_data(subreq,
2565 struct dcerpc_send_read_state);
2566 struct dcecli_connection *p = state->p;
2568 struct ncacn_packet *pkt;
2571 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2573 TALLOC_FREE(subreq);
2574 if (!NT_STATUS_IS_OK(status)) {
2576 dcerpc_transport_dead(p, status);
2581 * here we steal into thet connection context,
2582 * but p->transport.recv_data() will steal or free it again
2584 talloc_steal(p, blob.data);
2587 if (p->transport.pending_reads > 0) {
2588 p->transport.pending_reads--;
2590 status = dcerpc_send_read(p);
2591 if (!NT_STATUS_IS_OK(status)) {
2592 dcerpc_transport_dead(p, status);
2597 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2600 struct dcerpc_send_request_state {
2601 struct dcecli_connection *p;
2606 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2608 struct dcecli_connection *p = state->p;
2610 p->transport.read_subreq = NULL;
2615 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2616 static void dcerpc_send_request_done(struct tevent_req *subreq);
2618 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2621 struct dcerpc_send_request_state *state;
2622 struct tevent_req *subreq;
2623 bool use_trans = trigger_read;
2625 if (p->transport.stream == NULL) {
2626 return NT_STATUS_CONNECTION_DISCONNECTED;
2629 state = talloc_zero(p, struct dcerpc_send_request_state);
2630 if (state == NULL) {
2631 return NT_STATUS_NO_MEMORY;
2635 state->blob = data_blob_talloc(state, data->data, data->length);
2636 if (state->blob.data == NULL) {
2638 return NT_STATUS_NO_MEMORY;
2640 state->iov.iov_base = (void *)state->blob.data;
2641 state->iov.iov_len = state->blob.length;
2643 if (p->transport.read_subreq != NULL) {
2647 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2653 * we need to block reads until our write is
2654 * the next in the write queue.
2656 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2657 p->transport.write_queue);
2658 if (p->transport.read_subreq == NULL) {
2660 return NT_STATUS_NO_MEMORY;
2662 tevent_req_set_callback(p->transport.read_subreq,
2663 dcerpc_send_request_wait_done,
2666 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2668 trigger_read = false;
2671 subreq = tstream_writev_queue_send(state, p->event_ctx,
2672 p->transport.stream,
2673 p->transport.write_queue,
2675 if (subreq == NULL) {
2677 return NT_STATUS_NO_MEMORY;
2679 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2682 dcerpc_send_read(p);
2685 return NT_STATUS_OK;
2688 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2690 struct dcerpc_send_request_state *state =
2691 tevent_req_callback_data(subreq,
2692 struct dcerpc_send_request_state);
2693 struct dcecli_connection *p = state->p;
2697 p->transport.read_subreq = NULL;
2698 talloc_set_destructor(state, NULL);
2700 ok = tevent_queue_wait_recv(subreq);
2703 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2707 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2708 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2709 if (!NT_STATUS_IS_OK(status)) {
2711 dcerpc_transport_dead(p, status);
2716 /* we free subreq after tstream_cli_np_use_trans */
2717 TALLOC_FREE(subreq);
2719 dcerpc_send_read(p);
2722 static void dcerpc_send_request_done(struct tevent_req *subreq)
2724 struct dcerpc_send_request_state *state =
2725 tevent_req_callback_data(subreq,
2726 struct dcerpc_send_request_state);
2730 ret = tstream_writev_queue_recv(subreq, &error);
2731 TALLOC_FREE(subreq);
2733 struct dcecli_connection *p = state->p;
2734 NTSTATUS status = map_nt_error_from_unix_common(error);
2737 dcerpc_transport_dead(p, status);