2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "librpc/rpc/rpc_common.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "libcli/smb/tstream_smbXcli_np.h"
39 enum rpc_request_state {
46 handle for an async dcerpc request
49 struct rpc_request *next, *prev;
50 struct dcerpc_pipe *p;
53 enum rpc_request_state state;
58 /* this is used to distinguish bind and alter_context requests
59 from normal requests */
60 void (*recv_handler)(struct rpc_request *conn,
61 DATA_BLOB *blob, struct ncacn_packet *pkt);
63 const struct GUID *object;
65 DATA_BLOB request_data;
70 void (*callback)(struct rpc_request *);
75 _PUBLIC_ NTSTATUS dcerpc_init(void)
80 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
81 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
83 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
84 struct dcerpc_pipe *p,
85 const struct GUID *object,
87 DATA_BLOB *stub_data);
88 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
90 DATA_BLOB *stub_data);
91 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
95 ndr_push_flags_fn_t ndr_push,
96 ndr_pull_flags_fn_t ndr_pull);
97 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
98 struct ndr_pull *pull_in,
101 ndr_push_flags_fn_t ndr_push,
102 ndr_pull_flags_fn_t ndr_pull,
103 ndr_print_function_t ndr_print);
104 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
105 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
107 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
109 /* destroy a dcerpc connection */
110 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
113 conn->free_skipped = true;
116 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
121 /* initialise a dcerpc connection.
122 the event context is optional
124 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
125 struct tevent_context *ev)
127 struct dcecli_connection *c;
129 c = talloc_zero(mem_ctx, struct dcecli_connection);
136 if (c->event_ctx == NULL) {
142 c->security_state.auth_info = NULL;
143 c->security_state.session_key = dcerpc_generic_session_key;
144 c->security_state.generic_state = NULL;
147 * Windows uses 5840 for ncacn_ip_tcp,
148 * so we also use it (for every transport)
149 * by default. But we give the transport
150 * the chance to overwrite it.
152 c->srv_max_xmit_frag = 5840;
153 c->srv_max_recv_frag = 5840;
156 c->io_trigger = tevent_create_immediate(c);
157 if (c->io_trigger == NULL) {
162 talloc_set_destructor(c, dcerpc_connection_destructor);
167 struct dcerpc_bh_state {
168 struct dcerpc_pipe *p;
171 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
173 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
174 struct dcerpc_bh_state);
184 if (hs->p->conn->dead) {
191 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
194 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
195 struct dcerpc_bh_state);
199 return DCERPC_REQUEST_TIMEOUT;
202 old = hs->p->request_timeout;
203 hs->p->request_timeout = timeout;
208 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
209 enum dcerpc_AuthType *auth_type,
210 enum dcerpc_AuthLevel *auth_level)
212 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
213 struct dcerpc_bh_state);
219 if (hs->p->conn == NULL) {
223 if (hs->p->conn->security_state.auth_info == NULL) {
227 *auth_type = hs->p->conn->security_state.auth_info->auth_type;
228 *auth_level = hs->p->conn->security_state.auth_info->auth_level;
231 struct dcerpc_bh_raw_call_state {
232 struct tevent_context *ev;
233 struct dcerpc_binding_handle *h;
239 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
241 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
242 struct tevent_context *ev,
243 struct dcerpc_binding_handle *h,
244 const struct GUID *object,
247 const uint8_t *in_data,
250 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
251 struct dcerpc_bh_state);
252 struct tevent_req *req;
253 struct dcerpc_bh_raw_call_state *state;
255 struct rpc_request *subreq;
257 req = tevent_req_create(mem_ctx, &state,
258 struct dcerpc_bh_raw_call_state);
264 state->in_data.data = discard_const_p(uint8_t, in_data);
265 state->in_data.length = in_length;
267 ok = dcerpc_bh_is_connected(h);
269 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
270 return tevent_req_post(req, ev);
273 subreq = dcerpc_request_send(state,
278 if (tevent_req_nomem(subreq, req)) {
279 return tevent_req_post(req, ev);
281 subreq->async.callback = dcerpc_bh_raw_call_done;
282 subreq->async.private_data = req;
287 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
289 struct tevent_req *req =
290 talloc_get_type_abort(subreq->async.private_data,
292 struct dcerpc_bh_raw_call_state *state =
294 struct dcerpc_bh_raw_call_state);
298 state->out_flags = 0;
299 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
300 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
303 fault_code = subreq->fault_code;
305 status = dcerpc_request_recv(subreq, state, &state->out_data);
306 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
307 status = dcerpc_fault_to_nt_status(fault_code);
311 * We trigger the callback in the next event run
312 * because the code in this file might trigger
313 * multiple request callbacks from within a single
316 * In order to avoid segfaults from within
317 * dcerpc_connection_dead() we call
318 * tevent_req_defer_callback().
320 tevent_req_defer_callback(req, state->ev);
322 if (!NT_STATUS_IS_OK(status)) {
323 tevent_req_nterror(req, status);
327 tevent_req_done(req);
330 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
336 struct dcerpc_bh_raw_call_state *state =
338 struct dcerpc_bh_raw_call_state);
341 if (tevent_req_is_nterror(req, &status)) {
342 tevent_req_received(req);
346 *out_data = talloc_move(mem_ctx, &state->out_data.data);
347 *out_length = state->out_data.length;
348 *out_flags = state->out_flags;
349 tevent_req_received(req);
353 struct dcerpc_bh_disconnect_state {
357 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
358 struct tevent_context *ev,
359 struct dcerpc_binding_handle *h)
361 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
362 struct dcerpc_bh_state);
363 struct tevent_req *req;
364 struct dcerpc_bh_disconnect_state *state;
367 req = tevent_req_create(mem_ctx, &state,
368 struct dcerpc_bh_disconnect_state);
373 ok = dcerpc_bh_is_connected(h);
375 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
376 return tevent_req_post(req, ev);
379 /* TODO: do a real disconnect ... */
382 tevent_req_done(req);
383 return tevent_req_post(req, ev);
386 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
390 if (tevent_req_is_nterror(req, &status)) {
391 tevent_req_received(req);
395 tevent_req_received(req);
399 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
401 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
402 struct dcerpc_bh_state);
404 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
411 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
413 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
414 struct dcerpc_bh_state);
416 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
423 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
425 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
426 struct dcerpc_bh_state);
428 if (hs->p->conn->flags & DCERPC_NDR64) {
435 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
437 const void *_struct_ptr,
438 const struct ndr_interface_call *call)
440 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
441 struct dcerpc_bh_state);
442 void *struct_ptr = discard_const(_struct_ptr);
444 if (ndr_flags & NDR_IN) {
445 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
446 ndr_print_function_debug(call->ndr_print,
452 if (ndr_flags & NDR_OUT) {
453 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
454 ndr_print_function_debug(call->ndr_print,
462 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
464 const void *struct_ptr,
465 const struct ndr_interface_call *call)
467 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
468 call->name, nt_errstr(error)));
471 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
473 const DATA_BLOB *blob,
474 const struct ndr_interface_call *call)
476 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
477 struct dcerpc_bh_state);
478 const uint32_t num_examples = 20;
481 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
482 call->name, nt_errstr(error)));
484 if (hs->p->conn->packet_log_dir == NULL) return;
486 for (i=0;i<num_examples;i++) {
488 asprintf(&name, "%s/rpclog/%s-out.%d",
489 hs->p->conn->packet_log_dir,
494 if (!file_exist(name)) {
495 if (file_save(name, blob->data, blob->length)) {
496 DEBUG(10,("Logged rpc packet to %s\n", name));
505 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
507 const DATA_BLOB *blob,
508 const struct ndr_interface_call *call)
510 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
511 struct dcerpc_bh_state);
513 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
516 status = dcerpc_ndr_validate_in(hs->p->conn,
522 if (!NT_STATUS_IS_OK(status)) {
523 DEBUG(0,("Validation [in] failed for %s - %s\n",
524 call->name, nt_errstr(status)));
529 DEBUG(10,("rpc request data:\n"));
530 dump_data(10, blob->data, blob->length);
535 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
536 struct ndr_pull *pull_in,
537 const void *_struct_ptr,
538 const struct ndr_interface_call *call)
540 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
541 struct dcerpc_bh_state);
542 void *struct_ptr = discard_const(_struct_ptr);
544 DEBUG(10,("rpc reply data:\n"));
545 dump_data(10, pull_in->data, pull_in->data_size);
547 if (pull_in->offset != pull_in->data_size) {
548 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
549 pull_in->data_size - pull_in->offset,
550 pull_in->offset, pull_in->offset,
552 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
553 but it turns out that early versions of NT
554 (specifically NT3.1) add junk onto the end of rpc
555 packets, so if we want to interoperate at all with
556 those versions then we need to ignore this error */
559 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
562 status = dcerpc_ndr_validate_out(hs->p->conn,
569 if (!NT_STATUS_IS_OK(status)) {
570 DEBUG(2,("Validation [out] failed for %s - %s\n",
571 call->name, nt_errstr(status)));
579 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
581 .is_connected = dcerpc_bh_is_connected,
582 .set_timeout = dcerpc_bh_set_timeout,
583 .auth_info = dcerpc_bh_auth_info,
584 .raw_call_send = dcerpc_bh_raw_call_send,
585 .raw_call_recv = dcerpc_bh_raw_call_recv,
586 .disconnect_send = dcerpc_bh_disconnect_send,
587 .disconnect_recv = dcerpc_bh_disconnect_recv,
589 .push_bigendian = dcerpc_bh_push_bigendian,
590 .ref_alloc = dcerpc_bh_ref_alloc,
591 .use_ndr64 = dcerpc_bh_use_ndr64,
592 .do_ndr_print = dcerpc_bh_do_ndr_print,
593 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
594 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
595 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
596 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
599 /* initialise a dcerpc pipe. */
600 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
602 struct dcerpc_binding_handle *h;
603 struct dcerpc_bh_state *hs;
605 h = dcerpc_binding_handle_create(p,
610 struct dcerpc_bh_state,
617 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
622 /* initialise a dcerpc pipe. */
623 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
625 struct dcerpc_pipe *p;
627 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
632 p->conn = dcerpc_connection_init(p, ev);
633 if (p->conn == NULL) {
638 p->last_fault_code = 0;
640 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
643 ZERO_STRUCT(p->syntax);
644 ZERO_STRUCT(p->transfer_syntax);
647 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
650 p->binding_handle = dcerpc_pipe_binding_handle(p);
651 if (p->binding_handle == NULL) {
661 choose the next call id to use
663 static uint32_t next_call_id(struct dcecli_connection *c)
666 if (c->call_id == 0) {
673 setup for a ndr pull, also setting up any flags from the binding string
675 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
676 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
678 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
680 if (ndr == NULL) return ndr;
682 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
683 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
686 if (c->flags & DCERPC_NDR_REF_ALLOC) {
687 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
690 if (c->flags & DCERPC_NDR64) {
691 ndr->flags |= LIBNDR_FLAG_NDR64;
698 parse a data blob into a ncacn_packet structure. This handles both
699 input and output packets
701 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
702 struct ncacn_packet *pkt)
704 struct ndr_pull *ndr;
705 enum ndr_err_code ndr_err;
707 ndr = ndr_pull_init_blob(blob, mem_ctx);
709 return NT_STATUS_NO_MEMORY;
712 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
713 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
716 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
717 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
720 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
722 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
723 return ndr_map_error2ntstatus(ndr_err);
726 if (pkt->frag_length != blob->length) {
727 return NT_STATUS_RPC_PROTOCOL_ERROR;
734 parse the authentication information on a dcerpc response packet
736 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
737 DATA_BLOB *raw_packet,
738 struct ncacn_packet *pkt)
741 struct dcerpc_auth auth;
742 uint32_t auth_length;
744 if (!c->security_state.auth_info ||
745 !c->security_state.generic_state) {
749 switch (c->security_state.auth_info->auth_level) {
750 case DCERPC_AUTH_LEVEL_PRIVACY:
751 case DCERPC_AUTH_LEVEL_INTEGRITY:
754 case DCERPC_AUTH_LEVEL_CONNECT:
755 if (pkt->auth_length != 0) {
759 case DCERPC_AUTH_LEVEL_NONE:
760 if (pkt->auth_length != 0) {
761 return NT_STATUS_INVALID_NETWORK_RESPONSE;
766 return NT_STATUS_INVALID_LEVEL;
769 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
770 &pkt->u.response.stub_and_verifier,
771 &auth, &auth_length, false);
772 NT_STATUS_NOT_OK_RETURN(status);
774 pkt->u.response.stub_and_verifier.length -= auth_length;
776 /* check signature or unseal the packet */
777 switch (c->security_state.auth_info->auth_level) {
778 case DCERPC_AUTH_LEVEL_PRIVACY:
779 status = gensec_unseal_packet(c->security_state.generic_state,
780 raw_packet->data + DCERPC_REQUEST_LENGTH,
781 pkt->u.response.stub_and_verifier.length,
783 raw_packet->length - auth.credentials.length,
785 memcpy(pkt->u.response.stub_and_verifier.data,
786 raw_packet->data + DCERPC_REQUEST_LENGTH,
787 pkt->u.response.stub_and_verifier.length);
790 case DCERPC_AUTH_LEVEL_INTEGRITY:
791 status = gensec_check_packet(c->security_state.generic_state,
792 pkt->u.response.stub_and_verifier.data,
793 pkt->u.response.stub_and_verifier.length,
795 raw_packet->length - auth.credentials.length,
799 case DCERPC_AUTH_LEVEL_CONNECT:
800 /* for now we ignore possible signatures here */
801 status = NT_STATUS_OK;
805 status = NT_STATUS_INVALID_LEVEL;
809 /* remove the indicated amount of padding */
810 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
811 return NT_STATUS_INFO_LENGTH_MISMATCH;
813 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
820 push a dcerpc request packet into a blob, possibly signing it.
822 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
823 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
825 struct ncacn_packet *pkt)
828 struct ndr_push *ndr;
830 size_t payload_length;
831 enum ndr_err_code ndr_err;
832 size_t hdr_size = DCERPC_REQUEST_LENGTH;
834 /* non-signed packets are simpler */
836 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
839 switch (c->security_state.auth_info->auth_level) {
840 case DCERPC_AUTH_LEVEL_PRIVACY:
841 case DCERPC_AUTH_LEVEL_INTEGRITY:
844 case DCERPC_AUTH_LEVEL_CONNECT:
845 /* TODO: let the gensec mech decide if it wants to generate a signature */
846 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
848 case DCERPC_AUTH_LEVEL_NONE:
849 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
852 return NT_STATUS_INVALID_LEVEL;
855 ndr = ndr_push_init_ctx(mem_ctx);
857 return NT_STATUS_NO_MEMORY;
860 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
861 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
864 if (c->flags & DCERPC_NDR64) {
865 ndr->flags |= LIBNDR_FLAG_NDR64;
868 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
869 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
873 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
874 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
875 return ndr_map_error2ntstatus(ndr_err);
878 /* pad to 16 byte multiple in the payload portion of the
879 packet. This matches what w2k3 does. Note that we can't use
880 ndr_push_align() as that is relative to the start of the
881 whole packet, whereas w2k8 wants it relative to the start
883 c->security_state.auth_info->auth_pad_length =
884 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
885 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
886 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
887 return ndr_map_error2ntstatus(ndr_err);
890 payload_length = pkt->u.request.stub_and_verifier.length +
891 c->security_state.auth_info->auth_pad_length;
893 /* we start without signature, it will appended later */
894 c->security_state.auth_info->credentials = data_blob(NULL,0);
896 /* add the auth verifier */
897 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
898 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
899 return ndr_map_error2ntstatus(ndr_err);
902 /* extract the whole packet as a blob */
903 *blob = ndr_push_blob(ndr);
906 * Setup the frag and auth length in the packet buffer.
907 * This is needed if the GENSEC mech does AEAD signing
908 * of the packet headers. The signature itself will be
911 dcerpc_set_frag_length(blob, blob->length + sig_size);
912 dcerpc_set_auth_length(blob, sig_size);
914 /* sign or seal the packet */
915 switch (c->security_state.auth_info->auth_level) {
916 case DCERPC_AUTH_LEVEL_PRIVACY:
917 status = gensec_seal_packet(c->security_state.generic_state,
919 blob->data + hdr_size,
924 if (!NT_STATUS_IS_OK(status)) {
929 case DCERPC_AUTH_LEVEL_INTEGRITY:
930 status = gensec_sign_packet(c->security_state.generic_state,
932 blob->data + hdr_size,
937 if (!NT_STATUS_IS_OK(status)) {
943 status = NT_STATUS_INVALID_LEVEL;
947 if (creds2.length != sig_size) {
948 /* this means the sig_size estimate for the signature
949 was incorrect. We have to correct the packet
950 sizes. That means we could go over the max fragment
952 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
953 (unsigned) creds2.length,
955 (unsigned) c->security_state.auth_info->auth_pad_length,
956 (unsigned) pkt->u.request.stub_and_verifier.length));
957 dcerpc_set_frag_length(blob, blob->length + creds2.length);
958 dcerpc_set_auth_length(blob, creds2.length);
961 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
962 return NT_STATUS_NO_MEMORY;
970 fill in the fixed values in a dcerpc header
972 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
975 pkt->rpc_vers_minor = 0;
976 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
979 pkt->drep[0] = DCERPC_DREP_LE;
987 map a bind nak reason to a NTSTATUS
989 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
992 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
993 return NT_STATUS_REVISION_MISMATCH;
994 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
995 return NT_STATUS_INVALID_PARAMETER;
999 return NT_STATUS_UNSUCCESSFUL;
1002 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
1005 return NT_STATUS_RPC_PROTOCOL_ERROR;
1008 switch (ack->result) {
1009 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
1011 * We have not asked for this...
1013 return NT_STATUS_RPC_PROTOCOL_ERROR;
1018 switch (ack->reason.value) {
1019 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
1020 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1021 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
1022 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1026 return NT_STATUS_UNSUCCESSFUL;
1030 remove requests from the pending or queued queues
1032 static int dcerpc_req_dequeue(struct rpc_request *req)
1034 switch (req->state) {
1035 case RPC_REQUEST_QUEUED:
1036 DLIST_REMOVE(req->p->conn->request_queue, req);
1038 case RPC_REQUEST_PENDING:
1039 DLIST_REMOVE(req->p->conn->pending, req);
1041 case RPC_REQUEST_DONE:
1049 mark the dcerpc connection dead. All outstanding requests get an error
1051 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1053 if (conn->dead) return;
1057 TALLOC_FREE(conn->io_trigger);
1058 conn->io_trigger_pending = false;
1060 dcerpc_shutdown_pipe(conn, status);
1062 /* all pending requests get the error */
1063 while (conn->pending) {
1064 struct rpc_request *req = conn->pending;
1065 dcerpc_req_dequeue(req);
1066 req->state = RPC_REQUEST_DONE;
1067 req->status = status;
1068 if (req->async.callback) {
1069 req->async.callback(req);
1073 /* all requests, which are not shipped */
1074 while (conn->request_queue) {
1075 struct rpc_request *req = conn->request_queue;
1076 dcerpc_req_dequeue(req);
1077 req->state = RPC_REQUEST_DONE;
1078 req->status = status;
1079 if (req->async.callback) {
1080 req->async.callback(req);
1084 talloc_set_destructor(conn, NULL);
1085 if (conn->free_skipped) {
1091 forward declarations of the recv_data handlers for the types of
1092 packets we need to handle
1094 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1095 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1098 receive a dcerpc reply from the transport. Here we work out what
1099 type of reply it is (normal request, bind or alter context) and
1100 dispatch to the appropriate handler
1102 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1104 struct ncacn_packet pkt;
1110 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1111 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1114 /* the transport may be telling us of a severe error, such as
1116 if (!NT_STATUS_IS_OK(status)) {
1117 data_blob_free(blob);
1118 dcerpc_connection_dead(conn, status);
1122 /* parse the basic packet to work out what type of response this is */
1123 status = ncacn_pull(conn, blob, blob->data, &pkt);
1124 if (!NT_STATUS_IS_OK(status)) {
1125 data_blob_free(blob);
1126 dcerpc_connection_dead(conn, status);
1130 dcerpc_request_recv_data(conn, blob, &pkt);
1134 handle timeouts of individual dcerpc requests
1136 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1137 struct timeval t, void *private_data)
1139 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1141 if (req->ignore_timeout) {
1142 dcerpc_req_dequeue(req);
1143 req->state = RPC_REQUEST_DONE;
1144 req->status = NT_STATUS_IO_TIMEOUT;
1145 if (req->async.callback) {
1146 req->async.callback(req);
1151 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1154 struct dcerpc_bind_state {
1155 struct tevent_context *ev;
1156 struct dcerpc_pipe *p;
1159 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1160 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1161 DATA_BLOB *raw_packet,
1162 struct ncacn_packet *pkt);
1164 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1165 struct tevent_context *ev,
1166 struct dcerpc_pipe *p,
1167 const struct ndr_syntax_id *syntax,
1168 const struct ndr_syntax_id *transfer_syntax)
1170 struct tevent_req *req;
1171 struct dcerpc_bind_state *state;
1172 struct ncacn_packet pkt;
1175 struct rpc_request *subreq;
1178 req = tevent_req_create(mem_ctx, &state,
1179 struct dcerpc_bind_state);
1187 p->syntax = *syntax;
1188 p->transfer_syntax = *transfer_syntax;
1190 flags = dcerpc_binding_get_flags(p->binding);
1192 init_ncacn_hdr(p->conn, &pkt);
1194 pkt.ptype = DCERPC_PKT_BIND;
1195 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1196 pkt.call_id = p->conn->call_id;
1197 pkt.auth_length = 0;
1199 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1200 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1203 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1204 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1207 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1208 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1209 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1210 pkt.u.bind.num_contexts = 1;
1211 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1212 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1213 return tevent_req_post(req, ev);
1215 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1216 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1217 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1218 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1219 pkt.u.bind.auth_info = data_blob(NULL, 0);
1221 /* construct the NDR form of the packet */
1222 status = ncacn_push_auth(&blob, state, &pkt,
1223 p->conn->security_state.auth_info);
1224 if (tevent_req_nterror(req, status)) {
1225 return tevent_req_post(req, ev);
1229 * we allocate a dcerpc_request so we can be in the same
1230 * request queue as normal requests
1232 subreq = talloc_zero(state, struct rpc_request);
1233 if (tevent_req_nomem(subreq, req)) {
1234 return tevent_req_post(req, ev);
1237 subreq->state = RPC_REQUEST_PENDING;
1238 subreq->call_id = pkt.call_id;
1239 subreq->async.private_data = req;
1240 subreq->async.callback = dcerpc_bind_fail_handler;
1242 subreq->recv_handler = dcerpc_bind_recv_handler;
1243 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1244 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1246 status = dcerpc_send_request(p->conn, &blob, true);
1247 if (tevent_req_nterror(req, status)) {
1248 return tevent_req_post(req, ev);
1251 tevent_add_timer(ev, subreq,
1252 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1253 dcerpc_timeout_handler, subreq);
1258 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1260 struct tevent_req *req =
1261 talloc_get_type_abort(subreq->async.private_data,
1263 struct dcerpc_bind_state *state =
1264 tevent_req_data(req,
1265 struct dcerpc_bind_state);
1266 NTSTATUS status = subreq->status;
1268 TALLOC_FREE(subreq);
1271 * We trigger the callback in the next event run
1272 * because the code in this file might trigger
1273 * multiple request callbacks from within a single
1276 * In order to avoid segfaults from within
1277 * dcerpc_connection_dead() we call
1278 * tevent_req_defer_callback().
1280 tevent_req_defer_callback(req, state->ev);
1282 tevent_req_nterror(req, status);
1285 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1286 DATA_BLOB *raw_packet,
1287 struct ncacn_packet *pkt)
1289 struct tevent_req *req =
1290 talloc_get_type_abort(subreq->async.private_data,
1292 struct dcerpc_bind_state *state =
1293 tevent_req_data(req,
1294 struct dcerpc_bind_state);
1295 struct dcecli_connection *conn = state->p->conn;
1296 struct dcerpc_binding *b = NULL;
1301 * Note that pkt is allocated under raw_packet->data,
1302 * while raw_packet->data is a child of subreq.
1304 talloc_steal(state, raw_packet->data);
1305 TALLOC_FREE(subreq);
1308 * We trigger the callback in the next event run
1309 * because the code in this file might trigger
1310 * multiple request callbacks from within a single
1313 * In order to avoid segfaults from within
1314 * dcerpc_connection_dead() we call
1315 * tevent_req_defer_callback().
1317 tevent_req_defer_callback(req, state->ev);
1319 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1320 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1322 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1323 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1325 tevent_req_nterror(req, status);
1329 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1330 (pkt->u.bind_ack.num_results == 0) ||
1331 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1332 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1333 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1338 * DCE-RPC 1.1 (c706) specifies
1339 * CONST_MUST_RCV_FRAG_SIZE as 1432
1341 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1342 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1343 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1346 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1347 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1348 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1351 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1352 pkt->u.bind_ack.max_xmit_frag);
1353 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1354 pkt->u.bind_ack.max_recv_frag);
1356 flags = dcerpc_binding_get_flags(state->p->binding);
1358 if ((flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1359 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1360 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1363 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1364 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1365 conn->flags |= DCERPC_HEADER_SIGNING;
1368 /* the bind_ack might contain a reply set of credentials */
1369 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1370 uint32_t auth_length;
1372 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1373 conn->security_state.auth_info, &auth_length, true);
1374 if (tevent_req_nterror(req, status)) {
1380 * We're the owner of the binding, so we're allowed to modify it.
1382 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1383 status = dcerpc_binding_set_assoc_group_id(b,
1384 pkt->u.bind_ack.assoc_group_id);
1385 if (tevent_req_nterror(req, status)) {
1389 tevent_req_done(req);
1392 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1394 return tevent_req_simple_recv_ntstatus(req);
1398 perform a continued bind (and auth3)
1400 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1401 TALLOC_CTX *mem_ctx)
1403 struct ncacn_packet pkt;
1408 flags = dcerpc_binding_get_flags(p->binding);
1410 init_ncacn_hdr(p->conn, &pkt);
1412 pkt.ptype = DCERPC_PKT_AUTH3;
1413 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1414 pkt.call_id = next_call_id(p->conn);
1415 pkt.auth_length = 0;
1416 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1418 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1419 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1422 /* construct the NDR form of the packet */
1423 status = ncacn_push_auth(&blob, mem_ctx,
1425 p->conn->security_state.auth_info);
1426 if (!NT_STATUS_IS_OK(status)) {
1430 /* send it on its way */
1431 status = dcerpc_send_request(p->conn, &blob, false);
1432 if (!NT_STATUS_IS_OK(status)) {
1436 return NT_STATUS_OK;
1441 process a fragment received from the transport layer during a
1444 This function frees the data
1446 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1447 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1449 struct rpc_request *req;
1450 unsigned int length;
1451 NTSTATUS status = NT_STATUS_OK;
1454 if this is an authenticated connection then parse and check
1455 the auth info. We have to do this before finding the
1456 matching packet, as the request structure might have been
1457 removed due to a timeout, but if it has been we still need
1458 to run the auth routines so that we don't get the sign/seal
1459 info out of step with the server
1461 if (c->security_state.auth_info && c->security_state.generic_state &&
1462 pkt->ptype == DCERPC_PKT_RESPONSE) {
1463 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1466 /* find the matching request */
1467 for (req=c->pending;req;req=req->next) {
1468 if (pkt->call_id == req->call_id) break;
1472 /* useful for testing certain vendors RPC servers */
1473 if (req == NULL && c->pending && pkt->call_id == 0) {
1474 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1480 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1481 data_blob_free(raw_packet);
1485 talloc_steal(req, raw_packet->data);
1487 if (req->recv_handler != NULL) {
1488 dcerpc_req_dequeue(req);
1489 req->state = RPC_REQUEST_DONE;
1492 * We have to look at shipping further requests before calling
1493 * the async function, that one might close the pipe
1495 dcerpc_schedule_io_trigger(c);
1497 req->recv_handler(req, raw_packet, pkt);
1501 if (pkt->ptype == DCERPC_PKT_FAULT) {
1502 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1503 req->fault_code = pkt->u.fault.status;
1504 req->status = NT_STATUS_NET_WRITE_FAULT;
1508 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1509 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1511 req->fault_code = DCERPC_FAULT_OTHER;
1512 req->status = NT_STATUS_NET_WRITE_FAULT;
1516 /* now check the status from the auth routines, and if it failed then fail
1517 this request accordingly */
1518 if (!NT_STATUS_IS_OK(status)) {
1519 req->status = status;
1523 length = pkt->u.response.stub_and_verifier.length;
1526 req->payload.data = talloc_realloc(req,
1529 req->payload.length + length);
1530 if (!req->payload.data) {
1531 req->status = NT_STATUS_NO_MEMORY;
1534 memcpy(req->payload.data+req->payload.length,
1535 pkt->u.response.stub_and_verifier.data, length);
1536 req->payload.length += length;
1539 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1540 data_blob_free(raw_packet);
1541 dcerpc_send_read(c);
1545 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1546 req->flags |= DCERPC_PULL_BIGENDIAN;
1548 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1552 data_blob_free(raw_packet);
1554 /* we've got the full payload */
1555 dcerpc_req_dequeue(req);
1556 req->state = RPC_REQUEST_DONE;
1559 * We have to look at shipping further requests before calling
1560 * the async function, that one might close the pipe
1562 dcerpc_schedule_io_trigger(c);
1564 if (req->async.callback) {
1565 req->async.callback(req);
1570 perform the send side of a async dcerpc request
1572 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1573 struct dcerpc_pipe *p,
1574 const struct GUID *object,
1576 DATA_BLOB *stub_data)
1578 struct rpc_request *req;
1580 req = talloc_zero(mem_ctx, struct rpc_request);
1586 req->call_id = next_call_id(p->conn);
1587 req->state = RPC_REQUEST_QUEUED;
1589 if (object != NULL) {
1590 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1591 if (req->object == NULL) {
1598 req->request_data.length = stub_data->length;
1599 req->request_data.data = stub_data->data;
1601 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1602 talloc_set_destructor(req, dcerpc_req_dequeue);
1604 dcerpc_schedule_io_trigger(p->conn);
1606 if (p->request_timeout) {
1607 tevent_add_timer(p->conn->event_ctx, req,
1608 timeval_current_ofs(p->request_timeout, 0),
1609 dcerpc_timeout_handler, req);
1616 Send a request using the transport
1619 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1621 struct rpc_request *req;
1622 struct dcerpc_pipe *p;
1623 DATA_BLOB *stub_data;
1624 struct ncacn_packet pkt;
1626 uint32_t remaining, chunk_size;
1627 bool first_packet = true;
1628 size_t sig_size = 0;
1629 bool need_async = false;
1630 bool can_async = true;
1632 req = c->request_queue;
1638 stub_data = &req->request_data;
1644 if (c->security_state.auth_info &&
1645 c->security_state.generic_state)
1647 struct gensec_security *gensec = c->security_state.generic_state;
1649 switch (c->security_state.auth_info->auth_level) {
1650 case DCERPC_AUTH_LEVEL_PRIVACY:
1651 case DCERPC_AUTH_LEVEL_INTEGRITY:
1652 can_async = gensec_have_feature(gensec,
1653 GENSEC_FEATURE_ASYNC_REPLIES);
1655 case DCERPC_AUTH_LEVEL_CONNECT:
1656 case DCERPC_AUTH_LEVEL_NONE:
1665 if (need_async && !can_async) {
1666 req->wait_for_sync = true;
1670 DLIST_REMOVE(c->request_queue, req);
1671 DLIST_ADD(c->pending, req);
1672 req->state = RPC_REQUEST_PENDING;
1674 init_ncacn_hdr(p->conn, &pkt);
1676 remaining = stub_data->length;
1678 /* we can write a full max_recv_frag size, minus the dcerpc
1679 request header size */
1680 chunk_size = p->conn->srv_max_recv_frag;
1681 chunk_size -= DCERPC_REQUEST_LENGTH;
1682 if (c->security_state.auth_info &&
1683 c->security_state.generic_state) {
1684 size_t max_payload = chunk_size;
1686 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1687 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1689 sig_size = gensec_sig_size(c->security_state.generic_state,
1692 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1693 chunk_size -= sig_size;
1696 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1698 pkt.ptype = DCERPC_PKT_REQUEST;
1699 pkt.call_id = req->call_id;
1700 pkt.auth_length = 0;
1702 pkt.u.request.context_id = p->context_id;
1703 pkt.u.request.opnum = req->opnum;
1706 pkt.u.request.object.object = *req->object;
1707 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1708 chunk_size -= ndr_size_GUID(req->object,0);
1711 /* we send a series of pdus without waiting for a reply */
1712 while (remaining > 0 || first_packet) {
1713 uint32_t chunk = MIN(chunk_size, remaining);
1714 bool last_frag = false;
1715 bool do_trans = false;
1717 first_packet = false;
1718 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1720 if (remaining == stub_data->length) {
1721 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1723 if (chunk == remaining) {
1724 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1728 pkt.u.request.alloc_hint = remaining;
1729 pkt.u.request.stub_and_verifier.data = stub_data->data +
1730 (stub_data->length - remaining);
1731 pkt.u.request.stub_and_verifier.length = chunk;
1733 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1734 if (!NT_STATUS_IS_OK(req->status)) {
1735 req->state = RPC_REQUEST_DONE;
1736 DLIST_REMOVE(p->conn->pending, req);
1740 if (last_frag && !need_async) {
1744 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1745 if (!NT_STATUS_IS_OK(req->status)) {
1746 req->state = RPC_REQUEST_DONE;
1747 DLIST_REMOVE(p->conn->pending, req);
1751 if (last_frag && !do_trans) {
1752 req->status = dcerpc_send_read(p->conn);
1753 if (!NT_STATUS_IS_OK(req->status)) {
1754 req->state = RPC_REQUEST_DONE;
1755 DLIST_REMOVE(p->conn->pending, req);
1764 static void dcerpc_io_trigger(struct tevent_context *ctx,
1765 struct tevent_immediate *im,
1768 struct dcecli_connection *c =
1769 talloc_get_type_abort(private_data,
1770 struct dcecli_connection);
1772 c->io_trigger_pending = false;
1774 dcerpc_schedule_io_trigger(c);
1776 dcerpc_ship_next_request(c);
1779 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1785 if (c->request_queue == NULL) {
1789 if (c->request_queue->wait_for_sync && c->pending) {
1793 if (c->io_trigger_pending) {
1797 c->io_trigger_pending = true;
1799 tevent_schedule_immediate(c->io_trigger,
1806 perform the receive side of a async dcerpc request
1808 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1809 TALLOC_CTX *mem_ctx,
1810 DATA_BLOB *stub_data)
1814 while (req->state != RPC_REQUEST_DONE) {
1815 struct tevent_context *ctx = req->p->conn->event_ctx;
1816 if (tevent_loop_once(ctx) != 0) {
1817 return NT_STATUS_CONNECTION_DISCONNECTED;
1820 *stub_data = req->payload;
1821 status = req->status;
1822 if (stub_data->data) {
1823 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1825 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1826 req->p->last_fault_code = req->fault_code;
1828 talloc_unlink(talloc_parent(req), req);
1833 this is a paranoid NDR validator. For every packet we push onto the wire
1834 we pull it back again, then push it again. Then we compare the raw NDR data
1835 for that to the NDR we initially generated. If they don't match then we know
1836 we must have a bug in either the pull or push side of our code
1838 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1839 TALLOC_CTX *mem_ctx,
1842 ndr_push_flags_fn_t ndr_push,
1843 ndr_pull_flags_fn_t ndr_pull)
1846 struct ndr_pull *pull;
1847 struct ndr_push *push;
1849 enum ndr_err_code ndr_err;
1851 st = talloc_size(mem_ctx, struct_size);
1853 return NT_STATUS_NO_MEMORY;
1856 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1858 return NT_STATUS_NO_MEMORY;
1860 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1862 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1863 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1866 if (c->flags & DCERPC_NDR64) {
1867 pull->flags |= LIBNDR_FLAG_NDR64;
1870 ndr_err = ndr_pull(pull, NDR_IN, st);
1871 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1872 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1873 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1874 "failed input validation pull - %s",
1876 return ndr_map_error2ntstatus(ndr_err);
1879 push = ndr_push_init_ctx(mem_ctx);
1881 return NT_STATUS_NO_MEMORY;
1884 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1885 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1888 if (c->flags & DCERPC_NDR64) {
1889 push->flags |= LIBNDR_FLAG_NDR64;
1892 ndr_err = ndr_push(push, NDR_IN, st);
1893 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1894 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1895 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1896 "failed input validation push - %s",
1898 return ndr_map_error2ntstatus(ndr_err);
1901 blob2 = ndr_push_blob(push);
1903 if (data_blob_cmp(&blob, &blob2) != 0) {
1904 DEBUG(3,("original:\n"));
1905 dump_data(3, blob.data, blob.length);
1906 DEBUG(3,("secondary:\n"));
1907 dump_data(3, blob2.data, blob2.length);
1908 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1909 "failed input validation blobs doesn't match");
1910 return ndr_map_error2ntstatus(ndr_err);
1913 return NT_STATUS_OK;
1917 this is a paranoid NDR input validator. For every packet we pull
1918 from the wire we push it back again then pull and push it
1919 again. Then we compare the raw NDR data for that to the NDR we
1920 initially generated. If they don't match then we know we must have a
1921 bug in either the pull or push side of our code
1923 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1924 struct ndr_pull *pull_in,
1927 ndr_push_flags_fn_t ndr_push,
1928 ndr_pull_flags_fn_t ndr_pull,
1929 ndr_print_function_t ndr_print)
1932 struct ndr_pull *pull;
1933 struct ndr_push *push;
1934 DATA_BLOB blob, blob2;
1935 TALLOC_CTX *mem_ctx = pull_in;
1937 enum ndr_err_code ndr_err;
1939 st = talloc_size(mem_ctx, struct_size);
1941 return NT_STATUS_NO_MEMORY;
1943 memcpy(st, struct_ptr, struct_size);
1945 push = ndr_push_init_ctx(mem_ctx);
1947 return NT_STATUS_NO_MEMORY;
1950 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1951 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1952 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1953 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1954 "failed output validation push - %s",
1956 return ndr_map_error2ntstatus(ndr_err);
1959 blob = ndr_push_blob(push);
1961 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1963 return NT_STATUS_NO_MEMORY;
1966 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1967 ndr_err = ndr_pull(pull, NDR_OUT, st);
1968 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1969 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1970 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1971 "failed output validation pull - %s",
1973 return ndr_map_error2ntstatus(ndr_err);
1976 push = ndr_push_init_ctx(mem_ctx);
1978 return NT_STATUS_NO_MEMORY;
1981 ndr_err = ndr_push(push, NDR_OUT, st);
1982 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1983 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1984 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1985 "failed output validation push2 - %s",
1987 return ndr_map_error2ntstatus(ndr_err);
1990 blob2 = ndr_push_blob(push);
1992 if (data_blob_cmp(&blob, &blob2) != 0) {
1993 DEBUG(3,("original:\n"));
1994 dump_data(3, blob.data, blob.length);
1995 DEBUG(3,("secondary:\n"));
1996 dump_data(3, blob2.data, blob2.length);
1997 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1998 "failed output validation blobs doesn't match");
1999 return ndr_map_error2ntstatus(ndr_err);
2002 /* this checks the printed forms of the two structures, which effectively
2003 tests all of the value() attributes */
2004 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2005 NDR_OUT, struct_ptr);
2006 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2008 if (strcmp(s1, s2) != 0) {
2010 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2012 /* this is sometimes useful */
2013 printf("VALIDATE ERROR\n");
2014 file_save("wire.dat", s1, strlen(s1));
2015 file_save("gen.dat", s2, strlen(s2));
2016 system("diff -u wire.dat gen.dat");
2018 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2019 "failed output validation strings doesn't match");
2020 return ndr_map_error2ntstatus(ndr_err);
2023 return NT_STATUS_OK;
2027 a useful function for retrieving the server name we connected to
2029 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2031 return p->conn ? p->conn->server_name : NULL;
2036 get the dcerpc auth_level for a open connection
2038 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2042 if (c->flags & DCERPC_SEAL) {
2043 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2044 } else if (c->flags & DCERPC_SIGN) {
2045 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2046 } else if (c->flags & DCERPC_CONNECT) {
2047 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2049 auth_level = DCERPC_AUTH_LEVEL_NONE;
2054 struct dcerpc_alter_context_state {
2055 struct tevent_context *ev;
2056 struct dcerpc_pipe *p;
2059 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2060 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2061 DATA_BLOB *raw_packet,
2062 struct ncacn_packet *pkt);
2064 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2065 struct tevent_context *ev,
2066 struct dcerpc_pipe *p,
2067 const struct ndr_syntax_id *syntax,
2068 const struct ndr_syntax_id *transfer_syntax)
2070 struct tevent_req *req;
2071 struct dcerpc_alter_context_state *state;
2072 struct ncacn_packet pkt;
2075 struct rpc_request *subreq;
2078 req = tevent_req_create(mem_ctx, &state,
2079 struct dcerpc_alter_context_state);
2087 p->syntax = *syntax;
2088 p->transfer_syntax = *transfer_syntax;
2090 flags = dcerpc_binding_get_flags(p->binding);
2092 init_ncacn_hdr(p->conn, &pkt);
2094 pkt.ptype = DCERPC_PKT_ALTER;
2095 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2096 pkt.call_id = p->conn->call_id;
2097 pkt.auth_length = 0;
2099 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2100 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2103 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2104 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2105 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2106 pkt.u.alter.num_contexts = 1;
2107 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2108 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2109 return tevent_req_post(req, ev);
2111 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2112 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2113 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2114 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2115 pkt.u.alter.auth_info = data_blob(NULL, 0);
2117 /* construct the NDR form of the packet */
2118 status = ncacn_push_auth(&blob, state, &pkt,
2119 p->conn->security_state.auth_info);
2120 if (tevent_req_nterror(req, status)) {
2121 return tevent_req_post(req, ev);
2125 * we allocate a dcerpc_request so we can be in the same
2126 * request queue as normal requests
2128 subreq = talloc_zero(state, struct rpc_request);
2129 if (tevent_req_nomem(subreq, req)) {
2130 return tevent_req_post(req, ev);
2133 subreq->state = RPC_REQUEST_PENDING;
2134 subreq->call_id = pkt.call_id;
2135 subreq->async.private_data = req;
2136 subreq->async.callback = dcerpc_alter_context_fail_handler;
2138 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2139 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2140 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2142 status = dcerpc_send_request(p->conn, &blob, true);
2143 if (tevent_req_nterror(req, status)) {
2144 return tevent_req_post(req, ev);
2147 tevent_add_timer(ev, subreq,
2148 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2149 dcerpc_timeout_handler, subreq);
2154 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2156 struct tevent_req *req =
2157 talloc_get_type_abort(subreq->async.private_data,
2159 struct dcerpc_alter_context_state *state =
2160 tevent_req_data(req,
2161 struct dcerpc_alter_context_state);
2162 NTSTATUS status = subreq->status;
2164 TALLOC_FREE(subreq);
2167 * We trigger the callback in the next event run
2168 * because the code in this file might trigger
2169 * multiple request callbacks from within a single
2172 * In order to avoid segfaults from within
2173 * dcerpc_connection_dead() we call
2174 * tevent_req_defer_callback().
2176 tevent_req_defer_callback(req, state->ev);
2178 tevent_req_nterror(req, status);
2181 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2182 DATA_BLOB *raw_packet,
2183 struct ncacn_packet *pkt)
2185 struct tevent_req *req =
2186 talloc_get_type_abort(subreq->async.private_data,
2188 struct dcerpc_alter_context_state *state =
2189 tevent_req_data(req,
2190 struct dcerpc_alter_context_state);
2191 struct dcecli_connection *conn = state->p->conn;
2195 * Note that pkt is allocated under raw_packet->data,
2196 * while raw_packet->data is a child of subreq.
2198 talloc_steal(state, raw_packet->data);
2199 TALLOC_FREE(subreq);
2202 * We trigger the callback in the next event run
2203 * because the code in this file might trigger
2204 * multiple request callbacks from within a single
2207 * In order to avoid segfaults from within
2208 * dcerpc_connection_dead() we call
2209 * tevent_req_defer_callback().
2211 tevent_req_defer_callback(req, state->ev);
2213 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2214 pkt->u.alter_resp.num_results == 1 &&
2215 pkt->u.alter_resp.ctx_list[0].result != 0) {
2216 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2217 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2218 pkt->u.alter_resp.ctx_list[0].reason.value,
2219 nt_errstr(status)));
2220 tevent_req_nterror(req, status);
2224 if (pkt->ptype == DCERPC_PKT_FAULT) {
2225 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2226 dcerpc_errstr(state, pkt->u.fault.status)));
2227 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2228 state->p->last_fault_code = pkt->u.fault.status;
2229 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2231 state->p->last_fault_code = pkt->u.fault.status;
2232 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2233 tevent_req_nterror(req, status);
2238 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2239 pkt->u.alter_resp.num_results == 0 ||
2240 pkt->u.alter_resp.ctx_list[0].result != 0) {
2241 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2242 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2246 /* the alter_resp might contain a reply set of credentials */
2247 if (conn->security_state.auth_info &&
2248 pkt->u.alter_resp.auth_info.length) {
2249 uint32_t auth_length;
2251 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2252 conn->security_state.auth_info, &auth_length, true);
2253 if (tevent_req_nterror(req, status)) {
2258 tevent_req_done(req);
2261 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2263 return tevent_req_simple_recv_ntstatus(req);
2267 send a dcerpc alter_context request
2269 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2270 TALLOC_CTX *mem_ctx,
2271 const struct ndr_syntax_id *syntax,
2272 const struct ndr_syntax_id *transfer_syntax)
2274 struct tevent_req *subreq;
2275 struct tevent_context *ev = p->conn->event_ctx;
2278 /* TODO: create a new event context here */
2280 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2281 p, syntax, transfer_syntax);
2282 if (subreq == NULL) {
2283 return NT_STATUS_NO_MEMORY;
2286 ok = tevent_req_poll(subreq, ev);
2289 status = map_nt_error_from_unix_common(errno);
2293 return dcerpc_alter_context_recv(subreq);
2296 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2298 if (c->transport.stream == NULL) {
2302 tevent_queue_stop(c->transport.write_queue);
2303 TALLOC_FREE(c->transport.read_subreq);
2304 TALLOC_FREE(c->transport.stream);
2306 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2307 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2310 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2311 status = NT_STATUS_END_OF_FILE;
2314 dcerpc_recv_data(c, NULL, status);
2319 shutdown SMB pipe connection
2321 struct dcerpc_shutdown_pipe_state {
2322 struct dcecli_connection *c;
2326 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2328 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2330 struct dcerpc_shutdown_pipe_state *state;
2331 struct tevent_req *subreq;
2333 if (c->transport.stream == NULL) {
2334 return NT_STATUS_OK;
2337 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2338 if (state == NULL) {
2339 return NT_STATUS_NO_MEMORY;
2342 state->status = status;
2344 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2345 if (subreq == NULL) {
2346 return NT_STATUS_NO_MEMORY;
2348 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2353 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2355 struct dcerpc_shutdown_pipe_state *state =
2356 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2357 struct dcecli_connection *c = state->c;
2358 NTSTATUS status = state->status;
2362 * here we ignore the return values...
2364 tstream_disconnect_recv(subreq, &error);
2365 TALLOC_FREE(subreq);
2369 dcerpc_transport_dead(c, status);
2374 struct dcerpc_send_read_state {
2375 struct dcecli_connection *p;
2378 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2380 struct dcecli_connection *p = state->p;
2382 p->transport.read_subreq = NULL;
2387 static void dcerpc_send_read_done(struct tevent_req *subreq);
2389 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2391 struct dcerpc_send_read_state *state;
2393 if (p->transport.read_subreq != NULL) {
2394 p->transport.pending_reads++;
2395 return NT_STATUS_OK;
2398 state = talloc_zero(p, struct dcerpc_send_read_state);
2399 if (state == NULL) {
2400 return NT_STATUS_NO_MEMORY;
2404 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2406 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2408 p->transport.stream);
2409 if (p->transport.read_subreq == NULL) {
2410 return NT_STATUS_NO_MEMORY;
2412 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2414 return NT_STATUS_OK;
2417 static void dcerpc_send_read_done(struct tevent_req *subreq)
2419 struct dcerpc_send_read_state *state =
2420 tevent_req_callback_data(subreq,
2421 struct dcerpc_send_read_state);
2422 struct dcecli_connection *p = state->p;
2424 struct ncacn_packet *pkt;
2427 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2429 TALLOC_FREE(subreq);
2430 if (!NT_STATUS_IS_OK(status)) {
2432 dcerpc_transport_dead(p, status);
2437 * here we steal into thet connection context,
2438 * but p->transport.recv_data() will steal or free it again
2440 talloc_steal(p, blob.data);
2443 if (p->transport.pending_reads > 0) {
2444 p->transport.pending_reads--;
2446 status = dcerpc_send_read(p);
2447 if (!NT_STATUS_IS_OK(status)) {
2448 dcerpc_transport_dead(p, status);
2453 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2456 struct dcerpc_send_request_state {
2457 struct dcecli_connection *p;
2462 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2464 struct dcecli_connection *p = state->p;
2466 p->transport.read_subreq = NULL;
2471 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2472 static void dcerpc_send_request_done(struct tevent_req *subreq);
2474 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2477 struct dcerpc_send_request_state *state;
2478 struct tevent_req *subreq;
2479 bool use_trans = trigger_read;
2481 if (p->transport.stream == NULL) {
2482 return NT_STATUS_CONNECTION_DISCONNECTED;
2485 state = talloc_zero(p, struct dcerpc_send_request_state);
2486 if (state == NULL) {
2487 return NT_STATUS_NO_MEMORY;
2491 state->blob = data_blob_talloc(state, data->data, data->length);
2492 if (state->blob.data == NULL) {
2494 return NT_STATUS_NO_MEMORY;
2496 state->iov.iov_base = (void *)state->blob.data;
2497 state->iov.iov_len = state->blob.length;
2499 if (p->transport.read_subreq != NULL) {
2503 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2509 * we need to block reads until our write is
2510 * the next in the write queue.
2512 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2513 p->transport.write_queue);
2514 if (p->transport.read_subreq == NULL) {
2516 return NT_STATUS_NO_MEMORY;
2518 tevent_req_set_callback(p->transport.read_subreq,
2519 dcerpc_send_request_wait_done,
2522 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2524 trigger_read = false;
2527 subreq = tstream_writev_queue_send(state, p->event_ctx,
2528 p->transport.stream,
2529 p->transport.write_queue,
2531 if (subreq == NULL) {
2533 return NT_STATUS_NO_MEMORY;
2535 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2538 dcerpc_send_read(p);
2541 return NT_STATUS_OK;
2544 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2546 struct dcerpc_send_request_state *state =
2547 tevent_req_callback_data(subreq,
2548 struct dcerpc_send_request_state);
2549 struct dcecli_connection *p = state->p;
2553 p->transport.read_subreq = NULL;
2554 talloc_set_destructor(state, NULL);
2556 ok = tevent_queue_wait_recv(subreq);
2559 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2563 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2564 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2565 if (!NT_STATUS_IS_OK(status)) {
2567 dcerpc_transport_dead(p, status);
2572 /* we free subreq after tstream_cli_np_use_trans */
2573 TALLOC_FREE(subreq);
2575 dcerpc_send_read(p);
2578 static void dcerpc_send_request_done(struct tevent_req *subreq)
2580 struct dcerpc_send_request_state *state =
2581 tevent_req_callback_data(subreq,
2582 struct dcerpc_send_request_state);
2586 ret = tstream_writev_queue_recv(subreq, &error);
2587 TALLOC_FREE(subreq);
2589 struct dcecli_connection *p = state->p;
2590 NTSTATUS status = map_nt_error_from_unix_common(error);
2593 dcerpc_transport_dead(p, status);