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.auth_info = NULL;
148 c->security_state.session_key = dcerpc_generic_session_key;
149 c->security_state.generic_state = NULL;
152 * Windows uses 5840 for ncacn_ip_tcp,
153 * so we also use it (for every transport)
154 * by default. But we give the transport
155 * the chance to overwrite it.
157 c->srv_max_xmit_frag = 5840;
158 c->srv_max_recv_frag = 5840;
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);
445 if (ndr_flags & NDR_IN) {
446 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
447 ndr_print_function_debug(call->ndr_print,
453 if (ndr_flags & NDR_OUT) {
454 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
455 ndr_print_function_debug(call->ndr_print,
463 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
465 const void *struct_ptr,
466 const struct ndr_interface_call *call)
468 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
469 call->name, nt_errstr(error)));
472 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
474 const DATA_BLOB *blob,
475 const struct ndr_interface_call *call)
477 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
478 struct dcerpc_bh_state);
479 const uint32_t num_examples = 20;
482 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
483 call->name, nt_errstr(error)));
485 if (hs->p->conn->packet_log_dir == NULL) return;
487 for (i=0;i<num_examples;i++) {
491 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
492 hs->p->conn->packet_log_dir,
497 if (!file_exist(name)) {
498 if (file_save(name, blob->data, blob->length)) {
499 DEBUG(10,("Logged rpc packet to %s\n", name));
508 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
510 const DATA_BLOB *blob,
511 const struct ndr_interface_call *call)
513 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
514 struct dcerpc_bh_state);
516 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
519 status = dcerpc_ndr_validate_in(hs->p->conn,
525 if (!NT_STATUS_IS_OK(status)) {
526 DEBUG(0,("Validation [in] failed for %s - %s\n",
527 call->name, nt_errstr(status)));
532 DEBUG(10,("rpc request data:\n"));
533 dump_data(10, blob->data, blob->length);
538 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
539 struct ndr_pull *pull_in,
540 const void *_struct_ptr,
541 const struct ndr_interface_call *call)
543 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
544 struct dcerpc_bh_state);
545 void *struct_ptr = discard_const(_struct_ptr);
547 DEBUG(10,("rpc reply data:\n"));
548 dump_data(10, pull_in->data, pull_in->data_size);
550 if (pull_in->offset != pull_in->data_size) {
551 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
552 pull_in->data_size - pull_in->offset,
553 pull_in->offset, pull_in->offset,
555 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
556 but it turns out that early versions of NT
557 (specifically NT3.1) add junk onto the end of rpc
558 packets, so if we want to interoperate at all with
559 those versions then we need to ignore this error */
562 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
565 status = dcerpc_ndr_validate_out(hs->p->conn,
572 if (!NT_STATUS_IS_OK(status)) {
573 DEBUG(2,("Validation [out] failed for %s - %s\n",
574 call->name, nt_errstr(status)));
582 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
584 .is_connected = dcerpc_bh_is_connected,
585 .set_timeout = dcerpc_bh_set_timeout,
586 .auth_info = dcerpc_bh_auth_info,
587 .raw_call_send = dcerpc_bh_raw_call_send,
588 .raw_call_recv = dcerpc_bh_raw_call_recv,
589 .disconnect_send = dcerpc_bh_disconnect_send,
590 .disconnect_recv = dcerpc_bh_disconnect_recv,
592 .push_bigendian = dcerpc_bh_push_bigendian,
593 .ref_alloc = dcerpc_bh_ref_alloc,
594 .use_ndr64 = dcerpc_bh_use_ndr64,
595 .do_ndr_print = dcerpc_bh_do_ndr_print,
596 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
597 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
598 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
599 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
602 /* initialise a dcerpc pipe. */
603 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
605 struct dcerpc_binding_handle *h;
606 struct dcerpc_bh_state *hs;
608 h = dcerpc_binding_handle_create(p,
613 struct dcerpc_bh_state,
620 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
625 /* initialise a dcerpc pipe. */
626 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
628 struct dcerpc_pipe *p;
630 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
635 p->conn = dcerpc_connection_init(p, ev);
636 if (p->conn == NULL) {
641 p->last_fault_code = 0;
643 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
646 ZERO_STRUCT(p->syntax);
647 ZERO_STRUCT(p->transfer_syntax);
650 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
653 p->binding_handle = dcerpc_pipe_binding_handle(p);
654 if (p->binding_handle == NULL) {
664 choose the next call id to use
666 static uint32_t next_call_id(struct dcecli_connection *c)
669 if (c->call_id == 0) {
676 setup for a ndr pull, also setting up any flags from the binding string
678 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
679 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
681 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
683 if (ndr == NULL) return ndr;
685 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
686 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
689 if (c->flags & DCERPC_NDR_REF_ALLOC) {
690 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
693 if (c->flags & DCERPC_NDR64) {
694 ndr->flags |= LIBNDR_FLAG_NDR64;
701 parse a data blob into a ncacn_packet structure. This handles both
702 input and output packets
704 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
705 struct ncacn_packet *pkt)
707 struct ndr_pull *ndr;
708 enum ndr_err_code ndr_err;
710 ndr = ndr_pull_init_blob(blob, mem_ctx);
712 return NT_STATUS_NO_MEMORY;
715 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
716 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
719 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
720 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
723 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
725 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
726 return ndr_map_error2ntstatus(ndr_err);
729 if (pkt->frag_length != blob->length) {
730 return NT_STATUS_RPC_PROTOCOL_ERROR;
737 parse the authentication information on a dcerpc response packet
739 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
740 DATA_BLOB *raw_packet,
741 struct ncacn_packet *pkt)
744 struct dcerpc_auth auth;
745 uint32_t auth_length;
747 if (!c->security_state.auth_info ||
748 !c->security_state.generic_state) {
752 switch (c->security_state.auth_info->auth_level) {
753 case DCERPC_AUTH_LEVEL_PRIVACY:
754 case DCERPC_AUTH_LEVEL_INTEGRITY:
757 case DCERPC_AUTH_LEVEL_CONNECT:
758 if (pkt->auth_length != 0) {
762 case DCERPC_AUTH_LEVEL_NONE:
763 if (pkt->auth_length != 0) {
764 return NT_STATUS_INVALID_NETWORK_RESPONSE;
769 return NT_STATUS_INVALID_LEVEL;
772 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
773 &pkt->u.response.stub_and_verifier,
774 &auth, &auth_length, false);
775 NT_STATUS_NOT_OK_RETURN(status);
777 pkt->u.response.stub_and_verifier.length -= auth_length;
779 /* check signature or unseal the packet */
780 switch (c->security_state.auth_info->auth_level) {
781 case DCERPC_AUTH_LEVEL_PRIVACY:
782 status = gensec_unseal_packet(c->security_state.generic_state,
783 raw_packet->data + DCERPC_REQUEST_LENGTH,
784 pkt->u.response.stub_and_verifier.length,
786 raw_packet->length - auth.credentials.length,
788 memcpy(pkt->u.response.stub_and_verifier.data,
789 raw_packet->data + DCERPC_REQUEST_LENGTH,
790 pkt->u.response.stub_and_verifier.length);
793 case DCERPC_AUTH_LEVEL_INTEGRITY:
794 status = gensec_check_packet(c->security_state.generic_state,
795 pkt->u.response.stub_and_verifier.data,
796 pkt->u.response.stub_and_verifier.length,
798 raw_packet->length - auth.credentials.length,
802 case DCERPC_AUTH_LEVEL_CONNECT:
803 /* for now we ignore possible signatures here */
804 status = NT_STATUS_OK;
808 status = NT_STATUS_INVALID_LEVEL;
812 /* remove the indicated amount of padding */
813 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
814 return NT_STATUS_INFO_LENGTH_MISMATCH;
816 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
823 push a dcerpc request packet into a blob, possibly signing it.
825 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
826 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
828 struct ncacn_packet *pkt)
831 struct ndr_push *ndr;
833 size_t payload_length;
834 enum ndr_err_code ndr_err;
835 size_t hdr_size = DCERPC_REQUEST_LENGTH;
836 struct dcerpc_auth auth_info = {
837 .auth_type = c->security_state.auth_type,
838 .auth_level = c->security_state.auth_level,
839 .auth_context_id = c->security_state.auth_context_id,
842 switch (c->security_state.auth_level) {
843 case DCERPC_AUTH_LEVEL_PRIVACY:
844 case DCERPC_AUTH_LEVEL_INTEGRITY:
846 return NT_STATUS_INTERNAL_ERROR;
850 case DCERPC_AUTH_LEVEL_CONNECT:
851 /* TODO: let the gensec mech decide if it wants to generate a signature */
852 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
854 case DCERPC_AUTH_LEVEL_NONE:
855 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
858 return NT_STATUS_INVALID_LEVEL;
861 ndr = ndr_push_init_ctx(mem_ctx);
863 return NT_STATUS_NO_MEMORY;
866 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
867 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
870 if (c->flags & DCERPC_NDR64) {
871 ndr->flags |= LIBNDR_FLAG_NDR64;
874 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
875 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
879 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
880 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
881 return ndr_map_error2ntstatus(ndr_err);
884 /* pad to 16 byte multiple in the payload portion of the
885 packet. This matches what w2k3 does. Note that we can't use
886 ndr_push_align() as that is relative to the start of the
887 whole packet, whereas w2k8 wants it relative to the start
889 auth_info.auth_pad_length =
890 DCERPC_AUTH_PAD_LENGTH(pkt->u.request.stub_and_verifier.length);
891 ndr_err = ndr_push_zero(ndr, auth_info.auth_pad_length);
892 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
893 return ndr_map_error2ntstatus(ndr_err);
896 payload_length = pkt->u.request.stub_and_verifier.length +
897 auth_info.auth_pad_length;
899 /* add the auth verifier */
900 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth_info);
901 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
902 return ndr_map_error2ntstatus(ndr_err);
905 /* extract the whole packet as a blob */
906 *blob = ndr_push_blob(ndr);
909 * Setup the frag and auth length in the packet buffer.
910 * This is needed if the GENSEC mech does AEAD signing
911 * of the packet headers. The signature itself will be
914 dcerpc_set_frag_length(blob, blob->length + sig_size);
915 dcerpc_set_auth_length(blob, sig_size);
917 /* sign or seal the packet */
918 switch (c->security_state.auth_level) {
919 case DCERPC_AUTH_LEVEL_PRIVACY:
920 status = gensec_seal_packet(c->security_state.generic_state,
922 blob->data + hdr_size,
927 if (!NT_STATUS_IS_OK(status)) {
932 case DCERPC_AUTH_LEVEL_INTEGRITY:
933 status = gensec_sign_packet(c->security_state.generic_state,
935 blob->data + hdr_size,
940 if (!NT_STATUS_IS_OK(status)) {
946 status = NT_STATUS_INVALID_LEVEL;
950 if (creds2.length != sig_size) {
951 /* this means the sig_size estimate for the signature
952 was incorrect. We have to correct the packet
953 sizes. That means we could go over the max fragment
955 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
956 (unsigned) creds2.length,
958 (unsigned) auth_info.auth_pad_length,
959 (unsigned) pkt->u.request.stub_and_verifier.length));
960 dcerpc_set_frag_length(blob, blob->length + creds2.length);
961 dcerpc_set_auth_length(blob, creds2.length);
964 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
965 return NT_STATUS_NO_MEMORY;
973 fill in the fixed values in a dcerpc header
975 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
978 pkt->rpc_vers_minor = 0;
979 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
982 pkt->drep[0] = DCERPC_DREP_LE;
990 map a bind nak reason to a NTSTATUS
992 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
995 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
996 return NT_STATUS_REVISION_MISMATCH;
997 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
998 return NT_STATUS_INVALID_PARAMETER;
1002 return NT_STATUS_UNSUCCESSFUL;
1005 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
1008 return NT_STATUS_RPC_PROTOCOL_ERROR;
1011 switch (ack->result) {
1012 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
1014 * We have not asked for this...
1016 return NT_STATUS_RPC_PROTOCOL_ERROR;
1021 switch (ack->reason.value) {
1022 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
1023 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1024 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
1025 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1029 return NT_STATUS_UNSUCCESSFUL;
1033 remove requests from the pending or queued queues
1035 static int dcerpc_req_dequeue(struct rpc_request *req)
1037 switch (req->state) {
1038 case RPC_REQUEST_QUEUED:
1039 DLIST_REMOVE(req->p->conn->request_queue, req);
1041 case RPC_REQUEST_PENDING:
1042 DLIST_REMOVE(req->p->conn->pending, req);
1044 case RPC_REQUEST_DONE:
1052 mark the dcerpc connection dead. All outstanding requests get an error
1054 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1056 if (conn->dead) return;
1060 TALLOC_FREE(conn->io_trigger);
1061 conn->io_trigger_pending = false;
1063 dcerpc_shutdown_pipe(conn, status);
1065 /* all pending requests get the error */
1066 while (conn->pending) {
1067 struct rpc_request *req = conn->pending;
1068 dcerpc_req_dequeue(req);
1069 req->state = RPC_REQUEST_DONE;
1070 req->status = status;
1071 if (req->async.callback) {
1072 req->async.callback(req);
1076 /* all requests, which are not shipped */
1077 while (conn->request_queue) {
1078 struct rpc_request *req = conn->request_queue;
1079 dcerpc_req_dequeue(req);
1080 req->state = RPC_REQUEST_DONE;
1081 req->status = status;
1082 if (req->async.callback) {
1083 req->async.callback(req);
1087 talloc_set_destructor(conn, NULL);
1088 if (conn->free_skipped) {
1094 forward declarations of the recv_data handlers for the types of
1095 packets we need to handle
1097 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1098 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1101 receive a dcerpc reply from the transport. Here we work out what
1102 type of reply it is (normal request, bind or alter context) and
1103 dispatch to the appropriate handler
1105 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1107 struct ncacn_packet pkt;
1113 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1114 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1117 /* the transport may be telling us of a severe error, such as
1119 if (!NT_STATUS_IS_OK(status)) {
1120 data_blob_free(blob);
1121 dcerpc_connection_dead(conn, status);
1125 /* parse the basic packet to work out what type of response this is */
1126 status = ncacn_pull(conn, blob, blob->data, &pkt);
1127 if (!NT_STATUS_IS_OK(status)) {
1128 data_blob_free(blob);
1129 dcerpc_connection_dead(conn, status);
1133 dcerpc_request_recv_data(conn, blob, &pkt);
1137 handle timeouts of individual dcerpc requests
1139 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1140 struct timeval t, void *private_data)
1142 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1144 if (req->ignore_timeout) {
1145 dcerpc_req_dequeue(req);
1146 req->state = RPC_REQUEST_DONE;
1147 req->status = NT_STATUS_IO_TIMEOUT;
1148 if (req->async.callback) {
1149 req->async.callback(req);
1154 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1157 struct dcerpc_bind_state {
1158 struct tevent_context *ev;
1159 struct dcerpc_pipe *p;
1162 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1163 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1164 DATA_BLOB *raw_packet,
1165 struct ncacn_packet *pkt);
1167 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1168 struct tevent_context *ev,
1169 struct dcerpc_pipe *p,
1170 const struct ndr_syntax_id *syntax,
1171 const struct ndr_syntax_id *transfer_syntax)
1173 struct tevent_req *req;
1174 struct dcerpc_bind_state *state;
1175 struct ncacn_packet pkt;
1178 struct rpc_request *subreq;
1181 req = tevent_req_create(mem_ctx, &state,
1182 struct dcerpc_bind_state);
1190 p->syntax = *syntax;
1191 p->transfer_syntax = *transfer_syntax;
1193 flags = dcerpc_binding_get_flags(p->binding);
1195 init_ncacn_hdr(p->conn, &pkt);
1197 pkt.ptype = DCERPC_PKT_BIND;
1198 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1199 pkt.call_id = p->conn->call_id;
1200 pkt.auth_length = 0;
1202 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1203 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1206 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1207 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1210 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1211 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1212 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1213 pkt.u.bind.num_contexts = 1;
1214 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1215 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1216 return tevent_req_post(req, ev);
1218 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1219 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1220 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1221 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1222 pkt.u.bind.auth_info = data_blob(NULL, 0);
1224 /* construct the NDR form of the packet */
1225 status = ncacn_push_auth(&blob, state, &pkt,
1226 p->conn->security_state.auth_info);
1227 if (tevent_req_nterror(req, status)) {
1228 return tevent_req_post(req, ev);
1232 * we allocate a dcerpc_request so we can be in the same
1233 * request queue as normal requests
1235 subreq = talloc_zero(state, struct rpc_request);
1236 if (tevent_req_nomem(subreq, req)) {
1237 return tevent_req_post(req, ev);
1240 subreq->state = RPC_REQUEST_PENDING;
1241 subreq->call_id = pkt.call_id;
1242 subreq->async.private_data = req;
1243 subreq->async.callback = dcerpc_bind_fail_handler;
1245 subreq->recv_handler = dcerpc_bind_recv_handler;
1246 DLIST_ADD_END(p->conn->pending, subreq);
1247 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1249 status = dcerpc_send_request(p->conn, &blob, true);
1250 if (tevent_req_nterror(req, status)) {
1251 return tevent_req_post(req, ev);
1254 tevent_add_timer(ev, subreq,
1255 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1256 dcerpc_timeout_handler, subreq);
1261 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1263 struct tevent_req *req =
1264 talloc_get_type_abort(subreq->async.private_data,
1266 struct dcerpc_bind_state *state =
1267 tevent_req_data(req,
1268 struct dcerpc_bind_state);
1269 NTSTATUS status = subreq->status;
1271 TALLOC_FREE(subreq);
1274 * We trigger the callback in the next event run
1275 * because the code in this file might trigger
1276 * multiple request callbacks from within a single
1279 * In order to avoid segfaults from within
1280 * dcerpc_connection_dead() we call
1281 * tevent_req_defer_callback().
1283 tevent_req_defer_callback(req, state->ev);
1285 tevent_req_nterror(req, status);
1288 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1289 DATA_BLOB *raw_packet,
1290 struct ncacn_packet *pkt)
1292 struct tevent_req *req =
1293 talloc_get_type_abort(subreq->async.private_data,
1295 struct dcerpc_bind_state *state =
1296 tevent_req_data(req,
1297 struct dcerpc_bind_state);
1298 struct dcecli_connection *conn = state->p->conn;
1299 struct dcerpc_binding *b = NULL;
1304 * Note that pkt is allocated under raw_packet->data,
1305 * while raw_packet->data is a child of subreq.
1307 talloc_steal(state, raw_packet->data);
1308 TALLOC_FREE(subreq);
1311 * We trigger the callback in the next event run
1312 * because the code in this file might trigger
1313 * multiple request callbacks from within a single
1316 * In order to avoid segfaults from within
1317 * dcerpc_connection_dead() we call
1318 * tevent_req_defer_callback().
1320 tevent_req_defer_callback(req, state->ev);
1322 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1323 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1325 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1326 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1328 tevent_req_nterror(req, status);
1332 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1333 (pkt->u.bind_ack.num_results == 0) ||
1334 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1335 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1336 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1341 * DCE-RPC 1.1 (c706) specifies
1342 * CONST_MUST_RCV_FRAG_SIZE as 1432
1344 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1345 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1346 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1349 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1350 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1351 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1354 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1355 pkt->u.bind_ack.max_xmit_frag);
1356 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1357 pkt->u.bind_ack.max_recv_frag);
1359 flags = dcerpc_binding_get_flags(state->p->binding);
1361 if ((flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1362 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1363 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1366 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1367 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1368 conn->flags |= DCERPC_HEADER_SIGNING;
1371 /* the bind_ack might contain a reply set of credentials */
1372 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1373 uint32_t auth_length;
1375 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1376 conn->security_state.auth_info, &auth_length, true);
1377 if (tevent_req_nterror(req, status)) {
1383 * We're the owner of the binding, so we're allowed to modify it.
1385 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1386 status = dcerpc_binding_set_assoc_group_id(b,
1387 pkt->u.bind_ack.assoc_group_id);
1388 if (tevent_req_nterror(req, status)) {
1392 tevent_req_done(req);
1395 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1397 return tevent_req_simple_recv_ntstatus(req);
1401 perform a continued bind (and auth3)
1403 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1404 TALLOC_CTX *mem_ctx)
1406 struct ncacn_packet pkt;
1411 flags = dcerpc_binding_get_flags(p->binding);
1413 init_ncacn_hdr(p->conn, &pkt);
1415 pkt.ptype = DCERPC_PKT_AUTH3;
1416 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1417 pkt.call_id = next_call_id(p->conn);
1418 pkt.auth_length = 0;
1419 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1421 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1422 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1425 /* construct the NDR form of the packet */
1426 status = ncacn_push_auth(&blob, mem_ctx,
1428 p->conn->security_state.auth_info);
1429 if (!NT_STATUS_IS_OK(status)) {
1433 /* send it on its way */
1434 status = dcerpc_send_request(p->conn, &blob, false);
1435 if (!NT_STATUS_IS_OK(status)) {
1439 return NT_STATUS_OK;
1444 process a fragment received from the transport layer during a
1447 This function frees the data
1449 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1450 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1452 struct rpc_request *req;
1453 unsigned int length;
1454 NTSTATUS status = NT_STATUS_OK;
1457 if this is an authenticated connection then parse and check
1458 the auth info. We have to do this before finding the
1459 matching packet, as the request structure might have been
1460 removed due to a timeout, but if it has been we still need
1461 to run the auth routines so that we don't get the sign/seal
1462 info out of step with the server
1464 if (c->security_state.auth_info && c->security_state.generic_state &&
1465 pkt->ptype == DCERPC_PKT_RESPONSE) {
1466 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1469 /* find the matching request */
1470 for (req=c->pending;req;req=req->next) {
1471 if (pkt->call_id == req->call_id) break;
1475 /* useful for testing certain vendors RPC servers */
1476 if (req == NULL && c->pending && pkt->call_id == 0) {
1477 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1483 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1484 data_blob_free(raw_packet);
1488 talloc_steal(req, raw_packet->data);
1490 if (req->recv_handler != NULL) {
1491 dcerpc_req_dequeue(req);
1492 req->state = RPC_REQUEST_DONE;
1495 * We have to look at shipping further requests before calling
1496 * the async function, that one might close the pipe
1498 dcerpc_schedule_io_trigger(c);
1500 req->recv_handler(req, raw_packet, pkt);
1504 if (pkt->ptype == DCERPC_PKT_FAULT) {
1505 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1506 req->fault_code = pkt->u.fault.status;
1507 req->status = NT_STATUS_NET_WRITE_FAULT;
1511 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1512 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1514 req->fault_code = DCERPC_FAULT_OTHER;
1515 req->status = NT_STATUS_NET_WRITE_FAULT;
1519 /* now check the status from the auth routines, and if it failed then fail
1520 this request accordingly */
1521 if (!NT_STATUS_IS_OK(status)) {
1522 req->status = status;
1526 length = pkt->u.response.stub_and_verifier.length;
1529 req->payload.data = talloc_realloc(req,
1532 req->payload.length + length);
1533 if (!req->payload.data) {
1534 req->status = NT_STATUS_NO_MEMORY;
1537 memcpy(req->payload.data+req->payload.length,
1538 pkt->u.response.stub_and_verifier.data, length);
1539 req->payload.length += length;
1542 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1543 data_blob_free(raw_packet);
1544 dcerpc_send_read(c);
1548 if (req->verify_bitmask1) {
1549 req->p->conn->security_state.verified_bitmask1 = true;
1551 if (req->verify_pcontext) {
1552 req->p->verified_pcontext = true;
1555 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1556 req->flags |= DCERPC_PULL_BIGENDIAN;
1558 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1562 data_blob_free(raw_packet);
1564 /* we've got the full payload */
1565 dcerpc_req_dequeue(req);
1566 req->state = RPC_REQUEST_DONE;
1569 * We have to look at shipping further requests before calling
1570 * the async function, that one might close the pipe
1572 dcerpc_schedule_io_trigger(c);
1574 if (req->async.callback) {
1575 req->async.callback(req);
1579 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1582 perform the send side of a async dcerpc request
1584 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1585 struct dcerpc_pipe *p,
1586 const struct GUID *object,
1588 DATA_BLOB *stub_data)
1590 struct rpc_request *req;
1593 req = talloc_zero(mem_ctx, struct rpc_request);
1599 req->call_id = next_call_id(p->conn);
1600 req->state = RPC_REQUEST_QUEUED;
1602 if (object != NULL) {
1603 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1604 if (req->object == NULL) {
1611 req->request_data.length = stub_data->length;
1612 req->request_data.data = stub_data->data;
1614 status = dcerpc_request_prepare_vt(req);
1615 if (!NT_STATUS_IS_OK(status)) {
1620 DLIST_ADD_END(p->conn->request_queue, req);
1621 talloc_set_destructor(req, dcerpc_req_dequeue);
1623 dcerpc_schedule_io_trigger(p->conn);
1625 if (p->request_timeout) {
1626 tevent_add_timer(p->conn->event_ctx, req,
1627 timeval_current_ofs(p->request_timeout, 0),
1628 dcerpc_timeout_handler, req);
1634 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1636 struct dcecli_security *sec = &req->p->conn->security_state;
1637 struct dcerpc_sec_verification_trailer *t;
1638 struct dcerpc_sec_vt *c = NULL;
1639 struct ndr_push *ndr = NULL;
1640 enum ndr_err_code ndr_err;
1642 if (sec->auth_info == NULL) {
1643 return NT_STATUS_OK;
1646 if (sec->auth_info->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
1647 return NT_STATUS_OK;
1650 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1652 return NT_STATUS_NO_MEMORY;
1655 if (!sec->verified_bitmask1) {
1656 t->commands = talloc_realloc(t, t->commands,
1657 struct dcerpc_sec_vt,
1658 t->count.count + 1);
1659 if (t->commands == NULL) {
1660 return NT_STATUS_NO_MEMORY;
1662 c = &t->commands[t->count.count++];
1665 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1666 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1667 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1669 req->verify_bitmask1 = true;
1672 if (!req->p->verified_pcontext) {
1673 t->commands = talloc_realloc(t, t->commands,
1674 struct dcerpc_sec_vt,
1675 t->count.count + 1);
1676 if (t->commands == NULL) {
1677 return NT_STATUS_NO_MEMORY;
1679 c = &t->commands[t->count.count++];
1682 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1683 c->u.pcontext.abstract_syntax = req->p->syntax;
1684 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1686 req->verify_pcontext = true;
1689 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1690 t->commands = talloc_realloc(t, t->commands,
1691 struct dcerpc_sec_vt,
1692 t->count.count + 1);
1693 if (t->commands == NULL) {
1694 return NT_STATUS_NO_MEMORY;
1696 c = &t->commands[t->count.count++];
1699 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1700 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1701 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1702 c->u.header2.drep[0] = 0;
1704 c->u.header2.drep[0] = DCERPC_DREP_LE;
1706 c->u.header2.drep[1] = 0;
1707 c->u.header2.drep[2] = 0;
1708 c->u.header2.drep[3] = 0;
1709 c->u.header2.call_id = req->call_id;
1710 c->u.header2.context_id = req->p->context_id;
1711 c->u.header2.opnum = req->opnum;
1714 if (t->count.count == 0) {
1716 return NT_STATUS_OK;
1719 c = &t->commands[t->count.count - 1];
1720 c->command |= DCERPC_SEC_VT_COMMAND_END;
1722 if (DEBUGLEVEL >= 10) {
1723 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1726 ndr = ndr_push_init_ctx(req);
1728 return NT_STATUS_NO_MEMORY;
1732 * for now we just copy and append
1735 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1736 req->request_data.length);
1737 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1738 return ndr_map_error2ntstatus(ndr_err);
1741 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1742 NDR_SCALARS | NDR_BUFFERS,
1744 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1745 return ndr_map_error2ntstatus(ndr_err);
1747 req->request_data = ndr_push_blob(ndr);
1749 return NT_STATUS_OK;
1753 Send a request using the transport
1756 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1758 struct rpc_request *req;
1759 struct dcerpc_pipe *p;
1760 DATA_BLOB *stub_data;
1761 struct ncacn_packet pkt;
1763 uint32_t remaining, chunk_size;
1764 bool first_packet = true;
1765 size_t sig_size = 0;
1766 bool need_async = false;
1767 bool can_async = true;
1769 req = c->request_queue;
1775 stub_data = &req->request_data;
1781 if (c->security_state.auth_info &&
1782 c->security_state.generic_state)
1784 struct gensec_security *gensec = c->security_state.generic_state;
1786 switch (c->security_state.auth_info->auth_level) {
1787 case DCERPC_AUTH_LEVEL_PRIVACY:
1788 case DCERPC_AUTH_LEVEL_INTEGRITY:
1789 can_async = gensec_have_feature(gensec,
1790 GENSEC_FEATURE_ASYNC_REPLIES);
1792 case DCERPC_AUTH_LEVEL_CONNECT:
1793 case DCERPC_AUTH_LEVEL_NONE:
1802 if (need_async && !can_async) {
1803 req->wait_for_sync = true;
1807 DLIST_REMOVE(c->request_queue, req);
1808 DLIST_ADD(c->pending, req);
1809 req->state = RPC_REQUEST_PENDING;
1811 init_ncacn_hdr(p->conn, &pkt);
1813 remaining = stub_data->length;
1815 /* we can write a full max_recv_frag size, minus the dcerpc
1816 request header size */
1817 chunk_size = p->conn->srv_max_recv_frag;
1818 chunk_size -= DCERPC_REQUEST_LENGTH;
1819 if (c->security_state.auth_info &&
1820 c->security_state.generic_state) {
1821 size_t max_payload = chunk_size;
1823 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1824 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1826 sig_size = gensec_sig_size(c->security_state.generic_state,
1829 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1830 chunk_size -= sig_size;
1833 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1835 pkt.ptype = DCERPC_PKT_REQUEST;
1836 pkt.call_id = req->call_id;
1837 pkt.auth_length = 0;
1839 pkt.u.request.context_id = p->context_id;
1840 pkt.u.request.opnum = req->opnum;
1843 pkt.u.request.object.object = *req->object;
1844 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1845 chunk_size -= ndr_size_GUID(req->object,0);
1848 /* we send a series of pdus without waiting for a reply */
1849 while (remaining > 0 || first_packet) {
1850 uint32_t chunk = MIN(chunk_size, remaining);
1851 bool last_frag = false;
1852 bool do_trans = false;
1854 first_packet = false;
1855 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1857 if (remaining == stub_data->length) {
1858 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1860 if (chunk == remaining) {
1861 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1865 pkt.u.request.alloc_hint = remaining;
1866 pkt.u.request.stub_and_verifier.data = stub_data->data +
1867 (stub_data->length - remaining);
1868 pkt.u.request.stub_and_verifier.length = chunk;
1870 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1871 if (!NT_STATUS_IS_OK(req->status)) {
1872 req->state = RPC_REQUEST_DONE;
1873 DLIST_REMOVE(p->conn->pending, req);
1877 if (last_frag && !need_async) {
1881 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1882 if (!NT_STATUS_IS_OK(req->status)) {
1883 req->state = RPC_REQUEST_DONE;
1884 DLIST_REMOVE(p->conn->pending, req);
1888 if (last_frag && !do_trans) {
1889 req->status = dcerpc_send_read(p->conn);
1890 if (!NT_STATUS_IS_OK(req->status)) {
1891 req->state = RPC_REQUEST_DONE;
1892 DLIST_REMOVE(p->conn->pending, req);
1901 static void dcerpc_io_trigger(struct tevent_context *ctx,
1902 struct tevent_immediate *im,
1905 struct dcecli_connection *c =
1906 talloc_get_type_abort(private_data,
1907 struct dcecli_connection);
1909 c->io_trigger_pending = false;
1911 dcerpc_schedule_io_trigger(c);
1913 dcerpc_ship_next_request(c);
1916 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1922 if (c->request_queue == NULL) {
1926 if (c->request_queue->wait_for_sync && c->pending) {
1930 if (c->io_trigger_pending) {
1934 c->io_trigger_pending = true;
1936 tevent_schedule_immediate(c->io_trigger,
1943 perform the receive side of a async dcerpc request
1945 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1946 TALLOC_CTX *mem_ctx,
1947 DATA_BLOB *stub_data)
1951 while (req->state != RPC_REQUEST_DONE) {
1952 struct tevent_context *ctx = req->p->conn->event_ctx;
1953 if (tevent_loop_once(ctx) != 0) {
1954 return NT_STATUS_CONNECTION_DISCONNECTED;
1957 *stub_data = req->payload;
1958 status = req->status;
1959 if (stub_data->data) {
1960 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1962 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1963 req->p->last_fault_code = req->fault_code;
1965 talloc_unlink(talloc_parent(req), req);
1970 this is a paranoid NDR validator. For every packet we push onto the wire
1971 we pull it back again, then push it again. Then we compare the raw NDR data
1972 for that to the NDR we initially generated. If they don't match then we know
1973 we must have a bug in either the pull or push side of our code
1975 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1976 TALLOC_CTX *mem_ctx,
1979 ndr_push_flags_fn_t ndr_push,
1980 ndr_pull_flags_fn_t ndr_pull)
1983 struct ndr_pull *pull;
1984 struct ndr_push *push;
1986 enum ndr_err_code ndr_err;
1988 st = talloc_size(mem_ctx, struct_size);
1990 return NT_STATUS_NO_MEMORY;
1993 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1995 return NT_STATUS_NO_MEMORY;
1997 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1999 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2000 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
2003 if (c->flags & DCERPC_NDR64) {
2004 pull->flags |= LIBNDR_FLAG_NDR64;
2007 ndr_err = ndr_pull(pull, NDR_IN, st);
2008 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2009 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2010 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2011 "failed input validation pull - %s",
2013 return ndr_map_error2ntstatus(ndr_err);
2016 push = ndr_push_init_ctx(mem_ctx);
2018 return NT_STATUS_NO_MEMORY;
2021 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2022 push->flags |= LIBNDR_FLAG_BIGENDIAN;
2025 if (c->flags & DCERPC_NDR64) {
2026 push->flags |= LIBNDR_FLAG_NDR64;
2029 ndr_err = ndr_push(push, NDR_IN, st);
2030 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2031 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2032 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2033 "failed input validation push - %s",
2035 return ndr_map_error2ntstatus(ndr_err);
2038 blob2 = ndr_push_blob(push);
2040 if (data_blob_cmp(&blob, &blob2) != 0) {
2041 DEBUG(3,("original:\n"));
2042 dump_data(3, blob.data, blob.length);
2043 DEBUG(3,("secondary:\n"));
2044 dump_data(3, blob2.data, blob2.length);
2045 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2046 "failed input validation blobs doesn't match");
2047 return ndr_map_error2ntstatus(ndr_err);
2050 return NT_STATUS_OK;
2054 this is a paranoid NDR input validator. For every packet we pull
2055 from the wire we push it back again then pull and push it
2056 again. Then we compare the raw NDR data for that to the NDR we
2057 initially generated. If they don't match then we know we must have a
2058 bug in either the pull or push side of our code
2060 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
2061 struct ndr_pull *pull_in,
2064 ndr_push_flags_fn_t ndr_push,
2065 ndr_pull_flags_fn_t ndr_pull,
2066 ndr_print_function_t ndr_print)
2069 struct ndr_pull *pull;
2070 struct ndr_push *push;
2071 DATA_BLOB blob, blob2;
2072 TALLOC_CTX *mem_ctx = pull_in;
2074 enum ndr_err_code ndr_err;
2076 st = talloc_size(mem_ctx, struct_size);
2078 return NT_STATUS_NO_MEMORY;
2080 memcpy(st, struct_ptr, struct_size);
2082 push = ndr_push_init_ctx(mem_ctx);
2084 return NT_STATUS_NO_MEMORY;
2087 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2088 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2089 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2090 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2091 "failed output validation push - %s",
2093 return ndr_map_error2ntstatus(ndr_err);
2096 blob = ndr_push_blob(push);
2098 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2100 return NT_STATUS_NO_MEMORY;
2103 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2104 ndr_err = ndr_pull(pull, NDR_OUT, st);
2105 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2106 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2107 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2108 "failed output validation pull - %s",
2110 return ndr_map_error2ntstatus(ndr_err);
2113 push = ndr_push_init_ctx(mem_ctx);
2115 return NT_STATUS_NO_MEMORY;
2118 ndr_err = ndr_push(push, NDR_OUT, st);
2119 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2120 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2121 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2122 "failed output validation push2 - %s",
2124 return ndr_map_error2ntstatus(ndr_err);
2127 blob2 = ndr_push_blob(push);
2129 if (data_blob_cmp(&blob, &blob2) != 0) {
2130 DEBUG(3,("original:\n"));
2131 dump_data(3, blob.data, blob.length);
2132 DEBUG(3,("secondary:\n"));
2133 dump_data(3, blob2.data, blob2.length);
2134 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2135 "failed output validation blobs doesn't match");
2136 return ndr_map_error2ntstatus(ndr_err);
2139 /* this checks the printed forms of the two structures, which effectively
2140 tests all of the value() attributes */
2141 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2142 NDR_OUT, struct_ptr);
2143 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2145 if (strcmp(s1, s2) != 0) {
2147 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2149 /* this is sometimes useful */
2150 printf("VALIDATE ERROR\n");
2151 file_save("wire.dat", s1, strlen(s1));
2152 file_save("gen.dat", s2, strlen(s2));
2153 system("diff -u wire.dat gen.dat");
2155 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2156 "failed output validation strings doesn't match");
2157 return ndr_map_error2ntstatus(ndr_err);
2160 return NT_STATUS_OK;
2164 a useful function for retrieving the server name we connected to
2166 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2168 return p->conn ? p->conn->server_name : NULL;
2173 get the dcerpc auth_level for a open connection
2175 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2179 if (c->flags & DCERPC_SEAL) {
2180 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2181 } else if (c->flags & DCERPC_SIGN) {
2182 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2183 } else if (c->flags & DCERPC_CONNECT) {
2184 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2186 auth_level = DCERPC_AUTH_LEVEL_NONE;
2191 struct dcerpc_alter_context_state {
2192 struct tevent_context *ev;
2193 struct dcerpc_pipe *p;
2196 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2197 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2198 DATA_BLOB *raw_packet,
2199 struct ncacn_packet *pkt);
2201 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2202 struct tevent_context *ev,
2203 struct dcerpc_pipe *p,
2204 const struct ndr_syntax_id *syntax,
2205 const struct ndr_syntax_id *transfer_syntax)
2207 struct tevent_req *req;
2208 struct dcerpc_alter_context_state *state;
2209 struct ncacn_packet pkt;
2212 struct rpc_request *subreq;
2215 req = tevent_req_create(mem_ctx, &state,
2216 struct dcerpc_alter_context_state);
2224 p->syntax = *syntax;
2225 p->transfer_syntax = *transfer_syntax;
2227 flags = dcerpc_binding_get_flags(p->binding);
2229 init_ncacn_hdr(p->conn, &pkt);
2231 pkt.ptype = DCERPC_PKT_ALTER;
2232 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2233 pkt.call_id = p->conn->call_id;
2234 pkt.auth_length = 0;
2236 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2237 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2240 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2241 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2242 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2243 pkt.u.alter.num_contexts = 1;
2244 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2245 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2246 return tevent_req_post(req, ev);
2248 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2249 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2250 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2251 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2252 pkt.u.alter.auth_info = data_blob(NULL, 0);
2254 /* construct the NDR form of the packet */
2255 status = ncacn_push_auth(&blob, state, &pkt,
2256 p->conn->security_state.auth_info);
2257 if (tevent_req_nterror(req, status)) {
2258 return tevent_req_post(req, ev);
2262 * we allocate a dcerpc_request so we can be in the same
2263 * request queue as normal requests
2265 subreq = talloc_zero(state, struct rpc_request);
2266 if (tevent_req_nomem(subreq, req)) {
2267 return tevent_req_post(req, ev);
2270 subreq->state = RPC_REQUEST_PENDING;
2271 subreq->call_id = pkt.call_id;
2272 subreq->async.private_data = req;
2273 subreq->async.callback = dcerpc_alter_context_fail_handler;
2275 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2276 DLIST_ADD_END(p->conn->pending, subreq);
2277 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2279 status = dcerpc_send_request(p->conn, &blob, true);
2280 if (tevent_req_nterror(req, status)) {
2281 return tevent_req_post(req, ev);
2284 tevent_add_timer(ev, subreq,
2285 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2286 dcerpc_timeout_handler, subreq);
2291 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2293 struct tevent_req *req =
2294 talloc_get_type_abort(subreq->async.private_data,
2296 struct dcerpc_alter_context_state *state =
2297 tevent_req_data(req,
2298 struct dcerpc_alter_context_state);
2299 NTSTATUS status = subreq->status;
2301 TALLOC_FREE(subreq);
2304 * We trigger the callback in the next event run
2305 * because the code in this file might trigger
2306 * multiple request callbacks from within a single
2309 * In order to avoid segfaults from within
2310 * dcerpc_connection_dead() we call
2311 * tevent_req_defer_callback().
2313 tevent_req_defer_callback(req, state->ev);
2315 tevent_req_nterror(req, status);
2318 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2319 DATA_BLOB *raw_packet,
2320 struct ncacn_packet *pkt)
2322 struct tevent_req *req =
2323 talloc_get_type_abort(subreq->async.private_data,
2325 struct dcerpc_alter_context_state *state =
2326 tevent_req_data(req,
2327 struct dcerpc_alter_context_state);
2328 struct dcecli_connection *conn = state->p->conn;
2332 * Note that pkt is allocated under raw_packet->data,
2333 * while raw_packet->data is a child of subreq.
2335 talloc_steal(state, raw_packet->data);
2336 TALLOC_FREE(subreq);
2339 * We trigger the callback in the next event run
2340 * because the code in this file might trigger
2341 * multiple request callbacks from within a single
2344 * In order to avoid segfaults from within
2345 * dcerpc_connection_dead() we call
2346 * tevent_req_defer_callback().
2348 tevent_req_defer_callback(req, state->ev);
2350 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2351 pkt->u.alter_resp.num_results == 1 &&
2352 pkt->u.alter_resp.ctx_list[0].result != 0) {
2353 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2354 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2355 pkt->u.alter_resp.ctx_list[0].reason.value,
2356 nt_errstr(status)));
2357 tevent_req_nterror(req, status);
2361 if (pkt->ptype == DCERPC_PKT_FAULT) {
2362 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2363 dcerpc_errstr(state, pkt->u.fault.status)));
2364 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2365 state->p->last_fault_code = pkt->u.fault.status;
2366 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2367 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2368 state->p->last_fault_code = pkt->u.fault.status;
2369 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2371 state->p->last_fault_code = pkt->u.fault.status;
2372 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2373 tevent_req_nterror(req, status);
2378 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2379 pkt->u.alter_resp.num_results == 0 ||
2380 pkt->u.alter_resp.ctx_list[0].result != 0) {
2381 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2382 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2386 /* the alter_resp might contain a reply set of credentials */
2387 if (conn->security_state.auth_info &&
2388 pkt->u.alter_resp.auth_info.length) {
2389 uint32_t auth_length;
2391 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2392 conn->security_state.auth_info, &auth_length, true);
2393 if (tevent_req_nterror(req, status)) {
2398 tevent_req_done(req);
2401 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2403 return tevent_req_simple_recv_ntstatus(req);
2407 send a dcerpc alter_context request
2409 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2410 TALLOC_CTX *mem_ctx,
2411 const struct ndr_syntax_id *syntax,
2412 const struct ndr_syntax_id *transfer_syntax)
2414 struct tevent_req *subreq;
2415 struct tevent_context *ev = p->conn->event_ctx;
2418 /* TODO: create a new event context here */
2420 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2421 p, syntax, transfer_syntax);
2422 if (subreq == NULL) {
2423 return NT_STATUS_NO_MEMORY;
2426 ok = tevent_req_poll(subreq, ev);
2429 status = map_nt_error_from_unix_common(errno);
2433 return dcerpc_alter_context_recv(subreq);
2436 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2438 if (c->transport.stream == NULL) {
2442 tevent_queue_stop(c->transport.write_queue);
2443 TALLOC_FREE(c->transport.read_subreq);
2444 TALLOC_FREE(c->transport.stream);
2446 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2447 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2450 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2451 status = NT_STATUS_END_OF_FILE;
2454 dcerpc_recv_data(c, NULL, status);
2459 shutdown SMB pipe connection
2461 struct dcerpc_shutdown_pipe_state {
2462 struct dcecli_connection *c;
2466 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2468 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2470 struct dcerpc_shutdown_pipe_state *state;
2471 struct tevent_req *subreq;
2473 if (c->transport.stream == NULL) {
2474 return NT_STATUS_OK;
2477 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2478 if (state == NULL) {
2479 return NT_STATUS_NO_MEMORY;
2482 state->status = status;
2484 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2485 if (subreq == NULL) {
2486 return NT_STATUS_NO_MEMORY;
2488 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2493 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2495 struct dcerpc_shutdown_pipe_state *state =
2496 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2497 struct dcecli_connection *c = state->c;
2498 NTSTATUS status = state->status;
2502 * here we ignore the return values...
2504 tstream_disconnect_recv(subreq, &error);
2505 TALLOC_FREE(subreq);
2509 dcerpc_transport_dead(c, status);
2514 struct dcerpc_send_read_state {
2515 struct dcecli_connection *p;
2518 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2520 struct dcecli_connection *p = state->p;
2522 p->transport.read_subreq = NULL;
2527 static void dcerpc_send_read_done(struct tevent_req *subreq);
2529 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2531 struct dcerpc_send_read_state *state;
2533 if (p->transport.read_subreq != NULL) {
2534 p->transport.pending_reads++;
2535 return NT_STATUS_OK;
2538 state = talloc_zero(p, struct dcerpc_send_read_state);
2539 if (state == NULL) {
2540 return NT_STATUS_NO_MEMORY;
2544 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2546 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2548 p->transport.stream);
2549 if (p->transport.read_subreq == NULL) {
2550 return NT_STATUS_NO_MEMORY;
2552 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2554 return NT_STATUS_OK;
2557 static void dcerpc_send_read_done(struct tevent_req *subreq)
2559 struct dcerpc_send_read_state *state =
2560 tevent_req_callback_data(subreq,
2561 struct dcerpc_send_read_state);
2562 struct dcecli_connection *p = state->p;
2564 struct ncacn_packet *pkt;
2567 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2569 TALLOC_FREE(subreq);
2570 if (!NT_STATUS_IS_OK(status)) {
2572 dcerpc_transport_dead(p, status);
2577 * here we steal into thet connection context,
2578 * but p->transport.recv_data() will steal or free it again
2580 talloc_steal(p, blob.data);
2583 if (p->transport.pending_reads > 0) {
2584 p->transport.pending_reads--;
2586 status = dcerpc_send_read(p);
2587 if (!NT_STATUS_IS_OK(status)) {
2588 dcerpc_transport_dead(p, status);
2593 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2596 struct dcerpc_send_request_state {
2597 struct dcecli_connection *p;
2602 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2604 struct dcecli_connection *p = state->p;
2606 p->transport.read_subreq = NULL;
2611 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2612 static void dcerpc_send_request_done(struct tevent_req *subreq);
2614 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2617 struct dcerpc_send_request_state *state;
2618 struct tevent_req *subreq;
2619 bool use_trans = trigger_read;
2621 if (p->transport.stream == NULL) {
2622 return NT_STATUS_CONNECTION_DISCONNECTED;
2625 state = talloc_zero(p, struct dcerpc_send_request_state);
2626 if (state == NULL) {
2627 return NT_STATUS_NO_MEMORY;
2631 state->blob = data_blob_talloc(state, data->data, data->length);
2632 if (state->blob.data == NULL) {
2634 return NT_STATUS_NO_MEMORY;
2636 state->iov.iov_base = (void *)state->blob.data;
2637 state->iov.iov_len = state->blob.length;
2639 if (p->transport.read_subreq != NULL) {
2643 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2649 * we need to block reads until our write is
2650 * the next in the write queue.
2652 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2653 p->transport.write_queue);
2654 if (p->transport.read_subreq == NULL) {
2656 return NT_STATUS_NO_MEMORY;
2658 tevent_req_set_callback(p->transport.read_subreq,
2659 dcerpc_send_request_wait_done,
2662 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2664 trigger_read = false;
2667 subreq = tstream_writev_queue_send(state, p->event_ctx,
2668 p->transport.stream,
2669 p->transport.write_queue,
2671 if (subreq == NULL) {
2673 return NT_STATUS_NO_MEMORY;
2675 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2678 dcerpc_send_read(p);
2681 return NT_STATUS_OK;
2684 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2686 struct dcerpc_send_request_state *state =
2687 tevent_req_callback_data(subreq,
2688 struct dcerpc_send_request_state);
2689 struct dcecli_connection *p = state->p;
2693 p->transport.read_subreq = NULL;
2694 talloc_set_destructor(state, NULL);
2696 ok = tevent_queue_wait_recv(subreq);
2699 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2703 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2704 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2705 if (!NT_STATUS_IS_OK(status)) {
2707 dcerpc_transport_dead(p, status);
2712 /* we free subreq after tstream_cli_np_use_trans */
2713 TALLOC_FREE(subreq);
2715 dcerpc_send_read(p);
2718 static void dcerpc_send_request_done(struct tevent_req *subreq)
2720 struct dcerpc_send_request_state *state =
2721 tevent_req_callback_data(subreq,
2722 struct dcerpc_send_request_state);
2726 ret = tstream_writev_queue_recv(subreq, &error);
2727 TALLOC_FREE(subreq);
2729 struct dcecli_connection *p = state->p;
2730 NTSTATUS status = map_nt_error_from_unix_common(error);
2733 dcerpc_transport_dead(p, status);