2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "librpc/rpc/rpc_common.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "libcli/smb/tstream_smbXcli_np.h"
39 enum rpc_request_state {
46 handle for an async dcerpc request
49 struct rpc_request *next, *prev;
50 struct dcerpc_pipe *p;
53 enum rpc_request_state state;
58 /* this is used to distinguish bind and alter_context requests
59 from normal requests */
60 void (*recv_handler)(struct rpc_request *conn,
61 DATA_BLOB *blob, struct ncacn_packet *pkt);
63 const struct GUID *object;
65 DATA_BLOB request_data;
72 void (*callback)(struct rpc_request *);
77 _PUBLIC_ NTSTATUS dcerpc_init(void)
82 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
83 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
85 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
86 struct dcerpc_pipe *p,
87 const struct GUID *object,
89 DATA_BLOB *stub_data);
90 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
92 DATA_BLOB *stub_data);
93 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
97 ndr_push_flags_fn_t ndr_push,
98 ndr_pull_flags_fn_t ndr_pull);
99 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
100 struct ndr_pull *pull_in,
103 ndr_push_flags_fn_t ndr_push,
104 ndr_pull_flags_fn_t ndr_pull,
105 ndr_print_function_t ndr_print);
106 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
107 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
109 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
111 /* destroy a dcerpc connection */
112 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
115 conn->free_skipped = true;
118 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
123 /* initialise a dcerpc connection.
124 the event context is optional
126 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
127 struct tevent_context *ev)
129 struct dcecli_connection *c;
131 c = talloc_zero(mem_ctx, struct dcecli_connection);
138 if (c->event_ctx == NULL) {
144 c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
145 c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
146 c->security_state.auth_context_id = 0;
147 c->security_state.session_key = dcerpc_generic_session_key;
148 c->security_state.generic_state = NULL;
151 * Windows uses 5840 for ncacn_ip_tcp,
152 * so we also use it (for every transport)
153 * by default. But we give the transport
154 * the chance to overwrite it.
156 c->srv_max_xmit_frag = 5840;
157 c->srv_max_recv_frag = 5840;
160 c->io_trigger = tevent_create_immediate(c);
161 if (c->io_trigger == NULL) {
166 talloc_set_destructor(c, dcerpc_connection_destructor);
171 struct dcerpc_bh_state {
172 struct dcerpc_pipe *p;
175 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
177 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
178 struct dcerpc_bh_state);
188 if (hs->p->conn->dead) {
195 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
198 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
199 struct dcerpc_bh_state);
203 return DCERPC_REQUEST_TIMEOUT;
206 old = hs->p->request_timeout;
207 hs->p->request_timeout = timeout;
212 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
213 enum dcerpc_AuthType *auth_type,
214 enum dcerpc_AuthLevel *auth_level)
216 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
217 struct dcerpc_bh_state);
223 if (hs->p->conn == NULL) {
227 *auth_type = hs->p->conn->security_state.auth_type;
228 *auth_level = hs->p->conn->security_state.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 status = dcerpc_verify_ncacn_packet_header(pkt, DCERPC_PKT_RESPONSE,
745 pkt->u.response.stub_and_verifier.length,
746 0, /* required_flags */
747 DCERPC_PFC_FLAG_FIRST |
748 DCERPC_PFC_FLAG_LAST);
749 if (!NT_STATUS_IS_OK(status)) {
753 switch (c->security_state.auth_level) {
754 case DCERPC_AUTH_LEVEL_PRIVACY:
755 case DCERPC_AUTH_LEVEL_INTEGRITY:
758 case DCERPC_AUTH_LEVEL_CONNECT:
759 if (pkt->auth_length != 0) {
763 case DCERPC_AUTH_LEVEL_NONE:
764 if (pkt->auth_length != 0) {
765 return NT_STATUS_INVALID_NETWORK_RESPONSE;
770 return NT_STATUS_INVALID_LEVEL;
773 if (pkt->auth_length == 0) {
774 return NT_STATUS_INVALID_NETWORK_RESPONSE;
777 if (c->security_state.generic_state == NULL) {
778 return NT_STATUS_INTERNAL_ERROR;
781 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
782 &pkt->u.response.stub_and_verifier,
783 &auth, &auth_length, false);
784 NT_STATUS_NOT_OK_RETURN(status);
786 pkt->u.response.stub_and_verifier.length -= auth_length;
788 if (auth.auth_type != c->security_state.auth_type) {
789 return NT_STATUS_RPC_PROTOCOL_ERROR;
792 if (auth.auth_level != c->security_state.auth_level) {
793 return NT_STATUS_RPC_PROTOCOL_ERROR;
796 if (auth.auth_context_id != c->security_state.auth_context_id) {
797 return NT_STATUS_RPC_PROTOCOL_ERROR;
800 /* check signature or unseal the packet */
801 switch (c->security_state.auth_level) {
802 case DCERPC_AUTH_LEVEL_PRIVACY:
803 status = gensec_unseal_packet(c->security_state.generic_state,
804 raw_packet->data + DCERPC_REQUEST_LENGTH,
805 pkt->u.response.stub_and_verifier.length,
807 raw_packet->length - auth.credentials.length,
809 memcpy(pkt->u.response.stub_and_verifier.data,
810 raw_packet->data + DCERPC_REQUEST_LENGTH,
811 pkt->u.response.stub_and_verifier.length);
814 case DCERPC_AUTH_LEVEL_INTEGRITY:
815 status = gensec_check_packet(c->security_state.generic_state,
816 pkt->u.response.stub_and_verifier.data,
817 pkt->u.response.stub_and_verifier.length,
819 raw_packet->length - auth.credentials.length,
823 case DCERPC_AUTH_LEVEL_CONNECT:
824 /* for now we ignore possible signatures here */
825 status = NT_STATUS_OK;
829 status = NT_STATUS_INVALID_LEVEL;
833 /* remove the indicated amount of padding */
834 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
835 return NT_STATUS_INFO_LENGTH_MISMATCH;
837 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
844 push a dcerpc request packet into a blob, possibly signing it.
846 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
847 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
849 struct ncacn_packet *pkt)
852 struct ndr_push *ndr;
854 size_t payload_length;
855 enum ndr_err_code ndr_err;
856 size_t hdr_size = DCERPC_REQUEST_LENGTH;
857 struct dcerpc_auth auth_info = {
858 .auth_type = c->security_state.auth_type,
859 .auth_level = c->security_state.auth_level,
860 .auth_context_id = c->security_state.auth_context_id,
863 switch (c->security_state.auth_level) {
864 case DCERPC_AUTH_LEVEL_PRIVACY:
865 case DCERPC_AUTH_LEVEL_INTEGRITY:
867 return NT_STATUS_INTERNAL_ERROR;
871 case DCERPC_AUTH_LEVEL_CONNECT:
872 /* TODO: let the gensec mech decide if it wants to generate a signature */
873 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
875 case DCERPC_AUTH_LEVEL_NONE:
876 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
879 return NT_STATUS_INVALID_LEVEL;
882 ndr = ndr_push_init_ctx(mem_ctx);
884 return NT_STATUS_NO_MEMORY;
887 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
888 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
891 if (c->flags & DCERPC_NDR64) {
892 ndr->flags |= LIBNDR_FLAG_NDR64;
895 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
896 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
900 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
901 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
902 return ndr_map_error2ntstatus(ndr_err);
905 /* pad to 16 byte multiple in the payload portion of the
906 packet. This matches what w2k3 does. Note that we can't use
907 ndr_push_align() as that is relative to the start of the
908 whole packet, whereas w2k8 wants it relative to the start
910 auth_info.auth_pad_length =
911 DCERPC_AUTH_PAD_LENGTH(pkt->u.request.stub_and_verifier.length);
912 ndr_err = ndr_push_zero(ndr, auth_info.auth_pad_length);
913 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
914 return ndr_map_error2ntstatus(ndr_err);
917 payload_length = pkt->u.request.stub_and_verifier.length +
918 auth_info.auth_pad_length;
920 /* add the auth verifier */
921 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth_info);
922 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
923 return ndr_map_error2ntstatus(ndr_err);
926 /* extract the whole packet as a blob */
927 *blob = ndr_push_blob(ndr);
930 * Setup the frag and auth length in the packet buffer.
931 * This is needed if the GENSEC mech does AEAD signing
932 * of the packet headers. The signature itself will be
935 dcerpc_set_frag_length(blob, blob->length + sig_size);
936 dcerpc_set_auth_length(blob, sig_size);
938 /* sign or seal the packet */
939 switch (c->security_state.auth_level) {
940 case DCERPC_AUTH_LEVEL_PRIVACY:
941 status = gensec_seal_packet(c->security_state.generic_state,
943 blob->data + hdr_size,
948 if (!NT_STATUS_IS_OK(status)) {
953 case DCERPC_AUTH_LEVEL_INTEGRITY:
954 status = gensec_sign_packet(c->security_state.generic_state,
956 blob->data + hdr_size,
961 if (!NT_STATUS_IS_OK(status)) {
967 status = NT_STATUS_INVALID_LEVEL;
971 if (creds2.length != sig_size) {
972 /* this means the sig_size estimate for the signature
973 was incorrect. We have to correct the packet
974 sizes. That means we could go over the max fragment
976 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
977 (unsigned) creds2.length,
979 (unsigned) auth_info.auth_pad_length,
980 (unsigned) pkt->u.request.stub_and_verifier.length));
981 dcerpc_set_frag_length(blob, blob->length + creds2.length);
982 dcerpc_set_auth_length(blob, creds2.length);
985 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
986 return NT_STATUS_NO_MEMORY;
994 fill in the fixed values in a dcerpc header
996 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
999 pkt->rpc_vers_minor = 0;
1000 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1003 pkt->drep[0] = DCERPC_DREP_LE;
1011 map a bind nak reason to a NTSTATUS
1013 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
1016 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
1017 return NT_STATUS_REVISION_MISMATCH;
1018 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
1019 return NT_STATUS_INVALID_PARAMETER;
1023 return NT_STATUS_UNSUCCESSFUL;
1026 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
1029 return NT_STATUS_RPC_PROTOCOL_ERROR;
1032 switch (ack->result) {
1033 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
1035 * We have not asked for this...
1037 return NT_STATUS_RPC_PROTOCOL_ERROR;
1042 switch (ack->reason.value) {
1043 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
1044 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1045 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
1046 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1050 return NT_STATUS_UNSUCCESSFUL;
1054 remove requests from the pending or queued queues
1056 static int dcerpc_req_dequeue(struct rpc_request *req)
1058 switch (req->state) {
1059 case RPC_REQUEST_QUEUED:
1060 DLIST_REMOVE(req->p->conn->request_queue, req);
1062 case RPC_REQUEST_PENDING:
1063 DLIST_REMOVE(req->p->conn->pending, req);
1065 case RPC_REQUEST_DONE:
1073 mark the dcerpc connection dead. All outstanding requests get an error
1075 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1077 if (conn->dead) return;
1081 TALLOC_FREE(conn->io_trigger);
1082 conn->io_trigger_pending = false;
1084 dcerpc_shutdown_pipe(conn, status);
1086 /* all pending requests get the error */
1087 while (conn->pending) {
1088 struct rpc_request *req = conn->pending;
1089 dcerpc_req_dequeue(req);
1090 req->state = RPC_REQUEST_DONE;
1091 req->status = status;
1092 if (req->async.callback) {
1093 req->async.callback(req);
1097 /* all requests, which are not shipped */
1098 while (conn->request_queue) {
1099 struct rpc_request *req = conn->request_queue;
1100 dcerpc_req_dequeue(req);
1101 req->state = RPC_REQUEST_DONE;
1102 req->status = status;
1103 if (req->async.callback) {
1104 req->async.callback(req);
1108 talloc_set_destructor(conn, NULL);
1109 if (conn->free_skipped) {
1115 forward declarations of the recv_data handlers for the types of
1116 packets we need to handle
1118 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1119 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1122 receive a dcerpc reply from the transport. Here we work out what
1123 type of reply it is (normal request, bind or alter context) and
1124 dispatch to the appropriate handler
1126 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1128 struct ncacn_packet pkt;
1134 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1135 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1138 /* the transport may be telling us of a severe error, such as
1140 if (!NT_STATUS_IS_OK(status)) {
1141 data_blob_free(blob);
1142 dcerpc_connection_dead(conn, status);
1146 /* parse the basic packet to work out what type of response this is */
1147 status = ncacn_pull(conn, blob, blob->data, &pkt);
1148 if (!NT_STATUS_IS_OK(status)) {
1149 data_blob_free(blob);
1150 dcerpc_connection_dead(conn, status);
1154 dcerpc_request_recv_data(conn, blob, &pkt);
1158 handle timeouts of individual dcerpc requests
1160 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1161 struct timeval t, void *private_data)
1163 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1165 if (req->ignore_timeout) {
1166 dcerpc_req_dequeue(req);
1167 req->state = RPC_REQUEST_DONE;
1168 req->status = NT_STATUS_IO_TIMEOUT;
1169 if (req->async.callback) {
1170 req->async.callback(req);
1175 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1178 struct dcerpc_bind_state {
1179 struct tevent_context *ev;
1180 struct dcerpc_pipe *p;
1183 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1184 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1185 DATA_BLOB *raw_packet,
1186 struct ncacn_packet *pkt);
1188 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1189 struct tevent_context *ev,
1190 struct dcerpc_pipe *p,
1191 const struct ndr_syntax_id *syntax,
1192 const struct ndr_syntax_id *transfer_syntax)
1194 struct tevent_req *req;
1195 struct dcerpc_bind_state *state;
1196 struct ncacn_packet pkt;
1199 struct rpc_request *subreq;
1202 req = tevent_req_create(mem_ctx, &state,
1203 struct dcerpc_bind_state);
1211 p->syntax = *syntax;
1212 p->transfer_syntax = *transfer_syntax;
1214 flags = dcerpc_binding_get_flags(p->binding);
1216 init_ncacn_hdr(p->conn, &pkt);
1218 pkt.ptype = DCERPC_PKT_BIND;
1219 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1220 pkt.call_id = p->conn->call_id;
1221 pkt.auth_length = 0;
1223 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1224 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1227 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1228 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1231 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1232 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1233 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1234 pkt.u.bind.num_contexts = 1;
1235 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1236 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1237 return tevent_req_post(req, ev);
1239 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1240 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1241 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1242 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1243 pkt.u.bind.auth_info = data_blob(NULL, 0);
1245 /* construct the NDR form of the packet */
1246 status = ncacn_push_auth(&blob, state, &pkt,
1247 p->conn->security_state.tmp_auth_info.out);
1248 if (tevent_req_nterror(req, status)) {
1249 return tevent_req_post(req, ev);
1253 * we allocate a dcerpc_request so we can be in the same
1254 * request queue as normal requests
1256 subreq = talloc_zero(state, struct rpc_request);
1257 if (tevent_req_nomem(subreq, req)) {
1258 return tevent_req_post(req, ev);
1261 subreq->state = RPC_REQUEST_PENDING;
1262 subreq->call_id = pkt.call_id;
1263 subreq->async.private_data = req;
1264 subreq->async.callback = dcerpc_bind_fail_handler;
1266 subreq->recv_handler = dcerpc_bind_recv_handler;
1267 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1268 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1270 status = dcerpc_send_request(p->conn, &blob, true);
1271 if (tevent_req_nterror(req, status)) {
1272 return tevent_req_post(req, ev);
1275 tevent_add_timer(ev, subreq,
1276 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1277 dcerpc_timeout_handler, subreq);
1282 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1284 struct tevent_req *req =
1285 talloc_get_type_abort(subreq->async.private_data,
1287 struct dcerpc_bind_state *state =
1288 tevent_req_data(req,
1289 struct dcerpc_bind_state);
1290 NTSTATUS status = subreq->status;
1292 TALLOC_FREE(subreq);
1295 * We trigger the callback in the next event run
1296 * because the code in this file might trigger
1297 * multiple request callbacks from within a single
1300 * In order to avoid segfaults from within
1301 * dcerpc_connection_dead() we call
1302 * tevent_req_defer_callback().
1304 tevent_req_defer_callback(req, state->ev);
1306 tevent_req_nterror(req, status);
1309 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1310 DATA_BLOB *raw_packet,
1311 struct ncacn_packet *pkt)
1313 struct tevent_req *req =
1314 talloc_get_type_abort(subreq->async.private_data,
1316 struct dcerpc_bind_state *state =
1317 tevent_req_data(req,
1318 struct dcerpc_bind_state);
1319 struct dcecli_connection *conn = state->p->conn;
1320 struct dcecli_security *sec = &conn->security_state;
1321 struct dcerpc_binding *b = NULL;
1326 * Note that pkt is allocated under raw_packet->data,
1327 * while raw_packet->data is a child of subreq.
1329 talloc_steal(state, raw_packet->data);
1330 TALLOC_FREE(subreq);
1333 * We trigger the callback in the next event run
1334 * because the code in this file might trigger
1335 * multiple request callbacks from within a single
1338 * In order to avoid segfaults from within
1339 * dcerpc_connection_dead() we call
1340 * tevent_req_defer_callback().
1342 tevent_req_defer_callback(req, state->ev);
1344 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1345 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1347 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1348 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1350 tevent_req_nterror(req, status);
1354 status = dcerpc_verify_ncacn_packet_header(pkt,
1355 DCERPC_PKT_BIND_ACK,
1356 pkt->u.bind_ack.auth_info.length,
1357 DCERPC_PFC_FLAG_FIRST |
1358 DCERPC_PFC_FLAG_LAST,
1359 DCERPC_PFC_FLAG_CONC_MPX |
1360 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1361 if (!NT_STATUS_IS_OK(status)) {
1362 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1363 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1367 if (pkt->u.bind_ack.num_results != 1) {
1368 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1369 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1373 if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1374 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1375 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1376 pkt->u.bind_ack.ctx_list[0].reason.value,
1377 nt_errstr(status)));
1378 tevent_req_nterror(req, status);
1383 * DCE-RPC 1.1 (c706) specifies
1384 * CONST_MUST_RCV_FRAG_SIZE as 1432
1386 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1387 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1388 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1391 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1392 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1393 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1396 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1397 pkt->u.bind_ack.max_xmit_frag);
1398 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1399 pkt->u.bind_ack.max_recv_frag);
1401 flags = dcerpc_binding_get_flags(state->p->binding);
1403 if ((flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1404 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1405 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1408 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1409 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1410 conn->flags |= DCERPC_HEADER_SIGNING;
1413 /* the bind_ack might contain a reply set of credentials */
1414 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1415 uint32_t auth_length;
1417 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1418 &pkt->u.bind_ack.auth_info,
1419 sec->tmp_auth_info.in,
1420 &auth_length, true);
1421 if (tevent_req_nterror(req, status)) {
1427 * We're the owner of the binding, so we're allowed to modify it.
1429 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1430 status = dcerpc_binding_set_assoc_group_id(b,
1431 pkt->u.bind_ack.assoc_group_id);
1432 if (tevent_req_nterror(req, status)) {
1436 tevent_req_done(req);
1439 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1441 return tevent_req_simple_recv_ntstatus(req);
1445 perform a continued bind (and auth3)
1447 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1448 TALLOC_CTX *mem_ctx)
1450 struct ncacn_packet pkt;
1455 flags = dcerpc_binding_get_flags(p->binding);
1457 init_ncacn_hdr(p->conn, &pkt);
1459 pkt.ptype = DCERPC_PKT_AUTH3;
1460 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1461 pkt.call_id = next_call_id(p->conn);
1462 pkt.auth_length = 0;
1463 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1465 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1466 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1469 /* construct the NDR form of the packet */
1470 status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1471 p->conn->security_state.tmp_auth_info.out);
1472 if (!NT_STATUS_IS_OK(status)) {
1476 /* send it on its way */
1477 status = dcerpc_send_request(p->conn, &blob, false);
1478 if (!NT_STATUS_IS_OK(status)) {
1482 return NT_STATUS_OK;
1487 process a fragment received from the transport layer during a
1490 This function frees the data
1492 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1493 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1495 struct rpc_request *req;
1496 unsigned int length;
1497 NTSTATUS status = NT_STATUS_OK;
1500 if this is an authenticated connection then parse and check
1501 the auth info. We have to do this before finding the
1502 matching packet, as the request structure might have been
1503 removed due to a timeout, but if it has been we still need
1504 to run the auth routines so that we don't get the sign/seal
1505 info out of step with the server
1507 if (pkt->ptype == DCERPC_PKT_RESPONSE) {
1508 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1511 /* find the matching request */
1512 for (req=c->pending;req;req=req->next) {
1513 if (pkt->call_id == req->call_id) break;
1517 /* useful for testing certain vendors RPC servers */
1518 if (req == NULL && c->pending && pkt->call_id == 0) {
1519 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1525 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1526 data_blob_free(raw_packet);
1530 talloc_steal(req, raw_packet->data);
1532 if (req->recv_handler != NULL) {
1533 dcerpc_req_dequeue(req);
1534 req->state = RPC_REQUEST_DONE;
1537 * We have to look at shipping further requests before calling
1538 * the async function, that one might close the pipe
1540 dcerpc_schedule_io_trigger(c);
1542 req->recv_handler(req, raw_packet, pkt);
1546 if (pkt->ptype == DCERPC_PKT_FAULT) {
1547 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1548 req->fault_code = pkt->u.fault.status;
1549 req->status = NT_STATUS_NET_WRITE_FAULT;
1553 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1554 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1556 req->fault_code = DCERPC_FAULT_OTHER;
1557 req->status = NT_STATUS_NET_WRITE_FAULT;
1561 /* now check the status from the auth routines, and if it failed then fail
1562 this request accordingly */
1563 if (!NT_STATUS_IS_OK(status)) {
1564 req->status = status;
1568 length = pkt->u.response.stub_and_verifier.length;
1571 req->payload.data = talloc_realloc(req,
1574 req->payload.length + length);
1575 if (!req->payload.data) {
1576 req->status = NT_STATUS_NO_MEMORY;
1579 memcpy(req->payload.data+req->payload.length,
1580 pkt->u.response.stub_and_verifier.data, length);
1581 req->payload.length += length;
1584 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1585 data_blob_free(raw_packet);
1586 dcerpc_send_read(c);
1590 if (req->verify_bitmask1) {
1591 req->p->conn->security_state.verified_bitmask1 = true;
1593 if (req->verify_pcontext) {
1594 req->p->verified_pcontext = true;
1597 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1598 req->flags |= DCERPC_PULL_BIGENDIAN;
1600 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1604 data_blob_free(raw_packet);
1606 /* we've got the full payload */
1607 dcerpc_req_dequeue(req);
1608 req->state = RPC_REQUEST_DONE;
1611 * We have to look at shipping further requests before calling
1612 * the async function, that one might close the pipe
1614 dcerpc_schedule_io_trigger(c);
1616 if (req->async.callback) {
1617 req->async.callback(req);
1621 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1624 perform the send side of a async dcerpc request
1626 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1627 struct dcerpc_pipe *p,
1628 const struct GUID *object,
1630 DATA_BLOB *stub_data)
1632 struct rpc_request *req;
1635 req = talloc_zero(mem_ctx, struct rpc_request);
1641 req->call_id = next_call_id(p->conn);
1642 req->state = RPC_REQUEST_QUEUED;
1644 if (object != NULL) {
1645 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1646 if (req->object == NULL) {
1653 req->request_data.length = stub_data->length;
1654 req->request_data.data = stub_data->data;
1656 status = dcerpc_request_prepare_vt(req);
1657 if (!NT_STATUS_IS_OK(status)) {
1662 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1663 talloc_set_destructor(req, dcerpc_req_dequeue);
1665 dcerpc_schedule_io_trigger(p->conn);
1667 if (p->request_timeout) {
1668 tevent_add_timer(p->conn->event_ctx, req,
1669 timeval_current_ofs(p->request_timeout, 0),
1670 dcerpc_timeout_handler, req);
1676 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1678 struct dcecli_security *sec = &req->p->conn->security_state;
1679 struct dcerpc_sec_verification_trailer *t;
1680 struct dcerpc_sec_vt *c = NULL;
1681 struct ndr_push *ndr = NULL;
1682 enum ndr_err_code ndr_err;
1684 if (sec->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
1685 return NT_STATUS_OK;
1688 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1690 return NT_STATUS_NO_MEMORY;
1693 if (!sec->verified_bitmask1) {
1694 t->commands = talloc_realloc(t, t->commands,
1695 struct dcerpc_sec_vt,
1696 t->count.count + 1);
1697 if (t->commands == NULL) {
1698 return NT_STATUS_NO_MEMORY;
1700 c = &t->commands[t->count.count++];
1703 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1704 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1705 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1707 req->verify_bitmask1 = true;
1710 if (!req->p->verified_pcontext) {
1711 t->commands = talloc_realloc(t, t->commands,
1712 struct dcerpc_sec_vt,
1713 t->count.count + 1);
1714 if (t->commands == NULL) {
1715 return NT_STATUS_NO_MEMORY;
1717 c = &t->commands[t->count.count++];
1720 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1721 c->u.pcontext.abstract_syntax = req->p->syntax;
1722 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1724 req->verify_pcontext = true;
1727 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1728 t->commands = talloc_realloc(t, t->commands,
1729 struct dcerpc_sec_vt,
1730 t->count.count + 1);
1731 if (t->commands == NULL) {
1732 return NT_STATUS_NO_MEMORY;
1734 c = &t->commands[t->count.count++];
1737 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1738 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1739 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1740 c->u.header2.drep[0] = 0;
1742 c->u.header2.drep[0] = DCERPC_DREP_LE;
1744 c->u.header2.drep[1] = 0;
1745 c->u.header2.drep[2] = 0;
1746 c->u.header2.drep[3] = 0;
1747 c->u.header2.call_id = req->call_id;
1748 c->u.header2.context_id = req->p->context_id;
1749 c->u.header2.opnum = req->opnum;
1752 if (t->count.count == 0) {
1754 return NT_STATUS_OK;
1757 c = &t->commands[t->count.count - 1];
1758 c->command |= DCERPC_SEC_VT_COMMAND_END;
1760 if (DEBUGLEVEL >= 10) {
1761 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1764 ndr = ndr_push_init_ctx(req);
1766 return NT_STATUS_NO_MEMORY;
1770 * for now we just copy and append
1773 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1774 req->request_data.length);
1775 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1776 return ndr_map_error2ntstatus(ndr_err);
1779 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1780 NDR_SCALARS | NDR_BUFFERS,
1782 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1783 return ndr_map_error2ntstatus(ndr_err);
1785 req->request_data = ndr_push_blob(ndr);
1787 return NT_STATUS_OK;
1791 Send a request using the transport
1794 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1796 struct rpc_request *req;
1797 struct dcerpc_pipe *p;
1798 DATA_BLOB *stub_data;
1799 struct ncacn_packet pkt;
1801 uint32_t remaining, chunk_size;
1802 bool first_packet = true;
1803 size_t sig_size = 0;
1804 bool need_async = false;
1805 bool can_async = true;
1807 req = c->request_queue;
1813 stub_data = &req->request_data;
1819 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
1820 can_async = gensec_have_feature(c->security_state.generic_state,
1821 GENSEC_FEATURE_ASYNC_REPLIES);
1824 if (need_async && !can_async) {
1825 req->wait_for_sync = true;
1829 DLIST_REMOVE(c->request_queue, req);
1830 DLIST_ADD(c->pending, req);
1831 req->state = RPC_REQUEST_PENDING;
1833 init_ncacn_hdr(p->conn, &pkt);
1835 remaining = stub_data->length;
1837 /* we can write a full max_recv_frag size, minus the dcerpc
1838 request header size */
1839 chunk_size = p->conn->srv_max_recv_frag;
1840 chunk_size -= DCERPC_REQUEST_LENGTH;
1841 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
1842 size_t max_payload = chunk_size;
1844 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1845 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1847 sig_size = gensec_sig_size(c->security_state.generic_state,
1850 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1851 chunk_size -= sig_size;
1854 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1856 pkt.ptype = DCERPC_PKT_REQUEST;
1857 pkt.call_id = req->call_id;
1858 pkt.auth_length = 0;
1860 pkt.u.request.context_id = p->context_id;
1861 pkt.u.request.opnum = req->opnum;
1864 pkt.u.request.object.object = *req->object;
1865 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1866 chunk_size -= ndr_size_GUID(req->object,0);
1869 /* we send a series of pdus without waiting for a reply */
1870 while (remaining > 0 || first_packet) {
1871 uint32_t chunk = MIN(chunk_size, remaining);
1872 bool last_frag = false;
1873 bool do_trans = false;
1875 first_packet = false;
1876 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1878 if (remaining == stub_data->length) {
1879 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1881 if (chunk == remaining) {
1882 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1886 pkt.u.request.alloc_hint = remaining;
1887 pkt.u.request.stub_and_verifier.data = stub_data->data +
1888 (stub_data->length - remaining);
1889 pkt.u.request.stub_and_verifier.length = chunk;
1891 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1892 if (!NT_STATUS_IS_OK(req->status)) {
1893 req->state = RPC_REQUEST_DONE;
1894 DLIST_REMOVE(p->conn->pending, req);
1898 if (last_frag && !need_async) {
1902 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1903 if (!NT_STATUS_IS_OK(req->status)) {
1904 req->state = RPC_REQUEST_DONE;
1905 DLIST_REMOVE(p->conn->pending, req);
1909 if (last_frag && !do_trans) {
1910 req->status = dcerpc_send_read(p->conn);
1911 if (!NT_STATUS_IS_OK(req->status)) {
1912 req->state = RPC_REQUEST_DONE;
1913 DLIST_REMOVE(p->conn->pending, req);
1922 static void dcerpc_io_trigger(struct tevent_context *ctx,
1923 struct tevent_immediate *im,
1926 struct dcecli_connection *c =
1927 talloc_get_type_abort(private_data,
1928 struct dcecli_connection);
1930 c->io_trigger_pending = false;
1932 dcerpc_schedule_io_trigger(c);
1934 dcerpc_ship_next_request(c);
1937 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1943 if (c->request_queue == NULL) {
1947 if (c->request_queue->wait_for_sync && c->pending) {
1951 if (c->io_trigger_pending) {
1955 c->io_trigger_pending = true;
1957 tevent_schedule_immediate(c->io_trigger,
1964 perform the receive side of a async dcerpc request
1966 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1967 TALLOC_CTX *mem_ctx,
1968 DATA_BLOB *stub_data)
1972 while (req->state != RPC_REQUEST_DONE) {
1973 struct tevent_context *ctx = req->p->conn->event_ctx;
1974 if (tevent_loop_once(ctx) != 0) {
1975 return NT_STATUS_CONNECTION_DISCONNECTED;
1978 *stub_data = req->payload;
1979 status = req->status;
1980 if (stub_data->data) {
1981 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1983 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1984 req->p->last_fault_code = req->fault_code;
1986 talloc_unlink(talloc_parent(req), req);
1991 this is a paranoid NDR validator. For every packet we push onto the wire
1992 we pull it back again, then push it again. Then we compare the raw NDR data
1993 for that to the NDR we initially generated. If they don't match then we know
1994 we must have a bug in either the pull or push side of our code
1996 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1997 TALLOC_CTX *mem_ctx,
2000 ndr_push_flags_fn_t ndr_push,
2001 ndr_pull_flags_fn_t ndr_pull)
2004 struct ndr_pull *pull;
2005 struct ndr_push *push;
2007 enum ndr_err_code ndr_err;
2009 st = talloc_size(mem_ctx, struct_size);
2011 return NT_STATUS_NO_MEMORY;
2014 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2016 return NT_STATUS_NO_MEMORY;
2018 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2020 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2021 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
2024 if (c->flags & DCERPC_NDR64) {
2025 pull->flags |= LIBNDR_FLAG_NDR64;
2028 ndr_err = ndr_pull(pull, NDR_IN, st);
2029 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2030 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2031 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2032 "failed input validation pull - %s",
2034 return ndr_map_error2ntstatus(ndr_err);
2037 push = ndr_push_init_ctx(mem_ctx);
2039 return NT_STATUS_NO_MEMORY;
2042 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2043 push->flags |= LIBNDR_FLAG_BIGENDIAN;
2046 if (c->flags & DCERPC_NDR64) {
2047 push->flags |= LIBNDR_FLAG_NDR64;
2050 ndr_err = ndr_push(push, NDR_IN, st);
2051 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2052 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2053 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2054 "failed input validation push - %s",
2056 return ndr_map_error2ntstatus(ndr_err);
2059 blob2 = ndr_push_blob(push);
2061 if (data_blob_cmp(&blob, &blob2) != 0) {
2062 DEBUG(3,("original:\n"));
2063 dump_data(3, blob.data, blob.length);
2064 DEBUG(3,("secondary:\n"));
2065 dump_data(3, blob2.data, blob2.length);
2066 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2067 "failed input validation blobs doesn't match");
2068 return ndr_map_error2ntstatus(ndr_err);
2071 return NT_STATUS_OK;
2075 this is a paranoid NDR input validator. For every packet we pull
2076 from the wire we push it back again then pull and push it
2077 again. Then we compare the raw NDR data for that to the NDR we
2078 initially generated. If they don't match then we know we must have a
2079 bug in either the pull or push side of our code
2081 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
2082 struct ndr_pull *pull_in,
2085 ndr_push_flags_fn_t ndr_push,
2086 ndr_pull_flags_fn_t ndr_pull,
2087 ndr_print_function_t ndr_print)
2090 struct ndr_pull *pull;
2091 struct ndr_push *push;
2092 DATA_BLOB blob, blob2;
2093 TALLOC_CTX *mem_ctx = pull_in;
2095 enum ndr_err_code ndr_err;
2097 st = talloc_size(mem_ctx, struct_size);
2099 return NT_STATUS_NO_MEMORY;
2101 memcpy(st, struct_ptr, struct_size);
2103 push = ndr_push_init_ctx(mem_ctx);
2105 return NT_STATUS_NO_MEMORY;
2108 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2109 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2110 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2111 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2112 "failed output validation push - %s",
2114 return ndr_map_error2ntstatus(ndr_err);
2117 blob = ndr_push_blob(push);
2119 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2121 return NT_STATUS_NO_MEMORY;
2124 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2125 ndr_err = ndr_pull(pull, NDR_OUT, st);
2126 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2127 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2128 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2129 "failed output validation pull - %s",
2131 return ndr_map_error2ntstatus(ndr_err);
2134 push = ndr_push_init_ctx(mem_ctx);
2136 return NT_STATUS_NO_MEMORY;
2139 ndr_err = ndr_push(push, NDR_OUT, st);
2140 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2141 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2142 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2143 "failed output validation push2 - %s",
2145 return ndr_map_error2ntstatus(ndr_err);
2148 blob2 = ndr_push_blob(push);
2150 if (data_blob_cmp(&blob, &blob2) != 0) {
2151 DEBUG(3,("original:\n"));
2152 dump_data(3, blob.data, blob.length);
2153 DEBUG(3,("secondary:\n"));
2154 dump_data(3, blob2.data, blob2.length);
2155 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2156 "failed output validation blobs doesn't match");
2157 return ndr_map_error2ntstatus(ndr_err);
2160 /* this checks the printed forms of the two structures, which effectively
2161 tests all of the value() attributes */
2162 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2163 NDR_OUT, struct_ptr);
2164 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2166 if (strcmp(s1, s2) != 0) {
2168 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2170 /* this is sometimes useful */
2171 printf("VALIDATE ERROR\n");
2172 file_save("wire.dat", s1, strlen(s1));
2173 file_save("gen.dat", s2, strlen(s2));
2174 system("diff -u wire.dat gen.dat");
2176 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2177 "failed output validation strings doesn't match");
2178 return ndr_map_error2ntstatus(ndr_err);
2181 return NT_STATUS_OK;
2185 a useful function for retrieving the server name we connected to
2187 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2189 return p->conn ? p->conn->server_name : NULL;
2194 get the dcerpc auth_level for a open connection
2196 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2200 if (c->flags & DCERPC_SEAL) {
2201 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2202 } else if (c->flags & DCERPC_SIGN) {
2203 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2204 } else if (c->flags & DCERPC_CONNECT) {
2205 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2207 auth_level = DCERPC_AUTH_LEVEL_NONE;
2212 struct dcerpc_alter_context_state {
2213 struct tevent_context *ev;
2214 struct dcerpc_pipe *p;
2217 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2218 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2219 DATA_BLOB *raw_packet,
2220 struct ncacn_packet *pkt);
2222 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2223 struct tevent_context *ev,
2224 struct dcerpc_pipe *p,
2225 const struct ndr_syntax_id *syntax,
2226 const struct ndr_syntax_id *transfer_syntax)
2228 struct tevent_req *req;
2229 struct dcerpc_alter_context_state *state;
2230 struct ncacn_packet pkt;
2233 struct rpc_request *subreq;
2236 req = tevent_req_create(mem_ctx, &state,
2237 struct dcerpc_alter_context_state);
2245 p->syntax = *syntax;
2246 p->transfer_syntax = *transfer_syntax;
2248 flags = dcerpc_binding_get_flags(p->binding);
2250 init_ncacn_hdr(p->conn, &pkt);
2252 pkt.ptype = DCERPC_PKT_ALTER;
2253 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2254 pkt.call_id = p->conn->call_id;
2255 pkt.auth_length = 0;
2257 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2258 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2261 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2262 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2263 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2264 pkt.u.alter.num_contexts = 1;
2265 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2266 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2267 return tevent_req_post(req, ev);
2269 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2270 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2271 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2272 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2273 pkt.u.alter.auth_info = data_blob(NULL, 0);
2275 /* construct the NDR form of the packet */
2276 status = ncacn_push_auth(&blob, state, &pkt,
2277 p->conn->security_state.tmp_auth_info.out);
2278 if (tevent_req_nterror(req, status)) {
2279 return tevent_req_post(req, ev);
2283 * we allocate a dcerpc_request so we can be in the same
2284 * request queue as normal requests
2286 subreq = talloc_zero(state, struct rpc_request);
2287 if (tevent_req_nomem(subreq, req)) {
2288 return tevent_req_post(req, ev);
2291 subreq->state = RPC_REQUEST_PENDING;
2292 subreq->call_id = pkt.call_id;
2293 subreq->async.private_data = req;
2294 subreq->async.callback = dcerpc_alter_context_fail_handler;
2296 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2297 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2298 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2300 status = dcerpc_send_request(p->conn, &blob, true);
2301 if (tevent_req_nterror(req, status)) {
2302 return tevent_req_post(req, ev);
2305 tevent_add_timer(ev, subreq,
2306 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2307 dcerpc_timeout_handler, subreq);
2312 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2314 struct tevent_req *req =
2315 talloc_get_type_abort(subreq->async.private_data,
2317 struct dcerpc_alter_context_state *state =
2318 tevent_req_data(req,
2319 struct dcerpc_alter_context_state);
2320 NTSTATUS status = subreq->status;
2322 TALLOC_FREE(subreq);
2325 * We trigger the callback in the next event run
2326 * because the code in this file might trigger
2327 * multiple request callbacks from within a single
2330 * In order to avoid segfaults from within
2331 * dcerpc_connection_dead() we call
2332 * tevent_req_defer_callback().
2334 tevent_req_defer_callback(req, state->ev);
2336 tevent_req_nterror(req, status);
2339 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2340 DATA_BLOB *raw_packet,
2341 struct ncacn_packet *pkt)
2343 struct tevent_req *req =
2344 talloc_get_type_abort(subreq->async.private_data,
2346 struct dcerpc_alter_context_state *state =
2347 tevent_req_data(req,
2348 struct dcerpc_alter_context_state);
2349 struct dcecli_connection *conn = state->p->conn;
2350 struct dcecli_security *sec = &conn->security_state;
2354 * Note that pkt is allocated under raw_packet->data,
2355 * while raw_packet->data is a child of subreq.
2357 talloc_steal(state, raw_packet->data);
2358 TALLOC_FREE(subreq);
2361 * We trigger the callback in the next event run
2362 * because the code in this file might trigger
2363 * multiple request callbacks from within a single
2366 * In order to avoid segfaults from within
2367 * dcerpc_connection_dead() we call
2368 * tevent_req_defer_callback().
2370 tevent_req_defer_callback(req, state->ev);
2372 if (pkt->ptype == DCERPC_PKT_FAULT) {
2373 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2374 dcerpc_errstr(state, pkt->u.fault.status)));
2375 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2376 state->p->last_fault_code = pkt->u.fault.status;
2377 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2378 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2379 state->p->last_fault_code = pkt->u.fault.status;
2380 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2382 state->p->last_fault_code = pkt->u.fault.status;
2383 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2384 tevent_req_nterror(req, status);
2389 status = dcerpc_verify_ncacn_packet_header(pkt,
2390 DCERPC_PKT_ALTER_RESP,
2391 pkt->u.alter_resp.auth_info.length,
2392 DCERPC_PFC_FLAG_FIRST |
2393 DCERPC_PFC_FLAG_LAST,
2394 DCERPC_PFC_FLAG_CONC_MPX |
2395 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2396 if (!NT_STATUS_IS_OK(status)) {
2397 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2398 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2402 if (pkt->u.alter_resp.num_results != 1) {
2403 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2404 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2408 if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2409 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2410 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2411 pkt->u.alter_resp.ctx_list[0].reason.value,
2412 nt_errstr(status)));
2413 tevent_req_nterror(req, status);
2417 /* the alter_resp might contain a reply set of credentials */
2418 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2419 uint32_t auth_length;
2421 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2422 &pkt->u.alter_resp.auth_info,
2423 sec->tmp_auth_info.in,
2424 &auth_length, true);
2425 if (tevent_req_nterror(req, status)) {
2430 tevent_req_done(req);
2433 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2435 return tevent_req_simple_recv_ntstatus(req);
2439 send a dcerpc alter_context request
2441 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2442 TALLOC_CTX *mem_ctx,
2443 const struct ndr_syntax_id *syntax,
2444 const struct ndr_syntax_id *transfer_syntax)
2446 struct tevent_req *subreq;
2447 struct tevent_context *ev = p->conn->event_ctx;
2450 /* TODO: create a new event context here */
2452 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2453 p, syntax, transfer_syntax);
2454 if (subreq == NULL) {
2455 return NT_STATUS_NO_MEMORY;
2458 ok = tevent_req_poll(subreq, ev);
2461 status = map_nt_error_from_unix_common(errno);
2465 return dcerpc_alter_context_recv(subreq);
2468 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2470 if (c->transport.stream == NULL) {
2474 tevent_queue_stop(c->transport.write_queue);
2475 TALLOC_FREE(c->transport.read_subreq);
2476 TALLOC_FREE(c->transport.stream);
2478 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2479 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2482 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2483 status = NT_STATUS_END_OF_FILE;
2486 dcerpc_recv_data(c, NULL, status);
2491 shutdown SMB pipe connection
2493 struct dcerpc_shutdown_pipe_state {
2494 struct dcecli_connection *c;
2498 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2500 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2502 struct dcerpc_shutdown_pipe_state *state;
2503 struct tevent_req *subreq;
2505 if (c->transport.stream == NULL) {
2506 return NT_STATUS_OK;
2509 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2510 if (state == NULL) {
2511 return NT_STATUS_NO_MEMORY;
2514 state->status = status;
2516 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2517 if (subreq == NULL) {
2518 return NT_STATUS_NO_MEMORY;
2520 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2525 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2527 struct dcerpc_shutdown_pipe_state *state =
2528 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2529 struct dcecli_connection *c = state->c;
2530 NTSTATUS status = state->status;
2534 * here we ignore the return values...
2536 tstream_disconnect_recv(subreq, &error);
2537 TALLOC_FREE(subreq);
2541 dcerpc_transport_dead(c, status);
2546 struct dcerpc_send_read_state {
2547 struct dcecli_connection *p;
2550 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2552 struct dcecli_connection *p = state->p;
2554 p->transport.read_subreq = NULL;
2559 static void dcerpc_send_read_done(struct tevent_req *subreq);
2561 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2563 struct dcerpc_send_read_state *state;
2565 if (p->transport.read_subreq != NULL) {
2566 p->transport.pending_reads++;
2567 return NT_STATUS_OK;
2570 state = talloc_zero(p, struct dcerpc_send_read_state);
2571 if (state == NULL) {
2572 return NT_STATUS_NO_MEMORY;
2576 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2578 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2580 p->transport.stream);
2581 if (p->transport.read_subreq == NULL) {
2582 return NT_STATUS_NO_MEMORY;
2584 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2586 return NT_STATUS_OK;
2589 static void dcerpc_send_read_done(struct tevent_req *subreq)
2591 struct dcerpc_send_read_state *state =
2592 tevent_req_callback_data(subreq,
2593 struct dcerpc_send_read_state);
2594 struct dcecli_connection *p = state->p;
2596 struct ncacn_packet *pkt;
2599 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2601 TALLOC_FREE(subreq);
2602 if (!NT_STATUS_IS_OK(status)) {
2604 dcerpc_transport_dead(p, status);
2609 * here we steal into thet connection context,
2610 * but p->transport.recv_data() will steal or free it again
2612 talloc_steal(p, blob.data);
2615 if (p->transport.pending_reads > 0) {
2616 p->transport.pending_reads--;
2618 status = dcerpc_send_read(p);
2619 if (!NT_STATUS_IS_OK(status)) {
2620 dcerpc_transport_dead(p, status);
2625 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2628 struct dcerpc_send_request_state {
2629 struct dcecli_connection *p;
2634 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2636 struct dcecli_connection *p = state->p;
2638 p->transport.read_subreq = NULL;
2643 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2644 static void dcerpc_send_request_done(struct tevent_req *subreq);
2646 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2649 struct dcerpc_send_request_state *state;
2650 struct tevent_req *subreq;
2651 bool use_trans = trigger_read;
2653 if (p->transport.stream == NULL) {
2654 return NT_STATUS_CONNECTION_DISCONNECTED;
2657 state = talloc_zero(p, struct dcerpc_send_request_state);
2658 if (state == NULL) {
2659 return NT_STATUS_NO_MEMORY;
2663 state->blob = data_blob_talloc(state, data->data, data->length);
2664 if (state->blob.data == NULL) {
2666 return NT_STATUS_NO_MEMORY;
2668 state->iov.iov_base = (void *)state->blob.data;
2669 state->iov.iov_len = state->blob.length;
2671 if (p->transport.read_subreq != NULL) {
2675 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2681 * we need to block reads until our write is
2682 * the next in the write queue.
2684 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2685 p->transport.write_queue);
2686 if (p->transport.read_subreq == NULL) {
2688 return NT_STATUS_NO_MEMORY;
2690 tevent_req_set_callback(p->transport.read_subreq,
2691 dcerpc_send_request_wait_done,
2694 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2696 trigger_read = false;
2699 subreq = tstream_writev_queue_send(state, p->event_ctx,
2700 p->transport.stream,
2701 p->transport.write_queue,
2703 if (subreq == NULL) {
2705 return NT_STATUS_NO_MEMORY;
2707 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2710 dcerpc_send_read(p);
2713 return NT_STATUS_OK;
2716 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2718 struct dcerpc_send_request_state *state =
2719 tevent_req_callback_data(subreq,
2720 struct dcerpc_send_request_state);
2721 struct dcecli_connection *p = state->p;
2725 p->transport.read_subreq = NULL;
2726 talloc_set_destructor(state, NULL);
2728 ok = tevent_queue_wait_recv(subreq);
2731 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2735 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2736 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2737 if (!NT_STATUS_IS_OK(status)) {
2739 dcerpc_transport_dead(p, status);
2744 /* we free subreq after tstream_cli_np_use_trans */
2745 TALLOC_FREE(subreq);
2747 dcerpc_send_read(p);
2750 static void dcerpc_send_request_done(struct tevent_req *subreq)
2752 struct dcerpc_send_request_state *state =
2753 tevent_req_callback_data(subreq,
2754 struct dcerpc_send_request_state);
2758 ret = tstream_writev_queue_recv(subreq, &error);
2759 TALLOC_FREE(subreq);
2761 struct dcecli_connection *p = state->p;
2762 NTSTATUS status = map_nt_error_from_unix_common(error);
2765 dcerpc_transport_dead(p, status);