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 "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "auth/gensec/gensec.h"
31 #include "param/param.h"
32 #include "lib/util/tevent_ntstatus.h"
33 #include "librpc/rpc/rpc_common.h"
34 #include "lib/tsocket/tsocket.h"
37 enum rpc_request_state
{
44 handle for an async dcerpc request
47 struct rpc_request
*next
, *prev
;
48 struct dcerpc_pipe
*p
;
51 enum rpc_request_state state
;
56 /* this is used to distinguish bind and alter_context requests
57 from normal requests */
58 void (*recv_handler
)(struct rpc_request
*conn
,
59 DATA_BLOB
*blob
, struct ncacn_packet
*pkt
);
61 const struct GUID
*object
;
63 DATA_BLOB request_data
;
68 void (*callback
)(struct rpc_request
*);
73 _PUBLIC_ NTSTATUS
dcerpc_init(void)
78 static void dcerpc_connection_dead(struct dcecli_connection
*conn
, NTSTATUS status
);
79 static void dcerpc_schedule_io_trigger(struct dcecli_connection
*c
);
81 static struct rpc_request
*dcerpc_request_send(TALLOC_CTX
*mem_ctx
,
82 struct dcerpc_pipe
*p
,
83 const struct GUID
*object
,
85 DATA_BLOB
*stub_data
);
86 static NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
88 DATA_BLOB
*stub_data
);
89 static NTSTATUS
dcerpc_ndr_validate_in(struct dcecli_connection
*c
,
93 ndr_push_flags_fn_t ndr_push
,
94 ndr_pull_flags_fn_t ndr_pull
);
95 static NTSTATUS
dcerpc_ndr_validate_out(struct dcecli_connection
*c
,
96 struct ndr_pull
*pull_in
,
99 ndr_push_flags_fn_t ndr_push
,
100 ndr_pull_flags_fn_t ndr_pull
,
101 ndr_print_function_t ndr_print
);
103 /* destroy a dcerpc connection */
104 static int dcerpc_connection_destructor(struct dcecli_connection
*conn
)
107 conn
->free_skipped
= true;
110 dcerpc_connection_dead(conn
, NT_STATUS_LOCAL_DISCONNECT
);
115 /* initialise a dcerpc connection.
116 the event context is optional
118 static struct dcecli_connection
*dcerpc_connection_init(TALLOC_CTX
*mem_ctx
,
119 struct tevent_context
*ev
)
121 struct dcecli_connection
*c
;
123 c
= talloc_zero(mem_ctx
, struct dcecli_connection
);
130 if (c
->event_ctx
== NULL
) {
136 c
->security_state
.auth_info
= NULL
;
137 c
->security_state
.session_key
= dcerpc_generic_session_key
;
138 c
->security_state
.generic_state
= NULL
;
139 c
->binding_string
= NULL
;
142 * Windows uses 5840 for ncacn_ip_tcp,
143 * so we also use it (for every transport)
144 * by default. But we give the transport
145 * the chance to overwrite it.
147 c
->srv_max_xmit_frag
= 5840;
148 c
->srv_max_recv_frag
= 5840;
151 c
->io_trigger
= tevent_create_immediate(c
);
152 if (c
->io_trigger
== NULL
) {
157 talloc_set_destructor(c
, dcerpc_connection_destructor
);
162 struct dcerpc_bh_state
{
163 struct dcerpc_pipe
*p
;
166 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle
*h
)
168 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
169 struct dcerpc_bh_state
);
179 if (hs
->p
->conn
->dead
) {
186 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle
*h
,
189 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
190 struct dcerpc_bh_state
);
194 return DCERPC_REQUEST_TIMEOUT
;
197 old
= hs
->p
->request_timeout
;
198 hs
->p
->request_timeout
= timeout
;
203 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle
*h
,
204 enum dcerpc_AuthType
*auth_type
,
205 enum dcerpc_AuthLevel
*auth_level
)
207 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
208 struct dcerpc_bh_state
);
214 if (hs
->p
->conn
== NULL
) {
218 if (hs
->p
->conn
->security_state
.auth_info
== NULL
) {
222 *auth_type
= hs
->p
->conn
->security_state
.auth_info
->auth_type
;
223 *auth_level
= hs
->p
->conn
->security_state
.auth_info
->auth_level
;
226 struct dcerpc_bh_raw_call_state
{
227 struct tevent_context
*ev
;
228 struct dcerpc_binding_handle
*h
;
234 static void dcerpc_bh_raw_call_done(struct rpc_request
*subreq
);
236 static struct tevent_req
*dcerpc_bh_raw_call_send(TALLOC_CTX
*mem_ctx
,
237 struct tevent_context
*ev
,
238 struct dcerpc_binding_handle
*h
,
239 const struct GUID
*object
,
242 const uint8_t *in_data
,
245 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
246 struct dcerpc_bh_state
);
247 struct tevent_req
*req
;
248 struct dcerpc_bh_raw_call_state
*state
;
250 struct rpc_request
*subreq
;
252 req
= tevent_req_create(mem_ctx
, &state
,
253 struct dcerpc_bh_raw_call_state
);
259 state
->in_data
.data
= discard_const_p(uint8_t, in_data
);
260 state
->in_data
.length
= in_length
;
262 ok
= dcerpc_bh_is_connected(h
);
264 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
265 return tevent_req_post(req
, ev
);
268 subreq
= dcerpc_request_send(state
,
273 if (tevent_req_nomem(subreq
, req
)) {
274 return tevent_req_post(req
, ev
);
276 subreq
->async
.callback
= dcerpc_bh_raw_call_done
;
277 subreq
->async
.private_data
= req
;
282 static void dcerpc_bh_raw_call_done(struct rpc_request
*subreq
)
284 struct tevent_req
*req
=
285 talloc_get_type_abort(subreq
->async
.private_data
,
287 struct dcerpc_bh_raw_call_state
*state
=
289 struct dcerpc_bh_raw_call_state
);
293 state
->out_flags
= 0;
294 if (subreq
->flags
& DCERPC_PULL_BIGENDIAN
) {
295 state
->out_flags
|= LIBNDR_FLAG_BIGENDIAN
;
298 fault_code
= subreq
->fault_code
;
300 status
= dcerpc_request_recv(subreq
, state
, &state
->out_data
);
301 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
302 status
= dcerpc_fault_to_nt_status(fault_code
);
306 * We trigger the callback in the next event run
307 * because the code in this file might trigger
308 * multiple request callbacks from within a single
311 * In order to avoid segfaults from within
312 * dcerpc_connection_dead() we call
313 * tevent_req_defer_callback().
315 tevent_req_defer_callback(req
, state
->ev
);
317 if (!NT_STATUS_IS_OK(status
)) {
318 tevent_req_nterror(req
, status
);
322 tevent_req_done(req
);
325 static NTSTATUS
dcerpc_bh_raw_call_recv(struct tevent_req
*req
,
331 struct dcerpc_bh_raw_call_state
*state
=
333 struct dcerpc_bh_raw_call_state
);
336 if (tevent_req_is_nterror(req
, &status
)) {
337 tevent_req_received(req
);
341 *out_data
= talloc_move(mem_ctx
, &state
->out_data
.data
);
342 *out_length
= state
->out_data
.length
;
343 *out_flags
= state
->out_flags
;
344 tevent_req_received(req
);
348 struct dcerpc_bh_disconnect_state
{
352 static struct tevent_req
*dcerpc_bh_disconnect_send(TALLOC_CTX
*mem_ctx
,
353 struct tevent_context
*ev
,
354 struct dcerpc_binding_handle
*h
)
356 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
357 struct dcerpc_bh_state
);
358 struct tevent_req
*req
;
359 struct dcerpc_bh_disconnect_state
*state
;
362 req
= tevent_req_create(mem_ctx
, &state
,
363 struct dcerpc_bh_disconnect_state
);
368 ok
= dcerpc_bh_is_connected(h
);
370 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
371 return tevent_req_post(req
, ev
);
374 /* TODO: do a real disconnect ... */
377 tevent_req_done(req
);
378 return tevent_req_post(req
, ev
);
381 static NTSTATUS
dcerpc_bh_disconnect_recv(struct tevent_req
*req
)
385 if (tevent_req_is_nterror(req
, &status
)) {
386 tevent_req_received(req
);
390 tevent_req_received(req
);
394 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle
*h
)
396 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
397 struct dcerpc_bh_state
);
399 if (hs
->p
->conn
->flags
& DCERPC_PUSH_BIGENDIAN
) {
406 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle
*h
)
408 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
409 struct dcerpc_bh_state
);
411 if (hs
->p
->conn
->flags
& DCERPC_NDR_REF_ALLOC
) {
418 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle
*h
)
420 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
421 struct dcerpc_bh_state
);
423 if (hs
->p
->conn
->flags
& DCERPC_NDR64
) {
430 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle
*h
,
432 const void *_struct_ptr
,
433 const struct ndr_interface_call
*call
)
435 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
436 struct dcerpc_bh_state
);
437 void *struct_ptr
= discard_const(_struct_ptr
);
439 if (ndr_flags
& NDR_IN
) {
440 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_PRINT_IN
) {
441 ndr_print_function_debug(call
->ndr_print
,
447 if (ndr_flags
& NDR_OUT
) {
448 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_PRINT_OUT
) {
449 ndr_print_function_debug(call
->ndr_print
,
457 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle
*h
,
459 const void *struct_ptr
,
460 const struct ndr_interface_call
*call
)
462 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
463 call
->name
, nt_errstr(error
)));
466 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle
*h
,
468 const DATA_BLOB
*blob
,
469 const struct ndr_interface_call
*call
)
471 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
472 struct dcerpc_bh_state
);
473 const uint32_t num_examples
= 20;
476 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
477 call
->name
, nt_errstr(error
)));
479 if (hs
->p
->conn
->packet_log_dir
== NULL
) return;
481 for (i
=0;i
<num_examples
;i
++) {
483 asprintf(&name
, "%s/rpclog/%s-out.%d",
484 hs
->p
->conn
->packet_log_dir
,
489 if (!file_exist(name
)) {
490 if (file_save(name
, blob
->data
, blob
->length
)) {
491 DEBUG(10,("Logged rpc packet to %s\n", name
));
500 static NTSTATUS
dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle
*h
,
502 const DATA_BLOB
*blob
,
503 const struct ndr_interface_call
*call
)
505 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
506 struct dcerpc_bh_state
);
508 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_IN
) {
511 status
= dcerpc_ndr_validate_in(hs
->p
->conn
,
517 if (!NT_STATUS_IS_OK(status
)) {
518 DEBUG(0,("Validation [in] failed for %s - %s\n",
519 call
->name
, nt_errstr(status
)));
524 DEBUG(10,("rpc request data:\n"));
525 dump_data(10, blob
->data
, blob
->length
);
530 static NTSTATUS
dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle
*h
,
531 struct ndr_pull
*pull_in
,
532 const void *_struct_ptr
,
533 const struct ndr_interface_call
*call
)
535 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
536 struct dcerpc_bh_state
);
537 void *struct_ptr
= discard_const(_struct_ptr
);
539 DEBUG(10,("rpc reply data:\n"));
540 dump_data(10, pull_in
->data
, pull_in
->data_size
);
542 if (pull_in
->offset
!= pull_in
->data_size
) {
543 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
544 pull_in
->data_size
- pull_in
->offset
,
545 pull_in
->offset
, pull_in
->offset
,
547 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
548 but it turns out that early versions of NT
549 (specifically NT3.1) add junk onto the end of rpc
550 packets, so if we want to interoperate at all with
551 those versions then we need to ignore this error */
554 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_OUT
) {
557 status
= dcerpc_ndr_validate_out(hs
->p
->conn
,
564 if (!NT_STATUS_IS_OK(status
)) {
565 DEBUG(2,("Validation [out] failed for %s - %s\n",
566 call
->name
, nt_errstr(status
)));
574 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops
= {
576 .is_connected
= dcerpc_bh_is_connected
,
577 .set_timeout
= dcerpc_bh_set_timeout
,
578 .auth_info
= dcerpc_bh_auth_info
,
579 .raw_call_send
= dcerpc_bh_raw_call_send
,
580 .raw_call_recv
= dcerpc_bh_raw_call_recv
,
581 .disconnect_send
= dcerpc_bh_disconnect_send
,
582 .disconnect_recv
= dcerpc_bh_disconnect_recv
,
584 .push_bigendian
= dcerpc_bh_push_bigendian
,
585 .ref_alloc
= dcerpc_bh_ref_alloc
,
586 .use_ndr64
= dcerpc_bh_use_ndr64
,
587 .do_ndr_print
= dcerpc_bh_do_ndr_print
,
588 .ndr_push_failed
= dcerpc_bh_ndr_push_failed
,
589 .ndr_pull_failed
= dcerpc_bh_ndr_pull_failed
,
590 .ndr_validate_in
= dcerpc_bh_ndr_validate_in
,
591 .ndr_validate_out
= dcerpc_bh_ndr_validate_out
,
594 /* initialise a dcerpc pipe. */
595 struct dcerpc_binding_handle
*dcerpc_pipe_binding_handle(struct dcerpc_pipe
*p
)
597 struct dcerpc_binding_handle
*h
;
598 struct dcerpc_bh_state
*hs
;
600 h
= dcerpc_binding_handle_create(p
,
605 struct dcerpc_bh_state
,
612 dcerpc_binding_handle_set_sync_ev(h
, p
->conn
->event_ctx
);
617 /* initialise a dcerpc pipe. */
618 _PUBLIC_
struct dcerpc_pipe
*dcerpc_pipe_init(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
)
620 struct dcerpc_pipe
*p
;
622 p
= talloc_zero(mem_ctx
, struct dcerpc_pipe
);
627 p
->conn
= dcerpc_connection_init(p
, ev
);
628 if (p
->conn
== NULL
) {
633 p
->last_fault_code
= 0;
635 p
->request_timeout
= DCERPC_REQUEST_TIMEOUT
;
638 ZERO_STRUCT(p
->syntax
);
639 ZERO_STRUCT(p
->transfer_syntax
);
642 p
->conn
->flags
|= DCERPC_DEBUG_PRINT_BOTH
;
645 p
->binding_handle
= dcerpc_pipe_binding_handle(p
);
646 if (p
->binding_handle
== NULL
) {
656 choose the next call id to use
658 static uint32_t next_call_id(struct dcecli_connection
*c
)
661 if (c
->call_id
== 0) {
668 setup for a ndr pull, also setting up any flags from the binding string
670 static struct ndr_pull
*ndr_pull_init_flags(struct dcecli_connection
*c
,
671 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
673 struct ndr_pull
*ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
675 if (ndr
== NULL
) return ndr
;
677 if (c
->flags
& DCERPC_DEBUG_PAD_CHECK
) {
678 ndr
->flags
|= LIBNDR_FLAG_PAD_CHECK
;
681 if (c
->flags
& DCERPC_NDR_REF_ALLOC
) {
682 ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
685 if (c
->flags
& DCERPC_NDR64
) {
686 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
693 parse a data blob into a ncacn_packet structure. This handles both
694 input and output packets
696 static NTSTATUS
ncacn_pull(struct dcecli_connection
*c
, DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
697 struct ncacn_packet
*pkt
)
699 struct ndr_pull
*ndr
;
700 enum ndr_err_code ndr_err
;
702 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
704 return NT_STATUS_NO_MEMORY
;
707 if (! (CVAL(blob
->data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
708 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
711 if (CVAL(blob
->data
, DCERPC_PFC_OFFSET
) & DCERPC_PFC_FLAG_OBJECT_UUID
) {
712 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
715 ndr_err
= ndr_pull_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
717 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
718 return ndr_map_error2ntstatus(ndr_err
);
721 if (pkt
->frag_length
!= blob
->length
) {
722 return NT_STATUS_RPC_PROTOCOL_ERROR
;
729 parse the authentication information on a dcerpc response packet
731 static NTSTATUS
ncacn_pull_request_auth(struct dcecli_connection
*c
, TALLOC_CTX
*mem_ctx
,
732 DATA_BLOB
*raw_packet
,
733 struct ncacn_packet
*pkt
)
736 struct dcerpc_auth auth
;
737 uint32_t auth_length
;
739 if (!c
->security_state
.auth_info
||
740 !c
->security_state
.generic_state
) {
744 switch (c
->security_state
.auth_info
->auth_level
) {
745 case DCERPC_AUTH_LEVEL_PRIVACY
:
746 case DCERPC_AUTH_LEVEL_INTEGRITY
:
749 case DCERPC_AUTH_LEVEL_CONNECT
:
750 if (pkt
->auth_length
!= 0) {
754 case DCERPC_AUTH_LEVEL_NONE
:
755 if (pkt
->auth_length
!= 0) {
756 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
761 return NT_STATUS_INVALID_LEVEL
;
764 status
= dcerpc_pull_auth_trailer(pkt
, mem_ctx
,
765 &pkt
->u
.response
.stub_and_verifier
,
766 &auth
, &auth_length
, false);
767 NT_STATUS_NOT_OK_RETURN(status
);
769 pkt
->u
.response
.stub_and_verifier
.length
-= auth_length
;
771 /* check signature or unseal the packet */
772 switch (c
->security_state
.auth_info
->auth_level
) {
773 case DCERPC_AUTH_LEVEL_PRIVACY
:
774 status
= gensec_unseal_packet(c
->security_state
.generic_state
,
775 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
776 pkt
->u
.response
.stub_and_verifier
.length
,
778 raw_packet
->length
- auth
.credentials
.length
,
780 memcpy(pkt
->u
.response
.stub_and_verifier
.data
,
781 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
782 pkt
->u
.response
.stub_and_verifier
.length
);
785 case DCERPC_AUTH_LEVEL_INTEGRITY
:
786 status
= gensec_check_packet(c
->security_state
.generic_state
,
787 pkt
->u
.response
.stub_and_verifier
.data
,
788 pkt
->u
.response
.stub_and_verifier
.length
,
790 raw_packet
->length
- auth
.credentials
.length
,
794 case DCERPC_AUTH_LEVEL_CONNECT
:
795 /* for now we ignore possible signatures here */
796 status
= NT_STATUS_OK
;
800 status
= NT_STATUS_INVALID_LEVEL
;
804 /* remove the indicated amount of padding */
805 if (pkt
->u
.response
.stub_and_verifier
.length
< auth
.auth_pad_length
) {
806 return NT_STATUS_INFO_LENGTH_MISMATCH
;
808 pkt
->u
.response
.stub_and_verifier
.length
-= auth
.auth_pad_length
;
815 push a dcerpc request packet into a blob, possibly signing it.
817 static NTSTATUS
ncacn_push_request_sign(struct dcecli_connection
*c
,
818 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
820 struct ncacn_packet
*pkt
)
823 struct ndr_push
*ndr
;
825 size_t payload_length
;
826 enum ndr_err_code ndr_err
;
827 size_t hdr_size
= DCERPC_REQUEST_LENGTH
;
829 /* non-signed packets are simpler */
831 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
834 switch (c
->security_state
.auth_info
->auth_level
) {
835 case DCERPC_AUTH_LEVEL_PRIVACY
:
836 case DCERPC_AUTH_LEVEL_INTEGRITY
:
839 case DCERPC_AUTH_LEVEL_CONNECT
:
840 /* TODO: let the gensec mech decide if it wants to generate a signature */
841 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
843 case DCERPC_AUTH_LEVEL_NONE
:
844 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
847 return NT_STATUS_INVALID_LEVEL
;
850 ndr
= ndr_push_init_ctx(mem_ctx
);
852 return NT_STATUS_NO_MEMORY
;
855 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
856 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
859 if (c
->flags
& DCERPC_NDR64
) {
860 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
863 if (pkt
->pfc_flags
& DCERPC_PFC_FLAG_OBJECT_UUID
) {
864 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
868 ndr_err
= ndr_push_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
869 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
870 return ndr_map_error2ntstatus(ndr_err
);
873 /* pad to 16 byte multiple in the payload portion of the
874 packet. This matches what w2k3 does. Note that we can't use
875 ndr_push_align() as that is relative to the start of the
876 whole packet, whereas w2k8 wants it relative to the start
878 c
->security_state
.auth_info
->auth_pad_length
=
879 (16 - (pkt
->u
.request
.stub_and_verifier
.length
& 15)) & 15;
880 ndr_err
= ndr_push_zero(ndr
, c
->security_state
.auth_info
->auth_pad_length
);
881 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
882 return ndr_map_error2ntstatus(ndr_err
);
885 payload_length
= pkt
->u
.request
.stub_and_verifier
.length
+
886 c
->security_state
.auth_info
->auth_pad_length
;
888 /* we start without signature, it will appended later */
889 c
->security_state
.auth_info
->credentials
= data_blob(NULL
,0);
891 /* add the auth verifier */
892 ndr_err
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, c
->security_state
.auth_info
);
893 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
894 return ndr_map_error2ntstatus(ndr_err
);
897 /* extract the whole packet as a blob */
898 *blob
= ndr_push_blob(ndr
);
901 * Setup the frag and auth length in the packet buffer.
902 * This is needed if the GENSEC mech does AEAD signing
903 * of the packet headers. The signature itself will be
906 dcerpc_set_frag_length(blob
, blob
->length
+ sig_size
);
907 dcerpc_set_auth_length(blob
, sig_size
);
909 /* sign or seal the packet */
910 switch (c
->security_state
.auth_info
->auth_level
) {
911 case DCERPC_AUTH_LEVEL_PRIVACY
:
912 status
= gensec_seal_packet(c
->security_state
.generic_state
,
914 blob
->data
+ hdr_size
,
919 if (!NT_STATUS_IS_OK(status
)) {
924 case DCERPC_AUTH_LEVEL_INTEGRITY
:
925 status
= gensec_sign_packet(c
->security_state
.generic_state
,
927 blob
->data
+ hdr_size
,
932 if (!NT_STATUS_IS_OK(status
)) {
938 status
= NT_STATUS_INVALID_LEVEL
;
942 if (creds2
.length
!= sig_size
) {
943 /* this means the sig_size estimate for the signature
944 was incorrect. We have to correct the packet
945 sizes. That means we could go over the max fragment
947 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
948 (unsigned) creds2
.length
,
950 (unsigned) c
->security_state
.auth_info
->auth_pad_length
,
951 (unsigned) pkt
->u
.request
.stub_and_verifier
.length
));
952 dcerpc_set_frag_length(blob
, blob
->length
+ creds2
.length
);
953 dcerpc_set_auth_length(blob
, creds2
.length
);
956 if (!data_blob_append(mem_ctx
, blob
, creds2
.data
, creds2
.length
)) {
957 return NT_STATUS_NO_MEMORY
;
965 fill in the fixed values in a dcerpc header
967 static void init_ncacn_hdr(struct dcecli_connection
*c
, struct ncacn_packet
*pkt
)
970 pkt
->rpc_vers_minor
= 0;
971 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
974 pkt
->drep
[0] = DCERPC_DREP_LE
;
982 map a bind nak reason to a NTSTATUS
984 static NTSTATUS
dcerpc_map_reason(uint16_t reason
)
987 case DCERPC_BIND_REASON_ASYNTAX
:
988 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX
;
989 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE
:
990 return NT_STATUS_INVALID_PARAMETER
;
992 return NT_STATUS_UNSUCCESSFUL
;
996 remove requests from the pending or queued queues
998 static int dcerpc_req_dequeue(struct rpc_request
*req
)
1000 switch (req
->state
) {
1001 case RPC_REQUEST_QUEUED
:
1002 DLIST_REMOVE(req
->p
->conn
->request_queue
, req
);
1004 case RPC_REQUEST_PENDING
:
1005 DLIST_REMOVE(req
->p
->conn
->pending
, req
);
1007 case RPC_REQUEST_DONE
:
1014 static NTSTATUS
dcerpc_shutdown_pipe(struct dcecli_connection
*p
, NTSTATUS status
);
1016 mark the dcerpc connection dead. All outstanding requests get an error
1018 static void dcerpc_connection_dead(struct dcecli_connection
*conn
, NTSTATUS status
)
1020 if (conn
->dead
) return;
1024 TALLOC_FREE(conn
->io_trigger
);
1025 conn
->io_trigger_pending
= false;
1027 conn
->transport
.recv_data
= NULL
;
1029 dcerpc_shutdown_pipe(conn
, status
);
1031 /* all pending requests get the error */
1032 while (conn
->pending
) {
1033 struct rpc_request
*req
= conn
->pending
;
1034 dcerpc_req_dequeue(req
);
1035 req
->state
= RPC_REQUEST_DONE
;
1036 req
->status
= status
;
1037 if (req
->async
.callback
) {
1038 req
->async
.callback(req
);
1042 /* all requests, which are not shipped */
1043 while (conn
->request_queue
) {
1044 struct rpc_request
*req
= conn
->request_queue
;
1045 dcerpc_req_dequeue(req
);
1046 req
->state
= RPC_REQUEST_DONE
;
1047 req
->status
= status
;
1048 if (req
->async
.callback
) {
1049 req
->async
.callback(req
);
1053 talloc_set_destructor(conn
, NULL
);
1054 if (conn
->free_skipped
) {
1060 forward declarations of the recv_data handlers for the types of
1061 packets we need to handle
1063 static void dcerpc_request_recv_data(struct dcecli_connection
*c
,
1064 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
);
1067 receive a dcerpc reply from the transport. Here we work out what
1068 type of reply it is (normal request, bind or alter context) and
1069 dispatch to the appropriate handler
1071 static void dcerpc_recv_data(struct dcecli_connection
*conn
, DATA_BLOB
*blob
, NTSTATUS status
)
1073 struct ncacn_packet pkt
;
1075 if (NT_STATUS_IS_OK(status
) && blob
->length
== 0) {
1076 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
1079 /* the transport may be telling us of a severe error, such as
1081 if (!NT_STATUS_IS_OK(status
)) {
1082 data_blob_free(blob
);
1083 dcerpc_connection_dead(conn
, status
);
1087 /* parse the basic packet to work out what type of response this is */
1088 status
= ncacn_pull(conn
, blob
, blob
->data
, &pkt
);
1089 if (!NT_STATUS_IS_OK(status
)) {
1090 data_blob_free(blob
);
1091 dcerpc_connection_dead(conn
, status
);
1095 dcerpc_request_recv_data(conn
, blob
, &pkt
);
1099 handle timeouts of individual dcerpc requests
1101 static void dcerpc_timeout_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
1102 struct timeval t
, void *private_data
)
1104 struct rpc_request
*req
= talloc_get_type(private_data
, struct rpc_request
);
1106 if (req
->ignore_timeout
) {
1107 dcerpc_req_dequeue(req
);
1108 req
->state
= RPC_REQUEST_DONE
;
1109 req
->status
= NT_STATUS_IO_TIMEOUT
;
1110 if (req
->async
.callback
) {
1111 req
->async
.callback(req
);
1116 dcerpc_connection_dead(req
->p
->conn
, NT_STATUS_IO_TIMEOUT
);
1119 struct dcerpc_bind_state
{
1120 struct tevent_context
*ev
;
1121 struct dcerpc_pipe
*p
;
1124 static void dcerpc_bind_fail_handler(struct rpc_request
*subreq
);
1125 static void dcerpc_bind_recv_handler(struct rpc_request
*subreq
,
1126 DATA_BLOB
*raw_packet
,
1127 struct ncacn_packet
*pkt
);
1129 struct tevent_req
*dcerpc_bind_send(TALLOC_CTX
*mem_ctx
,
1130 struct tevent_context
*ev
,
1131 struct dcerpc_pipe
*p
,
1132 const struct ndr_syntax_id
*syntax
,
1133 const struct ndr_syntax_id
*transfer_syntax
)
1135 struct tevent_req
*req
;
1136 struct dcerpc_bind_state
*state
;
1137 struct ncacn_packet pkt
;
1140 struct rpc_request
*subreq
;
1142 req
= tevent_req_create(mem_ctx
, &state
,
1143 struct dcerpc_bind_state
);
1151 p
->syntax
= *syntax
;
1152 p
->transfer_syntax
= *transfer_syntax
;
1154 init_ncacn_hdr(p
->conn
, &pkt
);
1156 pkt
.ptype
= DCERPC_PKT_BIND
;
1157 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1158 pkt
.call_id
= p
->conn
->call_id
;
1159 pkt
.auth_length
= 0;
1161 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1162 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1165 if (p
->conn
->flags
& DCERPC_PROPOSE_HEADER_SIGNING
) {
1166 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
1169 pkt
.u
.bind
.max_xmit_frag
= p
->conn
->srv_max_xmit_frag
;
1170 pkt
.u
.bind
.max_recv_frag
= p
->conn
->srv_max_recv_frag
;
1171 pkt
.u
.bind
.assoc_group_id
= p
->binding
->assoc_group_id
;
1172 pkt
.u
.bind
.num_contexts
= 1;
1173 pkt
.u
.bind
.ctx_list
= talloc_array(mem_ctx
, struct dcerpc_ctx_list
, 1);
1174 if (tevent_req_nomem(pkt
.u
.bind
.ctx_list
, req
)) {
1175 return tevent_req_post(req
, ev
);
1177 pkt
.u
.bind
.ctx_list
[0].context_id
= p
->context_id
;
1178 pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
= 1;
1179 pkt
.u
.bind
.ctx_list
[0].abstract_syntax
= p
->syntax
;
1180 pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
1181 pkt
.u
.bind
.auth_info
= data_blob(NULL
, 0);
1183 /* construct the NDR form of the packet */
1184 status
= ncacn_push_auth(&blob
, state
, &pkt
,
1185 p
->conn
->security_state
.auth_info
);
1186 if (tevent_req_nterror(req
, status
)) {
1187 return tevent_req_post(req
, ev
);
1190 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1193 * we allocate a dcerpc_request so we can be in the same
1194 * request queue as normal requests
1196 subreq
= talloc_zero(state
, struct rpc_request
);
1197 if (tevent_req_nomem(subreq
, req
)) {
1198 return tevent_req_post(req
, ev
);
1201 subreq
->state
= RPC_REQUEST_PENDING
;
1202 subreq
->call_id
= pkt
.call_id
;
1203 subreq
->async
.private_data
= req
;
1204 subreq
->async
.callback
= dcerpc_bind_fail_handler
;
1206 subreq
->recv_handler
= dcerpc_bind_recv_handler
;
1207 DLIST_ADD_END(p
->conn
->pending
, subreq
, struct rpc_request
*);
1208 talloc_set_destructor(subreq
, dcerpc_req_dequeue
);
1210 status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, true);
1211 if (tevent_req_nterror(req
, status
)) {
1212 return tevent_req_post(req
, ev
);
1215 tevent_add_timer(ev
, subreq
,
1216 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
1217 dcerpc_timeout_handler
, subreq
);
1222 static void dcerpc_bind_fail_handler(struct rpc_request
*subreq
)
1224 struct tevent_req
*req
=
1225 talloc_get_type_abort(subreq
->async
.private_data
,
1227 struct dcerpc_bind_state
*state
=
1228 tevent_req_data(req
,
1229 struct dcerpc_bind_state
);
1230 NTSTATUS status
= subreq
->status
;
1232 TALLOC_FREE(subreq
);
1235 * We trigger the callback in the next event run
1236 * because the code in this file might trigger
1237 * multiple request callbacks from within a single
1240 * In order to avoid segfaults from within
1241 * dcerpc_connection_dead() we call
1242 * tevent_req_defer_callback().
1244 tevent_req_defer_callback(req
, state
->ev
);
1246 tevent_req_nterror(req
, status
);
1249 static void dcerpc_bind_recv_handler(struct rpc_request
*subreq
,
1250 DATA_BLOB
*raw_packet
,
1251 struct ncacn_packet
*pkt
)
1253 struct tevent_req
*req
=
1254 talloc_get_type_abort(subreq
->async
.private_data
,
1256 struct dcerpc_bind_state
*state
=
1257 tevent_req_data(req
,
1258 struct dcerpc_bind_state
);
1259 struct dcecli_connection
*conn
= state
->p
->conn
;
1263 * Note that pkt is allocated under raw_packet->data,
1264 * while raw_packet->data is a child of subreq.
1266 talloc_steal(state
, raw_packet
->data
);
1267 TALLOC_FREE(subreq
);
1270 * We trigger the callback in the next event run
1271 * because the code in this file might trigger
1272 * multiple request callbacks from within a single
1275 * In order to avoid segfaults from within
1276 * dcerpc_connection_dead() we call
1277 * tevent_req_defer_callback().
1279 tevent_req_defer_callback(req
, state
->ev
);
1281 if (pkt
->ptype
== DCERPC_PKT_BIND_NAK
) {
1282 status
= dcerpc_map_reason(pkt
->u
.bind_nak
.reject_reason
);
1284 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1285 pkt
->u
.bind_nak
.reject_reason
, nt_errstr(status
)));
1287 tevent_req_nterror(req
, status
);
1291 if ((pkt
->ptype
!= DCERPC_PKT_BIND_ACK
) ||
1292 (pkt
->u
.bind_ack
.num_results
== 0) ||
1293 (pkt
->u
.bind_ack
.ctx_list
[0].result
!= 0)) {
1294 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1295 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1300 * DCE-RPC 1.1 (c706) specifies
1301 * CONST_MUST_RCV_FRAG_SIZE as 1432
1303 if (pkt
->u
.bind_ack
.max_xmit_frag
< 1432) {
1304 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1305 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1308 if (pkt
->u
.bind_ack
.max_recv_frag
< 1432) {
1309 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1310 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1313 conn
->srv_max_xmit_frag
= MIN(conn
->srv_max_xmit_frag
,
1314 pkt
->u
.bind_ack
.max_xmit_frag
);
1315 conn
->srv_max_recv_frag
= MIN(conn
->srv_max_recv_frag
,
1316 pkt
->u
.bind_ack
.max_recv_frag
);
1318 if ((state
->p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) &&
1319 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_CONC_MPX
)) {
1320 conn
->flags
|= DCERPC_CONCURRENT_MULTIPLEX
;
1323 if ((conn
->flags
& DCERPC_PROPOSE_HEADER_SIGNING
) &&
1324 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
)) {
1325 conn
->flags
|= DCERPC_HEADER_SIGNING
;
1328 /* the bind_ack might contain a reply set of credentials */
1329 if (conn
->security_state
.auth_info
&& pkt
->u
.bind_ack
.auth_info
.length
) {
1330 uint32_t auth_length
;
1332 status
= dcerpc_pull_auth_trailer(pkt
, conn
, &pkt
->u
.bind_ack
.auth_info
,
1333 conn
->security_state
.auth_info
, &auth_length
, true);
1334 if (tevent_req_nterror(req
, status
)) {
1339 state
->p
->assoc_group_id
= pkt
->u
.bind_ack
.assoc_group_id
;
1341 tevent_req_done(req
);
1344 NTSTATUS
dcerpc_bind_recv(struct tevent_req
*req
)
1346 return tevent_req_simple_recv_ntstatus(req
);
1350 perform a continued bind (and auth3)
1352 NTSTATUS
dcerpc_auth3(struct dcerpc_pipe
*p
,
1353 TALLOC_CTX
*mem_ctx
)
1355 struct ncacn_packet pkt
;
1359 init_ncacn_hdr(p
->conn
, &pkt
);
1361 pkt
.ptype
= DCERPC_PKT_AUTH3
;
1362 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1363 pkt
.call_id
= next_call_id(p
->conn
);
1364 pkt
.auth_length
= 0;
1365 pkt
.u
.auth3
.auth_info
= data_blob(NULL
, 0);
1367 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1368 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1371 /* construct the NDR form of the packet */
1372 status
= ncacn_push_auth(&blob
, mem_ctx
,
1374 p
->conn
->security_state
.auth_info
);
1375 if (!NT_STATUS_IS_OK(status
)) {
1379 /* send it on its way */
1380 status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, false);
1381 if (!NT_STATUS_IS_OK(status
)) {
1385 return NT_STATUS_OK
;
1390 process a fragment received from the transport layer during a
1393 This function frees the data
1395 static void dcerpc_request_recv_data(struct dcecli_connection
*c
,
1396 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
1398 struct rpc_request
*req
;
1399 unsigned int length
;
1400 NTSTATUS status
= NT_STATUS_OK
;
1403 if this is an authenticated connection then parse and check
1404 the auth info. We have to do this before finding the
1405 matching packet, as the request structure might have been
1406 removed due to a timeout, but if it has been we still need
1407 to run the auth routines so that we don't get the sign/seal
1408 info out of step with the server
1410 if (c
->security_state
.auth_info
&& c
->security_state
.generic_state
&&
1411 pkt
->ptype
== DCERPC_PKT_RESPONSE
) {
1412 status
= ncacn_pull_request_auth(c
, raw_packet
->data
, raw_packet
, pkt
);
1415 /* find the matching request */
1416 for (req
=c
->pending
;req
;req
=req
->next
) {
1417 if (pkt
->call_id
== req
->call_id
) break;
1421 /* useful for testing certain vendors RPC servers */
1422 if (req
== NULL
&& c
->pending
&& pkt
->call_id
== 0) {
1423 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1429 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt
->call_id
));
1430 data_blob_free(raw_packet
);
1434 talloc_steal(req
, raw_packet
->data
);
1436 if (req
->recv_handler
!= NULL
) {
1437 dcerpc_req_dequeue(req
);
1438 req
->state
= RPC_REQUEST_DONE
;
1441 * We have to look at shipping further requests before calling
1442 * the async function, that one might close the pipe
1444 dcerpc_schedule_io_trigger(c
);
1446 req
->recv_handler(req
, raw_packet
, pkt
);
1450 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
1451 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c
, pkt
->u
.fault
.status
)));
1452 req
->fault_code
= pkt
->u
.fault
.status
;
1453 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
1457 if (pkt
->ptype
!= DCERPC_PKT_RESPONSE
) {
1458 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1460 req
->fault_code
= DCERPC_FAULT_OTHER
;
1461 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
1465 /* now check the status from the auth routines, and if it failed then fail
1466 this request accordingly */
1467 if (!NT_STATUS_IS_OK(status
)) {
1468 req
->status
= status
;
1472 length
= pkt
->u
.response
.stub_and_verifier
.length
;
1475 req
->payload
.data
= talloc_realloc(req
,
1478 req
->payload
.length
+ length
);
1479 if (!req
->payload
.data
) {
1480 req
->status
= NT_STATUS_NO_MEMORY
;
1483 memcpy(req
->payload
.data
+req
->payload
.length
,
1484 pkt
->u
.response
.stub_and_verifier
.data
, length
);
1485 req
->payload
.length
+= length
;
1488 if (!(pkt
->pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
1489 data_blob_free(raw_packet
);
1490 c
->transport
.send_read(c
);
1494 if (!(pkt
->drep
[0] & DCERPC_DREP_LE
)) {
1495 req
->flags
|= DCERPC_PULL_BIGENDIAN
;
1497 req
->flags
&= ~DCERPC_PULL_BIGENDIAN
;
1501 data_blob_free(raw_packet
);
1503 /* we've got the full payload */
1504 dcerpc_req_dequeue(req
);
1505 req
->state
= RPC_REQUEST_DONE
;
1508 * We have to look at shipping further requests before calling
1509 * the async function, that one might close the pipe
1511 dcerpc_schedule_io_trigger(c
);
1513 if (req
->async
.callback
) {
1514 req
->async
.callback(req
);
1519 perform the send side of a async dcerpc request
1521 static struct rpc_request
*dcerpc_request_send(TALLOC_CTX
*mem_ctx
,
1522 struct dcerpc_pipe
*p
,
1523 const struct GUID
*object
,
1525 DATA_BLOB
*stub_data
)
1527 struct rpc_request
*req
;
1529 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1531 req
= talloc_zero(mem_ctx
, struct rpc_request
);
1537 req
->call_id
= next_call_id(p
->conn
);
1538 req
->state
= RPC_REQUEST_QUEUED
;
1540 if (object
!= NULL
) {
1541 req
->object
= (struct GUID
*)talloc_memdup(req
, (const void *)object
, sizeof(*object
));
1542 if (req
->object
== NULL
) {
1549 req
->request_data
.length
= stub_data
->length
;
1550 req
->request_data
.data
= stub_data
->data
;
1552 DLIST_ADD_END(p
->conn
->request_queue
, req
, struct rpc_request
*);
1553 talloc_set_destructor(req
, dcerpc_req_dequeue
);
1555 dcerpc_schedule_io_trigger(p
->conn
);
1557 if (p
->request_timeout
) {
1558 tevent_add_timer(dcerpc_event_context(p
), req
,
1559 timeval_current_ofs(p
->request_timeout
, 0),
1560 dcerpc_timeout_handler
, req
);
1567 Send a request using the transport
1570 static void dcerpc_ship_next_request(struct dcecli_connection
*c
)
1572 struct rpc_request
*req
;
1573 struct dcerpc_pipe
*p
;
1574 DATA_BLOB
*stub_data
;
1575 struct ncacn_packet pkt
;
1577 uint32_t remaining
, chunk_size
;
1578 bool first_packet
= true;
1579 size_t sig_size
= 0;
1580 bool need_async
= false;
1581 bool can_async
= true;
1583 req
= c
->request_queue
;
1589 stub_data
= &req
->request_data
;
1595 if (c
->security_state
.auth_info
&&
1596 c
->security_state
.generic_state
)
1598 struct gensec_security
*gensec
= c
->security_state
.generic_state
;
1600 switch (c
->security_state
.auth_info
->auth_level
) {
1601 case DCERPC_AUTH_LEVEL_PRIVACY
:
1602 case DCERPC_AUTH_LEVEL_INTEGRITY
:
1603 can_async
= gensec_have_feature(gensec
,
1604 GENSEC_FEATURE_ASYNC_REPLIES
);
1606 case DCERPC_AUTH_LEVEL_CONNECT
:
1607 case DCERPC_AUTH_LEVEL_NONE
:
1616 if (need_async
&& !can_async
) {
1617 req
->wait_for_sync
= true;
1621 DLIST_REMOVE(c
->request_queue
, req
);
1622 DLIST_ADD(c
->pending
, req
);
1623 req
->state
= RPC_REQUEST_PENDING
;
1625 init_ncacn_hdr(p
->conn
, &pkt
);
1627 remaining
= stub_data
->length
;
1629 /* we can write a full max_recv_frag size, minus the dcerpc
1630 request header size */
1631 chunk_size
= p
->conn
->srv_max_recv_frag
;
1632 chunk_size
-= DCERPC_REQUEST_LENGTH
;
1633 if (c
->security_state
.auth_info
&&
1634 c
->security_state
.generic_state
) {
1635 sig_size
= gensec_sig_size(c
->security_state
.generic_state
,
1636 p
->conn
->srv_max_recv_frag
);
1638 chunk_size
-= DCERPC_AUTH_TRAILER_LENGTH
;
1639 chunk_size
-= sig_size
;
1642 chunk_size
-= (chunk_size
% 16);
1644 pkt
.ptype
= DCERPC_PKT_REQUEST
;
1645 pkt
.call_id
= req
->call_id
;
1646 pkt
.auth_length
= 0;
1648 pkt
.u
.request
.context_id
= p
->context_id
;
1649 pkt
.u
.request
.opnum
= req
->opnum
;
1652 pkt
.u
.request
.object
.object
= *req
->object
;
1653 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_OBJECT_UUID
;
1654 chunk_size
-= ndr_size_GUID(req
->object
,0);
1657 /* we send a series of pdus without waiting for a reply */
1658 while (remaining
> 0 || first_packet
) {
1659 uint32_t chunk
= MIN(chunk_size
, remaining
);
1660 bool last_frag
= false;
1661 bool do_trans
= false;
1663 first_packet
= false;
1664 pkt
.pfc_flags
&= ~(DCERPC_PFC_FLAG_FIRST
|DCERPC_PFC_FLAG_LAST
);
1666 if (remaining
== stub_data
->length
) {
1667 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_FIRST
;
1669 if (chunk
== remaining
) {
1670 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_LAST
;
1674 pkt
.u
.request
.alloc_hint
= remaining
;
1675 pkt
.u
.request
.stub_and_verifier
.data
= stub_data
->data
+
1676 (stub_data
->length
- remaining
);
1677 pkt
.u
.request
.stub_and_verifier
.length
= chunk
;
1679 req
->status
= ncacn_push_request_sign(p
->conn
, &blob
, req
, sig_size
, &pkt
);
1680 if (!NT_STATUS_IS_OK(req
->status
)) {
1681 req
->state
= RPC_REQUEST_DONE
;
1682 DLIST_REMOVE(p
->conn
->pending
, req
);
1686 if (last_frag
&& !need_async
) {
1690 req
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, do_trans
);
1691 if (!NT_STATUS_IS_OK(req
->status
)) {
1692 req
->state
= RPC_REQUEST_DONE
;
1693 DLIST_REMOVE(p
->conn
->pending
, req
);
1697 if (last_frag
&& !do_trans
) {
1698 req
->status
= p
->conn
->transport
.send_read(p
->conn
);
1699 if (!NT_STATUS_IS_OK(req
->status
)) {
1700 req
->state
= RPC_REQUEST_DONE
;
1701 DLIST_REMOVE(p
->conn
->pending
, req
);
1710 static void dcerpc_io_trigger(struct tevent_context
*ctx
,
1711 struct tevent_immediate
*im
,
1714 struct dcecli_connection
*c
=
1715 talloc_get_type_abort(private_data
,
1716 struct dcecli_connection
);
1718 c
->io_trigger_pending
= false;
1720 dcerpc_schedule_io_trigger(c
);
1722 dcerpc_ship_next_request(c
);
1725 static void dcerpc_schedule_io_trigger(struct dcecli_connection
*c
)
1731 if (c
->request_queue
== NULL
) {
1735 if (c
->request_queue
->wait_for_sync
&& c
->pending
) {
1739 if (c
->io_trigger_pending
) {
1743 c
->io_trigger_pending
= true;
1745 tevent_schedule_immediate(c
->io_trigger
,
1752 return the event context for a dcerpc pipe
1753 used by callers who wish to operate asynchronously
1755 _PUBLIC_
struct tevent_context
*dcerpc_event_context(struct dcerpc_pipe
*p
)
1757 return p
->conn
->event_ctx
;
1763 perform the receive side of a async dcerpc request
1765 static NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
1766 TALLOC_CTX
*mem_ctx
,
1767 DATA_BLOB
*stub_data
)
1771 while (req
->state
!= RPC_REQUEST_DONE
) {
1772 struct tevent_context
*ctx
= dcerpc_event_context(req
->p
);
1773 if (tevent_loop_once(ctx
) != 0) {
1774 return NT_STATUS_CONNECTION_DISCONNECTED
;
1777 *stub_data
= req
->payload
;
1778 status
= req
->status
;
1779 if (stub_data
->data
) {
1780 stub_data
->data
= talloc_steal(mem_ctx
, stub_data
->data
);
1782 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
1783 req
->p
->last_fault_code
= req
->fault_code
;
1785 talloc_unlink(talloc_parent(req
), req
);
1790 this is a paranoid NDR validator. For every packet we push onto the wire
1791 we pull it back again, then push it again. Then we compare the raw NDR data
1792 for that to the NDR we initially generated. If they don't match then we know
1793 we must have a bug in either the pull or push side of our code
1795 static NTSTATUS
dcerpc_ndr_validate_in(struct dcecli_connection
*c
,
1796 TALLOC_CTX
*mem_ctx
,
1799 ndr_push_flags_fn_t ndr_push
,
1800 ndr_pull_flags_fn_t ndr_pull
)
1803 struct ndr_pull
*pull
;
1804 struct ndr_push
*push
;
1806 enum ndr_err_code ndr_err
;
1808 st
= talloc_size(mem_ctx
, struct_size
);
1810 return NT_STATUS_NO_MEMORY
;
1813 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1815 return NT_STATUS_NO_MEMORY
;
1817 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1819 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1820 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1823 if (c
->flags
& DCERPC_NDR64
) {
1824 pull
->flags
|= LIBNDR_FLAG_NDR64
;
1827 ndr_err
= ndr_pull(pull
, NDR_IN
, st
);
1828 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1829 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1830 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1831 "failed input validation pull - %s",
1833 return ndr_map_error2ntstatus(ndr_err
);
1836 push
= ndr_push_init_ctx(mem_ctx
);
1838 return NT_STATUS_NO_MEMORY
;
1841 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1842 push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1845 if (c
->flags
& DCERPC_NDR64
) {
1846 push
->flags
|= LIBNDR_FLAG_NDR64
;
1849 ndr_err
= ndr_push(push
, NDR_IN
, st
);
1850 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1851 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1852 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1853 "failed input validation push - %s",
1855 return ndr_map_error2ntstatus(ndr_err
);
1858 blob2
= ndr_push_blob(push
);
1860 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1861 DEBUG(3,("original:\n"));
1862 dump_data(3, blob
.data
, blob
.length
);
1863 DEBUG(3,("secondary:\n"));
1864 dump_data(3, blob2
.data
, blob2
.length
);
1865 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1866 "failed input validation blobs doesn't match");
1867 return ndr_map_error2ntstatus(ndr_err
);
1870 return NT_STATUS_OK
;
1874 this is a paranoid NDR input validator. For every packet we pull
1875 from the wire we push it back again then pull and push it
1876 again. Then we compare the raw NDR data for that to the NDR we
1877 initially generated. If they don't match then we know we must have a
1878 bug in either the pull or push side of our code
1880 static NTSTATUS
dcerpc_ndr_validate_out(struct dcecli_connection
*c
,
1881 struct ndr_pull
*pull_in
,
1884 ndr_push_flags_fn_t ndr_push
,
1885 ndr_pull_flags_fn_t ndr_pull
,
1886 ndr_print_function_t ndr_print
)
1889 struct ndr_pull
*pull
;
1890 struct ndr_push
*push
;
1891 DATA_BLOB blob
, blob2
;
1892 TALLOC_CTX
*mem_ctx
= pull_in
;
1894 enum ndr_err_code ndr_err
;
1896 st
= talloc_size(mem_ctx
, struct_size
);
1898 return NT_STATUS_NO_MEMORY
;
1900 memcpy(st
, struct_ptr
, struct_size
);
1902 push
= ndr_push_init_ctx(mem_ctx
);
1904 return NT_STATUS_NO_MEMORY
;
1907 ndr_err
= ndr_push(push
, NDR_OUT
, struct_ptr
);
1908 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1909 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1910 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1911 "failed output validation push - %s",
1913 return ndr_map_error2ntstatus(ndr_err
);
1916 blob
= ndr_push_blob(push
);
1918 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1920 return NT_STATUS_NO_MEMORY
;
1923 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1924 ndr_err
= ndr_pull(pull
, NDR_OUT
, st
);
1925 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1926 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1927 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1928 "failed output validation pull - %s",
1930 return ndr_map_error2ntstatus(ndr_err
);
1933 push
= ndr_push_init_ctx(mem_ctx
);
1935 return NT_STATUS_NO_MEMORY
;
1938 ndr_err
= ndr_push(push
, NDR_OUT
, st
);
1939 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1940 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1941 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1942 "failed output validation push2 - %s",
1944 return ndr_map_error2ntstatus(ndr_err
);
1947 blob2
= ndr_push_blob(push
);
1949 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1950 DEBUG(3,("original:\n"));
1951 dump_data(3, blob
.data
, blob
.length
);
1952 DEBUG(3,("secondary:\n"));
1953 dump_data(3, blob2
.data
, blob2
.length
);
1954 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1955 "failed output validation blobs doesn't match");
1956 return ndr_map_error2ntstatus(ndr_err
);
1959 /* this checks the printed forms of the two structures, which effectively
1960 tests all of the value() attributes */
1961 s1
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1962 NDR_OUT
, struct_ptr
);
1963 s2
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1965 if (strcmp(s1
, s2
) != 0) {
1967 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1
, s2
));
1969 /* this is sometimes useful */
1970 printf("VALIDATE ERROR\n");
1971 file_save("wire.dat", s1
, strlen(s1
));
1972 file_save("gen.dat", s2
, strlen(s2
));
1973 system("diff -u wire.dat gen.dat");
1975 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1976 "failed output validation strings doesn't match");
1977 return ndr_map_error2ntstatus(ndr_err
);
1980 return NT_STATUS_OK
;
1984 a useful function for retrieving the server name we connected to
1986 _PUBLIC_
const char *dcerpc_server_name(struct dcerpc_pipe
*p
)
1988 return p
->conn
? p
->conn
->server_name
: NULL
;
1993 get the dcerpc auth_level for a open connection
1995 uint32_t dcerpc_auth_level(struct dcecli_connection
*c
)
1999 if (c
->flags
& DCERPC_SEAL
) {
2000 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
2001 } else if (c
->flags
& DCERPC_SIGN
) {
2002 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
2003 } else if (c
->flags
& DCERPC_CONNECT
) {
2004 auth_level
= DCERPC_AUTH_LEVEL_CONNECT
;
2006 auth_level
= DCERPC_AUTH_LEVEL_NONE
;
2011 struct dcerpc_alter_context_state
{
2012 struct tevent_context
*ev
;
2013 struct dcerpc_pipe
*p
;
2016 static void dcerpc_alter_context_fail_handler(struct rpc_request
*subreq
);
2017 static void dcerpc_alter_context_recv_handler(struct rpc_request
*req
,
2018 DATA_BLOB
*raw_packet
,
2019 struct ncacn_packet
*pkt
);
2021 struct tevent_req
*dcerpc_alter_context_send(TALLOC_CTX
*mem_ctx
,
2022 struct tevent_context
*ev
,
2023 struct dcerpc_pipe
*p
,
2024 const struct ndr_syntax_id
*syntax
,
2025 const struct ndr_syntax_id
*transfer_syntax
)
2027 struct tevent_req
*req
;
2028 struct dcerpc_alter_context_state
*state
;
2029 struct ncacn_packet pkt
;
2032 struct rpc_request
*subreq
;
2034 req
= tevent_req_create(mem_ctx
, &state
,
2035 struct dcerpc_alter_context_state
);
2043 p
->syntax
= *syntax
;
2044 p
->transfer_syntax
= *transfer_syntax
;
2046 init_ncacn_hdr(p
->conn
, &pkt
);
2048 pkt
.ptype
= DCERPC_PKT_ALTER
;
2049 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
2050 pkt
.call_id
= p
->conn
->call_id
;
2051 pkt
.auth_length
= 0;
2053 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
2054 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
2057 pkt
.u
.alter
.max_xmit_frag
= p
->conn
->srv_max_xmit_frag
;
2058 pkt
.u
.alter
.max_recv_frag
= p
->conn
->srv_max_recv_frag
;
2059 pkt
.u
.alter
.assoc_group_id
= p
->binding
->assoc_group_id
;
2060 pkt
.u
.alter
.num_contexts
= 1;
2061 pkt
.u
.alter
.ctx_list
= talloc_array(state
, struct dcerpc_ctx_list
, 1);
2062 if (tevent_req_nomem(pkt
.u
.alter
.ctx_list
, req
)) {
2063 return tevent_req_post(req
, ev
);
2065 pkt
.u
.alter
.ctx_list
[0].context_id
= p
->context_id
;
2066 pkt
.u
.alter
.ctx_list
[0].num_transfer_syntaxes
= 1;
2067 pkt
.u
.alter
.ctx_list
[0].abstract_syntax
= p
->syntax
;
2068 pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
2069 pkt
.u
.alter
.auth_info
= data_blob(NULL
, 0);
2071 /* construct the NDR form of the packet */
2072 status
= ncacn_push_auth(&blob
, state
, &pkt
,
2073 p
->conn
->security_state
.auth_info
);
2074 if (tevent_req_nterror(req
, status
)) {
2075 return tevent_req_post(req
, ev
);
2078 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
2081 * we allocate a dcerpc_request so we can be in the same
2082 * request queue as normal requests
2084 subreq
= talloc_zero(state
, struct rpc_request
);
2085 if (tevent_req_nomem(subreq
, req
)) {
2086 return tevent_req_post(req
, ev
);
2089 subreq
->state
= RPC_REQUEST_PENDING
;
2090 subreq
->call_id
= pkt
.call_id
;
2091 subreq
->async
.private_data
= req
;
2092 subreq
->async
.callback
= dcerpc_alter_context_fail_handler
;
2094 subreq
->recv_handler
= dcerpc_alter_context_recv_handler
;
2095 DLIST_ADD_END(p
->conn
->pending
, subreq
, struct rpc_request
*);
2096 talloc_set_destructor(subreq
, dcerpc_req_dequeue
);
2098 status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, true);
2099 if (tevent_req_nterror(req
, status
)) {
2100 return tevent_req_post(req
, ev
);
2103 tevent_add_timer(ev
, subreq
,
2104 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
2105 dcerpc_timeout_handler
, subreq
);
2110 static void dcerpc_alter_context_fail_handler(struct rpc_request
*subreq
)
2112 struct tevent_req
*req
=
2113 talloc_get_type_abort(subreq
->async
.private_data
,
2115 struct dcerpc_alter_context_state
*state
=
2116 tevent_req_data(req
,
2117 struct dcerpc_alter_context_state
);
2118 NTSTATUS status
= subreq
->status
;
2120 TALLOC_FREE(subreq
);
2123 * We trigger the callback in the next event run
2124 * because the code in this file might trigger
2125 * multiple request callbacks from within a single
2128 * In order to avoid segfaults from within
2129 * dcerpc_connection_dead() we call
2130 * tevent_req_defer_callback().
2132 tevent_req_defer_callback(req
, state
->ev
);
2134 tevent_req_nterror(req
, status
);
2137 static void dcerpc_alter_context_recv_handler(struct rpc_request
*subreq
,
2138 DATA_BLOB
*raw_packet
,
2139 struct ncacn_packet
*pkt
)
2141 struct tevent_req
*req
=
2142 talloc_get_type_abort(subreq
->async
.private_data
,
2144 struct dcerpc_alter_context_state
*state
=
2145 tevent_req_data(req
,
2146 struct dcerpc_alter_context_state
);
2147 struct dcecli_connection
*conn
= state
->p
->conn
;
2151 * Note that pkt is allocated under raw_packet->data,
2152 * while raw_packet->data is a child of subreq.
2154 talloc_steal(state
, raw_packet
->data
);
2155 TALLOC_FREE(subreq
);
2158 * We trigger the callback in the next event run
2159 * because the code in this file might trigger
2160 * multiple request callbacks from within a single
2163 * In order to avoid segfaults from within
2164 * dcerpc_connection_dead() we call
2165 * tevent_req_defer_callback().
2167 tevent_req_defer_callback(req
, state
->ev
);
2169 if (pkt
->ptype
== DCERPC_PKT_ALTER_RESP
&&
2170 pkt
->u
.alter_resp
.num_results
== 1 &&
2171 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
2172 status
= dcerpc_map_reason(pkt
->u
.alter_resp
.ctx_list
[0].reason
);
2173 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2174 pkt
->u
.alter_resp
.ctx_list
[0].reason
,
2175 nt_errstr(status
)));
2176 tevent_req_nterror(req
, status
);
2180 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
2181 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2182 dcerpc_errstr(state
, pkt
->u
.fault
.status
)));
2183 if (pkt
->u
.fault
.status
== DCERPC_FAULT_ACCESS_DENIED
) {
2184 state
->p
->last_fault_code
= pkt
->u
.fault
.status
;
2185 tevent_req_nterror(req
, NT_STATUS_LOGON_FAILURE
);
2187 state
->p
->last_fault_code
= pkt
->u
.fault
.status
;
2188 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
2193 if (pkt
->ptype
!= DCERPC_PKT_ALTER_RESP
||
2194 pkt
->u
.alter_resp
.num_results
== 0 ||
2195 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
2196 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
2197 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
2201 /* the alter_resp might contain a reply set of credentials */
2202 if (conn
->security_state
.auth_info
&&
2203 pkt
->u
.alter_resp
.auth_info
.length
) {
2204 uint32_t auth_length
;
2206 status
= dcerpc_pull_auth_trailer(pkt
, conn
, &pkt
->u
.alter_resp
.auth_info
,
2207 conn
->security_state
.auth_info
, &auth_length
, true);
2208 if (tevent_req_nterror(req
, status
)) {
2213 tevent_req_done(req
);
2216 NTSTATUS
dcerpc_alter_context_recv(struct tevent_req
*req
)
2218 return tevent_req_simple_recv_ntstatus(req
);
2222 send a dcerpc alter_context request
2224 _PUBLIC_ NTSTATUS
dcerpc_alter_context(struct dcerpc_pipe
*p
,
2225 TALLOC_CTX
*mem_ctx
,
2226 const struct ndr_syntax_id
*syntax
,
2227 const struct ndr_syntax_id
*transfer_syntax
)
2229 struct tevent_req
*subreq
;
2230 struct tevent_context
*ev
= p
->conn
->event_ctx
;
2233 /* TODO: create a new event context here */
2235 subreq
= dcerpc_alter_context_send(mem_ctx
, p
->conn
->event_ctx
,
2236 p
, syntax
, transfer_syntax
);
2237 if (subreq
== NULL
) {
2238 return NT_STATUS_NO_MEMORY
;
2241 ok
= tevent_req_poll(subreq
, ev
);
2244 status
= map_nt_error_from_unix_common(errno
);
2248 return dcerpc_alter_context_recv(subreq
);
2251 void dcerpc_transport_dead(struct dcecli_connection
*c
, NTSTATUS status
)
2253 if (c
->transport
.stream
== NULL
) {
2257 tevent_queue_stop(c
->transport
.write_queue
);
2258 TALLOC_FREE(c
->transport
.read_subreq
);
2259 TALLOC_FREE(c
->transport
.stream
);
2261 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL
, status
)) {
2262 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
2265 if (NT_STATUS_EQUAL(NT_STATUS_OK
, status
)) {
2266 status
= NT_STATUS_END_OF_FILE
;
2269 if (c
->transport
.recv_data
) {
2270 c
->transport
.recv_data(c
, NULL
, status
);
2276 shutdown SMB pipe connection
2278 struct dcerpc_shutdown_pipe_state
{
2279 struct dcecli_connection
*c
;
2283 static void dcerpc_shutdown_pipe_done(struct tevent_req
*subreq
);
2285 static NTSTATUS
dcerpc_shutdown_pipe(struct dcecli_connection
*c
, NTSTATUS status
)
2287 struct dcerpc_shutdown_pipe_state
*state
;
2288 struct tevent_req
*subreq
;
2290 if (c
->transport
.stream
== NULL
) {
2291 return NT_STATUS_OK
;
2294 state
= talloc_zero(c
, struct dcerpc_shutdown_pipe_state
);
2295 if (state
== NULL
) {
2296 return NT_STATUS_NO_MEMORY
;
2299 state
->status
= status
;
2301 subreq
= tstream_disconnect_send(state
, c
->event_ctx
, c
->transport
.stream
);
2302 if (subreq
== NULL
) {
2303 return NT_STATUS_NO_MEMORY
;
2305 tevent_req_set_callback(subreq
, dcerpc_shutdown_pipe_done
, state
);
2310 static void dcerpc_shutdown_pipe_done(struct tevent_req
*subreq
)
2312 struct dcerpc_shutdown_pipe_state
*state
=
2313 tevent_req_callback_data(subreq
, struct dcerpc_shutdown_pipe_state
);
2314 struct dcecli_connection
*c
= state
->c
;
2315 NTSTATUS status
= state
->status
;
2319 * here we ignore the return values...
2321 tstream_disconnect_recv(subreq
, &error
);
2322 TALLOC_FREE(subreq
);
2326 dcerpc_transport_dead(c
, status
);