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"
37 #include "librpc/rpc/dcerpc_connection.h"
40 enum rpc_request_state {
47 handle for an async dcerpc request
50 struct rpc_request *next, *prev;
51 struct dcerpc_pipe *p;
54 enum rpc_request_state state;
59 /* this is used to distinguish bind and alter_context requests
60 from normal requests */
61 void (*recv_handler)(struct rpc_request *conn,
62 DATA_BLOB *blob, struct ncacn_packet *pkt);
64 const struct GUID *object;
66 DATA_BLOB request_data;
73 void (*callback)(struct rpc_request *);
78 _PUBLIC_ NTSTATUS dcerpc_init(void)
83 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
84 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
86 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
87 struct dcerpc_pipe *p,
88 const struct GUID *object,
90 DATA_BLOB *stub_data);
91 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
93 DATA_BLOB *stub_data);
94 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
98 ndr_push_flags_fn_t ndr_push,
99 ndr_pull_flags_fn_t ndr_pull);
100 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
101 struct ndr_pull *pull_in,
104 ndr_push_flags_fn_t ndr_push,
105 ndr_pull_flags_fn_t ndr_pull,
106 ndr_print_function_t ndr_print);
107 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
108 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
110 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
112 /* destroy a dcerpc connection */
113 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
116 conn->free_skipped = true;
119 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
124 /* initialise a dcerpc connection.
125 the event context is optional
127 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
128 struct tevent_context *ev)
130 struct dcecli_connection *c;
132 c = talloc_zero(mem_ctx, struct dcecli_connection);
139 if (c->event_ctx == NULL) {
144 c->assoc = dcerpc_association_create(c, 0);
145 if (c->assoc == NULL) {
149 //c->conn = dcerpc_connection_create(c, c->assoc,
151 // c->security_state.sec = dcerpc_security_allocate(c, c->conn,
152 // DCERPC_AUTH_TYPE_NONE,
153 // DCERPC_AUTH_LEVEL_NONE,
155 // if (c->security_state.sec == NULL) {
159 c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
160 c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
161 c->security_state.auth_context_id = 0;
162 c->security_state.session_key = dcerpc_generic_session_key;
163 c->security_state.generic_state = NULL;
166 * Windows uses 5840 for ncacn_ip_tcp,
167 * so we also use it (for every transport)
168 * by default. But we give the transport
169 * the chance to overwrite it.
171 c->srv_max_xmit_frag = 5840;
172 c->srv_max_recv_frag = 5840;
173 c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
176 c->io_trigger = tevent_create_immediate(c);
177 if (c->io_trigger == NULL) {
182 talloc_set_destructor(c, dcerpc_connection_destructor);
187 struct dcerpc_bh_state {
188 struct dcerpc_pipe *p;
191 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
193 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
194 struct dcerpc_bh_state);
204 if (hs->p->conn->dead) {
211 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
214 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
215 struct dcerpc_bh_state);
219 return DCERPC_REQUEST_TIMEOUT;
222 old = hs->p->request_timeout;
223 hs->p->request_timeout = timeout;
228 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
229 enum dcerpc_AuthType *auth_type,
230 enum dcerpc_AuthLevel *auth_level)
232 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
233 struct dcerpc_bh_state);
239 if (hs->p->conn == NULL) {
243 *auth_type = hs->p->conn->security_state.auth_type;
244 *auth_level = hs->p->conn->security_state.auth_level;
247 struct dcerpc_bh_raw_call_state {
248 struct tevent_context *ev;
249 struct dcerpc_binding_handle *h;
255 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
257 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
258 struct tevent_context *ev,
259 struct dcerpc_binding_handle *h,
260 const struct GUID *object,
263 const uint8_t *in_data,
266 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
267 struct dcerpc_bh_state);
268 struct tevent_req *req;
269 struct dcerpc_bh_raw_call_state *state;
271 struct rpc_request *subreq;
273 req = tevent_req_create(mem_ctx, &state,
274 struct dcerpc_bh_raw_call_state);
280 state->in_data.data = discard_const_p(uint8_t, in_data);
281 state->in_data.length = in_length;
283 ok = dcerpc_bh_is_connected(h);
285 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
286 return tevent_req_post(req, ev);
289 subreq = dcerpc_request_send(state,
294 if (tevent_req_nomem(subreq, req)) {
295 return tevent_req_post(req, ev);
297 subreq->async.callback = dcerpc_bh_raw_call_done;
298 subreq->async.private_data = req;
303 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
305 struct tevent_req *req =
306 talloc_get_type_abort(subreq->async.private_data,
308 struct dcerpc_bh_raw_call_state *state =
310 struct dcerpc_bh_raw_call_state);
314 state->out_flags = 0;
315 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
316 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
319 fault_code = subreq->fault_code;
321 status = dcerpc_request_recv(subreq, state, &state->out_data);
322 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
323 status = dcerpc_fault_to_nt_status(fault_code);
327 * We trigger the callback in the next event run
328 * because the code in this file might trigger
329 * multiple request callbacks from within a single
332 * In order to avoid segfaults from within
333 * dcerpc_connection_dead() we call
334 * tevent_req_defer_callback().
336 tevent_req_defer_callback(req, state->ev);
338 if (!NT_STATUS_IS_OK(status)) {
339 tevent_req_nterror(req, status);
343 tevent_req_done(req);
346 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
352 struct dcerpc_bh_raw_call_state *state =
354 struct dcerpc_bh_raw_call_state);
357 if (tevent_req_is_nterror(req, &status)) {
358 tevent_req_received(req);
362 *out_data = talloc_move(mem_ctx, &state->out_data.data);
363 *out_length = state->out_data.length;
364 *out_flags = state->out_flags;
365 tevent_req_received(req);
369 struct dcerpc_bh_disconnect_state {
373 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
374 struct tevent_context *ev,
375 struct dcerpc_binding_handle *h)
377 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
378 struct dcerpc_bh_state);
379 struct tevent_req *req;
380 struct dcerpc_bh_disconnect_state *state;
383 req = tevent_req_create(mem_ctx, &state,
384 struct dcerpc_bh_disconnect_state);
389 ok = dcerpc_bh_is_connected(h);
391 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
392 return tevent_req_post(req, ev);
395 /* TODO: do a real disconnect ... */
398 tevent_req_done(req);
399 return tevent_req_post(req, ev);
402 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
406 if (tevent_req_is_nterror(req, &status)) {
407 tevent_req_received(req);
411 tevent_req_received(req);
415 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
417 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
418 struct dcerpc_bh_state);
420 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
427 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
429 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
430 struct dcerpc_bh_state);
432 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
439 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
441 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
442 struct dcerpc_bh_state);
444 if (hs->p->conn->flags & DCERPC_NDR64) {
451 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
453 const void *_struct_ptr,
454 const struct ndr_interface_call *call)
456 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
457 struct dcerpc_bh_state);
458 void *struct_ptr = discard_const(_struct_ptr);
459 bool print_in = false;
460 bool print_out = false;
462 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
466 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
470 if (DEBUGLEVEL >= 11) {
475 if (ndr_flags & NDR_IN) {
477 ndr_print_function_debug(call->ndr_print,
483 if (ndr_flags & NDR_OUT) {
485 ndr_print_function_debug(call->ndr_print,
493 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
495 const void *struct_ptr,
496 const struct ndr_interface_call *call)
498 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
499 call->name, nt_errstr(error)));
502 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
504 const DATA_BLOB *blob,
505 const struct ndr_interface_call *call)
507 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
508 struct dcerpc_bh_state);
509 const uint32_t num_examples = 20;
512 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
513 call->name, nt_errstr(error)));
515 if (hs->p->conn->packet_log_dir == NULL) return;
517 for (i=0;i<num_examples;i++) {
521 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
522 hs->p->conn->packet_log_dir,
527 if (!file_exist(name)) {
528 if (file_save(name, blob->data, blob->length)) {
529 DEBUG(10,("Logged rpc packet to %s\n", name));
538 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
540 const DATA_BLOB *blob,
541 const struct ndr_interface_call *call)
543 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
544 struct dcerpc_bh_state);
546 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
549 status = dcerpc_ndr_validate_in(hs->p->conn,
555 if (!NT_STATUS_IS_OK(status)) {
556 DEBUG(0,("Validation [in] failed for %s - %s\n",
557 call->name, nt_errstr(status)));
562 DEBUG(10,("rpc request data:\n"));
563 dump_data(10, blob->data, blob->length);
568 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
569 struct ndr_pull *pull_in,
570 const void *_struct_ptr,
571 const struct ndr_interface_call *call)
573 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
574 struct dcerpc_bh_state);
575 void *struct_ptr = discard_const(_struct_ptr);
577 DEBUG(10,("rpc reply data:\n"));
578 dump_data(10, pull_in->data, pull_in->data_size);
580 if (pull_in->offset != pull_in->data_size) {
581 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
582 pull_in->data_size - pull_in->offset,
583 pull_in->offset, pull_in->offset,
585 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
586 but it turns out that early versions of NT
587 (specifically NT3.1) add junk onto the end of rpc
588 packets, so if we want to interoperate at all with
589 those versions then we need to ignore this error */
592 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
595 status = dcerpc_ndr_validate_out(hs->p->conn,
602 if (!NT_STATUS_IS_OK(status)) {
603 DEBUG(2,("Validation [out] failed for %s - %s\n",
604 call->name, nt_errstr(status)));
612 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
614 .is_connected = dcerpc_bh_is_connected,
615 .set_timeout = dcerpc_bh_set_timeout,
616 .auth_info = dcerpc_bh_auth_info,
617 .raw_call_send = dcerpc_bh_raw_call_send,
618 .raw_call_recv = dcerpc_bh_raw_call_recv,
619 .disconnect_send = dcerpc_bh_disconnect_send,
620 .disconnect_recv = dcerpc_bh_disconnect_recv,
622 .push_bigendian = dcerpc_bh_push_bigendian,
623 .ref_alloc = dcerpc_bh_ref_alloc,
624 .use_ndr64 = dcerpc_bh_use_ndr64,
625 .do_ndr_print = dcerpc_bh_do_ndr_print,
626 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
627 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
628 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
629 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
632 /* initialise a dcerpc pipe. */
633 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p,
634 const struct GUID *object,
635 const struct ndr_interface_table *table)
637 struct dcerpc_binding_handle *h;
638 struct dcerpc_bh_state *hs;
640 h = dcerpc_binding_handle_create(p,
645 struct dcerpc_bh_state,
652 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
657 /* initialise a dcerpc pipe. */
658 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
660 struct dcerpc_pipe *p;
662 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
667 p->conn = dcerpc_connection_init(p, ev);
668 if (p->conn == NULL) {
673 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
676 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
684 choose the next call id to use
686 static uint32_t next_call_id(struct dcecli_connection *c)
689 if (c->call_id == 0) {
696 setup for a ndr pull, also setting up any flags from the binding string
698 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
699 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
701 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
703 if (ndr == NULL) return ndr;
705 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
706 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
709 if (c->flags & DCERPC_NDR_REF_ALLOC) {
710 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
713 if (c->flags & DCERPC_NDR64) {
714 ndr->flags |= LIBNDR_FLAG_NDR64;
721 parse the authentication information on a dcerpc response packet
723 static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c,
725 enum dcerpc_pkt_type ptype,
726 uint8_t required_flags,
727 uint8_t optional_flags,
728 uint8_t payload_offset,
729 DATA_BLOB *payload_and_verifier,
730 DATA_BLOB *raw_packet,
731 const struct ncacn_packet *pkt)
733 const struct dcerpc_auth tmp_auth = {
734 .auth_type = c->security_state.auth_type,
735 .auth_level = c->security_state.auth_level,
736 .auth_context_id = c->security_state.auth_context_id,
740 status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
741 c->security_state.generic_state,
747 payload_and_verifier,
750 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
751 return NT_STATUS_INVALID_NETWORK_RESPONSE;
753 if (!NT_STATUS_IS_OK(status)) {
762 push a dcerpc request packet into a blob, possibly signing it.
764 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
765 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
767 struct ncacn_packet *pkt)
769 const struct dcerpc_auth tmp_auth = {
770 .auth_type = c->security_state.auth_type,
771 .auth_level = c->security_state.auth_level,
772 .auth_context_id = c->security_state.auth_context_id,
775 uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
777 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
778 payload_offset += 16;
781 status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
782 c->security_state.generic_state,
786 &pkt->u.request.stub_and_verifier,
788 if (!NT_STATUS_IS_OK(status)) {
797 fill in the fixed values in a dcerpc header
799 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
802 pkt->rpc_vers_minor = 0;
803 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
806 pkt->drep[0] = DCERPC_DREP_LE;
814 map a bind nak reason to a NTSTATUS
816 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
819 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
820 return NT_STATUS_REVISION_MISMATCH;
821 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
822 return NT_STATUS_INVALID_PARAMETER;
826 return NT_STATUS_UNSUCCESSFUL;
829 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
832 return NT_STATUS_RPC_PROTOCOL_ERROR;
835 switch (ack->result) {
836 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
838 * We have not asked for this...
840 return NT_STATUS_RPC_PROTOCOL_ERROR;
845 switch (ack->reason.value) {
846 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
847 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
848 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
849 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
853 return NT_STATUS_UNSUCCESSFUL;
857 remove requests from the pending or queued queues
859 static int dcerpc_req_dequeue(struct rpc_request *req)
861 switch (req->state) {
862 case RPC_REQUEST_QUEUED:
863 DLIST_REMOVE(req->p->conn->request_queue, req);
865 case RPC_REQUEST_PENDING:
866 DLIST_REMOVE(req->p->conn->pending, req);
868 case RPC_REQUEST_DONE:
876 mark the dcerpc connection dead. All outstanding requests get an error
878 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
880 if (conn->dead) return;
884 TALLOC_FREE(conn->io_trigger);
885 conn->io_trigger_pending = false;
887 dcerpc_shutdown_pipe(conn, status);
889 /* all pending requests get the error */
890 while (conn->pending) {
891 struct rpc_request *req = conn->pending;
892 dcerpc_req_dequeue(req);
893 req->state = RPC_REQUEST_DONE;
894 req->status = status;
895 if (req->async.callback) {
896 req->async.callback(req);
900 /* all requests, which are not shipped */
901 while (conn->request_queue) {
902 struct rpc_request *req = conn->request_queue;
903 dcerpc_req_dequeue(req);
904 req->state = RPC_REQUEST_DONE;
905 req->status = status;
906 if (req->async.callback) {
907 req->async.callback(req);
911 talloc_set_destructor(conn, NULL);
912 if (conn->free_skipped) {
918 forward declarations of the recv_data handlers for the types of
919 packets we need to handle
921 static void dcerpc_request_recv_data(struct dcecli_connection *c,
922 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
925 receive a dcerpc reply from the transport. Here we work out what
926 type of reply it is (normal request, bind or alter context) and
927 dispatch to the appropriate handler
929 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
931 struct ncacn_packet pkt;
937 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
938 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
941 /* the transport may be telling us of a severe error, such as
943 if (!NT_STATUS_IS_OK(status)) {
944 data_blob_free(blob);
945 dcerpc_connection_dead(conn, status);
949 /* parse the basic packet to work out what type of response this is */
950 status = dcerpc_pull_ncacn_packet(blob->data, blob, &pkt);
951 if (!NT_STATUS_IS_OK(status)) {
952 data_blob_free(blob);
953 dcerpc_connection_dead(conn, status);
957 dcerpc_request_recv_data(conn, blob, &pkt);
961 handle timeouts of individual dcerpc requests
963 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
964 struct timeval t, void *private_data)
966 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
968 if (req->ignore_timeout) {
969 dcerpc_req_dequeue(req);
970 req->state = RPC_REQUEST_DONE;
971 req->status = NT_STATUS_IO_TIMEOUT;
972 if (req->async.callback) {
973 req->async.callback(req);
978 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
981 struct dcerpc_bind_state {
982 struct tevent_context *ev;
983 struct dcerpc_pipe *p;
986 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
987 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
988 DATA_BLOB *raw_packet,
989 struct ncacn_packet *pkt);
991 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
992 struct tevent_context *ev,
993 struct dcerpc_pipe *p,
994 const struct ndr_syntax_id *syntax,
995 const struct ndr_syntax_id *transfer_syntax)
997 struct tevent_req *req;
998 struct dcerpc_bind_state *state;
999 struct ncacn_packet pkt;
1002 struct rpc_request *subreq;
1004 struct ndr_syntax_id bind_time_features;
1006 bind_time_features = dcerpc_construct_bind_time_features(
1007 DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
1008 DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
1010 req = tevent_req_create(mem_ctx, &state,
1011 struct dcerpc_bind_state);
1019 p->syntax = *syntax;
1020 p->transfer_syntax = *transfer_syntax;
1022 flags = dcerpc_binding_get_flags(p->binding);
1024 init_ncacn_hdr(p->conn, &pkt);
1026 pkt.ptype = DCERPC_PKT_BIND;
1027 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1028 pkt.call_id = p->conn->call_id;
1029 pkt.auth_length = 0;
1031 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1032 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1035 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1036 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1039 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1040 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1041 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1042 pkt.u.bind.num_contexts = 2;
1043 pkt.u.bind.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
1044 pkt.u.bind.num_contexts);
1045 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1046 return tevent_req_post(req, ev);
1048 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1049 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1050 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1051 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1052 pkt.u.bind.ctx_list[1].context_id = p->context_id + 1;
1053 pkt.u.bind.ctx_list[1].num_transfer_syntaxes = 1;
1054 pkt.u.bind.ctx_list[1].abstract_syntax = p->syntax;
1055 pkt.u.bind.ctx_list[1].transfer_syntaxes = &bind_time_features;
1056 pkt.u.bind.auth_info = data_blob(NULL, 0);
1058 /* construct the NDR form of the packet */
1059 status = ncacn_push_auth(&blob, state, &pkt,
1060 p->conn->security_state.tmp_auth_info.out);
1061 if (tevent_req_nterror(req, status)) {
1062 return tevent_req_post(req, ev);
1066 * we allocate a dcerpc_request so we can be in the same
1067 * request queue as normal requests
1069 subreq = talloc_zero(state, struct rpc_request);
1070 if (tevent_req_nomem(subreq, req)) {
1071 return tevent_req_post(req, ev);
1074 subreq->state = RPC_REQUEST_PENDING;
1075 subreq->call_id = pkt.call_id;
1076 subreq->async.private_data = req;
1077 subreq->async.callback = dcerpc_bind_fail_handler;
1079 subreq->recv_handler = dcerpc_bind_recv_handler;
1080 DLIST_ADD_END(p->conn->pending, subreq);
1081 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1083 status = dcerpc_send_request(p->conn, &blob, true);
1084 if (tevent_req_nterror(req, status)) {
1085 return tevent_req_post(req, ev);
1088 tevent_add_timer(ev, subreq,
1089 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1090 dcerpc_timeout_handler, subreq);
1095 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1097 struct tevent_req *req =
1098 talloc_get_type_abort(subreq->async.private_data,
1100 struct dcerpc_bind_state *state =
1101 tevent_req_data(req,
1102 struct dcerpc_bind_state);
1103 NTSTATUS status = subreq->status;
1105 TALLOC_FREE(subreq);
1108 * We trigger the callback in the next event run
1109 * because the code in this file might trigger
1110 * multiple request callbacks from within a single
1113 * In order to avoid segfaults from within
1114 * dcerpc_connection_dead() we call
1115 * tevent_req_defer_callback().
1117 tevent_req_defer_callback(req, state->ev);
1119 tevent_req_nterror(req, status);
1122 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1123 DATA_BLOB *raw_packet,
1124 struct ncacn_packet *pkt)
1126 struct tevent_req *req =
1127 talloc_get_type_abort(subreq->async.private_data,
1129 struct dcerpc_bind_state *state =
1130 tevent_req_data(req,
1131 struct dcerpc_bind_state);
1132 struct dcecli_connection *conn = state->p->conn;
1133 struct dcecli_security *sec = &conn->security_state;
1134 struct dcerpc_binding *b = NULL;
1139 * Note that pkt is allocated under raw_packet->data,
1140 * while raw_packet->data is a child of subreq.
1142 talloc_steal(state, raw_packet->data);
1143 TALLOC_FREE(subreq);
1146 * We trigger the callback in the next event run
1147 * because the code in this file might trigger
1148 * multiple request callbacks from within a single
1151 * In order to avoid segfaults from within
1152 * dcerpc_connection_dead() we call
1153 * tevent_req_defer_callback().
1155 tevent_req_defer_callback(req, state->ev);
1157 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1158 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1160 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1161 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1163 tevent_req_nterror(req, status);
1167 status = dcerpc_verify_ncacn_packet_header(pkt,
1168 DCERPC_PKT_BIND_ACK,
1169 pkt->u.bind_ack.auth_info.length,
1170 DCERPC_PFC_FLAG_FIRST |
1171 DCERPC_PFC_FLAG_LAST,
1172 DCERPC_PFC_FLAG_CONC_MPX |
1173 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1174 if (!NT_STATUS_IS_OK(status)) {
1175 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1176 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1180 if (pkt->u.bind_ack.num_results < 1) {
1181 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1182 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1186 if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1187 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1188 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1189 pkt->u.bind_ack.ctx_list[0].reason.value,
1190 nt_errstr(status)));
1191 tevent_req_nterror(req, status);
1195 if (pkt->u.bind_ack.num_results >= 2) {
1196 if (pkt->u.bind_ack.ctx_list[1].result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1197 conn->bind_time_features = pkt->u.bind_ack.ctx_list[1].reason.negotiate;
1199 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[1]);
1200 DEBUG(10,("dcerpc: bind_time_feature failed - reason %d - %s\n",
1201 pkt->u.bind_ack.ctx_list[1].reason.value,
1202 nt_errstr(status)));
1203 status = NT_STATUS_OK;
1208 * DCE-RPC 1.1 (c706) specifies
1209 * CONST_MUST_RCV_FRAG_SIZE as 1432
1211 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1212 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1213 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1216 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1217 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1218 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1221 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1222 pkt->u.bind_ack.max_xmit_frag);
1223 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1224 pkt->u.bind_ack.max_recv_frag);
1226 flags = dcerpc_binding_get_flags(state->p->binding);
1228 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1229 if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1230 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1232 conn->flags &= ~DCERPC_CONCURRENT_MULTIPLEX;
1236 if (!(conn->flags & DCERPC_CONCURRENT_MULTIPLEX)) {
1237 struct dcerpc_binding *pb =
1238 discard_const_p(struct dcerpc_binding, state->p->binding);
1240 * clear DCERPC_CONCURRENT_MULTIPLEX
1242 status = dcerpc_binding_set_flags(pb, 0,
1243 DCERPC_CONCURRENT_MULTIPLEX);
1244 if (tevent_req_nterror(req, status)) {
1248 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1249 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1250 conn->flags |= DCERPC_HEADER_SIGNING;
1253 /* the bind_ack might contain a reply set of credentials */
1254 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1255 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1256 &pkt->u.bind_ack.auth_info,
1257 sec->tmp_auth_info.in,
1259 if (tevent_req_nterror(req, status)) {
1265 * We're the owner of the binding, so we're allowed to modify it.
1267 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1268 status = dcerpc_binding_set_assoc_group_id(b,
1269 pkt->u.bind_ack.assoc_group_id);
1270 if (tevent_req_nterror(req, status)) {
1274 tevent_req_done(req);
1277 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1279 return tevent_req_simple_recv_ntstatus(req);
1283 perform a continued bind (and auth3)
1285 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1286 TALLOC_CTX *mem_ctx)
1288 struct ncacn_packet pkt;
1293 flags = dcerpc_binding_get_flags(p->binding);
1295 init_ncacn_hdr(p->conn, &pkt);
1297 pkt.ptype = DCERPC_PKT_AUTH3;
1298 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1299 pkt.call_id = next_call_id(p->conn);
1300 pkt.auth_length = 0;
1301 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1303 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1304 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1307 /* construct the NDR form of the packet */
1308 status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1309 p->conn->security_state.tmp_auth_info.out);
1310 if (!NT_STATUS_IS_OK(status)) {
1314 /* send it on its way */
1315 status = dcerpc_send_request(p->conn, &blob, false);
1316 if (!NT_STATUS_IS_OK(status)) {
1320 return NT_STATUS_OK;
1325 process a fragment received from the transport layer during a
1328 This function frees the data
1330 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1331 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1333 struct rpc_request *req;
1334 unsigned int length;
1335 NTSTATUS status = NT_STATUS_OK;
1338 if this is an authenticated connection then parse and check
1339 the auth info. We have to do this before finding the
1340 matching packet, as the request structure might have been
1341 removed due to a timeout, but if it has been we still need
1342 to run the auth routines so that we don't get the sign/seal
1343 info out of step with the server
1345 switch (pkt->ptype) {
1346 case DCERPC_PKT_RESPONSE:
1347 status = ncacn_pull_pkt_auth(c, raw_packet->data,
1348 DCERPC_PKT_RESPONSE,
1349 0, /* required_flags */
1350 DCERPC_PFC_FLAG_FIRST |
1351 DCERPC_PFC_FLAG_LAST,
1352 DCERPC_REQUEST_LENGTH,
1353 &pkt->u.response.stub_and_verifier,
1360 /* find the matching request */
1361 for (req=c->pending;req;req=req->next) {
1362 if (pkt->call_id == req->call_id) break;
1366 /* useful for testing certain vendors RPC servers */
1367 if (req == NULL && c->pending && pkt->call_id == 0) {
1368 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1374 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1375 data_blob_free(raw_packet);
1379 talloc_steal(req, raw_packet->data);
1381 if (req->recv_handler != NULL) {
1382 dcerpc_req_dequeue(req);
1383 req->state = RPC_REQUEST_DONE;
1386 * We have to look at shipping further requests before calling
1387 * the async function, that one might close the pipe
1389 dcerpc_schedule_io_trigger(c);
1391 req->recv_handler(req, raw_packet, pkt);
1395 if (pkt->ptype == DCERPC_PKT_FAULT) {
1396 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1397 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1398 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
1399 dcerpc_connection_dead(c, status);
1402 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1403 dcerpc_connection_dead(c, status);
1406 req->fault_code = pkt->u.fault.status;
1407 req->status = NT_STATUS_NET_WRITE_FAULT;
1411 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1412 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1414 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1418 /* now check the status from the auth routines, and if it failed then fail
1419 this request accordingly */
1420 if (!NT_STATUS_IS_OK(status)) {
1421 dcerpc_connection_dead(c, status);
1425 length = pkt->u.response.stub_and_verifier.length;
1427 if (req->payload.length + length > c->max_total_response_size) {
1428 DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
1429 (unsigned)req->payload.length + length,
1430 (unsigned)c->max_total_response_size));
1431 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1436 req->payload.data = talloc_realloc(req,
1439 req->payload.length + length);
1440 if (!req->payload.data) {
1441 req->status = NT_STATUS_NO_MEMORY;
1444 memcpy(req->payload.data+req->payload.length,
1445 pkt->u.response.stub_and_verifier.data, length);
1446 req->payload.length += length;
1449 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1450 data_blob_free(raw_packet);
1451 dcerpc_send_read(c);
1455 if (req->verify_bitmask1) {
1456 req->p->conn->security_state.verified_bitmask1 = true;
1458 if (req->verify_pcontext) {
1459 req->p->verified_pcontext = true;
1462 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1463 req->flags |= DCERPC_PULL_BIGENDIAN;
1465 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1469 data_blob_free(raw_packet);
1471 /* we've got the full payload */
1472 dcerpc_req_dequeue(req);
1473 req->state = RPC_REQUEST_DONE;
1476 * We have to look at shipping further requests before calling
1477 * the async function, that one might close the pipe
1479 dcerpc_schedule_io_trigger(c);
1481 if (req->async.callback) {
1482 req->async.callback(req);
1486 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1489 perform the send side of a async dcerpc request
1491 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1492 struct dcerpc_pipe *p,
1493 const struct GUID *object,
1495 DATA_BLOB *stub_data)
1497 struct rpc_request *req;
1500 req = talloc_zero(mem_ctx, struct rpc_request);
1506 req->call_id = next_call_id(p->conn);
1507 req->state = RPC_REQUEST_QUEUED;
1509 if (object != NULL) {
1510 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1511 if (req->object == NULL) {
1518 req->request_data.length = stub_data->length;
1519 req->request_data.data = stub_data->data;
1521 status = dcerpc_request_prepare_vt(req);
1522 if (!NT_STATUS_IS_OK(status)) {
1527 DLIST_ADD_END(p->conn->request_queue, req);
1528 talloc_set_destructor(req, dcerpc_req_dequeue);
1530 dcerpc_schedule_io_trigger(p->conn);
1532 if (p->request_timeout) {
1533 tevent_add_timer(p->conn->event_ctx, req,
1534 timeval_current_ofs(p->request_timeout, 0),
1535 dcerpc_timeout_handler, req);
1541 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1543 struct dcecli_security *sec = &req->p->conn->security_state;
1544 struct dcerpc_sec_verification_trailer *t;
1545 struct dcerpc_sec_vt *c = NULL;
1546 struct ndr_push *ndr = NULL;
1547 enum ndr_err_code ndr_err;
1549 if (sec->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1550 return NT_STATUS_OK;
1553 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1555 return NT_STATUS_NO_MEMORY;
1558 if (!sec->verified_bitmask1) {
1559 t->commands = talloc_realloc(t, t->commands,
1560 struct dcerpc_sec_vt,
1561 t->count.count + 1);
1562 if (t->commands == NULL) {
1563 return NT_STATUS_NO_MEMORY;
1565 c = &t->commands[t->count.count++];
1568 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1569 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1570 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1572 req->verify_bitmask1 = true;
1575 if (!req->p->verified_pcontext) {
1576 t->commands = talloc_realloc(t, t->commands,
1577 struct dcerpc_sec_vt,
1578 t->count.count + 1);
1579 if (t->commands == NULL) {
1580 return NT_STATUS_NO_MEMORY;
1582 c = &t->commands[t->count.count++];
1585 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1586 c->u.pcontext.abstract_syntax = req->p->syntax;
1587 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1589 req->verify_pcontext = true;
1592 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1593 t->commands = talloc_realloc(t, t->commands,
1594 struct dcerpc_sec_vt,
1595 t->count.count + 1);
1596 if (t->commands == NULL) {
1597 return NT_STATUS_NO_MEMORY;
1599 c = &t->commands[t->count.count++];
1602 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1603 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1604 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1605 c->u.header2.drep[0] = 0;
1607 c->u.header2.drep[0] = DCERPC_DREP_LE;
1609 c->u.header2.drep[1] = 0;
1610 c->u.header2.drep[2] = 0;
1611 c->u.header2.drep[3] = 0;
1612 c->u.header2.call_id = req->call_id;
1613 c->u.header2.context_id = req->p->context_id;
1614 c->u.header2.opnum = req->opnum;
1617 if (t->count.count == 0) {
1619 return NT_STATUS_OK;
1622 c = &t->commands[t->count.count - 1];
1623 c->command |= DCERPC_SEC_VT_COMMAND_END;
1625 if (DEBUGLEVEL >= 10) {
1626 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1629 ndr = ndr_push_init_ctx(req);
1631 return NT_STATUS_NO_MEMORY;
1635 * for now we just copy and append
1638 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1639 req->request_data.length);
1640 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1641 return ndr_map_error2ntstatus(ndr_err);
1644 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1645 NDR_SCALARS | NDR_BUFFERS,
1647 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1648 return ndr_map_error2ntstatus(ndr_err);
1650 req->request_data = ndr_push_blob(ndr);
1652 return NT_STATUS_OK;
1656 Send a request using the transport
1659 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1661 struct rpc_request *req;
1662 struct dcerpc_pipe *p;
1663 DATA_BLOB *stub_data;
1664 struct ncacn_packet pkt;
1666 uint32_t remaining, chunk_size;
1667 bool first_packet = true;
1668 size_t sig_size = 0;
1669 bool need_async = false;
1670 bool can_async = true;
1672 req = c->request_queue;
1678 stub_data = &req->request_data;
1684 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1685 can_async = gensec_have_feature(c->security_state.generic_state,
1686 GENSEC_FEATURE_ASYNC_REPLIES);
1689 if (need_async && !can_async) {
1690 req->wait_for_sync = true;
1694 DLIST_REMOVE(c->request_queue, req);
1695 DLIST_ADD(c->pending, req);
1696 req->state = RPC_REQUEST_PENDING;
1698 init_ncacn_hdr(p->conn, &pkt);
1700 remaining = stub_data->length;
1702 /* we can write a full max_recv_frag size, minus the dcerpc
1703 request header size */
1704 chunk_size = p->conn->srv_max_recv_frag;
1705 chunk_size -= DCERPC_REQUEST_LENGTH;
1706 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1707 size_t max_payload = chunk_size;
1709 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1710 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1712 sig_size = gensec_sig_size(c->security_state.generic_state,
1715 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1716 chunk_size -= sig_size;
1719 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1721 pkt.ptype = DCERPC_PKT_REQUEST;
1722 pkt.call_id = req->call_id;
1723 pkt.auth_length = 0;
1725 pkt.u.request.context_id = p->context_id;
1726 pkt.u.request.opnum = req->opnum;
1729 pkt.u.request.object.object = *req->object;
1730 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1731 chunk_size -= ndr_size_GUID(req->object,0);
1734 /* we send a series of pdus without waiting for a reply */
1735 while (remaining > 0 || first_packet) {
1736 uint32_t chunk = MIN(chunk_size, remaining);
1737 bool last_frag = false;
1738 bool do_trans = false;
1740 first_packet = false;
1741 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1743 if (remaining == stub_data->length) {
1744 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1746 if (chunk == remaining) {
1747 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1751 pkt.u.request.alloc_hint = remaining;
1752 pkt.u.request.stub_and_verifier.data = stub_data->data +
1753 (stub_data->length - remaining);
1754 pkt.u.request.stub_and_verifier.length = chunk;
1756 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1757 if (!NT_STATUS_IS_OK(req->status)) {
1758 req->state = RPC_REQUEST_DONE;
1759 DLIST_REMOVE(p->conn->pending, req);
1763 if (last_frag && !need_async) {
1767 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1768 if (!NT_STATUS_IS_OK(req->status)) {
1769 req->state = RPC_REQUEST_DONE;
1770 DLIST_REMOVE(p->conn->pending, req);
1774 if (last_frag && !do_trans) {
1775 req->status = dcerpc_send_read(p->conn);
1776 if (!NT_STATUS_IS_OK(req->status)) {
1777 req->state = RPC_REQUEST_DONE;
1778 DLIST_REMOVE(p->conn->pending, req);
1787 static void dcerpc_io_trigger(struct tevent_context *ctx,
1788 struct tevent_immediate *im,
1791 struct dcecli_connection *c =
1792 talloc_get_type_abort(private_data,
1793 struct dcecli_connection);
1795 c->io_trigger_pending = false;
1797 dcerpc_schedule_io_trigger(c);
1799 dcerpc_ship_next_request(c);
1802 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1808 if (c->request_queue == NULL) {
1812 if (c->request_queue->wait_for_sync && c->pending) {
1816 if (c->io_trigger_pending) {
1820 c->io_trigger_pending = true;
1822 tevent_schedule_immediate(c->io_trigger,
1829 perform the receive side of a async dcerpc request
1831 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1832 TALLOC_CTX *mem_ctx,
1833 DATA_BLOB *stub_data)
1837 while (req->state != RPC_REQUEST_DONE) {
1838 struct tevent_context *ctx = req->p->conn->event_ctx;
1839 if (tevent_loop_once(ctx) != 0) {
1840 return NT_STATUS_CONNECTION_DISCONNECTED;
1843 *stub_data = req->payload;
1844 status = req->status;
1845 if (stub_data->data) {
1846 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1848 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1849 req->p->last_fault_code = req->fault_code;
1851 talloc_unlink(talloc_parent(req), req);
1856 this is a paranoid NDR validator. For every packet we push onto the wire
1857 we pull it back again, then push it again. Then we compare the raw NDR data
1858 for that to the NDR we initially generated. If they don't match then we know
1859 we must have a bug in either the pull or push side of our code
1861 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1862 TALLOC_CTX *mem_ctx,
1865 ndr_push_flags_fn_t ndr_push,
1866 ndr_pull_flags_fn_t ndr_pull)
1869 struct ndr_pull *pull;
1870 struct ndr_push *push;
1872 enum ndr_err_code ndr_err;
1874 st = talloc_size(mem_ctx, struct_size);
1876 return NT_STATUS_NO_MEMORY;
1879 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1881 return NT_STATUS_NO_MEMORY;
1883 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1885 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1886 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1889 if (c->flags & DCERPC_NDR64) {
1890 pull->flags |= LIBNDR_FLAG_NDR64;
1893 ndr_err = ndr_pull(pull, NDR_IN, st);
1894 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1895 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1896 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1897 "failed input validation pull - %s",
1899 return ndr_map_error2ntstatus(ndr_err);
1902 push = ndr_push_init_ctx(mem_ctx);
1904 return NT_STATUS_NO_MEMORY;
1907 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1908 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1911 if (c->flags & DCERPC_NDR64) {
1912 push->flags |= LIBNDR_FLAG_NDR64;
1915 ndr_err = ndr_push(push, NDR_IN, st);
1916 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1917 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1918 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1919 "failed input validation push - %s",
1921 return ndr_map_error2ntstatus(ndr_err);
1924 blob2 = ndr_push_blob(push);
1926 if (data_blob_cmp(&blob, &blob2) != 0) {
1927 DEBUG(3,("original:\n"));
1928 dump_data(3, blob.data, blob.length);
1929 DEBUG(3,("secondary:\n"));
1930 dump_data(3, blob2.data, blob2.length);
1931 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1932 "failed input validation blobs doesn't match");
1933 return ndr_map_error2ntstatus(ndr_err);
1936 return NT_STATUS_OK;
1940 this is a paranoid NDR input validator. For every packet we pull
1941 from the wire we push it back again then pull and push it
1942 again. Then we compare the raw NDR data for that to the NDR we
1943 initially generated. If they don't match then we know we must have a
1944 bug in either the pull or push side of our code
1946 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1947 struct ndr_pull *pull_in,
1950 ndr_push_flags_fn_t ndr_push,
1951 ndr_pull_flags_fn_t ndr_pull,
1952 ndr_print_function_t ndr_print)
1955 struct ndr_pull *pull;
1956 struct ndr_push *push;
1957 DATA_BLOB blob, blob2;
1958 TALLOC_CTX *mem_ctx = pull_in;
1960 enum ndr_err_code ndr_err;
1962 st = talloc_size(mem_ctx, struct_size);
1964 return NT_STATUS_NO_MEMORY;
1966 memcpy(st, struct_ptr, struct_size);
1968 push = ndr_push_init_ctx(mem_ctx);
1970 return NT_STATUS_NO_MEMORY;
1973 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1974 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1975 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1976 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1977 "failed output validation push - %s",
1979 return ndr_map_error2ntstatus(ndr_err);
1982 blob = ndr_push_blob(push);
1984 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1986 return NT_STATUS_NO_MEMORY;
1989 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1990 ndr_err = ndr_pull(pull, NDR_OUT, st);
1991 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1992 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1993 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1994 "failed output validation pull - %s",
1996 return ndr_map_error2ntstatus(ndr_err);
1999 push = ndr_push_init_ctx(mem_ctx);
2001 return NT_STATUS_NO_MEMORY;
2004 ndr_err = ndr_push(push, NDR_OUT, st);
2005 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2006 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2007 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2008 "failed output validation push2 - %s",
2010 return ndr_map_error2ntstatus(ndr_err);
2013 blob2 = ndr_push_blob(push);
2015 if (data_blob_cmp(&blob, &blob2) != 0) {
2016 DEBUG(3,("original:\n"));
2017 dump_data(3, blob.data, blob.length);
2018 DEBUG(3,("secondary:\n"));
2019 dump_data(3, blob2.data, blob2.length);
2020 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2021 "failed output validation blobs doesn't match");
2022 return ndr_map_error2ntstatus(ndr_err);
2025 /* this checks the printed forms of the two structures, which effectively
2026 tests all of the value() attributes */
2027 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2028 NDR_OUT, struct_ptr);
2029 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2031 if (strcmp(s1, s2) != 0) {
2033 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2035 /* this is sometimes useful */
2036 printf("VALIDATE ERROR\n");
2037 file_save("wire.dat", s1, strlen(s1));
2038 file_save("gen.dat", s2, strlen(s2));
2039 system("diff -u wire.dat gen.dat");
2041 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2042 "failed output validation strings doesn't match");
2043 return ndr_map_error2ntstatus(ndr_err);
2046 return NT_STATUS_OK;
2050 a useful function for retrieving the server name we connected to
2052 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2054 return p->conn ? p->conn->server_name : NULL;
2059 get the dcerpc auth_level for a open connection
2061 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2065 if (c->flags & DCERPC_SEAL) {
2066 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2067 } else if (c->flags & DCERPC_SIGN) {
2068 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2069 } else if (c->flags & DCERPC_PACKET) {
2070 auth_level = DCERPC_AUTH_LEVEL_PACKET;
2071 } else if (c->flags & DCERPC_CONNECT) {
2072 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2074 auth_level = DCERPC_AUTH_LEVEL_NONE;
2079 struct dcerpc_alter_context_state {
2080 struct tevent_context *ev;
2081 struct dcerpc_pipe *p;
2084 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2085 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2086 DATA_BLOB *raw_packet,
2087 struct ncacn_packet *pkt);
2089 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2090 struct tevent_context *ev,
2091 struct dcerpc_pipe *p,
2092 const struct ndr_syntax_id *syntax,
2093 const struct ndr_syntax_id *transfer_syntax)
2095 struct tevent_req *req;
2096 struct dcerpc_alter_context_state *state;
2097 struct ncacn_packet pkt;
2100 struct rpc_request *subreq;
2103 req = tevent_req_create(mem_ctx, &state,
2104 struct dcerpc_alter_context_state);
2112 p->syntax = *syntax;
2113 p->transfer_syntax = *transfer_syntax;
2115 flags = dcerpc_binding_get_flags(p->binding);
2117 init_ncacn_hdr(p->conn, &pkt);
2119 pkt.ptype = DCERPC_PKT_ALTER;
2120 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2121 pkt.call_id = p->conn->call_id;
2122 pkt.auth_length = 0;
2124 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2125 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2128 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2129 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2130 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2131 pkt.u.alter.num_contexts = 1;
2132 pkt.u.alter.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
2133 pkt.u.alter.num_contexts);
2134 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2135 return tevent_req_post(req, ev);
2137 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2138 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2139 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2140 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2141 pkt.u.alter.auth_info = data_blob(NULL, 0);
2143 /* construct the NDR form of the packet */
2144 status = ncacn_push_auth(&blob, state, &pkt,
2145 p->conn->security_state.tmp_auth_info.out);
2146 if (tevent_req_nterror(req, status)) {
2147 return tevent_req_post(req, ev);
2151 * we allocate a dcerpc_request so we can be in the same
2152 * request queue as normal requests
2154 subreq = talloc_zero(state, struct rpc_request);
2155 if (tevent_req_nomem(subreq, req)) {
2156 return tevent_req_post(req, ev);
2159 subreq->state = RPC_REQUEST_PENDING;
2160 subreq->call_id = pkt.call_id;
2161 subreq->async.private_data = req;
2162 subreq->async.callback = dcerpc_alter_context_fail_handler;
2164 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2165 DLIST_ADD_END(p->conn->pending, subreq);
2166 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2168 status = dcerpc_send_request(p->conn, &blob, true);
2169 if (tevent_req_nterror(req, status)) {
2170 return tevent_req_post(req, ev);
2173 tevent_add_timer(ev, subreq,
2174 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2175 dcerpc_timeout_handler, subreq);
2180 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2182 struct tevent_req *req =
2183 talloc_get_type_abort(subreq->async.private_data,
2185 struct dcerpc_alter_context_state *state =
2186 tevent_req_data(req,
2187 struct dcerpc_alter_context_state);
2188 NTSTATUS status = subreq->status;
2190 TALLOC_FREE(subreq);
2193 * We trigger the callback in the next event run
2194 * because the code in this file might trigger
2195 * multiple request callbacks from within a single
2198 * In order to avoid segfaults from within
2199 * dcerpc_connection_dead() we call
2200 * tevent_req_defer_callback().
2202 tevent_req_defer_callback(req, state->ev);
2204 tevent_req_nterror(req, status);
2207 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2208 DATA_BLOB *raw_packet,
2209 struct ncacn_packet *pkt)
2211 struct tevent_req *req =
2212 talloc_get_type_abort(subreq->async.private_data,
2214 struct dcerpc_alter_context_state *state =
2215 tevent_req_data(req,
2216 struct dcerpc_alter_context_state);
2217 struct dcecli_connection *conn = state->p->conn;
2218 struct dcecli_security *sec = &conn->security_state;
2222 * Note that pkt is allocated under raw_packet->data,
2223 * while raw_packet->data is a child of subreq.
2225 talloc_steal(state, raw_packet->data);
2226 TALLOC_FREE(subreq);
2229 * We trigger the callback in the next event run
2230 * because the code in this file might trigger
2231 * multiple request callbacks from within a single
2234 * In order to avoid segfaults from within
2235 * dcerpc_connection_dead() we call
2236 * tevent_req_defer_callback().
2238 tevent_req_defer_callback(req, state->ev);
2240 if (pkt->ptype == DCERPC_PKT_FAULT) {
2241 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2242 dcerpc_errstr(state, pkt->u.fault.status)));
2243 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2244 state->p->last_fault_code = pkt->u.fault.status;
2245 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2246 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2247 state->p->last_fault_code = pkt->u.fault.status;
2248 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2250 state->p->last_fault_code = pkt->u.fault.status;
2251 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2252 tevent_req_nterror(req, status);
2257 status = dcerpc_verify_ncacn_packet_header(pkt,
2258 DCERPC_PKT_ALTER_RESP,
2259 pkt->u.alter_resp.auth_info.length,
2260 DCERPC_PFC_FLAG_FIRST |
2261 DCERPC_PFC_FLAG_LAST,
2262 DCERPC_PFC_FLAG_CONC_MPX |
2263 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2264 if (!NT_STATUS_IS_OK(status)) {
2265 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2266 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2270 if (pkt->u.alter_resp.num_results != 1) {
2271 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2272 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2276 if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2277 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2278 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2279 pkt->u.alter_resp.ctx_list[0].reason.value,
2280 nt_errstr(status)));
2281 tevent_req_nterror(req, status);
2285 /* the alter_resp might contain a reply set of credentials */
2286 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2287 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2288 &pkt->u.alter_resp.auth_info,
2289 sec->tmp_auth_info.in,
2291 if (tevent_req_nterror(req, status)) {
2296 tevent_req_done(req);
2299 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2301 return tevent_req_simple_recv_ntstatus(req);
2305 send a dcerpc alter_context request
2307 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2308 TALLOC_CTX *mem_ctx,
2309 const struct ndr_syntax_id *syntax,
2310 const struct ndr_syntax_id *transfer_syntax)
2312 struct tevent_req *subreq;
2313 struct tevent_context *ev = p->conn->event_ctx;
2316 /* TODO: create a new event context here */
2318 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2319 p, syntax, transfer_syntax);
2320 if (subreq == NULL) {
2321 return NT_STATUS_NO_MEMORY;
2324 ok = tevent_req_poll(subreq, ev);
2327 status = map_nt_error_from_unix_common(errno);
2331 return dcerpc_alter_context_recv(subreq);
2334 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2336 if (c->transport.stream == NULL) {
2340 tevent_queue_stop(c->transport.write_queue);
2341 TALLOC_FREE(c->transport.read_subreq);
2342 TALLOC_FREE(c->transport.stream);
2344 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2345 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2348 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2349 status = NT_STATUS_END_OF_FILE;
2352 dcerpc_recv_data(c, NULL, status);
2357 shutdown SMB pipe connection
2359 struct dcerpc_shutdown_pipe_state {
2360 struct dcecli_connection *c;
2364 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2366 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2368 struct dcerpc_shutdown_pipe_state *state;
2369 struct tevent_req *subreq;
2371 if (c->transport.stream == NULL) {
2372 return NT_STATUS_OK;
2375 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2376 if (state == NULL) {
2377 return NT_STATUS_NO_MEMORY;
2380 state->status = status;
2382 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2383 if (subreq == NULL) {
2384 return NT_STATUS_NO_MEMORY;
2386 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2391 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2393 struct dcerpc_shutdown_pipe_state *state =
2394 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2395 struct dcecli_connection *c = state->c;
2396 NTSTATUS status = state->status;
2400 * here we ignore the return values...
2402 tstream_disconnect_recv(subreq, &error);
2403 TALLOC_FREE(subreq);
2407 dcerpc_transport_dead(c, status);
2412 struct dcerpc_send_read_state {
2413 struct dcecli_connection *p;
2416 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2418 struct dcecli_connection *p = state->p;
2420 p->transport.read_subreq = NULL;
2425 static void dcerpc_send_read_done(struct tevent_req *subreq);
2427 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2429 struct dcerpc_send_read_state *state;
2431 if (p->transport.read_subreq != NULL) {
2432 p->transport.pending_reads++;
2433 return NT_STATUS_OK;
2436 state = talloc_zero(p, struct dcerpc_send_read_state);
2437 if (state == NULL) {
2438 return NT_STATUS_NO_MEMORY;
2442 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2444 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2446 p->transport.stream);
2447 if (p->transport.read_subreq == NULL) {
2448 return NT_STATUS_NO_MEMORY;
2450 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2452 return NT_STATUS_OK;
2455 static void dcerpc_send_read_done(struct tevent_req *subreq)
2457 struct dcerpc_send_read_state *state =
2458 tevent_req_callback_data(subreq,
2459 struct dcerpc_send_read_state);
2460 struct dcecli_connection *p = state->p;
2462 struct ncacn_packet *pkt;
2465 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2467 TALLOC_FREE(subreq);
2468 if (!NT_STATUS_IS_OK(status)) {
2470 dcerpc_transport_dead(p, status);
2473 NDR_PRINT_DEBUG(ncacn_packet, pkt);
2475 * here we steal into thet connection context,
2476 * but p->transport.recv_data() will steal or free it again
2478 talloc_steal(p, blob.data);
2481 if (p->transport.pending_reads > 0) {
2482 p->transport.pending_reads--;
2484 status = dcerpc_send_read(p);
2485 if (!NT_STATUS_IS_OK(status)) {
2486 dcerpc_transport_dead(p, status);
2491 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2494 struct dcerpc_send_request_state {
2495 struct dcecli_connection *p;
2500 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2502 struct dcecli_connection *p = state->p;
2504 p->transport.read_subreq = NULL;
2509 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2510 static void dcerpc_send_request_done(struct tevent_req *subreq);
2512 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2515 struct dcerpc_send_request_state *state;
2516 struct tevent_req *subreq;
2517 bool use_trans = trigger_read;
2519 if (p->transport.stream == NULL) {
2520 return NT_STATUS_CONNECTION_DISCONNECTED;
2523 state = talloc_zero(p, struct dcerpc_send_request_state);
2524 if (state == NULL) {
2525 return NT_STATUS_NO_MEMORY;
2529 state->blob = data_blob_talloc(state, data->data, data->length);
2530 if (state->blob.data == NULL) {
2532 return NT_STATUS_NO_MEMORY;
2534 state->iov.iov_base = (void *)state->blob.data;
2535 state->iov.iov_len = state->blob.length;
2537 if (p->transport.read_subreq != NULL) {
2541 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2547 * we need to block reads until our write is
2548 * the next in the write queue.
2550 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2551 p->transport.write_queue);
2552 if (p->transport.read_subreq == NULL) {
2554 return NT_STATUS_NO_MEMORY;
2556 tevent_req_set_callback(p->transport.read_subreq,
2557 dcerpc_send_request_wait_done,
2560 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2562 trigger_read = false;
2565 subreq = tstream_writev_queue_send(state, p->event_ctx,
2566 p->transport.stream,
2567 p->transport.write_queue,
2569 if (subreq == NULL) {
2571 return NT_STATUS_NO_MEMORY;
2573 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2576 dcerpc_send_read(p);
2579 return NT_STATUS_OK;
2582 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2584 struct dcerpc_send_request_state *state =
2585 tevent_req_callback_data(subreq,
2586 struct dcerpc_send_request_state);
2587 struct dcecli_connection *p = state->p;
2591 p->transport.read_subreq = NULL;
2592 talloc_set_destructor(state, NULL);
2594 ok = tevent_queue_wait_recv(subreq);
2597 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2601 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2602 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2603 if (!NT_STATUS_IS_OK(status)) {
2605 dcerpc_transport_dead(p, status);
2610 /* we free subreq after tstream_cli_np_use_trans */
2611 TALLOC_FREE(subreq);
2613 dcerpc_send_read(p);
2616 static void dcerpc_send_request_done(struct tevent_req *subreq)
2618 struct dcerpc_send_request_state *state =
2619 tevent_req_callback_data(subreq,
2620 struct dcerpc_send_request_state);
2624 ret = tstream_writev_queue_recv(subreq, &error);
2625 TALLOC_FREE(subreq);
2627 struct dcecli_connection *p = state->p;
2628 NTSTATUS status = map_nt_error_from_unix_common(error);
2631 dcerpc_transport_dead(p, status);