2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "librpc/rpc/rpc_common.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "libcli/smb/tstream_smbXcli_np.h"
39 enum rpc_request_state
{
46 handle for an async dcerpc request
49 struct rpc_request
*next
, *prev
;
50 struct dcerpc_pipe
*p
;
53 enum rpc_request_state state
;
58 /* this is used to distinguish bind and alter_context requests
59 from normal requests */
60 void (*recv_handler
)(struct rpc_request
*conn
,
61 DATA_BLOB
*blob
, struct ncacn_packet
*pkt
);
63 const struct GUID
*object
;
65 DATA_BLOB request_data
;
70 void (*callback
)(struct rpc_request
*);
75 _PUBLIC_ NTSTATUS
dcerpc_init(void)
80 static void dcerpc_connection_dead(struct dcecli_connection
*conn
, NTSTATUS status
);
81 static void dcerpc_schedule_io_trigger(struct dcecli_connection
*c
);
83 static struct rpc_request
*dcerpc_request_send(TALLOC_CTX
*mem_ctx
,
84 struct dcerpc_pipe
*p
,
85 const struct GUID
*object
,
87 DATA_BLOB
*stub_data
);
88 static NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
90 DATA_BLOB
*stub_data
);
91 static NTSTATUS
dcerpc_ndr_validate_in(struct dcecli_connection
*c
,
95 ndr_push_flags_fn_t ndr_push
,
96 ndr_pull_flags_fn_t ndr_pull
);
97 static NTSTATUS
dcerpc_ndr_validate_out(struct dcecli_connection
*c
,
98 struct ndr_pull
*pull_in
,
101 ndr_push_flags_fn_t ndr_push
,
102 ndr_pull_flags_fn_t ndr_pull
,
103 ndr_print_function_t ndr_print
);
104 static NTSTATUS
dcerpc_shutdown_pipe(struct dcecli_connection
*p
, NTSTATUS status
);
105 static NTSTATUS
dcerpc_send_request(struct dcecli_connection
*p
, DATA_BLOB
*data
,
107 static NTSTATUS
dcerpc_send_read(struct dcecli_connection
*p
);
109 /* destroy a dcerpc connection */
110 static int dcerpc_connection_destructor(struct dcecli_connection
*conn
)
113 conn
->free_skipped
= true;
116 dcerpc_connection_dead(conn
, NT_STATUS_LOCAL_DISCONNECT
);
121 /* initialise a dcerpc connection.
122 the event context is optional
124 static struct dcecli_connection
*dcerpc_connection_init(TALLOC_CTX
*mem_ctx
,
125 struct tevent_context
*ev
)
127 struct dcecli_connection
*c
;
129 c
= talloc_zero(mem_ctx
, struct dcecli_connection
);
136 if (c
->event_ctx
== NULL
) {
142 c
->security_state
.auth_info
= NULL
;
143 c
->security_state
.session_key
= dcerpc_generic_session_key
;
144 c
->security_state
.generic_state
= NULL
;
145 c
->binding_string
= NULL
;
148 * Windows uses 5840 for ncacn_ip_tcp,
149 * so we also use it (for every transport)
150 * by default. But we give the transport
151 * the chance to overwrite it.
153 c
->srv_max_xmit_frag
= 5840;
154 c
->srv_max_recv_frag
= 5840;
157 c
->io_trigger
= tevent_create_immediate(c
);
158 if (c
->io_trigger
== NULL
) {
163 talloc_set_destructor(c
, dcerpc_connection_destructor
);
168 struct dcerpc_bh_state
{
169 struct dcerpc_pipe
*p
;
172 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle
*h
)
174 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
175 struct dcerpc_bh_state
);
185 if (hs
->p
->conn
->dead
) {
192 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle
*h
,
195 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
196 struct dcerpc_bh_state
);
200 return DCERPC_REQUEST_TIMEOUT
;
203 old
= hs
->p
->request_timeout
;
204 hs
->p
->request_timeout
= timeout
;
209 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle
*h
,
210 enum dcerpc_AuthType
*auth_type
,
211 enum dcerpc_AuthLevel
*auth_level
)
213 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
214 struct dcerpc_bh_state
);
220 if (hs
->p
->conn
== NULL
) {
224 if (hs
->p
->conn
->security_state
.auth_info
== NULL
) {
228 *auth_type
= hs
->p
->conn
->security_state
.auth_info
->auth_type
;
229 *auth_level
= hs
->p
->conn
->security_state
.auth_info
->auth_level
;
232 struct dcerpc_bh_raw_call_state
{
233 struct tevent_context
*ev
;
234 struct dcerpc_binding_handle
*h
;
240 static void dcerpc_bh_raw_call_done(struct rpc_request
*subreq
);
242 static struct tevent_req
*dcerpc_bh_raw_call_send(TALLOC_CTX
*mem_ctx
,
243 struct tevent_context
*ev
,
244 struct dcerpc_binding_handle
*h
,
245 const struct GUID
*object
,
248 const uint8_t *in_data
,
251 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
252 struct dcerpc_bh_state
);
253 struct tevent_req
*req
;
254 struct dcerpc_bh_raw_call_state
*state
;
256 struct rpc_request
*subreq
;
258 req
= tevent_req_create(mem_ctx
, &state
,
259 struct dcerpc_bh_raw_call_state
);
265 state
->in_data
.data
= discard_const_p(uint8_t, in_data
);
266 state
->in_data
.length
= in_length
;
268 ok
= dcerpc_bh_is_connected(h
);
270 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
271 return tevent_req_post(req
, ev
);
274 subreq
= dcerpc_request_send(state
,
279 if (tevent_req_nomem(subreq
, req
)) {
280 return tevent_req_post(req
, ev
);
282 subreq
->async
.callback
= dcerpc_bh_raw_call_done
;
283 subreq
->async
.private_data
= req
;
288 static void dcerpc_bh_raw_call_done(struct rpc_request
*subreq
)
290 struct tevent_req
*req
=
291 talloc_get_type_abort(subreq
->async
.private_data
,
293 struct dcerpc_bh_raw_call_state
*state
=
295 struct dcerpc_bh_raw_call_state
);
299 state
->out_flags
= 0;
300 if (subreq
->flags
& DCERPC_PULL_BIGENDIAN
) {
301 state
->out_flags
|= LIBNDR_FLAG_BIGENDIAN
;
304 fault_code
= subreq
->fault_code
;
306 status
= dcerpc_request_recv(subreq
, state
, &state
->out_data
);
307 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
308 status
= dcerpc_fault_to_nt_status(fault_code
);
312 * We trigger the callback in the next event run
313 * because the code in this file might trigger
314 * multiple request callbacks from within a single
317 * In order to avoid segfaults from within
318 * dcerpc_connection_dead() we call
319 * tevent_req_defer_callback().
321 tevent_req_defer_callback(req
, state
->ev
);
323 if (!NT_STATUS_IS_OK(status
)) {
324 tevent_req_nterror(req
, status
);
328 tevent_req_done(req
);
331 static NTSTATUS
dcerpc_bh_raw_call_recv(struct tevent_req
*req
,
337 struct dcerpc_bh_raw_call_state
*state
=
339 struct dcerpc_bh_raw_call_state
);
342 if (tevent_req_is_nterror(req
, &status
)) {
343 tevent_req_received(req
);
347 *out_data
= talloc_move(mem_ctx
, &state
->out_data
.data
);
348 *out_length
= state
->out_data
.length
;
349 *out_flags
= state
->out_flags
;
350 tevent_req_received(req
);
354 struct dcerpc_bh_disconnect_state
{
358 static struct tevent_req
*dcerpc_bh_disconnect_send(TALLOC_CTX
*mem_ctx
,
359 struct tevent_context
*ev
,
360 struct dcerpc_binding_handle
*h
)
362 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
363 struct dcerpc_bh_state
);
364 struct tevent_req
*req
;
365 struct dcerpc_bh_disconnect_state
*state
;
368 req
= tevent_req_create(mem_ctx
, &state
,
369 struct dcerpc_bh_disconnect_state
);
374 ok
= dcerpc_bh_is_connected(h
);
376 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
377 return tevent_req_post(req
, ev
);
380 /* TODO: do a real disconnect ... */
383 tevent_req_done(req
);
384 return tevent_req_post(req
, ev
);
387 static NTSTATUS
dcerpc_bh_disconnect_recv(struct tevent_req
*req
)
391 if (tevent_req_is_nterror(req
, &status
)) {
392 tevent_req_received(req
);
396 tevent_req_received(req
);
400 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle
*h
)
402 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
403 struct dcerpc_bh_state
);
405 if (hs
->p
->conn
->flags
& DCERPC_PUSH_BIGENDIAN
) {
412 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle
*h
)
414 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
415 struct dcerpc_bh_state
);
417 if (hs
->p
->conn
->flags
& DCERPC_NDR_REF_ALLOC
) {
424 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle
*h
)
426 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
427 struct dcerpc_bh_state
);
429 if (hs
->p
->conn
->flags
& DCERPC_NDR64
) {
436 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle
*h
,
438 const void *_struct_ptr
,
439 const struct ndr_interface_call
*call
)
441 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
442 struct dcerpc_bh_state
);
443 void *struct_ptr
= discard_const(_struct_ptr
);
445 if (ndr_flags
& NDR_IN
) {
446 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_PRINT_IN
) {
447 ndr_print_function_debug(call
->ndr_print
,
453 if (ndr_flags
& NDR_OUT
) {
454 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_PRINT_OUT
) {
455 ndr_print_function_debug(call
->ndr_print
,
463 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle
*h
,
465 const void *struct_ptr
,
466 const struct ndr_interface_call
*call
)
468 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
469 call
->name
, nt_errstr(error
)));
472 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle
*h
,
474 const DATA_BLOB
*blob
,
475 const struct ndr_interface_call
*call
)
477 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
478 struct dcerpc_bh_state
);
479 const uint32_t num_examples
= 20;
482 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
483 call
->name
, nt_errstr(error
)));
485 if (hs
->p
->conn
->packet_log_dir
== NULL
) return;
487 for (i
=0;i
<num_examples
;i
++) {
489 asprintf(&name
, "%s/rpclog/%s-out.%d",
490 hs
->p
->conn
->packet_log_dir
,
495 if (!file_exist(name
)) {
496 if (file_save(name
, blob
->data
, blob
->length
)) {
497 DEBUG(10,("Logged rpc packet to %s\n", name
));
506 static NTSTATUS
dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle
*h
,
508 const DATA_BLOB
*blob
,
509 const struct ndr_interface_call
*call
)
511 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
512 struct dcerpc_bh_state
);
514 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_IN
) {
517 status
= dcerpc_ndr_validate_in(hs
->p
->conn
,
523 if (!NT_STATUS_IS_OK(status
)) {
524 DEBUG(0,("Validation [in] failed for %s - %s\n",
525 call
->name
, nt_errstr(status
)));
530 DEBUG(10,("rpc request data:\n"));
531 dump_data(10, blob
->data
, blob
->length
);
536 static NTSTATUS
dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle
*h
,
537 struct ndr_pull
*pull_in
,
538 const void *_struct_ptr
,
539 const struct ndr_interface_call
*call
)
541 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
542 struct dcerpc_bh_state
);
543 void *struct_ptr
= discard_const(_struct_ptr
);
545 DEBUG(10,("rpc reply data:\n"));
546 dump_data(10, pull_in
->data
, pull_in
->data_size
);
548 if (pull_in
->offset
!= pull_in
->data_size
) {
549 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
550 pull_in
->data_size
- pull_in
->offset
,
551 pull_in
->offset
, pull_in
->offset
,
553 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
554 but it turns out that early versions of NT
555 (specifically NT3.1) add junk onto the end of rpc
556 packets, so if we want to interoperate at all with
557 those versions then we need to ignore this error */
560 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_OUT
) {
563 status
= dcerpc_ndr_validate_out(hs
->p
->conn
,
570 if (!NT_STATUS_IS_OK(status
)) {
571 DEBUG(2,("Validation [out] failed for %s - %s\n",
572 call
->name
, nt_errstr(status
)));
580 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops
= {
582 .is_connected
= dcerpc_bh_is_connected
,
583 .set_timeout
= dcerpc_bh_set_timeout
,
584 .auth_info
= dcerpc_bh_auth_info
,
585 .raw_call_send
= dcerpc_bh_raw_call_send
,
586 .raw_call_recv
= dcerpc_bh_raw_call_recv
,
587 .disconnect_send
= dcerpc_bh_disconnect_send
,
588 .disconnect_recv
= dcerpc_bh_disconnect_recv
,
590 .push_bigendian
= dcerpc_bh_push_bigendian
,
591 .ref_alloc
= dcerpc_bh_ref_alloc
,
592 .use_ndr64
= dcerpc_bh_use_ndr64
,
593 .do_ndr_print
= dcerpc_bh_do_ndr_print
,
594 .ndr_push_failed
= dcerpc_bh_ndr_push_failed
,
595 .ndr_pull_failed
= dcerpc_bh_ndr_pull_failed
,
596 .ndr_validate_in
= dcerpc_bh_ndr_validate_in
,
597 .ndr_validate_out
= dcerpc_bh_ndr_validate_out
,
600 /* initialise a dcerpc pipe. */
601 struct dcerpc_binding_handle
*dcerpc_pipe_binding_handle(struct dcerpc_pipe
*p
)
603 struct dcerpc_binding_handle
*h
;
604 struct dcerpc_bh_state
*hs
;
606 h
= dcerpc_binding_handle_create(p
,
611 struct dcerpc_bh_state
,
618 dcerpc_binding_handle_set_sync_ev(h
, p
->conn
->event_ctx
);
623 /* initialise a dcerpc pipe. */
624 _PUBLIC_
struct dcerpc_pipe
*dcerpc_pipe_init(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
)
626 struct dcerpc_pipe
*p
;
628 p
= talloc_zero(mem_ctx
, struct dcerpc_pipe
);
633 p
->conn
= dcerpc_connection_init(p
, ev
);
634 if (p
->conn
== NULL
) {
639 p
->last_fault_code
= 0;
641 p
->request_timeout
= DCERPC_REQUEST_TIMEOUT
;
644 ZERO_STRUCT(p
->syntax
);
645 ZERO_STRUCT(p
->transfer_syntax
);
648 p
->conn
->flags
|= DCERPC_DEBUG_PRINT_BOTH
;
651 p
->binding_handle
= dcerpc_pipe_binding_handle(p
);
652 if (p
->binding_handle
== NULL
) {
662 choose the next call id to use
664 static uint32_t next_call_id(struct dcecli_connection
*c
)
667 if (c
->call_id
== 0) {
674 setup for a ndr pull, also setting up any flags from the binding string
676 static struct ndr_pull
*ndr_pull_init_flags(struct dcecli_connection
*c
,
677 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
679 struct ndr_pull
*ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
681 if (ndr
== NULL
) return ndr
;
683 if (c
->flags
& DCERPC_DEBUG_PAD_CHECK
) {
684 ndr
->flags
|= LIBNDR_FLAG_PAD_CHECK
;
687 if (c
->flags
& DCERPC_NDR_REF_ALLOC
) {
688 ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
691 if (c
->flags
& DCERPC_NDR64
) {
692 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
699 parse a data blob into a ncacn_packet structure. This handles both
700 input and output packets
702 static NTSTATUS
ncacn_pull(struct dcecli_connection
*c
, DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
703 struct ncacn_packet
*pkt
)
705 struct ndr_pull
*ndr
;
706 enum ndr_err_code ndr_err
;
708 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
710 return NT_STATUS_NO_MEMORY
;
713 if (! (CVAL(blob
->data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
714 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
717 if (CVAL(blob
->data
, DCERPC_PFC_OFFSET
) & DCERPC_PFC_FLAG_OBJECT_UUID
) {
718 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
721 ndr_err
= ndr_pull_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
723 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
724 return ndr_map_error2ntstatus(ndr_err
);
727 if (pkt
->frag_length
!= blob
->length
) {
728 return NT_STATUS_RPC_PROTOCOL_ERROR
;
735 parse the authentication information on a dcerpc response packet
737 static NTSTATUS
ncacn_pull_request_auth(struct dcecli_connection
*c
, TALLOC_CTX
*mem_ctx
,
738 DATA_BLOB
*raw_packet
,
739 struct ncacn_packet
*pkt
)
742 struct dcerpc_auth auth
;
743 uint32_t auth_length
;
745 if (!c
->security_state
.auth_info
||
746 !c
->security_state
.generic_state
) {
750 switch (c
->security_state
.auth_info
->auth_level
) {
751 case DCERPC_AUTH_LEVEL_PRIVACY
:
752 case DCERPC_AUTH_LEVEL_INTEGRITY
:
755 case DCERPC_AUTH_LEVEL_CONNECT
:
756 if (pkt
->auth_length
!= 0) {
760 case DCERPC_AUTH_LEVEL_NONE
:
761 if (pkt
->auth_length
!= 0) {
762 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
767 return NT_STATUS_INVALID_LEVEL
;
770 status
= dcerpc_pull_auth_trailer(pkt
, mem_ctx
,
771 &pkt
->u
.response
.stub_and_verifier
,
772 &auth
, &auth_length
, false);
773 NT_STATUS_NOT_OK_RETURN(status
);
775 pkt
->u
.response
.stub_and_verifier
.length
-= auth_length
;
777 /* check signature or unseal the packet */
778 switch (c
->security_state
.auth_info
->auth_level
) {
779 case DCERPC_AUTH_LEVEL_PRIVACY
:
780 status
= gensec_unseal_packet(c
->security_state
.generic_state
,
781 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
782 pkt
->u
.response
.stub_and_verifier
.length
,
784 raw_packet
->length
- auth
.credentials
.length
,
786 memcpy(pkt
->u
.response
.stub_and_verifier
.data
,
787 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
788 pkt
->u
.response
.stub_and_verifier
.length
);
791 case DCERPC_AUTH_LEVEL_INTEGRITY
:
792 status
= gensec_check_packet(c
->security_state
.generic_state
,
793 pkt
->u
.response
.stub_and_verifier
.data
,
794 pkt
->u
.response
.stub_and_verifier
.length
,
796 raw_packet
->length
- auth
.credentials
.length
,
800 case DCERPC_AUTH_LEVEL_CONNECT
:
801 /* for now we ignore possible signatures here */
802 status
= NT_STATUS_OK
;
806 status
= NT_STATUS_INVALID_LEVEL
;
810 /* remove the indicated amount of padding */
811 if (pkt
->u
.response
.stub_and_verifier
.length
< auth
.auth_pad_length
) {
812 return NT_STATUS_INFO_LENGTH_MISMATCH
;
814 pkt
->u
.response
.stub_and_verifier
.length
-= auth
.auth_pad_length
;
821 push a dcerpc request packet into a blob, possibly signing it.
823 static NTSTATUS
ncacn_push_request_sign(struct dcecli_connection
*c
,
824 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
826 struct ncacn_packet
*pkt
)
829 struct ndr_push
*ndr
;
831 size_t payload_length
;
832 enum ndr_err_code ndr_err
;
833 size_t hdr_size
= DCERPC_REQUEST_LENGTH
;
835 /* non-signed packets are simpler */
837 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
840 switch (c
->security_state
.auth_info
->auth_level
) {
841 case DCERPC_AUTH_LEVEL_PRIVACY
:
842 case DCERPC_AUTH_LEVEL_INTEGRITY
:
845 case DCERPC_AUTH_LEVEL_CONNECT
:
846 /* TODO: let the gensec mech decide if it wants to generate a signature */
847 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
849 case DCERPC_AUTH_LEVEL_NONE
:
850 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
853 return NT_STATUS_INVALID_LEVEL
;
856 ndr
= ndr_push_init_ctx(mem_ctx
);
858 return NT_STATUS_NO_MEMORY
;
861 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
862 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
865 if (c
->flags
& DCERPC_NDR64
) {
866 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
869 if (pkt
->pfc_flags
& DCERPC_PFC_FLAG_OBJECT_UUID
) {
870 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
874 ndr_err
= ndr_push_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
875 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
876 return ndr_map_error2ntstatus(ndr_err
);
879 /* pad to 16 byte multiple in the payload portion of the
880 packet. This matches what w2k3 does. Note that we can't use
881 ndr_push_align() as that is relative to the start of the
882 whole packet, whereas w2k8 wants it relative to the start
884 c
->security_state
.auth_info
->auth_pad_length
=
885 (16 - (pkt
->u
.request
.stub_and_verifier
.length
& 15)) & 15;
886 ndr_err
= ndr_push_zero(ndr
, c
->security_state
.auth_info
->auth_pad_length
);
887 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
888 return ndr_map_error2ntstatus(ndr_err
);
891 payload_length
= pkt
->u
.request
.stub_and_verifier
.length
+
892 c
->security_state
.auth_info
->auth_pad_length
;
894 /* we start without signature, it will appended later */
895 c
->security_state
.auth_info
->credentials
= data_blob(NULL
,0);
897 /* add the auth verifier */
898 ndr_err
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, c
->security_state
.auth_info
);
899 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
900 return ndr_map_error2ntstatus(ndr_err
);
903 /* extract the whole packet as a blob */
904 *blob
= ndr_push_blob(ndr
);
907 * Setup the frag and auth length in the packet buffer.
908 * This is needed if the GENSEC mech does AEAD signing
909 * of the packet headers. The signature itself will be
912 dcerpc_set_frag_length(blob
, blob
->length
+ sig_size
);
913 dcerpc_set_auth_length(blob
, sig_size
);
915 /* sign or seal the packet */
916 switch (c
->security_state
.auth_info
->auth_level
) {
917 case DCERPC_AUTH_LEVEL_PRIVACY
:
918 status
= gensec_seal_packet(c
->security_state
.generic_state
,
920 blob
->data
+ hdr_size
,
925 if (!NT_STATUS_IS_OK(status
)) {
930 case DCERPC_AUTH_LEVEL_INTEGRITY
:
931 status
= gensec_sign_packet(c
->security_state
.generic_state
,
933 blob
->data
+ hdr_size
,
938 if (!NT_STATUS_IS_OK(status
)) {
944 status
= NT_STATUS_INVALID_LEVEL
;
948 if (creds2
.length
!= sig_size
) {
949 /* this means the sig_size estimate for the signature
950 was incorrect. We have to correct the packet
951 sizes. That means we could go over the max fragment
953 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
954 (unsigned) creds2
.length
,
956 (unsigned) c
->security_state
.auth_info
->auth_pad_length
,
957 (unsigned) pkt
->u
.request
.stub_and_verifier
.length
));
958 dcerpc_set_frag_length(blob
, blob
->length
+ creds2
.length
);
959 dcerpc_set_auth_length(blob
, creds2
.length
);
962 if (!data_blob_append(mem_ctx
, blob
, creds2
.data
, creds2
.length
)) {
963 return NT_STATUS_NO_MEMORY
;
971 fill in the fixed values in a dcerpc header
973 static void init_ncacn_hdr(struct dcecli_connection
*c
, struct ncacn_packet
*pkt
)
976 pkt
->rpc_vers_minor
= 0;
977 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
980 pkt
->drep
[0] = DCERPC_DREP_LE
;
988 map a bind nak reason to a NTSTATUS
990 static NTSTATUS
dcerpc_map_reason(uint16_t reason
)
993 case DCERPC_BIND_REASON_ASYNTAX
:
994 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX
;
995 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE
:
996 return NT_STATUS_INVALID_PARAMETER
;
998 return NT_STATUS_UNSUCCESSFUL
;
1002 remove requests from the pending or queued queues
1004 static int dcerpc_req_dequeue(struct rpc_request
*req
)
1006 switch (req
->state
) {
1007 case RPC_REQUEST_QUEUED
:
1008 DLIST_REMOVE(req
->p
->conn
->request_queue
, req
);
1010 case RPC_REQUEST_PENDING
:
1011 DLIST_REMOVE(req
->p
->conn
->pending
, req
);
1013 case RPC_REQUEST_DONE
:
1021 mark the dcerpc connection dead. All outstanding requests get an error
1023 static void dcerpc_connection_dead(struct dcecli_connection
*conn
, NTSTATUS status
)
1025 if (conn
->dead
) return;
1029 TALLOC_FREE(conn
->io_trigger
);
1030 conn
->io_trigger_pending
= false;
1032 conn
->transport
.recv_data
= NULL
;
1034 dcerpc_shutdown_pipe(conn
, status
);
1036 /* all pending requests get the error */
1037 while (conn
->pending
) {
1038 struct rpc_request
*req
= conn
->pending
;
1039 dcerpc_req_dequeue(req
);
1040 req
->state
= RPC_REQUEST_DONE
;
1041 req
->status
= status
;
1042 if (req
->async
.callback
) {
1043 req
->async
.callback(req
);
1047 /* all requests, which are not shipped */
1048 while (conn
->request_queue
) {
1049 struct rpc_request
*req
= conn
->request_queue
;
1050 dcerpc_req_dequeue(req
);
1051 req
->state
= RPC_REQUEST_DONE
;
1052 req
->status
= status
;
1053 if (req
->async
.callback
) {
1054 req
->async
.callback(req
);
1058 talloc_set_destructor(conn
, NULL
);
1059 if (conn
->free_skipped
) {
1065 forward declarations of the recv_data handlers for the types of
1066 packets we need to handle
1068 static void dcerpc_request_recv_data(struct dcecli_connection
*c
,
1069 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
);
1072 receive a dcerpc reply from the transport. Here we work out what
1073 type of reply it is (normal request, bind or alter context) and
1074 dispatch to the appropriate handler
1076 static void dcerpc_recv_data(struct dcecli_connection
*conn
, DATA_BLOB
*blob
, NTSTATUS status
)
1078 struct ncacn_packet pkt
;
1080 if (NT_STATUS_IS_OK(status
) && blob
->length
== 0) {
1081 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
1084 /* the transport may be telling us of a severe error, such as
1086 if (!NT_STATUS_IS_OK(status
)) {
1087 data_blob_free(blob
);
1088 dcerpc_connection_dead(conn
, status
);
1092 /* parse the basic packet to work out what type of response this is */
1093 status
= ncacn_pull(conn
, blob
, blob
->data
, &pkt
);
1094 if (!NT_STATUS_IS_OK(status
)) {
1095 data_blob_free(blob
);
1096 dcerpc_connection_dead(conn
, status
);
1100 dcerpc_request_recv_data(conn
, blob
, &pkt
);
1104 handle timeouts of individual dcerpc requests
1106 static void dcerpc_timeout_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
1107 struct timeval t
, void *private_data
)
1109 struct rpc_request
*req
= talloc_get_type(private_data
, struct rpc_request
);
1111 if (req
->ignore_timeout
) {
1112 dcerpc_req_dequeue(req
);
1113 req
->state
= RPC_REQUEST_DONE
;
1114 req
->status
= NT_STATUS_IO_TIMEOUT
;
1115 if (req
->async
.callback
) {
1116 req
->async
.callback(req
);
1121 dcerpc_connection_dead(req
->p
->conn
, NT_STATUS_IO_TIMEOUT
);
1124 struct dcerpc_bind_state
{
1125 struct tevent_context
*ev
;
1126 struct dcerpc_pipe
*p
;
1129 static void dcerpc_bind_fail_handler(struct rpc_request
*subreq
);
1130 static void dcerpc_bind_recv_handler(struct rpc_request
*subreq
,
1131 DATA_BLOB
*raw_packet
,
1132 struct ncacn_packet
*pkt
);
1134 struct tevent_req
*dcerpc_bind_send(TALLOC_CTX
*mem_ctx
,
1135 struct tevent_context
*ev
,
1136 struct dcerpc_pipe
*p
,
1137 const struct ndr_syntax_id
*syntax
,
1138 const struct ndr_syntax_id
*transfer_syntax
)
1140 struct tevent_req
*req
;
1141 struct dcerpc_bind_state
*state
;
1142 struct ncacn_packet pkt
;
1145 struct rpc_request
*subreq
;
1147 req
= tevent_req_create(mem_ctx
, &state
,
1148 struct dcerpc_bind_state
);
1156 p
->syntax
= *syntax
;
1157 p
->transfer_syntax
= *transfer_syntax
;
1159 init_ncacn_hdr(p
->conn
, &pkt
);
1161 pkt
.ptype
= DCERPC_PKT_BIND
;
1162 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1163 pkt
.call_id
= p
->conn
->call_id
;
1164 pkt
.auth_length
= 0;
1166 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1167 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1170 if (p
->conn
->flags
& DCERPC_PROPOSE_HEADER_SIGNING
) {
1171 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
1174 pkt
.u
.bind
.max_xmit_frag
= p
->conn
->srv_max_xmit_frag
;
1175 pkt
.u
.bind
.max_recv_frag
= p
->conn
->srv_max_recv_frag
;
1176 pkt
.u
.bind
.assoc_group_id
= p
->binding
->assoc_group_id
;
1177 pkt
.u
.bind
.num_contexts
= 1;
1178 pkt
.u
.bind
.ctx_list
= talloc_array(mem_ctx
, struct dcerpc_ctx_list
, 1);
1179 if (tevent_req_nomem(pkt
.u
.bind
.ctx_list
, req
)) {
1180 return tevent_req_post(req
, ev
);
1182 pkt
.u
.bind
.ctx_list
[0].context_id
= p
->context_id
;
1183 pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
= 1;
1184 pkt
.u
.bind
.ctx_list
[0].abstract_syntax
= p
->syntax
;
1185 pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
1186 pkt
.u
.bind
.auth_info
= data_blob(NULL
, 0);
1188 /* construct the NDR form of the packet */
1189 status
= ncacn_push_auth(&blob
, state
, &pkt
,
1190 p
->conn
->security_state
.auth_info
);
1191 if (tevent_req_nterror(req
, status
)) {
1192 return tevent_req_post(req
, ev
);
1195 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1198 * we allocate a dcerpc_request so we can be in the same
1199 * request queue as normal requests
1201 subreq
= talloc_zero(state
, struct rpc_request
);
1202 if (tevent_req_nomem(subreq
, req
)) {
1203 return tevent_req_post(req
, ev
);
1206 subreq
->state
= RPC_REQUEST_PENDING
;
1207 subreq
->call_id
= pkt
.call_id
;
1208 subreq
->async
.private_data
= req
;
1209 subreq
->async
.callback
= dcerpc_bind_fail_handler
;
1211 subreq
->recv_handler
= dcerpc_bind_recv_handler
;
1212 DLIST_ADD_END(p
->conn
->pending
, subreq
, struct rpc_request
*);
1213 talloc_set_destructor(subreq
, dcerpc_req_dequeue
);
1215 status
= dcerpc_send_request(p
->conn
, &blob
, true);
1216 if (tevent_req_nterror(req
, status
)) {
1217 return tevent_req_post(req
, ev
);
1220 tevent_add_timer(ev
, subreq
,
1221 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
1222 dcerpc_timeout_handler
, subreq
);
1227 static void dcerpc_bind_fail_handler(struct rpc_request
*subreq
)
1229 struct tevent_req
*req
=
1230 talloc_get_type_abort(subreq
->async
.private_data
,
1232 struct dcerpc_bind_state
*state
=
1233 tevent_req_data(req
,
1234 struct dcerpc_bind_state
);
1235 NTSTATUS status
= subreq
->status
;
1237 TALLOC_FREE(subreq
);
1240 * We trigger the callback in the next event run
1241 * because the code in this file might trigger
1242 * multiple request callbacks from within a single
1245 * In order to avoid segfaults from within
1246 * dcerpc_connection_dead() we call
1247 * tevent_req_defer_callback().
1249 tevent_req_defer_callback(req
, state
->ev
);
1251 tevent_req_nterror(req
, status
);
1254 static void dcerpc_bind_recv_handler(struct rpc_request
*subreq
,
1255 DATA_BLOB
*raw_packet
,
1256 struct ncacn_packet
*pkt
)
1258 struct tevent_req
*req
=
1259 talloc_get_type_abort(subreq
->async
.private_data
,
1261 struct dcerpc_bind_state
*state
=
1262 tevent_req_data(req
,
1263 struct dcerpc_bind_state
);
1264 struct dcecli_connection
*conn
= state
->p
->conn
;
1268 * Note that pkt is allocated under raw_packet->data,
1269 * while raw_packet->data is a child of subreq.
1271 talloc_steal(state
, raw_packet
->data
);
1272 TALLOC_FREE(subreq
);
1275 * We trigger the callback in the next event run
1276 * because the code in this file might trigger
1277 * multiple request callbacks from within a single
1280 * In order to avoid segfaults from within
1281 * dcerpc_connection_dead() we call
1282 * tevent_req_defer_callback().
1284 tevent_req_defer_callback(req
, state
->ev
);
1286 if (pkt
->ptype
== DCERPC_PKT_BIND_NAK
) {
1287 status
= dcerpc_map_reason(pkt
->u
.bind_nak
.reject_reason
);
1289 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1290 pkt
->u
.bind_nak
.reject_reason
, nt_errstr(status
)));
1292 tevent_req_nterror(req
, status
);
1296 if ((pkt
->ptype
!= DCERPC_PKT_BIND_ACK
) ||
1297 (pkt
->u
.bind_ack
.num_results
== 0) ||
1298 (pkt
->u
.bind_ack
.ctx_list
[0].result
!= 0)) {
1299 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1300 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1305 * DCE-RPC 1.1 (c706) specifies
1306 * CONST_MUST_RCV_FRAG_SIZE as 1432
1308 if (pkt
->u
.bind_ack
.max_xmit_frag
< 1432) {
1309 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1310 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1313 if (pkt
->u
.bind_ack
.max_recv_frag
< 1432) {
1314 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1315 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1318 conn
->srv_max_xmit_frag
= MIN(conn
->srv_max_xmit_frag
,
1319 pkt
->u
.bind_ack
.max_xmit_frag
);
1320 conn
->srv_max_recv_frag
= MIN(conn
->srv_max_recv_frag
,
1321 pkt
->u
.bind_ack
.max_recv_frag
);
1323 if ((state
->p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) &&
1324 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_CONC_MPX
)) {
1325 conn
->flags
|= DCERPC_CONCURRENT_MULTIPLEX
;
1328 if ((conn
->flags
& DCERPC_PROPOSE_HEADER_SIGNING
) &&
1329 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
)) {
1330 conn
->flags
|= DCERPC_HEADER_SIGNING
;
1333 /* the bind_ack might contain a reply set of credentials */
1334 if (conn
->security_state
.auth_info
&& pkt
->u
.bind_ack
.auth_info
.length
) {
1335 uint32_t auth_length
;
1337 status
= dcerpc_pull_auth_trailer(pkt
, conn
, &pkt
->u
.bind_ack
.auth_info
,
1338 conn
->security_state
.auth_info
, &auth_length
, true);
1339 if (tevent_req_nterror(req
, status
)) {
1344 state
->p
->assoc_group_id
= pkt
->u
.bind_ack
.assoc_group_id
;
1346 tevent_req_done(req
);
1349 NTSTATUS
dcerpc_bind_recv(struct tevent_req
*req
)
1351 return tevent_req_simple_recv_ntstatus(req
);
1355 perform a continued bind (and auth3)
1357 NTSTATUS
dcerpc_auth3(struct dcerpc_pipe
*p
,
1358 TALLOC_CTX
*mem_ctx
)
1360 struct ncacn_packet pkt
;
1364 init_ncacn_hdr(p
->conn
, &pkt
);
1366 pkt
.ptype
= DCERPC_PKT_AUTH3
;
1367 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1368 pkt
.call_id
= next_call_id(p
->conn
);
1369 pkt
.auth_length
= 0;
1370 pkt
.u
.auth3
.auth_info
= data_blob(NULL
, 0);
1372 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1373 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1376 /* construct the NDR form of the packet */
1377 status
= ncacn_push_auth(&blob
, mem_ctx
,
1379 p
->conn
->security_state
.auth_info
);
1380 if (!NT_STATUS_IS_OK(status
)) {
1384 /* send it on its way */
1385 status
= dcerpc_send_request(p
->conn
, &blob
, false);
1386 if (!NT_STATUS_IS_OK(status
)) {
1390 return NT_STATUS_OK
;
1395 process a fragment received from the transport layer during a
1398 This function frees the data
1400 static void dcerpc_request_recv_data(struct dcecli_connection
*c
,
1401 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
1403 struct rpc_request
*req
;
1404 unsigned int length
;
1405 NTSTATUS status
= NT_STATUS_OK
;
1408 if this is an authenticated connection then parse and check
1409 the auth info. We have to do this before finding the
1410 matching packet, as the request structure might have been
1411 removed due to a timeout, but if it has been we still need
1412 to run the auth routines so that we don't get the sign/seal
1413 info out of step with the server
1415 if (c
->security_state
.auth_info
&& c
->security_state
.generic_state
&&
1416 pkt
->ptype
== DCERPC_PKT_RESPONSE
) {
1417 status
= ncacn_pull_request_auth(c
, raw_packet
->data
, raw_packet
, pkt
);
1420 /* find the matching request */
1421 for (req
=c
->pending
;req
;req
=req
->next
) {
1422 if (pkt
->call_id
== req
->call_id
) break;
1426 /* useful for testing certain vendors RPC servers */
1427 if (req
== NULL
&& c
->pending
&& pkt
->call_id
== 0) {
1428 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1434 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt
->call_id
));
1435 data_blob_free(raw_packet
);
1439 talloc_steal(req
, raw_packet
->data
);
1441 if (req
->recv_handler
!= NULL
) {
1442 dcerpc_req_dequeue(req
);
1443 req
->state
= RPC_REQUEST_DONE
;
1446 * We have to look at shipping further requests before calling
1447 * the async function, that one might close the pipe
1449 dcerpc_schedule_io_trigger(c
);
1451 req
->recv_handler(req
, raw_packet
, pkt
);
1455 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
1456 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c
, pkt
->u
.fault
.status
)));
1457 req
->fault_code
= pkt
->u
.fault
.status
;
1458 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
1462 if (pkt
->ptype
!= DCERPC_PKT_RESPONSE
) {
1463 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1465 req
->fault_code
= DCERPC_FAULT_OTHER
;
1466 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
1470 /* now check the status from the auth routines, and if it failed then fail
1471 this request accordingly */
1472 if (!NT_STATUS_IS_OK(status
)) {
1473 req
->status
= status
;
1477 length
= pkt
->u
.response
.stub_and_verifier
.length
;
1480 req
->payload
.data
= talloc_realloc(req
,
1483 req
->payload
.length
+ length
);
1484 if (!req
->payload
.data
) {
1485 req
->status
= NT_STATUS_NO_MEMORY
;
1488 memcpy(req
->payload
.data
+req
->payload
.length
,
1489 pkt
->u
.response
.stub_and_verifier
.data
, length
);
1490 req
->payload
.length
+= length
;
1493 if (!(pkt
->pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
1494 data_blob_free(raw_packet
);
1495 dcerpc_send_read(c
);
1499 if (!(pkt
->drep
[0] & DCERPC_DREP_LE
)) {
1500 req
->flags
|= DCERPC_PULL_BIGENDIAN
;
1502 req
->flags
&= ~DCERPC_PULL_BIGENDIAN
;
1506 data_blob_free(raw_packet
);
1508 /* we've got the full payload */
1509 dcerpc_req_dequeue(req
);
1510 req
->state
= RPC_REQUEST_DONE
;
1513 * We have to look at shipping further requests before calling
1514 * the async function, that one might close the pipe
1516 dcerpc_schedule_io_trigger(c
);
1518 if (req
->async
.callback
) {
1519 req
->async
.callback(req
);
1524 perform the send side of a async dcerpc request
1526 static struct rpc_request
*dcerpc_request_send(TALLOC_CTX
*mem_ctx
,
1527 struct dcerpc_pipe
*p
,
1528 const struct GUID
*object
,
1530 DATA_BLOB
*stub_data
)
1532 struct rpc_request
*req
;
1534 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1536 req
= talloc_zero(mem_ctx
, struct rpc_request
);
1542 req
->call_id
= next_call_id(p
->conn
);
1543 req
->state
= RPC_REQUEST_QUEUED
;
1545 if (object
!= NULL
) {
1546 req
->object
= (struct GUID
*)talloc_memdup(req
, (const void *)object
, sizeof(*object
));
1547 if (req
->object
== NULL
) {
1554 req
->request_data
.length
= stub_data
->length
;
1555 req
->request_data
.data
= stub_data
->data
;
1557 DLIST_ADD_END(p
->conn
->request_queue
, req
, struct rpc_request
*);
1558 talloc_set_destructor(req
, dcerpc_req_dequeue
);
1560 dcerpc_schedule_io_trigger(p
->conn
);
1562 if (p
->request_timeout
) {
1563 tevent_add_timer(dcerpc_event_context(p
), req
,
1564 timeval_current_ofs(p
->request_timeout
, 0),
1565 dcerpc_timeout_handler
, req
);
1572 Send a request using the transport
1575 static void dcerpc_ship_next_request(struct dcecli_connection
*c
)
1577 struct rpc_request
*req
;
1578 struct dcerpc_pipe
*p
;
1579 DATA_BLOB
*stub_data
;
1580 struct ncacn_packet pkt
;
1582 uint32_t remaining
, chunk_size
;
1583 bool first_packet
= true;
1584 size_t sig_size
= 0;
1585 bool need_async
= false;
1586 bool can_async
= true;
1588 req
= c
->request_queue
;
1594 stub_data
= &req
->request_data
;
1600 if (c
->security_state
.auth_info
&&
1601 c
->security_state
.generic_state
)
1603 struct gensec_security
*gensec
= c
->security_state
.generic_state
;
1605 switch (c
->security_state
.auth_info
->auth_level
) {
1606 case DCERPC_AUTH_LEVEL_PRIVACY
:
1607 case DCERPC_AUTH_LEVEL_INTEGRITY
:
1608 can_async
= gensec_have_feature(gensec
,
1609 GENSEC_FEATURE_ASYNC_REPLIES
);
1611 case DCERPC_AUTH_LEVEL_CONNECT
:
1612 case DCERPC_AUTH_LEVEL_NONE
:
1621 if (need_async
&& !can_async
) {
1622 req
->wait_for_sync
= true;
1626 DLIST_REMOVE(c
->request_queue
, req
);
1627 DLIST_ADD(c
->pending
, req
);
1628 req
->state
= RPC_REQUEST_PENDING
;
1630 init_ncacn_hdr(p
->conn
, &pkt
);
1632 remaining
= stub_data
->length
;
1634 /* we can write a full max_recv_frag size, minus the dcerpc
1635 request header size */
1636 chunk_size
= p
->conn
->srv_max_recv_frag
;
1637 chunk_size
-= DCERPC_REQUEST_LENGTH
;
1638 if (c
->security_state
.auth_info
&&
1639 c
->security_state
.generic_state
) {
1640 sig_size
= gensec_sig_size(c
->security_state
.generic_state
,
1641 p
->conn
->srv_max_recv_frag
);
1643 chunk_size
-= DCERPC_AUTH_TRAILER_LENGTH
;
1644 chunk_size
-= sig_size
;
1647 chunk_size
-= (chunk_size
% 16);
1649 pkt
.ptype
= DCERPC_PKT_REQUEST
;
1650 pkt
.call_id
= req
->call_id
;
1651 pkt
.auth_length
= 0;
1653 pkt
.u
.request
.context_id
= p
->context_id
;
1654 pkt
.u
.request
.opnum
= req
->opnum
;
1657 pkt
.u
.request
.object
.object
= *req
->object
;
1658 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_OBJECT_UUID
;
1659 chunk_size
-= ndr_size_GUID(req
->object
,0);
1662 /* we send a series of pdus without waiting for a reply */
1663 while (remaining
> 0 || first_packet
) {
1664 uint32_t chunk
= MIN(chunk_size
, remaining
);
1665 bool last_frag
= false;
1666 bool do_trans
= false;
1668 first_packet
= false;
1669 pkt
.pfc_flags
&= ~(DCERPC_PFC_FLAG_FIRST
|DCERPC_PFC_FLAG_LAST
);
1671 if (remaining
== stub_data
->length
) {
1672 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_FIRST
;
1674 if (chunk
== remaining
) {
1675 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_LAST
;
1679 pkt
.u
.request
.alloc_hint
= remaining
;
1680 pkt
.u
.request
.stub_and_verifier
.data
= stub_data
->data
+
1681 (stub_data
->length
- remaining
);
1682 pkt
.u
.request
.stub_and_verifier
.length
= chunk
;
1684 req
->status
= ncacn_push_request_sign(p
->conn
, &blob
, req
, sig_size
, &pkt
);
1685 if (!NT_STATUS_IS_OK(req
->status
)) {
1686 req
->state
= RPC_REQUEST_DONE
;
1687 DLIST_REMOVE(p
->conn
->pending
, req
);
1691 if (last_frag
&& !need_async
) {
1695 req
->status
= dcerpc_send_request(p
->conn
, &blob
, do_trans
);
1696 if (!NT_STATUS_IS_OK(req
->status
)) {
1697 req
->state
= RPC_REQUEST_DONE
;
1698 DLIST_REMOVE(p
->conn
->pending
, req
);
1702 if (last_frag
&& !do_trans
) {
1703 req
->status
= dcerpc_send_read(p
->conn
);
1704 if (!NT_STATUS_IS_OK(req
->status
)) {
1705 req
->state
= RPC_REQUEST_DONE
;
1706 DLIST_REMOVE(p
->conn
->pending
, req
);
1715 static void dcerpc_io_trigger(struct tevent_context
*ctx
,
1716 struct tevent_immediate
*im
,
1719 struct dcecli_connection
*c
=
1720 talloc_get_type_abort(private_data
,
1721 struct dcecli_connection
);
1723 c
->io_trigger_pending
= false;
1725 dcerpc_schedule_io_trigger(c
);
1727 dcerpc_ship_next_request(c
);
1730 static void dcerpc_schedule_io_trigger(struct dcecli_connection
*c
)
1736 if (c
->request_queue
== NULL
) {
1740 if (c
->request_queue
->wait_for_sync
&& c
->pending
) {
1744 if (c
->io_trigger_pending
) {
1748 c
->io_trigger_pending
= true;
1750 tevent_schedule_immediate(c
->io_trigger
,
1757 return the event context for a dcerpc pipe
1758 used by callers who wish to operate asynchronously
1760 _PUBLIC_
struct tevent_context
*dcerpc_event_context(struct dcerpc_pipe
*p
)
1762 return p
->conn
->event_ctx
;
1768 perform the receive side of a async dcerpc request
1770 static NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
1771 TALLOC_CTX
*mem_ctx
,
1772 DATA_BLOB
*stub_data
)
1776 while (req
->state
!= RPC_REQUEST_DONE
) {
1777 struct tevent_context
*ctx
= dcerpc_event_context(req
->p
);
1778 if (tevent_loop_once(ctx
) != 0) {
1779 return NT_STATUS_CONNECTION_DISCONNECTED
;
1782 *stub_data
= req
->payload
;
1783 status
= req
->status
;
1784 if (stub_data
->data
) {
1785 stub_data
->data
= talloc_steal(mem_ctx
, stub_data
->data
);
1787 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
1788 req
->p
->last_fault_code
= req
->fault_code
;
1790 talloc_unlink(talloc_parent(req
), req
);
1795 this is a paranoid NDR validator. For every packet we push onto the wire
1796 we pull it back again, then push it again. Then we compare the raw NDR data
1797 for that to the NDR we initially generated. If they don't match then we know
1798 we must have a bug in either the pull or push side of our code
1800 static NTSTATUS
dcerpc_ndr_validate_in(struct dcecli_connection
*c
,
1801 TALLOC_CTX
*mem_ctx
,
1804 ndr_push_flags_fn_t ndr_push
,
1805 ndr_pull_flags_fn_t ndr_pull
)
1808 struct ndr_pull
*pull
;
1809 struct ndr_push
*push
;
1811 enum ndr_err_code ndr_err
;
1813 st
= talloc_size(mem_ctx
, struct_size
);
1815 return NT_STATUS_NO_MEMORY
;
1818 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1820 return NT_STATUS_NO_MEMORY
;
1822 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1824 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1825 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1828 if (c
->flags
& DCERPC_NDR64
) {
1829 pull
->flags
|= LIBNDR_FLAG_NDR64
;
1832 ndr_err
= ndr_pull(pull
, NDR_IN
, st
);
1833 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1834 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1835 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1836 "failed input validation pull - %s",
1838 return ndr_map_error2ntstatus(ndr_err
);
1841 push
= ndr_push_init_ctx(mem_ctx
);
1843 return NT_STATUS_NO_MEMORY
;
1846 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1847 push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1850 if (c
->flags
& DCERPC_NDR64
) {
1851 push
->flags
|= LIBNDR_FLAG_NDR64
;
1854 ndr_err
= ndr_push(push
, NDR_IN
, st
);
1855 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1856 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1857 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1858 "failed input validation push - %s",
1860 return ndr_map_error2ntstatus(ndr_err
);
1863 blob2
= ndr_push_blob(push
);
1865 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1866 DEBUG(3,("original:\n"));
1867 dump_data(3, blob
.data
, blob
.length
);
1868 DEBUG(3,("secondary:\n"));
1869 dump_data(3, blob2
.data
, blob2
.length
);
1870 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1871 "failed input validation blobs doesn't match");
1872 return ndr_map_error2ntstatus(ndr_err
);
1875 return NT_STATUS_OK
;
1879 this is a paranoid NDR input validator. For every packet we pull
1880 from the wire we push it back again then pull and push it
1881 again. Then we compare the raw NDR data for that to the NDR we
1882 initially generated. If they don't match then we know we must have a
1883 bug in either the pull or push side of our code
1885 static NTSTATUS
dcerpc_ndr_validate_out(struct dcecli_connection
*c
,
1886 struct ndr_pull
*pull_in
,
1889 ndr_push_flags_fn_t ndr_push
,
1890 ndr_pull_flags_fn_t ndr_pull
,
1891 ndr_print_function_t ndr_print
)
1894 struct ndr_pull
*pull
;
1895 struct ndr_push
*push
;
1896 DATA_BLOB blob
, blob2
;
1897 TALLOC_CTX
*mem_ctx
= pull_in
;
1899 enum ndr_err_code ndr_err
;
1901 st
= talloc_size(mem_ctx
, struct_size
);
1903 return NT_STATUS_NO_MEMORY
;
1905 memcpy(st
, struct_ptr
, struct_size
);
1907 push
= ndr_push_init_ctx(mem_ctx
);
1909 return NT_STATUS_NO_MEMORY
;
1912 ndr_err
= ndr_push(push
, NDR_OUT
, struct_ptr
);
1913 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1914 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1915 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1916 "failed output validation push - %s",
1918 return ndr_map_error2ntstatus(ndr_err
);
1921 blob
= ndr_push_blob(push
);
1923 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1925 return NT_STATUS_NO_MEMORY
;
1928 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1929 ndr_err
= ndr_pull(pull
, NDR_OUT
, st
);
1930 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1931 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1932 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1933 "failed output validation pull - %s",
1935 return ndr_map_error2ntstatus(ndr_err
);
1938 push
= ndr_push_init_ctx(mem_ctx
);
1940 return NT_STATUS_NO_MEMORY
;
1943 ndr_err
= ndr_push(push
, NDR_OUT
, st
);
1944 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1945 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1946 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1947 "failed output validation push2 - %s",
1949 return ndr_map_error2ntstatus(ndr_err
);
1952 blob2
= ndr_push_blob(push
);
1954 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1955 DEBUG(3,("original:\n"));
1956 dump_data(3, blob
.data
, blob
.length
);
1957 DEBUG(3,("secondary:\n"));
1958 dump_data(3, blob2
.data
, blob2
.length
);
1959 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1960 "failed output validation blobs doesn't match");
1961 return ndr_map_error2ntstatus(ndr_err
);
1964 /* this checks the printed forms of the two structures, which effectively
1965 tests all of the value() attributes */
1966 s1
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1967 NDR_OUT
, struct_ptr
);
1968 s2
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1970 if (strcmp(s1
, s2
) != 0) {
1972 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1
, s2
));
1974 /* this is sometimes useful */
1975 printf("VALIDATE ERROR\n");
1976 file_save("wire.dat", s1
, strlen(s1
));
1977 file_save("gen.dat", s2
, strlen(s2
));
1978 system("diff -u wire.dat gen.dat");
1980 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1981 "failed output validation strings doesn't match");
1982 return ndr_map_error2ntstatus(ndr_err
);
1985 return NT_STATUS_OK
;
1989 a useful function for retrieving the server name we connected to
1991 _PUBLIC_
const char *dcerpc_server_name(struct dcerpc_pipe
*p
)
1993 return p
->conn
? p
->conn
->server_name
: NULL
;
1998 get the dcerpc auth_level for a open connection
2000 uint32_t dcerpc_auth_level(struct dcecli_connection
*c
)
2004 if (c
->flags
& DCERPC_SEAL
) {
2005 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
2006 } else if (c
->flags
& DCERPC_SIGN
) {
2007 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
2008 } else if (c
->flags
& DCERPC_CONNECT
) {
2009 auth_level
= DCERPC_AUTH_LEVEL_CONNECT
;
2011 auth_level
= DCERPC_AUTH_LEVEL_NONE
;
2016 struct dcerpc_alter_context_state
{
2017 struct tevent_context
*ev
;
2018 struct dcerpc_pipe
*p
;
2021 static void dcerpc_alter_context_fail_handler(struct rpc_request
*subreq
);
2022 static void dcerpc_alter_context_recv_handler(struct rpc_request
*req
,
2023 DATA_BLOB
*raw_packet
,
2024 struct ncacn_packet
*pkt
);
2026 struct tevent_req
*dcerpc_alter_context_send(TALLOC_CTX
*mem_ctx
,
2027 struct tevent_context
*ev
,
2028 struct dcerpc_pipe
*p
,
2029 const struct ndr_syntax_id
*syntax
,
2030 const struct ndr_syntax_id
*transfer_syntax
)
2032 struct tevent_req
*req
;
2033 struct dcerpc_alter_context_state
*state
;
2034 struct ncacn_packet pkt
;
2037 struct rpc_request
*subreq
;
2039 req
= tevent_req_create(mem_ctx
, &state
,
2040 struct dcerpc_alter_context_state
);
2048 p
->syntax
= *syntax
;
2049 p
->transfer_syntax
= *transfer_syntax
;
2051 init_ncacn_hdr(p
->conn
, &pkt
);
2053 pkt
.ptype
= DCERPC_PKT_ALTER
;
2054 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
2055 pkt
.call_id
= p
->conn
->call_id
;
2056 pkt
.auth_length
= 0;
2058 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
2059 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
2062 pkt
.u
.alter
.max_xmit_frag
= p
->conn
->srv_max_xmit_frag
;
2063 pkt
.u
.alter
.max_recv_frag
= p
->conn
->srv_max_recv_frag
;
2064 pkt
.u
.alter
.assoc_group_id
= p
->binding
->assoc_group_id
;
2065 pkt
.u
.alter
.num_contexts
= 1;
2066 pkt
.u
.alter
.ctx_list
= talloc_array(state
, struct dcerpc_ctx_list
, 1);
2067 if (tevent_req_nomem(pkt
.u
.alter
.ctx_list
, req
)) {
2068 return tevent_req_post(req
, ev
);
2070 pkt
.u
.alter
.ctx_list
[0].context_id
= p
->context_id
;
2071 pkt
.u
.alter
.ctx_list
[0].num_transfer_syntaxes
= 1;
2072 pkt
.u
.alter
.ctx_list
[0].abstract_syntax
= p
->syntax
;
2073 pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
2074 pkt
.u
.alter
.auth_info
= data_blob(NULL
, 0);
2076 /* construct the NDR form of the packet */
2077 status
= ncacn_push_auth(&blob
, state
, &pkt
,
2078 p
->conn
->security_state
.auth_info
);
2079 if (tevent_req_nterror(req
, status
)) {
2080 return tevent_req_post(req
, ev
);
2083 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
2086 * we allocate a dcerpc_request so we can be in the same
2087 * request queue as normal requests
2089 subreq
= talloc_zero(state
, struct rpc_request
);
2090 if (tevent_req_nomem(subreq
, req
)) {
2091 return tevent_req_post(req
, ev
);
2094 subreq
->state
= RPC_REQUEST_PENDING
;
2095 subreq
->call_id
= pkt
.call_id
;
2096 subreq
->async
.private_data
= req
;
2097 subreq
->async
.callback
= dcerpc_alter_context_fail_handler
;
2099 subreq
->recv_handler
= dcerpc_alter_context_recv_handler
;
2100 DLIST_ADD_END(p
->conn
->pending
, subreq
, struct rpc_request
*);
2101 talloc_set_destructor(subreq
, dcerpc_req_dequeue
);
2103 status
= dcerpc_send_request(p
->conn
, &blob
, true);
2104 if (tevent_req_nterror(req
, status
)) {
2105 return tevent_req_post(req
, ev
);
2108 tevent_add_timer(ev
, subreq
,
2109 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
2110 dcerpc_timeout_handler
, subreq
);
2115 static void dcerpc_alter_context_fail_handler(struct rpc_request
*subreq
)
2117 struct tevent_req
*req
=
2118 talloc_get_type_abort(subreq
->async
.private_data
,
2120 struct dcerpc_alter_context_state
*state
=
2121 tevent_req_data(req
,
2122 struct dcerpc_alter_context_state
);
2123 NTSTATUS status
= subreq
->status
;
2125 TALLOC_FREE(subreq
);
2128 * We trigger the callback in the next event run
2129 * because the code in this file might trigger
2130 * multiple request callbacks from within a single
2133 * In order to avoid segfaults from within
2134 * dcerpc_connection_dead() we call
2135 * tevent_req_defer_callback().
2137 tevent_req_defer_callback(req
, state
->ev
);
2139 tevent_req_nterror(req
, status
);
2142 static void dcerpc_alter_context_recv_handler(struct rpc_request
*subreq
,
2143 DATA_BLOB
*raw_packet
,
2144 struct ncacn_packet
*pkt
)
2146 struct tevent_req
*req
=
2147 talloc_get_type_abort(subreq
->async
.private_data
,
2149 struct dcerpc_alter_context_state
*state
=
2150 tevent_req_data(req
,
2151 struct dcerpc_alter_context_state
);
2152 struct dcecli_connection
*conn
= state
->p
->conn
;
2156 * Note that pkt is allocated under raw_packet->data,
2157 * while raw_packet->data is a child of subreq.
2159 talloc_steal(state
, raw_packet
->data
);
2160 TALLOC_FREE(subreq
);
2163 * We trigger the callback in the next event run
2164 * because the code in this file might trigger
2165 * multiple request callbacks from within a single
2168 * In order to avoid segfaults from within
2169 * dcerpc_connection_dead() we call
2170 * tevent_req_defer_callback().
2172 tevent_req_defer_callback(req
, state
->ev
);
2174 if (pkt
->ptype
== DCERPC_PKT_ALTER_RESP
&&
2175 pkt
->u
.alter_resp
.num_results
== 1 &&
2176 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
2177 status
= dcerpc_map_reason(pkt
->u
.alter_resp
.ctx_list
[0].reason
);
2178 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2179 pkt
->u
.alter_resp
.ctx_list
[0].reason
,
2180 nt_errstr(status
)));
2181 tevent_req_nterror(req
, status
);
2185 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
2186 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2187 dcerpc_errstr(state
, pkt
->u
.fault
.status
)));
2188 if (pkt
->u
.fault
.status
== DCERPC_FAULT_ACCESS_DENIED
) {
2189 state
->p
->last_fault_code
= pkt
->u
.fault
.status
;
2190 tevent_req_nterror(req
, NT_STATUS_LOGON_FAILURE
);
2192 state
->p
->last_fault_code
= pkt
->u
.fault
.status
;
2193 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
2198 if (pkt
->ptype
!= DCERPC_PKT_ALTER_RESP
||
2199 pkt
->u
.alter_resp
.num_results
== 0 ||
2200 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
2201 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
2202 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
2206 /* the alter_resp might contain a reply set of credentials */
2207 if (conn
->security_state
.auth_info
&&
2208 pkt
->u
.alter_resp
.auth_info
.length
) {
2209 uint32_t auth_length
;
2211 status
= dcerpc_pull_auth_trailer(pkt
, conn
, &pkt
->u
.alter_resp
.auth_info
,
2212 conn
->security_state
.auth_info
, &auth_length
, true);
2213 if (tevent_req_nterror(req
, status
)) {
2218 tevent_req_done(req
);
2221 NTSTATUS
dcerpc_alter_context_recv(struct tevent_req
*req
)
2223 return tevent_req_simple_recv_ntstatus(req
);
2227 send a dcerpc alter_context request
2229 _PUBLIC_ NTSTATUS
dcerpc_alter_context(struct dcerpc_pipe
*p
,
2230 TALLOC_CTX
*mem_ctx
,
2231 const struct ndr_syntax_id
*syntax
,
2232 const struct ndr_syntax_id
*transfer_syntax
)
2234 struct tevent_req
*subreq
;
2235 struct tevent_context
*ev
= p
->conn
->event_ctx
;
2238 /* TODO: create a new event context here */
2240 subreq
= dcerpc_alter_context_send(mem_ctx
, p
->conn
->event_ctx
,
2241 p
, syntax
, transfer_syntax
);
2242 if (subreq
== NULL
) {
2243 return NT_STATUS_NO_MEMORY
;
2246 ok
= tevent_req_poll(subreq
, ev
);
2249 status
= map_nt_error_from_unix_common(errno
);
2253 return dcerpc_alter_context_recv(subreq
);
2256 static void dcerpc_transport_dead(struct dcecli_connection
*c
, NTSTATUS status
)
2258 if (c
->transport
.stream
== NULL
) {
2262 tevent_queue_stop(c
->transport
.write_queue
);
2263 TALLOC_FREE(c
->transport
.read_subreq
);
2264 TALLOC_FREE(c
->transport
.stream
);
2266 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL
, status
)) {
2267 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
2270 if (NT_STATUS_EQUAL(NT_STATUS_OK
, status
)) {
2271 status
= NT_STATUS_END_OF_FILE
;
2274 if (c
->transport
.recv_data
) {
2275 c
->transport
.recv_data(c
, NULL
, status
);
2281 shutdown SMB pipe connection
2283 struct dcerpc_shutdown_pipe_state
{
2284 struct dcecli_connection
*c
;
2288 static void dcerpc_shutdown_pipe_done(struct tevent_req
*subreq
);
2290 static NTSTATUS
dcerpc_shutdown_pipe(struct dcecli_connection
*c
, NTSTATUS status
)
2292 struct dcerpc_shutdown_pipe_state
*state
;
2293 struct tevent_req
*subreq
;
2295 if (c
->transport
.stream
== NULL
) {
2296 return NT_STATUS_OK
;
2299 state
= talloc_zero(c
, struct dcerpc_shutdown_pipe_state
);
2300 if (state
== NULL
) {
2301 return NT_STATUS_NO_MEMORY
;
2304 state
->status
= status
;
2306 subreq
= tstream_disconnect_send(state
, c
->event_ctx
, c
->transport
.stream
);
2307 if (subreq
== NULL
) {
2308 return NT_STATUS_NO_MEMORY
;
2310 tevent_req_set_callback(subreq
, dcerpc_shutdown_pipe_done
, state
);
2315 static void dcerpc_shutdown_pipe_done(struct tevent_req
*subreq
)
2317 struct dcerpc_shutdown_pipe_state
*state
=
2318 tevent_req_callback_data(subreq
, struct dcerpc_shutdown_pipe_state
);
2319 struct dcecli_connection
*c
= state
->c
;
2320 NTSTATUS status
= state
->status
;
2324 * here we ignore the return values...
2326 tstream_disconnect_recv(subreq
, &error
);
2327 TALLOC_FREE(subreq
);
2331 dcerpc_transport_dead(c
, status
);
2336 struct dcerpc_send_read_state
{
2337 struct dcecli_connection
*p
;
2340 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state
*state
)
2342 struct dcecli_connection
*p
= state
->p
;
2344 p
->transport
.read_subreq
= NULL
;
2349 static void dcerpc_send_read_done(struct tevent_req
*subreq
);
2351 static NTSTATUS
dcerpc_send_read(struct dcecli_connection
*p
)
2353 struct dcerpc_send_read_state
*state
;
2355 if (p
->transport
.read_subreq
!= NULL
) {
2356 p
->transport
.pending_reads
++;
2357 return NT_STATUS_OK
;
2360 state
= talloc_zero(p
, struct dcerpc_send_read_state
);
2361 if (state
== NULL
) {
2362 return NT_STATUS_NO_MEMORY
;
2366 talloc_set_destructor(state
, dcerpc_send_read_state_destructor
);
2368 p
->transport
.read_subreq
= dcerpc_read_ncacn_packet_send(state
,
2370 p
->transport
.stream
);
2371 if (p
->transport
.read_subreq
== NULL
) {
2372 return NT_STATUS_NO_MEMORY
;
2374 tevent_req_set_callback(p
->transport
.read_subreq
, dcerpc_send_read_done
, state
);
2376 return NT_STATUS_OK
;
2379 static void dcerpc_send_read_done(struct tevent_req
*subreq
)
2381 struct dcerpc_send_read_state
*state
=
2382 tevent_req_callback_data(subreq
,
2383 struct dcerpc_send_read_state
);
2384 struct dcecli_connection
*p
= state
->p
;
2386 struct ncacn_packet
*pkt
;
2389 status
= dcerpc_read_ncacn_packet_recv(subreq
, state
,
2391 TALLOC_FREE(subreq
);
2392 if (!NT_STATUS_IS_OK(status
)) {
2394 dcerpc_transport_dead(p
, status
);
2399 * here we steal into thet connection context,
2400 * but p->transport.recv_data() will steal or free it again
2402 talloc_steal(p
, blob
.data
);
2405 if (p
->transport
.pending_reads
> 0) {
2406 p
->transport
.pending_reads
--;
2408 status
= dcerpc_send_read(p
);
2409 if (!NT_STATUS_IS_OK(status
)) {
2410 dcerpc_transport_dead(p
, status
);
2415 if (p
->transport
.recv_data
) {
2416 p
->transport
.recv_data(p
, &blob
, NT_STATUS_OK
);
2420 struct dcerpc_send_request_state
{
2421 struct dcecli_connection
*p
;
2426 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state
*state
)
2428 struct dcecli_connection
*p
= state
->p
;
2430 p
->transport
.read_subreq
= NULL
;
2435 static void dcerpc_send_request_wait_done(struct tevent_req
*subreq
);
2436 static void dcerpc_send_request_done(struct tevent_req
*subreq
);
2438 static NTSTATUS
dcerpc_send_request(struct dcecli_connection
*p
, DATA_BLOB
*data
,
2441 struct dcerpc_send_request_state
*state
;
2442 struct tevent_req
*subreq
;
2443 bool use_trans
= trigger_read
;
2445 if (p
->transport
.stream
== NULL
) {
2446 return NT_STATUS_CONNECTION_DISCONNECTED
;
2449 state
= talloc_zero(p
, struct dcerpc_send_request_state
);
2450 if (state
== NULL
) {
2451 return NT_STATUS_NO_MEMORY
;
2455 state
->blob
= data_blob_talloc(state
, data
->data
, data
->length
);
2456 if (state
->blob
.data
== NULL
) {
2458 return NT_STATUS_NO_MEMORY
;
2460 state
->iov
.iov_base
= (void *)state
->blob
.data
;
2461 state
->iov
.iov_len
= state
->blob
.length
;
2463 if (p
->transport
.read_subreq
!= NULL
) {
2467 if (!tstream_is_smbXcli_np(p
->transport
.stream
)) {
2473 * we need to block reads until our write is
2474 * the next in the write queue.
2476 p
->transport
.read_subreq
= tevent_queue_wait_send(state
, p
->event_ctx
,
2477 p
->transport
.write_queue
);
2478 if (p
->transport
.read_subreq
== NULL
) {
2480 return NT_STATUS_NO_MEMORY
;
2482 tevent_req_set_callback(p
->transport
.read_subreq
,
2483 dcerpc_send_request_wait_done
,
2486 talloc_set_destructor(state
, dcerpc_send_request_state_destructor
);
2488 trigger_read
= false;
2491 subreq
= tstream_writev_queue_send(state
, p
->event_ctx
,
2492 p
->transport
.stream
,
2493 p
->transport
.write_queue
,
2495 if (subreq
== NULL
) {
2497 return NT_STATUS_NO_MEMORY
;
2499 tevent_req_set_callback(subreq
, dcerpc_send_request_done
, state
);
2502 dcerpc_send_read(p
);
2505 return NT_STATUS_OK
;
2508 static void dcerpc_send_request_wait_done(struct tevent_req
*subreq
)
2510 struct dcerpc_send_request_state
*state
=
2511 tevent_req_callback_data(subreq
,
2512 struct dcerpc_send_request_state
);
2513 struct dcecli_connection
*p
= state
->p
;
2517 p
->transport
.read_subreq
= NULL
;
2518 talloc_set_destructor(state
, NULL
);
2520 ok
= tevent_queue_wait_recv(subreq
);
2523 dcerpc_transport_dead(p
, NT_STATUS_NO_MEMORY
);
2527 if (tevent_queue_length(p
->transport
.write_queue
) <= 2) {
2528 status
= tstream_smbXcli_np_use_trans(p
->transport
.stream
);
2529 if (!NT_STATUS_IS_OK(status
)) {
2531 dcerpc_transport_dead(p
, status
);
2536 /* we free subreq after tstream_cli_np_use_trans */
2537 TALLOC_FREE(subreq
);
2539 dcerpc_send_read(p
);
2542 static void dcerpc_send_request_done(struct tevent_req
*subreq
)
2544 struct dcerpc_send_request_state
*state
=
2545 tevent_req_callback_data(subreq
,
2546 struct dcerpc_send_request_state
);
2550 ret
= tstream_writev_queue_recv(subreq
, &error
);
2551 TALLOC_FREE(subreq
);
2553 struct dcecli_connection
*p
= state
->p
;
2554 NTSTATUS status
= map_nt_error_from_unix_common(error
);
2557 dcerpc_transport_dead(p
, status
);