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;
72 void (*callback)(struct rpc_request *);
77 _PUBLIC_ NTSTATUS dcerpc_init(void)
82 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
83 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
85 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
86 struct dcerpc_pipe *p,
87 const struct GUID *object,
89 DATA_BLOB *stub_data);
90 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
92 DATA_BLOB *stub_data);
93 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
97 ndr_push_flags_fn_t ndr_push,
98 ndr_pull_flags_fn_t ndr_pull);
99 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
100 struct ndr_pull *pull_in,
103 ndr_push_flags_fn_t ndr_push,
104 ndr_pull_flags_fn_t ndr_pull,
105 ndr_print_function_t ndr_print);
106 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
107 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
109 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
111 /* destroy a dcerpc connection */
112 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
115 conn->free_skipped = true;
118 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
123 /* initialise a dcerpc connection.
124 the event context is optional
126 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
127 struct tevent_context *ev)
129 struct dcecli_connection *c;
131 c = talloc_zero(mem_ctx, struct dcecli_connection);
138 if (c->event_ctx == NULL) {
144 c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
145 c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
146 c->security_state.auth_context_id = 0;
147 c->security_state.session_key = dcerpc_generic_session_key;
148 c->security_state.generic_state = NULL;
151 * Windows uses 5840 for ncacn_ip_tcp,
152 * so we also use it (for every transport)
153 * by default. But we give the transport
154 * the chance to overwrite it.
156 c->srv_max_xmit_frag = 5840;
157 c->srv_max_recv_frag = 5840;
158 c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
161 c->io_trigger = tevent_create_immediate(c);
162 if (c->io_trigger == NULL) {
167 talloc_set_destructor(c, dcerpc_connection_destructor);
172 struct dcerpc_bh_state {
173 struct dcerpc_pipe *p;
176 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
178 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
179 struct dcerpc_bh_state);
189 if (hs->p->conn->dead) {
196 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
199 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
200 struct dcerpc_bh_state);
204 return DCERPC_REQUEST_TIMEOUT;
207 old = hs->p->request_timeout;
208 hs->p->request_timeout = timeout;
213 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
214 enum dcerpc_AuthType *auth_type,
215 enum dcerpc_AuthLevel *auth_level)
217 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
218 struct dcerpc_bh_state);
224 if (hs->p->conn == NULL) {
228 *auth_type = hs->p->conn->security_state.auth_type;
229 *auth_level = hs->p->conn->security_state.auth_level;
232 struct dcerpc_bh_raw_call_state {
233 struct tevent_context *ev;
234 struct dcerpc_binding_handle *h;
240 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
242 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
243 struct tevent_context *ev,
244 struct dcerpc_binding_handle *h,
245 const struct GUID *object,
248 const uint8_t *in_data,
251 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
252 struct dcerpc_bh_state);
253 struct tevent_req *req;
254 struct dcerpc_bh_raw_call_state *state;
256 struct rpc_request *subreq;
258 req = tevent_req_create(mem_ctx, &state,
259 struct dcerpc_bh_raw_call_state);
265 state->in_data.data = discard_const_p(uint8_t, in_data);
266 state->in_data.length = in_length;
268 ok = dcerpc_bh_is_connected(h);
270 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
271 return tevent_req_post(req, ev);
274 subreq = dcerpc_request_send(state,
279 if (tevent_req_nomem(subreq, req)) {
280 return tevent_req_post(req, ev);
282 subreq->async.callback = dcerpc_bh_raw_call_done;
283 subreq->async.private_data = req;
288 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
290 struct tevent_req *req =
291 talloc_get_type_abort(subreq->async.private_data,
293 struct dcerpc_bh_raw_call_state *state =
295 struct dcerpc_bh_raw_call_state);
299 state->out_flags = 0;
300 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
301 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
304 fault_code = subreq->fault_code;
306 status = dcerpc_request_recv(subreq, state, &state->out_data);
307 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
308 status = dcerpc_fault_to_nt_status(fault_code);
312 * We trigger the callback in the next event run
313 * because the code in this file might trigger
314 * multiple request callbacks from within a single
317 * In order to avoid segfaults from within
318 * dcerpc_connection_dead() we call
319 * tevent_req_defer_callback().
321 tevent_req_defer_callback(req, state->ev);
323 if (!NT_STATUS_IS_OK(status)) {
324 tevent_req_nterror(req, status);
328 tevent_req_done(req);
331 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
337 struct dcerpc_bh_raw_call_state *state =
339 struct dcerpc_bh_raw_call_state);
342 if (tevent_req_is_nterror(req, &status)) {
343 tevent_req_received(req);
347 *out_data = talloc_move(mem_ctx, &state->out_data.data);
348 *out_length = state->out_data.length;
349 *out_flags = state->out_flags;
350 tevent_req_received(req);
354 struct dcerpc_bh_disconnect_state {
358 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
359 struct tevent_context *ev,
360 struct dcerpc_binding_handle *h)
362 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
363 struct dcerpc_bh_state);
364 struct tevent_req *req;
365 struct dcerpc_bh_disconnect_state *state;
368 req = tevent_req_create(mem_ctx, &state,
369 struct dcerpc_bh_disconnect_state);
374 ok = dcerpc_bh_is_connected(h);
376 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
377 return tevent_req_post(req, ev);
380 /* TODO: do a real disconnect ... */
383 tevent_req_done(req);
384 return tevent_req_post(req, ev);
387 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
391 if (tevent_req_is_nterror(req, &status)) {
392 tevent_req_received(req);
396 tevent_req_received(req);
400 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
402 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
403 struct dcerpc_bh_state);
405 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
412 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
414 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
415 struct dcerpc_bh_state);
417 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
424 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
426 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
427 struct dcerpc_bh_state);
429 if (hs->p->conn->flags & DCERPC_NDR64) {
436 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
438 const void *_struct_ptr,
439 const struct ndr_interface_call *call)
441 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
442 struct dcerpc_bh_state);
443 void *struct_ptr = discard_const(_struct_ptr);
444 bool print_in = false;
445 bool print_out = false;
447 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
451 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
455 if (DEBUGLEVEL >= 11) {
460 if (ndr_flags & NDR_IN) {
462 ndr_print_function_debug(call->ndr_print,
468 if (ndr_flags & NDR_OUT) {
470 ndr_print_function_debug(call->ndr_print,
478 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
480 const void *struct_ptr,
481 const struct ndr_interface_call *call)
483 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
484 call->name, nt_errstr(error)));
487 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
489 const DATA_BLOB *blob,
490 const struct ndr_interface_call *call)
492 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
493 struct dcerpc_bh_state);
494 const uint32_t num_examples = 20;
497 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
498 call->name, nt_errstr(error)));
500 if (hs->p->conn->packet_log_dir == NULL) return;
502 for (i=0;i<num_examples;i++) {
506 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
507 hs->p->conn->packet_log_dir,
512 if (!file_exist(name)) {
513 if (file_save(name, blob->data, blob->length)) {
514 DEBUG(10,("Logged rpc packet to %s\n", name));
523 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
525 const DATA_BLOB *blob,
526 const struct ndr_interface_call *call)
528 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
529 struct dcerpc_bh_state);
531 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
534 status = dcerpc_ndr_validate_in(hs->p->conn,
540 if (!NT_STATUS_IS_OK(status)) {
541 DEBUG(0,("Validation [in] failed for %s - %s\n",
542 call->name, nt_errstr(status)));
547 DEBUG(10,("rpc request data:\n"));
548 dump_data(10, blob->data, blob->length);
553 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
554 struct ndr_pull *pull_in,
555 const void *_struct_ptr,
556 const struct ndr_interface_call *call)
558 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
559 struct dcerpc_bh_state);
560 void *struct_ptr = discard_const(_struct_ptr);
562 DEBUG(10,("rpc reply data:\n"));
563 dump_data(10, pull_in->data, pull_in->data_size);
565 if (pull_in->offset != pull_in->data_size) {
566 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
567 pull_in->data_size - pull_in->offset,
568 pull_in->offset, pull_in->offset,
570 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
571 but it turns out that early versions of NT
572 (specifically NT3.1) add junk onto the end of rpc
573 packets, so if we want to interoperate at all with
574 those versions then we need to ignore this error */
577 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
580 status = dcerpc_ndr_validate_out(hs->p->conn,
587 if (!NT_STATUS_IS_OK(status)) {
588 DEBUG(2,("Validation [out] failed for %s - %s\n",
589 call->name, nt_errstr(status)));
597 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
599 .is_connected = dcerpc_bh_is_connected,
600 .set_timeout = dcerpc_bh_set_timeout,
601 .auth_info = dcerpc_bh_auth_info,
602 .raw_call_send = dcerpc_bh_raw_call_send,
603 .raw_call_recv = dcerpc_bh_raw_call_recv,
604 .disconnect_send = dcerpc_bh_disconnect_send,
605 .disconnect_recv = dcerpc_bh_disconnect_recv,
607 .push_bigendian = dcerpc_bh_push_bigendian,
608 .ref_alloc = dcerpc_bh_ref_alloc,
609 .use_ndr64 = dcerpc_bh_use_ndr64,
610 .do_ndr_print = dcerpc_bh_do_ndr_print,
611 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
612 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
613 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
614 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
617 /* initialise a dcerpc pipe. */
618 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
620 struct dcerpc_binding_handle *h;
621 struct dcerpc_bh_state *hs;
623 h = dcerpc_binding_handle_create(p,
628 struct dcerpc_bh_state,
635 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
640 /* initialise a dcerpc pipe. */
641 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
643 struct dcerpc_pipe *p;
645 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
650 p->conn = dcerpc_connection_init(p, ev);
651 if (p->conn == NULL) {
656 p->last_fault_code = 0;
658 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
661 ZERO_STRUCT(p->syntax);
662 ZERO_STRUCT(p->transfer_syntax);
665 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
668 p->binding_handle = dcerpc_pipe_binding_handle(p);
669 if (p->binding_handle == NULL) {
679 choose the next call id to use
681 static uint32_t next_call_id(struct dcecli_connection *c)
684 if (c->call_id == 0) {
691 setup for a ndr pull, also setting up any flags from the binding string
693 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
694 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
696 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
698 if (ndr == NULL) return ndr;
700 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
701 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
704 if (c->flags & DCERPC_NDR_REF_ALLOC) {
705 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
708 if (c->flags & DCERPC_NDR64) {
709 ndr->flags |= LIBNDR_FLAG_NDR64;
716 parse the authentication information on a dcerpc response packet
718 static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c,
720 enum dcerpc_pkt_type ptype,
721 uint8_t required_flags,
722 uint8_t optional_flags,
723 uint8_t payload_offset,
724 DATA_BLOB *payload_and_verifier,
725 DATA_BLOB *raw_packet,
726 const struct ncacn_packet *pkt)
728 const struct dcerpc_auth tmp_auth = {
729 .auth_type = c->security_state.auth_type,
730 .auth_level = c->security_state.auth_level,
731 .auth_context_id = c->security_state.auth_context_id,
735 status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
736 c->security_state.generic_state,
742 payload_and_verifier,
745 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
746 return NT_STATUS_INVALID_NETWORK_RESPONSE;
748 if (!NT_STATUS_IS_OK(status)) {
757 push a dcerpc request packet into a blob, possibly signing it.
759 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
760 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
762 struct ncacn_packet *pkt)
764 const struct dcerpc_auth tmp_auth = {
765 .auth_type = c->security_state.auth_type,
766 .auth_level = c->security_state.auth_level,
767 .auth_context_id = c->security_state.auth_context_id,
770 uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
772 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
773 payload_offset += 16;
776 status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
777 c->security_state.generic_state,
781 &pkt->u.request.stub_and_verifier,
783 if (!NT_STATUS_IS_OK(status)) {
792 fill in the fixed values in a dcerpc header
794 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
797 pkt->rpc_vers_minor = 0;
798 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
801 pkt->drep[0] = DCERPC_DREP_LE;
809 map a bind nak reason to a NTSTATUS
811 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
814 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
815 return NT_STATUS_REVISION_MISMATCH;
816 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
817 return NT_STATUS_INVALID_PARAMETER;
821 return NT_STATUS_UNSUCCESSFUL;
824 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
827 return NT_STATUS_RPC_PROTOCOL_ERROR;
830 switch (ack->result) {
831 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
833 * We have not asked for this...
835 return NT_STATUS_RPC_PROTOCOL_ERROR;
840 switch (ack->reason.value) {
841 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
842 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
843 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
844 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
848 return NT_STATUS_UNSUCCESSFUL;
852 remove requests from the pending or queued queues
854 static int dcerpc_req_dequeue(struct rpc_request *req)
856 switch (req->state) {
857 case RPC_REQUEST_QUEUED:
858 DLIST_REMOVE(req->p->conn->request_queue, req);
860 case RPC_REQUEST_PENDING:
861 DLIST_REMOVE(req->p->conn->pending, req);
863 case RPC_REQUEST_DONE:
871 mark the dcerpc connection dead. All outstanding requests get an error
873 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
875 if (conn->dead) return;
879 TALLOC_FREE(conn->io_trigger);
880 conn->io_trigger_pending = false;
882 dcerpc_shutdown_pipe(conn, status);
884 /* all pending requests get the error */
885 while (conn->pending) {
886 struct rpc_request *req = conn->pending;
887 dcerpc_req_dequeue(req);
888 req->state = RPC_REQUEST_DONE;
889 req->status = status;
890 if (req->async.callback) {
891 req->async.callback(req);
895 /* all requests, which are not shipped */
896 while (conn->request_queue) {
897 struct rpc_request *req = conn->request_queue;
898 dcerpc_req_dequeue(req);
899 req->state = RPC_REQUEST_DONE;
900 req->status = status;
901 if (req->async.callback) {
902 req->async.callback(req);
906 talloc_set_destructor(conn, NULL);
907 if (conn->free_skipped) {
913 forward declarations of the recv_data handlers for the types of
914 packets we need to handle
916 static void dcerpc_request_recv_data(struct dcecli_connection *c,
917 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
920 receive a dcerpc reply from the transport. Here we work out what
921 type of reply it is (normal request, bind or alter context) and
922 dispatch to the appropriate handler
924 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
926 struct ncacn_packet pkt;
932 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
933 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
936 /* the transport may be telling us of a severe error, such as
938 if (!NT_STATUS_IS_OK(status)) {
939 data_blob_free(blob);
940 dcerpc_connection_dead(conn, status);
944 /* parse the basic packet to work out what type of response this is */
945 status = dcerpc_pull_ncacn_packet(blob->data, blob, &pkt);
946 if (!NT_STATUS_IS_OK(status)) {
947 data_blob_free(blob);
948 dcerpc_connection_dead(conn, status);
952 dcerpc_request_recv_data(conn, blob, &pkt);
956 handle timeouts of individual dcerpc requests
958 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
959 struct timeval t, void *private_data)
961 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
963 if (req->ignore_timeout) {
964 dcerpc_req_dequeue(req);
965 req->state = RPC_REQUEST_DONE;
966 req->status = NT_STATUS_IO_TIMEOUT;
967 if (req->async.callback) {
968 req->async.callback(req);
973 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
976 struct dcerpc_bind_state {
977 struct tevent_context *ev;
978 struct dcerpc_pipe *p;
981 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
982 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
983 DATA_BLOB *raw_packet,
984 struct ncacn_packet *pkt);
986 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
987 struct tevent_context *ev,
988 struct dcerpc_pipe *p,
989 const struct ndr_syntax_id *syntax,
990 const struct ndr_syntax_id *transfer_syntax)
992 struct tevent_req *req;
993 struct dcerpc_bind_state *state;
994 struct ncacn_packet pkt;
997 struct rpc_request *subreq;
999 struct ndr_syntax_id bind_time_features;
1001 bind_time_features = dcerpc_construct_bind_time_features(
1002 DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
1003 DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
1005 req = tevent_req_create(mem_ctx, &state,
1006 struct dcerpc_bind_state);
1014 p->syntax = *syntax;
1015 p->transfer_syntax = *transfer_syntax;
1017 flags = dcerpc_binding_get_flags(p->binding);
1019 init_ncacn_hdr(p->conn, &pkt);
1021 pkt.ptype = DCERPC_PKT_BIND;
1022 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1023 pkt.call_id = p->conn->call_id;
1024 pkt.auth_length = 0;
1026 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1027 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1030 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1031 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1034 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1035 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1036 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1037 pkt.u.bind.num_contexts = 2;
1038 pkt.u.bind.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
1039 pkt.u.bind.num_contexts);
1040 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1041 return tevent_req_post(req, ev);
1043 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1044 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1045 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1046 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1047 pkt.u.bind.ctx_list[1].context_id = p->context_id + 1;
1048 pkt.u.bind.ctx_list[1].num_transfer_syntaxes = 1;
1049 pkt.u.bind.ctx_list[1].abstract_syntax = p->syntax;
1050 pkt.u.bind.ctx_list[1].transfer_syntaxes = &bind_time_features;
1051 pkt.u.bind.auth_info = data_blob(NULL, 0);
1053 /* construct the NDR form of the packet */
1054 status = ncacn_push_auth(&blob, state, &pkt,
1055 p->conn->security_state.tmp_auth_info.out);
1056 if (tevent_req_nterror(req, status)) {
1057 return tevent_req_post(req, ev);
1061 * we allocate a dcerpc_request so we can be in the same
1062 * request queue as normal requests
1064 subreq = talloc_zero(state, struct rpc_request);
1065 if (tevent_req_nomem(subreq, req)) {
1066 return tevent_req_post(req, ev);
1069 subreq->state = RPC_REQUEST_PENDING;
1070 subreq->call_id = pkt.call_id;
1071 subreq->async.private_data = req;
1072 subreq->async.callback = dcerpc_bind_fail_handler;
1074 subreq->recv_handler = dcerpc_bind_recv_handler;
1075 DLIST_ADD_END(p->conn->pending, subreq);
1076 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1078 status = dcerpc_send_request(p->conn, &blob, true);
1079 if (tevent_req_nterror(req, status)) {
1080 return tevent_req_post(req, ev);
1083 tevent_add_timer(ev, subreq,
1084 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1085 dcerpc_timeout_handler, subreq);
1090 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1092 struct tevent_req *req =
1093 talloc_get_type_abort(subreq->async.private_data,
1095 struct dcerpc_bind_state *state =
1096 tevent_req_data(req,
1097 struct dcerpc_bind_state);
1098 NTSTATUS status = subreq->status;
1100 TALLOC_FREE(subreq);
1103 * We trigger the callback in the next event run
1104 * because the code in this file might trigger
1105 * multiple request callbacks from within a single
1108 * In order to avoid segfaults from within
1109 * dcerpc_connection_dead() we call
1110 * tevent_req_defer_callback().
1112 tevent_req_defer_callback(req, state->ev);
1114 tevent_req_nterror(req, status);
1117 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1118 DATA_BLOB *raw_packet,
1119 struct ncacn_packet *pkt)
1121 struct tevent_req *req =
1122 talloc_get_type_abort(subreq->async.private_data,
1124 struct dcerpc_bind_state *state =
1125 tevent_req_data(req,
1126 struct dcerpc_bind_state);
1127 struct dcecli_connection *conn = state->p->conn;
1128 struct dcecli_security *sec = &conn->security_state;
1129 struct dcerpc_binding *b = NULL;
1134 * Note that pkt is allocated under raw_packet->data,
1135 * while raw_packet->data is a child of subreq.
1137 talloc_steal(state, raw_packet->data);
1138 TALLOC_FREE(subreq);
1141 * We trigger the callback in the next event run
1142 * because the code in this file might trigger
1143 * multiple request callbacks from within a single
1146 * In order to avoid segfaults from within
1147 * dcerpc_connection_dead() we call
1148 * tevent_req_defer_callback().
1150 tevent_req_defer_callback(req, state->ev);
1152 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1153 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1155 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1156 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1158 tevent_req_nterror(req, status);
1162 status = dcerpc_verify_ncacn_packet_header(pkt,
1163 DCERPC_PKT_BIND_ACK,
1164 pkt->u.bind_ack.auth_info.length,
1165 DCERPC_PFC_FLAG_FIRST |
1166 DCERPC_PFC_FLAG_LAST,
1167 DCERPC_PFC_FLAG_CONC_MPX |
1168 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1169 if (!NT_STATUS_IS_OK(status)) {
1170 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1171 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1175 if (pkt->u.bind_ack.num_results < 1) {
1176 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1177 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1181 if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1182 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1183 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1184 pkt->u.bind_ack.ctx_list[0].reason.value,
1185 nt_errstr(status)));
1186 tevent_req_nterror(req, status);
1190 if (pkt->u.bind_ack.num_results >= 2) {
1191 if (pkt->u.bind_ack.ctx_list[1].result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1192 conn->bind_time_features = pkt->u.bind_ack.ctx_list[1].reason.negotiate;
1194 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[1]);
1195 DEBUG(10,("dcerpc: bind_time_feature failed - reason %d - %s\n",
1196 pkt->u.bind_ack.ctx_list[1].reason.value,
1197 nt_errstr(status)));
1198 status = NT_STATUS_OK;
1203 * DCE-RPC 1.1 (c706) specifies
1204 * CONST_MUST_RCV_FRAG_SIZE as 1432
1206 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1207 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1208 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1211 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1212 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1213 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1216 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1217 pkt->u.bind_ack.max_xmit_frag);
1218 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1219 pkt->u.bind_ack.max_recv_frag);
1221 flags = dcerpc_binding_get_flags(state->p->binding);
1223 if ((flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1224 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1225 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1228 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1229 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1230 conn->flags |= DCERPC_HEADER_SIGNING;
1233 /* the bind_ack might contain a reply set of credentials */
1234 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1235 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1236 &pkt->u.bind_ack.auth_info,
1237 sec->tmp_auth_info.in,
1239 if (tevent_req_nterror(req, status)) {
1245 * We're the owner of the binding, so we're allowed to modify it.
1247 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1248 status = dcerpc_binding_set_assoc_group_id(b,
1249 pkt->u.bind_ack.assoc_group_id);
1250 if (tevent_req_nterror(req, status)) {
1254 tevent_req_done(req);
1257 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1259 return tevent_req_simple_recv_ntstatus(req);
1263 perform a continued bind (and auth3)
1265 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1266 TALLOC_CTX *mem_ctx)
1268 struct ncacn_packet pkt;
1273 flags = dcerpc_binding_get_flags(p->binding);
1275 init_ncacn_hdr(p->conn, &pkt);
1277 pkt.ptype = DCERPC_PKT_AUTH3;
1278 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1279 pkt.call_id = next_call_id(p->conn);
1280 pkt.auth_length = 0;
1281 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1283 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1284 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1287 /* construct the NDR form of the packet */
1288 status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1289 p->conn->security_state.tmp_auth_info.out);
1290 if (!NT_STATUS_IS_OK(status)) {
1294 /* send it on its way */
1295 status = dcerpc_send_request(p->conn, &blob, false);
1296 if (!NT_STATUS_IS_OK(status)) {
1300 return NT_STATUS_OK;
1305 process a fragment received from the transport layer during a
1308 This function frees the data
1310 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1311 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1313 struct rpc_request *req;
1314 unsigned int length;
1315 NTSTATUS status = NT_STATUS_OK;
1318 if this is an authenticated connection then parse and check
1319 the auth info. We have to do this before finding the
1320 matching packet, as the request structure might have been
1321 removed due to a timeout, but if it has been we still need
1322 to run the auth routines so that we don't get the sign/seal
1323 info out of step with the server
1325 switch (pkt->ptype) {
1326 case DCERPC_PKT_RESPONSE:
1327 status = ncacn_pull_pkt_auth(c, raw_packet->data,
1328 DCERPC_PKT_RESPONSE,
1329 0, /* required_flags */
1330 DCERPC_PFC_FLAG_FIRST |
1331 DCERPC_PFC_FLAG_LAST,
1332 DCERPC_REQUEST_LENGTH,
1333 &pkt->u.response.stub_and_verifier,
1340 /* find the matching request */
1341 for (req=c->pending;req;req=req->next) {
1342 if (pkt->call_id == req->call_id) break;
1346 /* useful for testing certain vendors RPC servers */
1347 if (req == NULL && c->pending && pkt->call_id == 0) {
1348 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1354 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1355 data_blob_free(raw_packet);
1359 talloc_steal(req, raw_packet->data);
1361 if (req->recv_handler != NULL) {
1362 dcerpc_req_dequeue(req);
1363 req->state = RPC_REQUEST_DONE;
1366 * We have to look at shipping further requests before calling
1367 * the async function, that one might close the pipe
1369 dcerpc_schedule_io_trigger(c);
1371 req->recv_handler(req, raw_packet, pkt);
1375 if (pkt->ptype == DCERPC_PKT_FAULT) {
1376 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1377 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1378 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
1379 dcerpc_connection_dead(c, status);
1382 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1383 dcerpc_connection_dead(c, status);
1386 req->fault_code = pkt->u.fault.status;
1387 req->status = NT_STATUS_NET_WRITE_FAULT;
1391 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1392 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1394 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1398 /* now check the status from the auth routines, and if it failed then fail
1399 this request accordingly */
1400 if (!NT_STATUS_IS_OK(status)) {
1401 dcerpc_connection_dead(c, status);
1405 length = pkt->u.response.stub_and_verifier.length;
1407 if (req->payload.length + length > c->max_total_response_size) {
1408 DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
1409 (unsigned)req->payload.length + length,
1410 (unsigned)c->max_total_response_size));
1411 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1416 req->payload.data = talloc_realloc(req,
1419 req->payload.length + length);
1420 if (!req->payload.data) {
1421 req->status = NT_STATUS_NO_MEMORY;
1424 memcpy(req->payload.data+req->payload.length,
1425 pkt->u.response.stub_and_verifier.data, length);
1426 req->payload.length += length;
1429 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1430 data_blob_free(raw_packet);
1431 dcerpc_send_read(c);
1435 if (req->verify_bitmask1) {
1436 req->p->conn->security_state.verified_bitmask1 = true;
1438 if (req->verify_pcontext) {
1439 req->p->verified_pcontext = true;
1442 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1443 req->flags |= DCERPC_PULL_BIGENDIAN;
1445 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1449 data_blob_free(raw_packet);
1451 /* we've got the full payload */
1452 dcerpc_req_dequeue(req);
1453 req->state = RPC_REQUEST_DONE;
1456 * We have to look at shipping further requests before calling
1457 * the async function, that one might close the pipe
1459 dcerpc_schedule_io_trigger(c);
1461 if (req->async.callback) {
1462 req->async.callback(req);
1466 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1469 perform the send side of a async dcerpc request
1471 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1472 struct dcerpc_pipe *p,
1473 const struct GUID *object,
1475 DATA_BLOB *stub_data)
1477 struct rpc_request *req;
1480 req = talloc_zero(mem_ctx, struct rpc_request);
1486 req->call_id = next_call_id(p->conn);
1487 req->state = RPC_REQUEST_QUEUED;
1489 if (object != NULL) {
1490 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1491 if (req->object == NULL) {
1498 req->request_data.length = stub_data->length;
1499 req->request_data.data = stub_data->data;
1501 status = dcerpc_request_prepare_vt(req);
1502 if (!NT_STATUS_IS_OK(status)) {
1507 DLIST_ADD_END(p->conn->request_queue, req);
1508 talloc_set_destructor(req, dcerpc_req_dequeue);
1510 dcerpc_schedule_io_trigger(p->conn);
1512 if (p->request_timeout) {
1513 tevent_add_timer(p->conn->event_ctx, req,
1514 timeval_current_ofs(p->request_timeout, 0),
1515 dcerpc_timeout_handler, req);
1521 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1523 struct dcecli_security *sec = &req->p->conn->security_state;
1524 struct dcerpc_sec_verification_trailer *t;
1525 struct dcerpc_sec_vt *c = NULL;
1526 struct ndr_push *ndr = NULL;
1527 enum ndr_err_code ndr_err;
1529 if (sec->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1530 return NT_STATUS_OK;
1533 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1535 return NT_STATUS_NO_MEMORY;
1538 if (!sec->verified_bitmask1) {
1539 t->commands = talloc_realloc(t, t->commands,
1540 struct dcerpc_sec_vt,
1541 t->count.count + 1);
1542 if (t->commands == NULL) {
1543 return NT_STATUS_NO_MEMORY;
1545 c = &t->commands[t->count.count++];
1548 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1549 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1550 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1552 req->verify_bitmask1 = true;
1555 if (!req->p->verified_pcontext) {
1556 t->commands = talloc_realloc(t, t->commands,
1557 struct dcerpc_sec_vt,
1558 t->count.count + 1);
1559 if (t->commands == NULL) {
1560 return NT_STATUS_NO_MEMORY;
1562 c = &t->commands[t->count.count++];
1565 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1566 c->u.pcontext.abstract_syntax = req->p->syntax;
1567 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1569 req->verify_pcontext = true;
1572 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1573 t->commands = talloc_realloc(t, t->commands,
1574 struct dcerpc_sec_vt,
1575 t->count.count + 1);
1576 if (t->commands == NULL) {
1577 return NT_STATUS_NO_MEMORY;
1579 c = &t->commands[t->count.count++];
1582 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1583 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1584 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1585 c->u.header2.drep[0] = 0;
1587 c->u.header2.drep[0] = DCERPC_DREP_LE;
1589 c->u.header2.drep[1] = 0;
1590 c->u.header2.drep[2] = 0;
1591 c->u.header2.drep[3] = 0;
1592 c->u.header2.call_id = req->call_id;
1593 c->u.header2.context_id = req->p->context_id;
1594 c->u.header2.opnum = req->opnum;
1597 if (t->count.count == 0) {
1599 return NT_STATUS_OK;
1602 c = &t->commands[t->count.count - 1];
1603 c->command |= DCERPC_SEC_VT_COMMAND_END;
1605 if (DEBUGLEVEL >= 10) {
1606 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1609 ndr = ndr_push_init_ctx(req);
1611 return NT_STATUS_NO_MEMORY;
1615 * for now we just copy and append
1618 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1619 req->request_data.length);
1620 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1621 return ndr_map_error2ntstatus(ndr_err);
1624 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1625 NDR_SCALARS | NDR_BUFFERS,
1627 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1628 return ndr_map_error2ntstatus(ndr_err);
1630 req->request_data = ndr_push_blob(ndr);
1632 return NT_STATUS_OK;
1636 Send a request using the transport
1639 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1641 struct rpc_request *req;
1642 struct dcerpc_pipe *p;
1643 DATA_BLOB *stub_data;
1644 struct ncacn_packet pkt;
1646 uint32_t remaining, chunk_size;
1647 bool first_packet = true;
1648 size_t sig_size = 0;
1649 bool need_async = false;
1650 bool can_async = true;
1652 req = c->request_queue;
1658 stub_data = &req->request_data;
1664 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1665 can_async = gensec_have_feature(c->security_state.generic_state,
1666 GENSEC_FEATURE_ASYNC_REPLIES);
1669 if (need_async && !can_async) {
1670 req->wait_for_sync = true;
1674 DLIST_REMOVE(c->request_queue, req);
1675 DLIST_ADD(c->pending, req);
1676 req->state = RPC_REQUEST_PENDING;
1678 init_ncacn_hdr(p->conn, &pkt);
1680 remaining = stub_data->length;
1682 /* we can write a full max_recv_frag size, minus the dcerpc
1683 request header size */
1684 chunk_size = p->conn->srv_max_recv_frag;
1685 chunk_size -= DCERPC_REQUEST_LENGTH;
1686 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1687 size_t max_payload = chunk_size;
1689 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1690 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1692 sig_size = gensec_sig_size(c->security_state.generic_state,
1695 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1696 chunk_size -= sig_size;
1699 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1701 pkt.ptype = DCERPC_PKT_REQUEST;
1702 pkt.call_id = req->call_id;
1703 pkt.auth_length = 0;
1705 pkt.u.request.context_id = p->context_id;
1706 pkt.u.request.opnum = req->opnum;
1709 pkt.u.request.object.object = *req->object;
1710 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1711 chunk_size -= ndr_size_GUID(req->object,0);
1714 /* we send a series of pdus without waiting for a reply */
1715 while (remaining > 0 || first_packet) {
1716 uint32_t chunk = MIN(chunk_size, remaining);
1717 bool last_frag = false;
1718 bool do_trans = false;
1720 first_packet = false;
1721 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1723 if (remaining == stub_data->length) {
1724 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1726 if (chunk == remaining) {
1727 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1731 pkt.u.request.alloc_hint = remaining;
1732 pkt.u.request.stub_and_verifier.data = stub_data->data +
1733 (stub_data->length - remaining);
1734 pkt.u.request.stub_and_verifier.length = chunk;
1736 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1737 if (!NT_STATUS_IS_OK(req->status)) {
1738 req->state = RPC_REQUEST_DONE;
1739 DLIST_REMOVE(p->conn->pending, req);
1743 if (last_frag && !need_async) {
1747 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1748 if (!NT_STATUS_IS_OK(req->status)) {
1749 req->state = RPC_REQUEST_DONE;
1750 DLIST_REMOVE(p->conn->pending, req);
1754 if (last_frag && !do_trans) {
1755 req->status = dcerpc_send_read(p->conn);
1756 if (!NT_STATUS_IS_OK(req->status)) {
1757 req->state = RPC_REQUEST_DONE;
1758 DLIST_REMOVE(p->conn->pending, req);
1767 static void dcerpc_io_trigger(struct tevent_context *ctx,
1768 struct tevent_immediate *im,
1771 struct dcecli_connection *c =
1772 talloc_get_type_abort(private_data,
1773 struct dcecli_connection);
1775 c->io_trigger_pending = false;
1777 dcerpc_schedule_io_trigger(c);
1779 dcerpc_ship_next_request(c);
1782 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1788 if (c->request_queue == NULL) {
1792 if (c->request_queue->wait_for_sync && c->pending) {
1796 if (c->io_trigger_pending) {
1800 c->io_trigger_pending = true;
1802 tevent_schedule_immediate(c->io_trigger,
1809 perform the receive side of a async dcerpc request
1811 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1812 TALLOC_CTX *mem_ctx,
1813 DATA_BLOB *stub_data)
1817 while (req->state != RPC_REQUEST_DONE) {
1818 struct tevent_context *ctx = req->p->conn->event_ctx;
1819 if (tevent_loop_once(ctx) != 0) {
1820 return NT_STATUS_CONNECTION_DISCONNECTED;
1823 *stub_data = req->payload;
1824 status = req->status;
1825 if (stub_data->data) {
1826 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1828 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1829 req->p->last_fault_code = req->fault_code;
1831 talloc_unlink(talloc_parent(req), req);
1836 this is a paranoid NDR validator. For every packet we push onto the wire
1837 we pull it back again, then push it again. Then we compare the raw NDR data
1838 for that to the NDR we initially generated. If they don't match then we know
1839 we must have a bug in either the pull or push side of our code
1841 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1842 TALLOC_CTX *mem_ctx,
1845 ndr_push_flags_fn_t ndr_push,
1846 ndr_pull_flags_fn_t ndr_pull)
1849 struct ndr_pull *pull;
1850 struct ndr_push *push;
1852 enum ndr_err_code ndr_err;
1854 st = talloc_size(mem_ctx, struct_size);
1856 return NT_STATUS_NO_MEMORY;
1859 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1861 return NT_STATUS_NO_MEMORY;
1863 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1865 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1866 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1869 if (c->flags & DCERPC_NDR64) {
1870 pull->flags |= LIBNDR_FLAG_NDR64;
1873 ndr_err = ndr_pull(pull, NDR_IN, st);
1874 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1875 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1876 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1877 "failed input validation pull - %s",
1879 return ndr_map_error2ntstatus(ndr_err);
1882 push = ndr_push_init_ctx(mem_ctx);
1884 return NT_STATUS_NO_MEMORY;
1887 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1888 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1891 if (c->flags & DCERPC_NDR64) {
1892 push->flags |= LIBNDR_FLAG_NDR64;
1895 ndr_err = ndr_push(push, NDR_IN, st);
1896 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1897 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1898 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1899 "failed input validation push - %s",
1901 return ndr_map_error2ntstatus(ndr_err);
1904 blob2 = ndr_push_blob(push);
1906 if (data_blob_cmp(&blob, &blob2) != 0) {
1907 DEBUG(3,("original:\n"));
1908 dump_data(3, blob.data, blob.length);
1909 DEBUG(3,("secondary:\n"));
1910 dump_data(3, blob2.data, blob2.length);
1911 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1912 "failed input validation blobs doesn't match");
1913 return ndr_map_error2ntstatus(ndr_err);
1916 return NT_STATUS_OK;
1920 this is a paranoid NDR input validator. For every packet we pull
1921 from the wire we push it back again then pull and push it
1922 again. Then we compare the raw NDR data for that to the NDR we
1923 initially generated. If they don't match then we know we must have a
1924 bug in either the pull or push side of our code
1926 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1927 struct ndr_pull *pull_in,
1930 ndr_push_flags_fn_t ndr_push,
1931 ndr_pull_flags_fn_t ndr_pull,
1932 ndr_print_function_t ndr_print)
1935 struct ndr_pull *pull;
1936 struct ndr_push *push;
1937 DATA_BLOB blob, blob2;
1938 TALLOC_CTX *mem_ctx = pull_in;
1940 enum ndr_err_code ndr_err;
1942 st = talloc_size(mem_ctx, struct_size);
1944 return NT_STATUS_NO_MEMORY;
1946 memcpy(st, struct_ptr, struct_size);
1948 push = ndr_push_init_ctx(mem_ctx);
1950 return NT_STATUS_NO_MEMORY;
1953 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1954 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1955 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1956 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1957 "failed output validation push - %s",
1959 return ndr_map_error2ntstatus(ndr_err);
1962 blob = ndr_push_blob(push);
1964 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1966 return NT_STATUS_NO_MEMORY;
1969 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1970 ndr_err = ndr_pull(pull, NDR_OUT, st);
1971 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1972 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1973 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1974 "failed output validation pull - %s",
1976 return ndr_map_error2ntstatus(ndr_err);
1979 push = ndr_push_init_ctx(mem_ctx);
1981 return NT_STATUS_NO_MEMORY;
1984 ndr_err = ndr_push(push, NDR_OUT, st);
1985 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1986 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1987 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1988 "failed output validation push2 - %s",
1990 return ndr_map_error2ntstatus(ndr_err);
1993 blob2 = ndr_push_blob(push);
1995 if (data_blob_cmp(&blob, &blob2) != 0) {
1996 DEBUG(3,("original:\n"));
1997 dump_data(3, blob.data, blob.length);
1998 DEBUG(3,("secondary:\n"));
1999 dump_data(3, blob2.data, blob2.length);
2000 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2001 "failed output validation blobs doesn't match");
2002 return ndr_map_error2ntstatus(ndr_err);
2005 /* this checks the printed forms of the two structures, which effectively
2006 tests all of the value() attributes */
2007 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2008 NDR_OUT, struct_ptr);
2009 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2011 if (strcmp(s1, s2) != 0) {
2013 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2015 /* this is sometimes useful */
2016 printf("VALIDATE ERROR\n");
2017 file_save("wire.dat", s1, strlen(s1));
2018 file_save("gen.dat", s2, strlen(s2));
2019 system("diff -u wire.dat gen.dat");
2021 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2022 "failed output validation strings doesn't match");
2023 return ndr_map_error2ntstatus(ndr_err);
2026 return NT_STATUS_OK;
2030 a useful function for retrieving the server name we connected to
2032 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2034 return p->conn ? p->conn->server_name : NULL;
2039 get the dcerpc auth_level for a open connection
2041 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2045 if (c->flags & DCERPC_SEAL) {
2046 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2047 } else if (c->flags & DCERPC_SIGN) {
2048 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2049 } else if (c->flags & DCERPC_CONNECT) {
2050 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2051 } else if (c->flags & DCERPC_PACKET) {
2052 auth_level = DCERPC_AUTH_LEVEL_PACKET;
2054 auth_level = DCERPC_AUTH_LEVEL_NONE;
2059 struct dcerpc_alter_context_state {
2060 struct tevent_context *ev;
2061 struct dcerpc_pipe *p;
2064 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2065 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2066 DATA_BLOB *raw_packet,
2067 struct ncacn_packet *pkt);
2069 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2070 struct tevent_context *ev,
2071 struct dcerpc_pipe *p,
2072 const struct ndr_syntax_id *syntax,
2073 const struct ndr_syntax_id *transfer_syntax)
2075 struct tevent_req *req;
2076 struct dcerpc_alter_context_state *state;
2077 struct ncacn_packet pkt;
2080 struct rpc_request *subreq;
2083 req = tevent_req_create(mem_ctx, &state,
2084 struct dcerpc_alter_context_state);
2092 p->syntax = *syntax;
2093 p->transfer_syntax = *transfer_syntax;
2095 flags = dcerpc_binding_get_flags(p->binding);
2097 init_ncacn_hdr(p->conn, &pkt);
2099 pkt.ptype = DCERPC_PKT_ALTER;
2100 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2101 pkt.call_id = p->conn->call_id;
2102 pkt.auth_length = 0;
2104 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2105 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2108 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2109 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2110 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2111 pkt.u.alter.num_contexts = 1;
2112 pkt.u.alter.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
2113 pkt.u.alter.num_contexts);
2114 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2115 return tevent_req_post(req, ev);
2117 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2118 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2119 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2120 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2121 pkt.u.alter.auth_info = data_blob(NULL, 0);
2123 /* construct the NDR form of the packet */
2124 status = ncacn_push_auth(&blob, state, &pkt,
2125 p->conn->security_state.tmp_auth_info.out);
2126 if (tevent_req_nterror(req, status)) {
2127 return tevent_req_post(req, ev);
2131 * we allocate a dcerpc_request so we can be in the same
2132 * request queue as normal requests
2134 subreq = talloc_zero(state, struct rpc_request);
2135 if (tevent_req_nomem(subreq, req)) {
2136 return tevent_req_post(req, ev);
2139 subreq->state = RPC_REQUEST_PENDING;
2140 subreq->call_id = pkt.call_id;
2141 subreq->async.private_data = req;
2142 subreq->async.callback = dcerpc_alter_context_fail_handler;
2144 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2145 DLIST_ADD_END(p->conn->pending, subreq);
2146 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2148 status = dcerpc_send_request(p->conn, &blob, true);
2149 if (tevent_req_nterror(req, status)) {
2150 return tevent_req_post(req, ev);
2153 tevent_add_timer(ev, subreq,
2154 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2155 dcerpc_timeout_handler, subreq);
2160 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2162 struct tevent_req *req =
2163 talloc_get_type_abort(subreq->async.private_data,
2165 struct dcerpc_alter_context_state *state =
2166 tevent_req_data(req,
2167 struct dcerpc_alter_context_state);
2168 NTSTATUS status = subreq->status;
2170 TALLOC_FREE(subreq);
2173 * We trigger the callback in the next event run
2174 * because the code in this file might trigger
2175 * multiple request callbacks from within a single
2178 * In order to avoid segfaults from within
2179 * dcerpc_connection_dead() we call
2180 * tevent_req_defer_callback().
2182 tevent_req_defer_callback(req, state->ev);
2184 tevent_req_nterror(req, status);
2187 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2188 DATA_BLOB *raw_packet,
2189 struct ncacn_packet *pkt)
2191 struct tevent_req *req =
2192 talloc_get_type_abort(subreq->async.private_data,
2194 struct dcerpc_alter_context_state *state =
2195 tevent_req_data(req,
2196 struct dcerpc_alter_context_state);
2197 struct dcecli_connection *conn = state->p->conn;
2198 struct dcecli_security *sec = &conn->security_state;
2202 * Note that pkt is allocated under raw_packet->data,
2203 * while raw_packet->data is a child of subreq.
2205 talloc_steal(state, raw_packet->data);
2206 TALLOC_FREE(subreq);
2209 * We trigger the callback in the next event run
2210 * because the code in this file might trigger
2211 * multiple request callbacks from within a single
2214 * In order to avoid segfaults from within
2215 * dcerpc_connection_dead() we call
2216 * tevent_req_defer_callback().
2218 tevent_req_defer_callback(req, state->ev);
2220 if (pkt->ptype == DCERPC_PKT_FAULT) {
2221 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2222 dcerpc_errstr(state, pkt->u.fault.status)));
2223 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2224 state->p->last_fault_code = pkt->u.fault.status;
2225 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2226 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2227 state->p->last_fault_code = pkt->u.fault.status;
2228 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2230 state->p->last_fault_code = pkt->u.fault.status;
2231 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2232 tevent_req_nterror(req, status);
2237 status = dcerpc_verify_ncacn_packet_header(pkt,
2238 DCERPC_PKT_ALTER_RESP,
2239 pkt->u.alter_resp.auth_info.length,
2240 DCERPC_PFC_FLAG_FIRST |
2241 DCERPC_PFC_FLAG_LAST,
2242 DCERPC_PFC_FLAG_CONC_MPX |
2243 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2244 if (!NT_STATUS_IS_OK(status)) {
2245 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2246 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2250 if (pkt->u.alter_resp.num_results != 1) {
2251 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2252 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2256 if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2257 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2258 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2259 pkt->u.alter_resp.ctx_list[0].reason.value,
2260 nt_errstr(status)));
2261 tevent_req_nterror(req, status);
2265 /* the alter_resp might contain a reply set of credentials */
2266 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2267 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2268 &pkt->u.alter_resp.auth_info,
2269 sec->tmp_auth_info.in,
2271 if (tevent_req_nterror(req, status)) {
2276 tevent_req_done(req);
2279 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2281 return tevent_req_simple_recv_ntstatus(req);
2285 send a dcerpc alter_context request
2287 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2288 TALLOC_CTX *mem_ctx,
2289 const struct ndr_syntax_id *syntax,
2290 const struct ndr_syntax_id *transfer_syntax)
2292 struct tevent_req *subreq;
2293 struct tevent_context *ev = p->conn->event_ctx;
2296 /* TODO: create a new event context here */
2298 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2299 p, syntax, transfer_syntax);
2300 if (subreq == NULL) {
2301 return NT_STATUS_NO_MEMORY;
2304 ok = tevent_req_poll(subreq, ev);
2307 status = map_nt_error_from_unix_common(errno);
2311 return dcerpc_alter_context_recv(subreq);
2314 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2316 if (c->transport.stream == NULL) {
2320 tevent_queue_stop(c->transport.write_queue);
2321 TALLOC_FREE(c->transport.read_subreq);
2322 TALLOC_FREE(c->transport.stream);
2324 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2325 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2328 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2329 status = NT_STATUS_END_OF_FILE;
2332 dcerpc_recv_data(c, NULL, status);
2337 shutdown SMB pipe connection
2339 struct dcerpc_shutdown_pipe_state {
2340 struct dcecli_connection *c;
2344 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2346 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2348 struct dcerpc_shutdown_pipe_state *state;
2349 struct tevent_req *subreq;
2351 if (c->transport.stream == NULL) {
2352 return NT_STATUS_OK;
2355 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2356 if (state == NULL) {
2357 return NT_STATUS_NO_MEMORY;
2360 state->status = status;
2362 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2363 if (subreq == NULL) {
2364 return NT_STATUS_NO_MEMORY;
2366 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2371 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2373 struct dcerpc_shutdown_pipe_state *state =
2374 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2375 struct dcecli_connection *c = state->c;
2376 NTSTATUS status = state->status;
2380 * here we ignore the return values...
2382 tstream_disconnect_recv(subreq, &error);
2383 TALLOC_FREE(subreq);
2387 dcerpc_transport_dead(c, status);
2392 struct dcerpc_send_read_state {
2393 struct dcecli_connection *p;
2396 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2398 struct dcecli_connection *p = state->p;
2400 p->transport.read_subreq = NULL;
2405 static void dcerpc_send_read_done(struct tevent_req *subreq);
2407 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2409 struct dcerpc_send_read_state *state;
2411 if (p->transport.read_subreq != NULL) {
2412 p->transport.pending_reads++;
2413 return NT_STATUS_OK;
2416 state = talloc_zero(p, struct dcerpc_send_read_state);
2417 if (state == NULL) {
2418 return NT_STATUS_NO_MEMORY;
2422 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2424 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2426 p->transport.stream);
2427 if (p->transport.read_subreq == NULL) {
2428 return NT_STATUS_NO_MEMORY;
2430 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2432 return NT_STATUS_OK;
2435 static void dcerpc_send_read_done(struct tevent_req *subreq)
2437 struct dcerpc_send_read_state *state =
2438 tevent_req_callback_data(subreq,
2439 struct dcerpc_send_read_state);
2440 struct dcecli_connection *p = state->p;
2442 struct ncacn_packet *pkt;
2445 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2447 TALLOC_FREE(subreq);
2448 if (!NT_STATUS_IS_OK(status)) {
2450 dcerpc_transport_dead(p, status);
2455 * here we steal into thet connection context,
2456 * but p->transport.recv_data() will steal or free it again
2458 talloc_steal(p, blob.data);
2461 if (p->transport.pending_reads > 0) {
2462 p->transport.pending_reads--;
2464 status = dcerpc_send_read(p);
2465 if (!NT_STATUS_IS_OK(status)) {
2466 dcerpc_transport_dead(p, status);
2471 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2474 struct dcerpc_send_request_state {
2475 struct dcecli_connection *p;
2480 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2482 struct dcecli_connection *p = state->p;
2484 p->transport.read_subreq = NULL;
2489 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2490 static void dcerpc_send_request_done(struct tevent_req *subreq);
2492 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2495 struct dcerpc_send_request_state *state;
2496 struct tevent_req *subreq;
2497 bool use_trans = trigger_read;
2499 if (p->transport.stream == NULL) {
2500 return NT_STATUS_CONNECTION_DISCONNECTED;
2503 state = talloc_zero(p, struct dcerpc_send_request_state);
2504 if (state == NULL) {
2505 return NT_STATUS_NO_MEMORY;
2509 state->blob = data_blob_talloc(state, data->data, data->length);
2510 if (state->blob.data == NULL) {
2512 return NT_STATUS_NO_MEMORY;
2514 state->iov.iov_base = (void *)state->blob.data;
2515 state->iov.iov_len = state->blob.length;
2517 if (p->transport.read_subreq != NULL) {
2521 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2527 * we need to block reads until our write is
2528 * the next in the write queue.
2530 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2531 p->transport.write_queue);
2532 if (p->transport.read_subreq == NULL) {
2534 return NT_STATUS_NO_MEMORY;
2536 tevent_req_set_callback(p->transport.read_subreq,
2537 dcerpc_send_request_wait_done,
2540 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2542 trigger_read = false;
2545 subreq = tstream_writev_queue_send(state, p->event_ctx,
2546 p->transport.stream,
2547 p->transport.write_queue,
2549 if (subreq == NULL) {
2551 return NT_STATUS_NO_MEMORY;
2553 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2556 dcerpc_send_read(p);
2559 return NT_STATUS_OK;
2562 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2564 struct dcerpc_send_request_state *state =
2565 tevent_req_callback_data(subreq,
2566 struct dcerpc_send_request_state);
2567 struct dcecli_connection *p = state->p;
2571 p->transport.read_subreq = NULL;
2572 talloc_set_destructor(state, NULL);
2574 ok = tevent_queue_wait_recv(subreq);
2577 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2581 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2582 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2583 if (!NT_STATUS_IS_OK(status)) {
2585 dcerpc_transport_dead(p, status);
2590 /* we free subreq after tstream_cli_np_use_trans */
2591 TALLOC_FREE(subreq);
2593 dcerpc_send_read(p);
2596 static void dcerpc_send_request_done(struct tevent_req *subreq)
2598 struct dcerpc_send_request_state *state =
2599 tevent_req_callback_data(subreq,
2600 struct dcerpc_send_request_state);
2604 ret = tstream_writev_queue_recv(subreq, &error);
2605 TALLOC_FREE(subreq);
2607 struct dcecli_connection *p = state->p;
2608 NTSTATUS status = map_nt_error_from_unix_common(error);
2611 dcerpc_transport_dead(p, status);