2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "librpc/rpc/rpc_common.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "libcli/smb/tstream_smbXcli_np.h"
39 enum rpc_request_state
{
46 handle for an async dcerpc request
49 struct rpc_request
*next
, *prev
;
50 struct dcerpc_pipe
*p
;
53 enum rpc_request_state state
;
58 /* this is used to distinguish bind and alter_context requests
59 from normal requests */
60 void (*recv_handler
)(struct rpc_request
*conn
,
61 DATA_BLOB
*blob
, struct ncacn_packet
*pkt
);
63 const struct GUID
*object
;
65 DATA_BLOB request_data
;
72 void (*callback
)(struct rpc_request
*);
77 _PUBLIC_ NTSTATUS
dcerpc_init(void)
82 static void dcerpc_connection_dead(struct dcecli_connection
*conn
, NTSTATUS status
);
83 static void dcerpc_schedule_io_trigger(struct dcecli_connection
*c
);
85 static struct rpc_request
*dcerpc_request_send(TALLOC_CTX
*mem_ctx
,
86 struct dcerpc_pipe
*p
,
87 const struct GUID
*object
,
89 DATA_BLOB
*stub_data
);
90 static NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
92 DATA_BLOB
*stub_data
);
93 static NTSTATUS
dcerpc_ndr_validate_in(struct dcecli_connection
*c
,
97 ndr_push_flags_fn_t ndr_push
,
98 ndr_pull_flags_fn_t ndr_pull
);
99 static NTSTATUS
dcerpc_ndr_validate_out(struct dcecli_connection
*c
,
100 struct ndr_pull
*pull_in
,
103 ndr_push_flags_fn_t ndr_push
,
104 ndr_pull_flags_fn_t ndr_pull
,
105 ndr_print_function_t ndr_print
);
106 static NTSTATUS
dcerpc_shutdown_pipe(struct dcecli_connection
*p
, NTSTATUS status
);
107 static NTSTATUS
dcerpc_send_request(struct dcecli_connection
*p
, DATA_BLOB
*data
,
109 static NTSTATUS
dcerpc_send_read(struct dcecli_connection
*p
);
111 /* destroy a dcerpc connection */
112 static int dcerpc_connection_destructor(struct dcecli_connection
*conn
)
115 conn
->free_skipped
= true;
118 dcerpc_connection_dead(conn
, NT_STATUS_LOCAL_DISCONNECT
);
123 /* initialise a dcerpc connection.
124 the event context is optional
126 static struct dcecli_connection
*dcerpc_connection_init(TALLOC_CTX
*mem_ctx
,
127 struct tevent_context
*ev
)
129 struct dcecli_connection
*c
;
131 c
= talloc_zero(mem_ctx
, struct dcecli_connection
);
138 if (c
->event_ctx
== NULL
) {
144 c
->security_state
.auth_type
= DCERPC_AUTH_TYPE_NONE
;
145 c
->security_state
.auth_level
= DCERPC_AUTH_LEVEL_NONE
;
146 c
->security_state
.auth_context_id
= 0;
147 c
->security_state
.session_key
= dcerpc_generic_session_key
;
148 c
->security_state
.generic_state
= NULL
;
151 * Windows uses 5840 for ncacn_ip_tcp,
152 * so we also use it (for every transport)
153 * by default. But we give the transport
154 * the chance to overwrite it.
156 c
->srv_max_xmit_frag
= 5840;
157 c
->srv_max_recv_frag
= 5840;
160 c
->io_trigger
= tevent_create_immediate(c
);
161 if (c
->io_trigger
== NULL
) {
166 talloc_set_destructor(c
, dcerpc_connection_destructor
);
171 struct dcerpc_bh_state
{
172 struct dcerpc_pipe
*p
;
175 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle
*h
)
177 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
178 struct dcerpc_bh_state
);
188 if (hs
->p
->conn
->dead
) {
195 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle
*h
,
198 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
199 struct dcerpc_bh_state
);
203 return DCERPC_REQUEST_TIMEOUT
;
206 old
= hs
->p
->request_timeout
;
207 hs
->p
->request_timeout
= timeout
;
212 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle
*h
,
213 enum dcerpc_AuthType
*auth_type
,
214 enum dcerpc_AuthLevel
*auth_level
)
216 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
217 struct dcerpc_bh_state
);
223 if (hs
->p
->conn
== NULL
) {
227 *auth_type
= hs
->p
->conn
->security_state
.auth_type
;
228 *auth_level
= hs
->p
->conn
->security_state
.auth_level
;
231 struct dcerpc_bh_raw_call_state
{
232 struct tevent_context
*ev
;
233 struct dcerpc_binding_handle
*h
;
239 static void dcerpc_bh_raw_call_done(struct rpc_request
*subreq
);
241 static struct tevent_req
*dcerpc_bh_raw_call_send(TALLOC_CTX
*mem_ctx
,
242 struct tevent_context
*ev
,
243 struct dcerpc_binding_handle
*h
,
244 const struct GUID
*object
,
247 const uint8_t *in_data
,
250 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
251 struct dcerpc_bh_state
);
252 struct tevent_req
*req
;
253 struct dcerpc_bh_raw_call_state
*state
;
255 struct rpc_request
*subreq
;
257 req
= tevent_req_create(mem_ctx
, &state
,
258 struct dcerpc_bh_raw_call_state
);
264 state
->in_data
.data
= discard_const_p(uint8_t, in_data
);
265 state
->in_data
.length
= in_length
;
267 ok
= dcerpc_bh_is_connected(h
);
269 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
270 return tevent_req_post(req
, ev
);
273 subreq
= dcerpc_request_send(state
,
278 if (tevent_req_nomem(subreq
, req
)) {
279 return tevent_req_post(req
, ev
);
281 subreq
->async
.callback
= dcerpc_bh_raw_call_done
;
282 subreq
->async
.private_data
= req
;
287 static void dcerpc_bh_raw_call_done(struct rpc_request
*subreq
)
289 struct tevent_req
*req
=
290 talloc_get_type_abort(subreq
->async
.private_data
,
292 struct dcerpc_bh_raw_call_state
*state
=
294 struct dcerpc_bh_raw_call_state
);
298 state
->out_flags
= 0;
299 if (subreq
->flags
& DCERPC_PULL_BIGENDIAN
) {
300 state
->out_flags
|= LIBNDR_FLAG_BIGENDIAN
;
303 fault_code
= subreq
->fault_code
;
305 status
= dcerpc_request_recv(subreq
, state
, &state
->out_data
);
306 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
307 status
= dcerpc_fault_to_nt_status(fault_code
);
311 * We trigger the callback in the next event run
312 * because the code in this file might trigger
313 * multiple request callbacks from within a single
316 * In order to avoid segfaults from within
317 * dcerpc_connection_dead() we call
318 * tevent_req_defer_callback().
320 tevent_req_defer_callback(req
, state
->ev
);
322 if (!NT_STATUS_IS_OK(status
)) {
323 tevent_req_nterror(req
, status
);
327 tevent_req_done(req
);
330 static NTSTATUS
dcerpc_bh_raw_call_recv(struct tevent_req
*req
,
336 struct dcerpc_bh_raw_call_state
*state
=
338 struct dcerpc_bh_raw_call_state
);
341 if (tevent_req_is_nterror(req
, &status
)) {
342 tevent_req_received(req
);
346 *out_data
= talloc_move(mem_ctx
, &state
->out_data
.data
);
347 *out_length
= state
->out_data
.length
;
348 *out_flags
= state
->out_flags
;
349 tevent_req_received(req
);
353 struct dcerpc_bh_disconnect_state
{
357 static struct tevent_req
*dcerpc_bh_disconnect_send(TALLOC_CTX
*mem_ctx
,
358 struct tevent_context
*ev
,
359 struct dcerpc_binding_handle
*h
)
361 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
362 struct dcerpc_bh_state
);
363 struct tevent_req
*req
;
364 struct dcerpc_bh_disconnect_state
*state
;
367 req
= tevent_req_create(mem_ctx
, &state
,
368 struct dcerpc_bh_disconnect_state
);
373 ok
= dcerpc_bh_is_connected(h
);
375 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
376 return tevent_req_post(req
, ev
);
379 /* TODO: do a real disconnect ... */
382 tevent_req_done(req
);
383 return tevent_req_post(req
, ev
);
386 static NTSTATUS
dcerpc_bh_disconnect_recv(struct tevent_req
*req
)
390 if (tevent_req_is_nterror(req
, &status
)) {
391 tevent_req_received(req
);
395 tevent_req_received(req
);
399 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle
*h
)
401 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
402 struct dcerpc_bh_state
);
404 if (hs
->p
->conn
->flags
& DCERPC_PUSH_BIGENDIAN
) {
411 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle
*h
)
413 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
414 struct dcerpc_bh_state
);
416 if (hs
->p
->conn
->flags
& DCERPC_NDR_REF_ALLOC
) {
423 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle
*h
)
425 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
426 struct dcerpc_bh_state
);
428 if (hs
->p
->conn
->flags
& DCERPC_NDR64
) {
435 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle
*h
,
437 const void *_struct_ptr
,
438 const struct ndr_interface_call
*call
)
440 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
441 struct dcerpc_bh_state
);
442 void *struct_ptr
= discard_const(_struct_ptr
);
444 if (ndr_flags
& NDR_IN
) {
445 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_PRINT_IN
) {
446 ndr_print_function_debug(call
->ndr_print
,
452 if (ndr_flags
& NDR_OUT
) {
453 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_PRINT_OUT
) {
454 ndr_print_function_debug(call
->ndr_print
,
462 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle
*h
,
464 const void *struct_ptr
,
465 const struct ndr_interface_call
*call
)
467 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
468 call
->name
, nt_errstr(error
)));
471 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle
*h
,
473 const DATA_BLOB
*blob
,
474 const struct ndr_interface_call
*call
)
476 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
477 struct dcerpc_bh_state
);
478 const uint32_t num_examples
= 20;
481 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
482 call
->name
, nt_errstr(error
)));
484 if (hs
->p
->conn
->packet_log_dir
== NULL
) return;
486 for (i
=0;i
<num_examples
;i
++) {
490 ret
= asprintf(&name
, "%s/rpclog/%s-out.%d",
491 hs
->p
->conn
->packet_log_dir
,
496 if (!file_exist(name
)) {
497 if (file_save(name
, blob
->data
, blob
->length
)) {
498 DEBUG(10,("Logged rpc packet to %s\n", name
));
507 static NTSTATUS
dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle
*h
,
509 const DATA_BLOB
*blob
,
510 const struct ndr_interface_call
*call
)
512 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
513 struct dcerpc_bh_state
);
515 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_IN
) {
518 status
= dcerpc_ndr_validate_in(hs
->p
->conn
,
524 if (!NT_STATUS_IS_OK(status
)) {
525 DEBUG(0,("Validation [in] failed for %s - %s\n",
526 call
->name
, nt_errstr(status
)));
531 DEBUG(10,("rpc request data:\n"));
532 dump_data(10, blob
->data
, blob
->length
);
537 static NTSTATUS
dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle
*h
,
538 struct ndr_pull
*pull_in
,
539 const void *_struct_ptr
,
540 const struct ndr_interface_call
*call
)
542 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
543 struct dcerpc_bh_state
);
544 void *struct_ptr
= discard_const(_struct_ptr
);
546 DEBUG(10,("rpc reply data:\n"));
547 dump_data(10, pull_in
->data
, pull_in
->data_size
);
549 if (pull_in
->offset
!= pull_in
->data_size
) {
550 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
551 pull_in
->data_size
- pull_in
->offset
,
552 pull_in
->offset
, pull_in
->offset
,
554 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
555 but it turns out that early versions of NT
556 (specifically NT3.1) add junk onto the end of rpc
557 packets, so if we want to interoperate at all with
558 those versions then we need to ignore this error */
561 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_OUT
) {
564 status
= dcerpc_ndr_validate_out(hs
->p
->conn
,
571 if (!NT_STATUS_IS_OK(status
)) {
572 DEBUG(2,("Validation [out] failed for %s - %s\n",
573 call
->name
, nt_errstr(status
)));
581 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops
= {
583 .is_connected
= dcerpc_bh_is_connected
,
584 .set_timeout
= dcerpc_bh_set_timeout
,
585 .auth_info
= dcerpc_bh_auth_info
,
586 .raw_call_send
= dcerpc_bh_raw_call_send
,
587 .raw_call_recv
= dcerpc_bh_raw_call_recv
,
588 .disconnect_send
= dcerpc_bh_disconnect_send
,
589 .disconnect_recv
= dcerpc_bh_disconnect_recv
,
591 .push_bigendian
= dcerpc_bh_push_bigendian
,
592 .ref_alloc
= dcerpc_bh_ref_alloc
,
593 .use_ndr64
= dcerpc_bh_use_ndr64
,
594 .do_ndr_print
= dcerpc_bh_do_ndr_print
,
595 .ndr_push_failed
= dcerpc_bh_ndr_push_failed
,
596 .ndr_pull_failed
= dcerpc_bh_ndr_pull_failed
,
597 .ndr_validate_in
= dcerpc_bh_ndr_validate_in
,
598 .ndr_validate_out
= dcerpc_bh_ndr_validate_out
,
601 /* initialise a dcerpc pipe. */
602 struct dcerpc_binding_handle
*dcerpc_pipe_binding_handle(struct dcerpc_pipe
*p
)
604 struct dcerpc_binding_handle
*h
;
605 struct dcerpc_bh_state
*hs
;
607 h
= dcerpc_binding_handle_create(p
,
612 struct dcerpc_bh_state
,
619 dcerpc_binding_handle_set_sync_ev(h
, p
->conn
->event_ctx
);
624 /* initialise a dcerpc pipe. */
625 _PUBLIC_
struct dcerpc_pipe
*dcerpc_pipe_init(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
)
627 struct dcerpc_pipe
*p
;
629 p
= talloc_zero(mem_ctx
, struct dcerpc_pipe
);
634 p
->conn
= dcerpc_connection_init(p
, ev
);
635 if (p
->conn
== NULL
) {
640 p
->last_fault_code
= 0;
642 p
->request_timeout
= DCERPC_REQUEST_TIMEOUT
;
645 ZERO_STRUCT(p
->syntax
);
646 ZERO_STRUCT(p
->transfer_syntax
);
649 p
->conn
->flags
|= DCERPC_DEBUG_PRINT_BOTH
;
652 p
->binding_handle
= dcerpc_pipe_binding_handle(p
);
653 if (p
->binding_handle
== NULL
) {
663 choose the next call id to use
665 static uint32_t next_call_id(struct dcecli_connection
*c
)
668 if (c
->call_id
== 0) {
675 setup for a ndr pull, also setting up any flags from the binding string
677 static struct ndr_pull
*ndr_pull_init_flags(struct dcecli_connection
*c
,
678 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
680 struct ndr_pull
*ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
682 if (ndr
== NULL
) return ndr
;
684 if (c
->flags
& DCERPC_DEBUG_PAD_CHECK
) {
685 ndr
->flags
|= LIBNDR_FLAG_PAD_CHECK
;
688 if (c
->flags
& DCERPC_NDR_REF_ALLOC
) {
689 ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
692 if (c
->flags
& DCERPC_NDR64
) {
693 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
700 parse a data blob into a ncacn_packet structure. This handles both
701 input and output packets
703 static NTSTATUS
ncacn_pull(struct dcecli_connection
*c
, DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
704 struct ncacn_packet
*pkt
)
706 struct ndr_pull
*ndr
;
707 enum ndr_err_code ndr_err
;
709 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
711 return NT_STATUS_NO_MEMORY
;
714 if (! (CVAL(blob
->data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
715 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
718 if (CVAL(blob
->data
, DCERPC_PFC_OFFSET
) & DCERPC_PFC_FLAG_OBJECT_UUID
) {
719 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
722 ndr_err
= ndr_pull_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
724 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
725 return ndr_map_error2ntstatus(ndr_err
);
728 if (pkt
->frag_length
!= blob
->length
) {
729 return NT_STATUS_RPC_PROTOCOL_ERROR
;
736 parse the authentication information on a dcerpc response packet
738 static NTSTATUS
ncacn_pull_request_auth(struct dcecli_connection
*c
, TALLOC_CTX
*mem_ctx
,
739 DATA_BLOB
*raw_packet
,
740 struct ncacn_packet
*pkt
)
743 struct dcerpc_auth auth
;
744 uint32_t auth_length
;
746 status
= dcerpc_verify_ncacn_packet_header(pkt
, DCERPC_PKT_RESPONSE
,
747 pkt
->u
.response
.stub_and_verifier
.length
,
748 0, /* required_flags */
749 DCERPC_PFC_FLAG_FIRST
|
750 DCERPC_PFC_FLAG_LAST
);
751 if (!NT_STATUS_IS_OK(status
)) {
755 switch (c
->security_state
.auth_level
) {
756 case DCERPC_AUTH_LEVEL_PRIVACY
:
757 case DCERPC_AUTH_LEVEL_INTEGRITY
:
760 case DCERPC_AUTH_LEVEL_CONNECT
:
761 if (pkt
->auth_length
!= 0) {
765 case DCERPC_AUTH_LEVEL_NONE
:
766 if (pkt
->auth_length
!= 0) {
767 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
772 return NT_STATUS_INVALID_LEVEL
;
775 if (pkt
->auth_length
== 0) {
776 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
779 if (c
->security_state
.generic_state
== NULL
) {
780 return NT_STATUS_INTERNAL_ERROR
;
783 status
= dcerpc_pull_auth_trailer(pkt
, mem_ctx
,
784 &pkt
->u
.response
.stub_and_verifier
,
785 &auth
, &auth_length
, false);
786 NT_STATUS_NOT_OK_RETURN(status
);
788 pkt
->u
.response
.stub_and_verifier
.length
-= auth_length
;
790 if (auth
.auth_type
!= c
->security_state
.auth_type
) {
791 return NT_STATUS_RPC_PROTOCOL_ERROR
;
794 if (auth
.auth_level
!= c
->security_state
.auth_level
) {
795 return NT_STATUS_RPC_PROTOCOL_ERROR
;
798 if (auth
.auth_context_id
!= c
->security_state
.auth_context_id
) {
799 return NT_STATUS_RPC_PROTOCOL_ERROR
;
802 /* check signature or unseal the packet */
803 switch (c
->security_state
.auth_level
) {
804 case DCERPC_AUTH_LEVEL_PRIVACY
:
805 status
= gensec_unseal_packet(c
->security_state
.generic_state
,
806 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
807 pkt
->u
.response
.stub_and_verifier
.length
,
809 raw_packet
->length
- auth
.credentials
.length
,
811 memcpy(pkt
->u
.response
.stub_and_verifier
.data
,
812 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
813 pkt
->u
.response
.stub_and_verifier
.length
);
816 case DCERPC_AUTH_LEVEL_INTEGRITY
:
817 status
= gensec_check_packet(c
->security_state
.generic_state
,
818 pkt
->u
.response
.stub_and_verifier
.data
,
819 pkt
->u
.response
.stub_and_verifier
.length
,
821 raw_packet
->length
- auth
.credentials
.length
,
825 case DCERPC_AUTH_LEVEL_CONNECT
:
826 /* for now we ignore possible signatures here */
827 status
= NT_STATUS_OK
;
831 status
= NT_STATUS_INVALID_LEVEL
;
835 /* remove the indicated amount of padding */
836 if (pkt
->u
.response
.stub_and_verifier
.length
< auth
.auth_pad_length
) {
837 return NT_STATUS_INFO_LENGTH_MISMATCH
;
839 pkt
->u
.response
.stub_and_verifier
.length
-= auth
.auth_pad_length
;
846 push a dcerpc request packet into a blob, possibly signing it.
848 static NTSTATUS
ncacn_push_request_sign(struct dcecli_connection
*c
,
849 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
851 struct ncacn_packet
*pkt
)
854 struct ndr_push
*ndr
;
856 size_t payload_length
;
857 enum ndr_err_code ndr_err
;
858 size_t hdr_size
= DCERPC_REQUEST_LENGTH
;
859 struct dcerpc_auth auth_info
= {
860 .auth_type
= c
->security_state
.auth_type
,
861 .auth_level
= c
->security_state
.auth_level
,
862 .auth_context_id
= c
->security_state
.auth_context_id
,
865 switch (c
->security_state
.auth_level
) {
866 case DCERPC_AUTH_LEVEL_PRIVACY
:
867 case DCERPC_AUTH_LEVEL_INTEGRITY
:
869 return NT_STATUS_INTERNAL_ERROR
;
873 case DCERPC_AUTH_LEVEL_CONNECT
:
874 /* TODO: let the gensec mech decide if it wants to generate a signature */
875 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
877 case DCERPC_AUTH_LEVEL_NONE
:
878 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
881 return NT_STATUS_INVALID_LEVEL
;
884 ndr
= ndr_push_init_ctx(mem_ctx
);
886 return NT_STATUS_NO_MEMORY
;
889 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
890 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
893 if (c
->flags
& DCERPC_NDR64
) {
894 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
897 if (pkt
->pfc_flags
& DCERPC_PFC_FLAG_OBJECT_UUID
) {
898 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
902 ndr_err
= ndr_push_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
903 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
904 return ndr_map_error2ntstatus(ndr_err
);
907 /* pad to 16 byte multiple in the payload portion of the
908 packet. This matches what w2k3 does. Note that we can't use
909 ndr_push_align() as that is relative to the start of the
910 whole packet, whereas w2k8 wants it relative to the start
912 auth_info
.auth_pad_length
=
913 DCERPC_AUTH_PAD_LENGTH(pkt
->u
.request
.stub_and_verifier
.length
);
914 ndr_err
= ndr_push_zero(ndr
, auth_info
.auth_pad_length
);
915 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
916 return ndr_map_error2ntstatus(ndr_err
);
919 payload_length
= pkt
->u
.request
.stub_and_verifier
.length
+
920 auth_info
.auth_pad_length
;
922 /* add the auth verifier */
923 ndr_err
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, &auth_info
);
924 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
925 return ndr_map_error2ntstatus(ndr_err
);
928 /* extract the whole packet as a blob */
929 *blob
= ndr_push_blob(ndr
);
932 * Setup the frag and auth length in the packet buffer.
933 * This is needed if the GENSEC mech does AEAD signing
934 * of the packet headers. The signature itself will be
937 dcerpc_set_frag_length(blob
, blob
->length
+ sig_size
);
938 dcerpc_set_auth_length(blob
, sig_size
);
940 /* sign or seal the packet */
941 switch (c
->security_state
.auth_level
) {
942 case DCERPC_AUTH_LEVEL_PRIVACY
:
943 status
= gensec_seal_packet(c
->security_state
.generic_state
,
945 blob
->data
+ hdr_size
,
950 if (!NT_STATUS_IS_OK(status
)) {
955 case DCERPC_AUTH_LEVEL_INTEGRITY
:
956 status
= gensec_sign_packet(c
->security_state
.generic_state
,
958 blob
->data
+ hdr_size
,
963 if (!NT_STATUS_IS_OK(status
)) {
969 status
= NT_STATUS_INVALID_LEVEL
;
973 if (creds2
.length
!= sig_size
) {
974 /* this means the sig_size estimate for the signature
975 was incorrect. We have to correct the packet
976 sizes. That means we could go over the max fragment
978 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
979 (unsigned) creds2
.length
,
981 (unsigned) auth_info
.auth_pad_length
,
982 (unsigned) pkt
->u
.request
.stub_and_verifier
.length
));
983 dcerpc_set_frag_length(blob
, blob
->length
+ creds2
.length
);
984 dcerpc_set_auth_length(blob
, creds2
.length
);
987 if (!data_blob_append(mem_ctx
, blob
, creds2
.data
, creds2
.length
)) {
988 return NT_STATUS_NO_MEMORY
;
996 fill in the fixed values in a dcerpc header
998 static void init_ncacn_hdr(struct dcecli_connection
*c
, struct ncacn_packet
*pkt
)
1001 pkt
->rpc_vers_minor
= 0;
1002 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1005 pkt
->drep
[0] = DCERPC_DREP_LE
;
1013 map a bind nak reason to a NTSTATUS
1015 static NTSTATUS
dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason
)
1018 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED
:
1019 return NT_STATUS_REVISION_MISMATCH
;
1020 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE
:
1021 return NT_STATUS_INVALID_PARAMETER
;
1025 return NT_STATUS_UNSUCCESSFUL
;
1028 static NTSTATUS
dcerpc_map_ack_reason(const struct dcerpc_ack_ctx
*ack
)
1031 return NT_STATUS_RPC_PROTOCOL_ERROR
;
1034 switch (ack
->result
) {
1035 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK
:
1037 * We have not asked for this...
1039 return NT_STATUS_RPC_PROTOCOL_ERROR
;
1044 switch (ack
->reason
.value
) {
1045 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED
:
1046 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX
;
1047 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED
:
1048 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX
;
1052 return NT_STATUS_UNSUCCESSFUL
;
1056 remove requests from the pending or queued queues
1058 static int dcerpc_req_dequeue(struct rpc_request
*req
)
1060 switch (req
->state
) {
1061 case RPC_REQUEST_QUEUED
:
1062 DLIST_REMOVE(req
->p
->conn
->request_queue
, req
);
1064 case RPC_REQUEST_PENDING
:
1065 DLIST_REMOVE(req
->p
->conn
->pending
, req
);
1067 case RPC_REQUEST_DONE
:
1075 mark the dcerpc connection dead. All outstanding requests get an error
1077 static void dcerpc_connection_dead(struct dcecli_connection
*conn
, NTSTATUS status
)
1079 if (conn
->dead
) return;
1083 TALLOC_FREE(conn
->io_trigger
);
1084 conn
->io_trigger_pending
= false;
1086 dcerpc_shutdown_pipe(conn
, status
);
1088 /* all pending requests get the error */
1089 while (conn
->pending
) {
1090 struct rpc_request
*req
= conn
->pending
;
1091 dcerpc_req_dequeue(req
);
1092 req
->state
= RPC_REQUEST_DONE
;
1093 req
->status
= status
;
1094 if (req
->async
.callback
) {
1095 req
->async
.callback(req
);
1099 /* all requests, which are not shipped */
1100 while (conn
->request_queue
) {
1101 struct rpc_request
*req
= conn
->request_queue
;
1102 dcerpc_req_dequeue(req
);
1103 req
->state
= RPC_REQUEST_DONE
;
1104 req
->status
= status
;
1105 if (req
->async
.callback
) {
1106 req
->async
.callback(req
);
1110 talloc_set_destructor(conn
, NULL
);
1111 if (conn
->free_skipped
) {
1117 forward declarations of the recv_data handlers for the types of
1118 packets we need to handle
1120 static void dcerpc_request_recv_data(struct dcecli_connection
*c
,
1121 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
);
1124 receive a dcerpc reply from the transport. Here we work out what
1125 type of reply it is (normal request, bind or alter context) and
1126 dispatch to the appropriate handler
1128 static void dcerpc_recv_data(struct dcecli_connection
*conn
, DATA_BLOB
*blob
, NTSTATUS status
)
1130 struct ncacn_packet pkt
;
1136 if (NT_STATUS_IS_OK(status
) && blob
->length
== 0) {
1137 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
1140 /* the transport may be telling us of a severe error, such as
1142 if (!NT_STATUS_IS_OK(status
)) {
1143 data_blob_free(blob
);
1144 dcerpc_connection_dead(conn
, status
);
1148 /* parse the basic packet to work out what type of response this is */
1149 status
= ncacn_pull(conn
, blob
, blob
->data
, &pkt
);
1150 if (!NT_STATUS_IS_OK(status
)) {
1151 data_blob_free(blob
);
1152 dcerpc_connection_dead(conn
, status
);
1156 dcerpc_request_recv_data(conn
, blob
, &pkt
);
1160 handle timeouts of individual dcerpc requests
1162 static void dcerpc_timeout_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
1163 struct timeval t
, void *private_data
)
1165 struct rpc_request
*req
= talloc_get_type(private_data
, struct rpc_request
);
1167 if (req
->ignore_timeout
) {
1168 dcerpc_req_dequeue(req
);
1169 req
->state
= RPC_REQUEST_DONE
;
1170 req
->status
= NT_STATUS_IO_TIMEOUT
;
1171 if (req
->async
.callback
) {
1172 req
->async
.callback(req
);
1177 dcerpc_connection_dead(req
->p
->conn
, NT_STATUS_IO_TIMEOUT
);
1180 struct dcerpc_bind_state
{
1181 struct tevent_context
*ev
;
1182 struct dcerpc_pipe
*p
;
1185 static void dcerpc_bind_fail_handler(struct rpc_request
*subreq
);
1186 static void dcerpc_bind_recv_handler(struct rpc_request
*subreq
,
1187 DATA_BLOB
*raw_packet
,
1188 struct ncacn_packet
*pkt
);
1190 struct tevent_req
*dcerpc_bind_send(TALLOC_CTX
*mem_ctx
,
1191 struct tevent_context
*ev
,
1192 struct dcerpc_pipe
*p
,
1193 const struct ndr_syntax_id
*syntax
,
1194 const struct ndr_syntax_id
*transfer_syntax
)
1196 struct tevent_req
*req
;
1197 struct dcerpc_bind_state
*state
;
1198 struct ncacn_packet pkt
;
1201 struct rpc_request
*subreq
;
1204 req
= tevent_req_create(mem_ctx
, &state
,
1205 struct dcerpc_bind_state
);
1213 p
->syntax
= *syntax
;
1214 p
->transfer_syntax
= *transfer_syntax
;
1216 flags
= dcerpc_binding_get_flags(p
->binding
);
1218 init_ncacn_hdr(p
->conn
, &pkt
);
1220 pkt
.ptype
= DCERPC_PKT_BIND
;
1221 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1222 pkt
.call_id
= p
->conn
->call_id
;
1223 pkt
.auth_length
= 0;
1225 if (flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1226 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1229 if (p
->conn
->flags
& DCERPC_PROPOSE_HEADER_SIGNING
) {
1230 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
1233 pkt
.u
.bind
.max_xmit_frag
= p
->conn
->srv_max_xmit_frag
;
1234 pkt
.u
.bind
.max_recv_frag
= p
->conn
->srv_max_recv_frag
;
1235 pkt
.u
.bind
.assoc_group_id
= dcerpc_binding_get_assoc_group_id(p
->binding
);
1236 pkt
.u
.bind
.num_contexts
= 1;
1237 pkt
.u
.bind
.ctx_list
= talloc_array(mem_ctx
, struct dcerpc_ctx_list
, 1);
1238 if (tevent_req_nomem(pkt
.u
.bind
.ctx_list
, req
)) {
1239 return tevent_req_post(req
, ev
);
1241 pkt
.u
.bind
.ctx_list
[0].context_id
= p
->context_id
;
1242 pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
= 1;
1243 pkt
.u
.bind
.ctx_list
[0].abstract_syntax
= p
->syntax
;
1244 pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
1245 pkt
.u
.bind
.auth_info
= data_blob(NULL
, 0);
1247 /* construct the NDR form of the packet */
1248 status
= ncacn_push_auth(&blob
, state
, &pkt
,
1249 p
->conn
->security_state
.tmp_auth_info
.out
);
1250 if (tevent_req_nterror(req
, status
)) {
1251 return tevent_req_post(req
, ev
);
1255 * we allocate a dcerpc_request so we can be in the same
1256 * request queue as normal requests
1258 subreq
= talloc_zero(state
, struct rpc_request
);
1259 if (tevent_req_nomem(subreq
, req
)) {
1260 return tevent_req_post(req
, ev
);
1263 subreq
->state
= RPC_REQUEST_PENDING
;
1264 subreq
->call_id
= pkt
.call_id
;
1265 subreq
->async
.private_data
= req
;
1266 subreq
->async
.callback
= dcerpc_bind_fail_handler
;
1268 subreq
->recv_handler
= dcerpc_bind_recv_handler
;
1269 DLIST_ADD_END(p
->conn
->pending
, subreq
, struct rpc_request
*);
1270 talloc_set_destructor(subreq
, dcerpc_req_dequeue
);
1272 status
= dcerpc_send_request(p
->conn
, &blob
, true);
1273 if (tevent_req_nterror(req
, status
)) {
1274 return tevent_req_post(req
, ev
);
1277 tevent_add_timer(ev
, subreq
,
1278 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
1279 dcerpc_timeout_handler
, subreq
);
1284 static void dcerpc_bind_fail_handler(struct rpc_request
*subreq
)
1286 struct tevent_req
*req
=
1287 talloc_get_type_abort(subreq
->async
.private_data
,
1289 struct dcerpc_bind_state
*state
=
1290 tevent_req_data(req
,
1291 struct dcerpc_bind_state
);
1292 NTSTATUS status
= subreq
->status
;
1294 TALLOC_FREE(subreq
);
1297 * We trigger the callback in the next event run
1298 * because the code in this file might trigger
1299 * multiple request callbacks from within a single
1302 * In order to avoid segfaults from within
1303 * dcerpc_connection_dead() we call
1304 * tevent_req_defer_callback().
1306 tevent_req_defer_callback(req
, state
->ev
);
1308 tevent_req_nterror(req
, status
);
1311 static void dcerpc_bind_recv_handler(struct rpc_request
*subreq
,
1312 DATA_BLOB
*raw_packet
,
1313 struct ncacn_packet
*pkt
)
1315 struct tevent_req
*req
=
1316 talloc_get_type_abort(subreq
->async
.private_data
,
1318 struct dcerpc_bind_state
*state
=
1319 tevent_req_data(req
,
1320 struct dcerpc_bind_state
);
1321 struct dcecli_connection
*conn
= state
->p
->conn
;
1322 struct dcecli_security
*sec
= &conn
->security_state
;
1323 struct dcerpc_binding
*b
= NULL
;
1328 * Note that pkt is allocated under raw_packet->data,
1329 * while raw_packet->data is a child of subreq.
1331 talloc_steal(state
, raw_packet
->data
);
1332 TALLOC_FREE(subreq
);
1335 * We trigger the callback in the next event run
1336 * because the code in this file might trigger
1337 * multiple request callbacks from within a single
1340 * In order to avoid segfaults from within
1341 * dcerpc_connection_dead() we call
1342 * tevent_req_defer_callback().
1344 tevent_req_defer_callback(req
, state
->ev
);
1346 if (pkt
->ptype
== DCERPC_PKT_BIND_NAK
) {
1347 status
= dcerpc_map_nak_reason(pkt
->u
.bind_nak
.reject_reason
);
1349 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1350 pkt
->u
.bind_nak
.reject_reason
, nt_errstr(status
)));
1352 tevent_req_nterror(req
, status
);
1356 status
= dcerpc_verify_ncacn_packet_header(pkt
,
1357 DCERPC_PKT_BIND_ACK
,
1358 pkt
->u
.bind_ack
.auth_info
.length
,
1359 DCERPC_PFC_FLAG_FIRST
|
1360 DCERPC_PFC_FLAG_LAST
,
1361 DCERPC_PFC_FLAG_CONC_MPX
|
1362 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
);
1363 if (!NT_STATUS_IS_OK(status
)) {
1364 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1365 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1369 if (pkt
->u
.bind_ack
.num_results
!= 1) {
1370 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1371 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1375 if (pkt
->u
.bind_ack
.ctx_list
[0].result
!= 0) {
1376 status
= dcerpc_map_ack_reason(&pkt
->u
.bind_ack
.ctx_list
[0]);
1377 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1378 pkt
->u
.bind_ack
.ctx_list
[0].reason
.value
,
1379 nt_errstr(status
)));
1380 tevent_req_nterror(req
, status
);
1385 * DCE-RPC 1.1 (c706) specifies
1386 * CONST_MUST_RCV_FRAG_SIZE as 1432
1388 if (pkt
->u
.bind_ack
.max_xmit_frag
< 1432) {
1389 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1390 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1393 if (pkt
->u
.bind_ack
.max_recv_frag
< 1432) {
1394 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1395 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1398 conn
->srv_max_xmit_frag
= MIN(conn
->srv_max_xmit_frag
,
1399 pkt
->u
.bind_ack
.max_xmit_frag
);
1400 conn
->srv_max_recv_frag
= MIN(conn
->srv_max_recv_frag
,
1401 pkt
->u
.bind_ack
.max_recv_frag
);
1403 flags
= dcerpc_binding_get_flags(state
->p
->binding
);
1405 if ((flags
& DCERPC_CONCURRENT_MULTIPLEX
) &&
1406 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_CONC_MPX
)) {
1407 conn
->flags
|= DCERPC_CONCURRENT_MULTIPLEX
;
1410 if ((conn
->flags
& DCERPC_PROPOSE_HEADER_SIGNING
) &&
1411 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
)) {
1412 conn
->flags
|= DCERPC_HEADER_SIGNING
;
1415 /* the bind_ack might contain a reply set of credentials */
1416 if (pkt
->auth_length
!= 0 && sec
->tmp_auth_info
.in
!= NULL
) {
1417 uint32_t auth_length
;
1419 status
= dcerpc_pull_auth_trailer(pkt
, sec
->tmp_auth_info
.mem
,
1420 &pkt
->u
.bind_ack
.auth_info
,
1421 sec
->tmp_auth_info
.in
,
1422 &auth_length
, true);
1423 if (tevent_req_nterror(req
, status
)) {
1429 * We're the owner of the binding, so we're allowed to modify it.
1431 b
= discard_const_p(struct dcerpc_binding
, state
->p
->binding
);
1432 status
= dcerpc_binding_set_assoc_group_id(b
,
1433 pkt
->u
.bind_ack
.assoc_group_id
);
1434 if (tevent_req_nterror(req
, status
)) {
1438 tevent_req_done(req
);
1441 NTSTATUS
dcerpc_bind_recv(struct tevent_req
*req
)
1443 return tevent_req_simple_recv_ntstatus(req
);
1447 perform a continued bind (and auth3)
1449 NTSTATUS
dcerpc_auth3(struct dcerpc_pipe
*p
,
1450 TALLOC_CTX
*mem_ctx
)
1452 struct ncacn_packet pkt
;
1457 flags
= dcerpc_binding_get_flags(p
->binding
);
1459 init_ncacn_hdr(p
->conn
, &pkt
);
1461 pkt
.ptype
= DCERPC_PKT_AUTH3
;
1462 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1463 pkt
.call_id
= next_call_id(p
->conn
);
1464 pkt
.auth_length
= 0;
1465 pkt
.u
.auth3
.auth_info
= data_blob(NULL
, 0);
1467 if (flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1468 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1471 /* construct the NDR form of the packet */
1472 status
= ncacn_push_auth(&blob
, mem_ctx
, &pkt
,
1473 p
->conn
->security_state
.tmp_auth_info
.out
);
1474 if (!NT_STATUS_IS_OK(status
)) {
1478 /* send it on its way */
1479 status
= dcerpc_send_request(p
->conn
, &blob
, false);
1480 if (!NT_STATUS_IS_OK(status
)) {
1484 return NT_STATUS_OK
;
1489 process a fragment received from the transport layer during a
1492 This function frees the data
1494 static void dcerpc_request_recv_data(struct dcecli_connection
*c
,
1495 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
1497 struct rpc_request
*req
;
1498 unsigned int length
;
1499 NTSTATUS status
= NT_STATUS_OK
;
1502 if this is an authenticated connection then parse and check
1503 the auth info. We have to do this before finding the
1504 matching packet, as the request structure might have been
1505 removed due to a timeout, but if it has been we still need
1506 to run the auth routines so that we don't get the sign/seal
1507 info out of step with the server
1509 if (pkt
->ptype
== DCERPC_PKT_RESPONSE
) {
1510 status
= ncacn_pull_request_auth(c
, raw_packet
->data
, raw_packet
, pkt
);
1513 /* find the matching request */
1514 for (req
=c
->pending
;req
;req
=req
->next
) {
1515 if (pkt
->call_id
== req
->call_id
) break;
1519 /* useful for testing certain vendors RPC servers */
1520 if (req
== NULL
&& c
->pending
&& pkt
->call_id
== 0) {
1521 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1527 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt
->call_id
));
1528 data_blob_free(raw_packet
);
1532 talloc_steal(req
, raw_packet
->data
);
1534 if (req
->recv_handler
!= NULL
) {
1535 dcerpc_req_dequeue(req
);
1536 req
->state
= RPC_REQUEST_DONE
;
1539 * We have to look at shipping further requests before calling
1540 * the async function, that one might close the pipe
1542 dcerpc_schedule_io_trigger(c
);
1544 req
->recv_handler(req
, raw_packet
, pkt
);
1548 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
1549 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c
, pkt
->u
.fault
.status
)));
1550 req
->fault_code
= pkt
->u
.fault
.status
;
1551 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
1555 if (pkt
->ptype
!= DCERPC_PKT_RESPONSE
) {
1556 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1558 req
->fault_code
= DCERPC_FAULT_OTHER
;
1559 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
1563 /* now check the status from the auth routines, and if it failed then fail
1564 this request accordingly */
1565 if (!NT_STATUS_IS_OK(status
)) {
1566 req
->status
= status
;
1570 length
= pkt
->u
.response
.stub_and_verifier
.length
;
1573 req
->payload
.data
= talloc_realloc(req
,
1576 req
->payload
.length
+ length
);
1577 if (!req
->payload
.data
) {
1578 req
->status
= NT_STATUS_NO_MEMORY
;
1581 memcpy(req
->payload
.data
+req
->payload
.length
,
1582 pkt
->u
.response
.stub_and_verifier
.data
, length
);
1583 req
->payload
.length
+= length
;
1586 if (!(pkt
->pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
1587 data_blob_free(raw_packet
);
1588 dcerpc_send_read(c
);
1592 if (req
->verify_bitmask1
) {
1593 req
->p
->conn
->security_state
.verified_bitmask1
= true;
1595 if (req
->verify_pcontext
) {
1596 req
->p
->verified_pcontext
= true;
1599 if (!(pkt
->drep
[0] & DCERPC_DREP_LE
)) {
1600 req
->flags
|= DCERPC_PULL_BIGENDIAN
;
1602 req
->flags
&= ~DCERPC_PULL_BIGENDIAN
;
1606 data_blob_free(raw_packet
);
1608 /* we've got the full payload */
1609 dcerpc_req_dequeue(req
);
1610 req
->state
= RPC_REQUEST_DONE
;
1613 * We have to look at shipping further requests before calling
1614 * the async function, that one might close the pipe
1616 dcerpc_schedule_io_trigger(c
);
1618 if (req
->async
.callback
) {
1619 req
->async
.callback(req
);
1623 static NTSTATUS
dcerpc_request_prepare_vt(struct rpc_request
*req
);
1626 perform the send side of a async dcerpc request
1628 static struct rpc_request
*dcerpc_request_send(TALLOC_CTX
*mem_ctx
,
1629 struct dcerpc_pipe
*p
,
1630 const struct GUID
*object
,
1632 DATA_BLOB
*stub_data
)
1634 struct rpc_request
*req
;
1637 req
= talloc_zero(mem_ctx
, struct rpc_request
);
1643 req
->call_id
= next_call_id(p
->conn
);
1644 req
->state
= RPC_REQUEST_QUEUED
;
1646 if (object
!= NULL
) {
1647 req
->object
= (struct GUID
*)talloc_memdup(req
, (const void *)object
, sizeof(*object
));
1648 if (req
->object
== NULL
) {
1655 req
->request_data
.length
= stub_data
->length
;
1656 req
->request_data
.data
= stub_data
->data
;
1658 status
= dcerpc_request_prepare_vt(req
);
1659 if (!NT_STATUS_IS_OK(status
)) {
1664 DLIST_ADD_END(p
->conn
->request_queue
, req
, struct rpc_request
*);
1665 talloc_set_destructor(req
, dcerpc_req_dequeue
);
1667 dcerpc_schedule_io_trigger(p
->conn
);
1669 if (p
->request_timeout
) {
1670 tevent_add_timer(p
->conn
->event_ctx
, req
,
1671 timeval_current_ofs(p
->request_timeout
, 0),
1672 dcerpc_timeout_handler
, req
);
1678 static NTSTATUS
dcerpc_request_prepare_vt(struct rpc_request
*req
)
1680 struct dcecli_security
*sec
= &req
->p
->conn
->security_state
;
1681 struct dcerpc_sec_verification_trailer
*t
;
1682 struct dcerpc_sec_vt
*c
= NULL
;
1683 struct ndr_push
*ndr
= NULL
;
1684 enum ndr_err_code ndr_err
;
1686 if (sec
->auth_level
< DCERPC_AUTH_LEVEL_INTEGRITY
) {
1687 return NT_STATUS_OK
;
1690 t
= talloc_zero(req
, struct dcerpc_sec_verification_trailer
);
1692 return NT_STATUS_NO_MEMORY
;
1695 if (!sec
->verified_bitmask1
) {
1696 t
->commands
= talloc_realloc(t
, t
->commands
,
1697 struct dcerpc_sec_vt
,
1698 t
->count
.count
+ 1);
1699 if (t
->commands
== NULL
) {
1700 return NT_STATUS_NO_MEMORY
;
1702 c
= &t
->commands
[t
->count
.count
++];
1705 c
->command
= DCERPC_SEC_VT_COMMAND_BITMASK1
;
1706 if (req
->p
->conn
->flags
& DCERPC_PROPOSE_HEADER_SIGNING
) {
1707 c
->u
.bitmask1
= DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING
;
1709 req
->verify_bitmask1
= true;
1712 if (!req
->p
->verified_pcontext
) {
1713 t
->commands
= talloc_realloc(t
, t
->commands
,
1714 struct dcerpc_sec_vt
,
1715 t
->count
.count
+ 1);
1716 if (t
->commands
== NULL
) {
1717 return NT_STATUS_NO_MEMORY
;
1719 c
= &t
->commands
[t
->count
.count
++];
1722 c
->command
= DCERPC_SEC_VT_COMMAND_PCONTEXT
;
1723 c
->u
.pcontext
.abstract_syntax
= req
->p
->syntax
;
1724 c
->u
.pcontext
.transfer_syntax
= req
->p
->transfer_syntax
;
1726 req
->verify_pcontext
= true;
1729 if (!(req
->p
->conn
->flags
& DCERPC_HEADER_SIGNING
)) {
1730 t
->commands
= talloc_realloc(t
, t
->commands
,
1731 struct dcerpc_sec_vt
,
1732 t
->count
.count
+ 1);
1733 if (t
->commands
== NULL
) {
1734 return NT_STATUS_NO_MEMORY
;
1736 c
= &t
->commands
[t
->count
.count
++];
1739 c
->command
= DCERPC_SEC_VT_COMMAND_HEADER2
;
1740 c
->u
.header2
.ptype
= DCERPC_PKT_REQUEST
;
1741 if (req
->p
->conn
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1742 c
->u
.header2
.drep
[0] = 0;
1744 c
->u
.header2
.drep
[0] = DCERPC_DREP_LE
;
1746 c
->u
.header2
.drep
[1] = 0;
1747 c
->u
.header2
.drep
[2] = 0;
1748 c
->u
.header2
.drep
[3] = 0;
1749 c
->u
.header2
.call_id
= req
->call_id
;
1750 c
->u
.header2
.context_id
= req
->p
->context_id
;
1751 c
->u
.header2
.opnum
= req
->opnum
;
1754 if (t
->count
.count
== 0) {
1756 return NT_STATUS_OK
;
1759 c
= &t
->commands
[t
->count
.count
- 1];
1760 c
->command
|= DCERPC_SEC_VT_COMMAND_END
;
1762 if (DEBUGLEVEL
>= 10) {
1763 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer
, t
);
1766 ndr
= ndr_push_init_ctx(req
);
1768 return NT_STATUS_NO_MEMORY
;
1772 * for now we just copy and append
1775 ndr_err
= ndr_push_bytes(ndr
, req
->request_data
.data
,
1776 req
->request_data
.length
);
1777 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1778 return ndr_map_error2ntstatus(ndr_err
);
1781 ndr_err
= ndr_push_dcerpc_sec_verification_trailer(ndr
,
1782 NDR_SCALARS
| NDR_BUFFERS
,
1784 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1785 return ndr_map_error2ntstatus(ndr_err
);
1787 req
->request_data
= ndr_push_blob(ndr
);
1789 return NT_STATUS_OK
;
1793 Send a request using the transport
1796 static void dcerpc_ship_next_request(struct dcecli_connection
*c
)
1798 struct rpc_request
*req
;
1799 struct dcerpc_pipe
*p
;
1800 DATA_BLOB
*stub_data
;
1801 struct ncacn_packet pkt
;
1803 uint32_t remaining
, chunk_size
;
1804 bool first_packet
= true;
1805 size_t sig_size
= 0;
1806 bool need_async
= false;
1807 bool can_async
= true;
1809 req
= c
->request_queue
;
1815 stub_data
= &req
->request_data
;
1821 if (c
->security_state
.auth_level
>= DCERPC_AUTH_LEVEL_INTEGRITY
) {
1822 can_async
= gensec_have_feature(c
->security_state
.generic_state
,
1823 GENSEC_FEATURE_ASYNC_REPLIES
);
1826 if (need_async
&& !can_async
) {
1827 req
->wait_for_sync
= true;
1831 DLIST_REMOVE(c
->request_queue
, req
);
1832 DLIST_ADD(c
->pending
, req
);
1833 req
->state
= RPC_REQUEST_PENDING
;
1835 init_ncacn_hdr(p
->conn
, &pkt
);
1837 remaining
= stub_data
->length
;
1839 /* we can write a full max_recv_frag size, minus the dcerpc
1840 request header size */
1841 chunk_size
= p
->conn
->srv_max_recv_frag
;
1842 chunk_size
-= DCERPC_REQUEST_LENGTH
;
1843 if (c
->security_state
.auth_level
>= DCERPC_AUTH_LEVEL_INTEGRITY
) {
1844 size_t max_payload
= chunk_size
;
1846 max_payload
-= DCERPC_AUTH_TRAILER_LENGTH
;
1847 max_payload
-= (max_payload
% DCERPC_AUTH_PAD_ALIGNMENT
);
1849 sig_size
= gensec_sig_size(c
->security_state
.generic_state
,
1852 chunk_size
-= DCERPC_AUTH_TRAILER_LENGTH
;
1853 chunk_size
-= sig_size
;
1856 chunk_size
-= (chunk_size
% DCERPC_AUTH_PAD_ALIGNMENT
);
1858 pkt
.ptype
= DCERPC_PKT_REQUEST
;
1859 pkt
.call_id
= req
->call_id
;
1860 pkt
.auth_length
= 0;
1862 pkt
.u
.request
.context_id
= p
->context_id
;
1863 pkt
.u
.request
.opnum
= req
->opnum
;
1866 pkt
.u
.request
.object
.object
= *req
->object
;
1867 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_OBJECT_UUID
;
1868 chunk_size
-= ndr_size_GUID(req
->object
,0);
1871 /* we send a series of pdus without waiting for a reply */
1872 while (remaining
> 0 || first_packet
) {
1873 uint32_t chunk
= MIN(chunk_size
, remaining
);
1874 bool last_frag
= false;
1875 bool do_trans
= false;
1877 first_packet
= false;
1878 pkt
.pfc_flags
&= ~(DCERPC_PFC_FLAG_FIRST
|DCERPC_PFC_FLAG_LAST
);
1880 if (remaining
== stub_data
->length
) {
1881 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_FIRST
;
1883 if (chunk
== remaining
) {
1884 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_LAST
;
1888 pkt
.u
.request
.alloc_hint
= remaining
;
1889 pkt
.u
.request
.stub_and_verifier
.data
= stub_data
->data
+
1890 (stub_data
->length
- remaining
);
1891 pkt
.u
.request
.stub_and_verifier
.length
= chunk
;
1893 req
->status
= ncacn_push_request_sign(p
->conn
, &blob
, req
, sig_size
, &pkt
);
1894 if (!NT_STATUS_IS_OK(req
->status
)) {
1895 req
->state
= RPC_REQUEST_DONE
;
1896 DLIST_REMOVE(p
->conn
->pending
, req
);
1900 if (last_frag
&& !need_async
) {
1904 req
->status
= dcerpc_send_request(p
->conn
, &blob
, do_trans
);
1905 if (!NT_STATUS_IS_OK(req
->status
)) {
1906 req
->state
= RPC_REQUEST_DONE
;
1907 DLIST_REMOVE(p
->conn
->pending
, req
);
1911 if (last_frag
&& !do_trans
) {
1912 req
->status
= dcerpc_send_read(p
->conn
);
1913 if (!NT_STATUS_IS_OK(req
->status
)) {
1914 req
->state
= RPC_REQUEST_DONE
;
1915 DLIST_REMOVE(p
->conn
->pending
, req
);
1924 static void dcerpc_io_trigger(struct tevent_context
*ctx
,
1925 struct tevent_immediate
*im
,
1928 struct dcecli_connection
*c
=
1929 talloc_get_type_abort(private_data
,
1930 struct dcecli_connection
);
1932 c
->io_trigger_pending
= false;
1934 dcerpc_schedule_io_trigger(c
);
1936 dcerpc_ship_next_request(c
);
1939 static void dcerpc_schedule_io_trigger(struct dcecli_connection
*c
)
1945 if (c
->request_queue
== NULL
) {
1949 if (c
->request_queue
->wait_for_sync
&& c
->pending
) {
1953 if (c
->io_trigger_pending
) {
1957 c
->io_trigger_pending
= true;
1959 tevent_schedule_immediate(c
->io_trigger
,
1966 perform the receive side of a async dcerpc request
1968 static NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
1969 TALLOC_CTX
*mem_ctx
,
1970 DATA_BLOB
*stub_data
)
1974 while (req
->state
!= RPC_REQUEST_DONE
) {
1975 struct tevent_context
*ctx
= req
->p
->conn
->event_ctx
;
1976 if (tevent_loop_once(ctx
) != 0) {
1977 return NT_STATUS_CONNECTION_DISCONNECTED
;
1980 *stub_data
= req
->payload
;
1981 status
= req
->status
;
1982 if (stub_data
->data
) {
1983 stub_data
->data
= talloc_steal(mem_ctx
, stub_data
->data
);
1985 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
1986 req
->p
->last_fault_code
= req
->fault_code
;
1988 talloc_unlink(talloc_parent(req
), req
);
1993 this is a paranoid NDR validator. For every packet we push onto the wire
1994 we pull it back again, then push it again. Then we compare the raw NDR data
1995 for that to the NDR we initially generated. If they don't match then we know
1996 we must have a bug in either the pull or push side of our code
1998 static NTSTATUS
dcerpc_ndr_validate_in(struct dcecli_connection
*c
,
1999 TALLOC_CTX
*mem_ctx
,
2002 ndr_push_flags_fn_t ndr_push
,
2003 ndr_pull_flags_fn_t ndr_pull
)
2006 struct ndr_pull
*pull
;
2007 struct ndr_push
*push
;
2009 enum ndr_err_code ndr_err
;
2011 st
= talloc_size(mem_ctx
, struct_size
);
2013 return NT_STATUS_NO_MEMORY
;
2016 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
2018 return NT_STATUS_NO_MEMORY
;
2020 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
2022 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
2023 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
2026 if (c
->flags
& DCERPC_NDR64
) {
2027 pull
->flags
|= LIBNDR_FLAG_NDR64
;
2030 ndr_err
= ndr_pull(pull
, NDR_IN
, st
);
2031 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2032 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
2033 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
2034 "failed input validation pull - %s",
2036 return ndr_map_error2ntstatus(ndr_err
);
2039 push
= ndr_push_init_ctx(mem_ctx
);
2041 return NT_STATUS_NO_MEMORY
;
2044 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
2045 push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
2048 if (c
->flags
& DCERPC_NDR64
) {
2049 push
->flags
|= LIBNDR_FLAG_NDR64
;
2052 ndr_err
= ndr_push(push
, NDR_IN
, st
);
2053 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2054 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
2055 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
2056 "failed input validation push - %s",
2058 return ndr_map_error2ntstatus(ndr_err
);
2061 blob2
= ndr_push_blob(push
);
2063 if (data_blob_cmp(&blob
, &blob2
) != 0) {
2064 DEBUG(3,("original:\n"));
2065 dump_data(3, blob
.data
, blob
.length
);
2066 DEBUG(3,("secondary:\n"));
2067 dump_data(3, blob2
.data
, blob2
.length
);
2068 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
2069 "failed input validation blobs doesn't match");
2070 return ndr_map_error2ntstatus(ndr_err
);
2073 return NT_STATUS_OK
;
2077 this is a paranoid NDR input validator. For every packet we pull
2078 from the wire we push it back again then pull and push it
2079 again. Then we compare the raw NDR data for that to the NDR we
2080 initially generated. If they don't match then we know we must have a
2081 bug in either the pull or push side of our code
2083 static NTSTATUS
dcerpc_ndr_validate_out(struct dcecli_connection
*c
,
2084 struct ndr_pull
*pull_in
,
2087 ndr_push_flags_fn_t ndr_push
,
2088 ndr_pull_flags_fn_t ndr_pull
,
2089 ndr_print_function_t ndr_print
)
2092 struct ndr_pull
*pull
;
2093 struct ndr_push
*push
;
2094 DATA_BLOB blob
, blob2
;
2095 TALLOC_CTX
*mem_ctx
= pull_in
;
2097 enum ndr_err_code ndr_err
;
2099 st
= talloc_size(mem_ctx
, struct_size
);
2101 return NT_STATUS_NO_MEMORY
;
2103 memcpy(st
, struct_ptr
, struct_size
);
2105 push
= ndr_push_init_ctx(mem_ctx
);
2107 return NT_STATUS_NO_MEMORY
;
2110 ndr_err
= ndr_push(push
, NDR_OUT
, struct_ptr
);
2111 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2112 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
2113 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
2114 "failed output validation push - %s",
2116 return ndr_map_error2ntstatus(ndr_err
);
2119 blob
= ndr_push_blob(push
);
2121 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
2123 return NT_STATUS_NO_MEMORY
;
2126 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
2127 ndr_err
= ndr_pull(pull
, NDR_OUT
, st
);
2128 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2129 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
2130 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
2131 "failed output validation pull - %s",
2133 return ndr_map_error2ntstatus(ndr_err
);
2136 push
= ndr_push_init_ctx(mem_ctx
);
2138 return NT_STATUS_NO_MEMORY
;
2141 ndr_err
= ndr_push(push
, NDR_OUT
, st
);
2142 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2143 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
2144 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
2145 "failed output validation push2 - %s",
2147 return ndr_map_error2ntstatus(ndr_err
);
2150 blob2
= ndr_push_blob(push
);
2152 if (data_blob_cmp(&blob
, &blob2
) != 0) {
2153 DEBUG(3,("original:\n"));
2154 dump_data(3, blob
.data
, blob
.length
);
2155 DEBUG(3,("secondary:\n"));
2156 dump_data(3, blob2
.data
, blob2
.length
);
2157 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
2158 "failed output validation blobs doesn't match");
2159 return ndr_map_error2ntstatus(ndr_err
);
2162 /* this checks the printed forms of the two structures, which effectively
2163 tests all of the value() attributes */
2164 s1
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
2165 NDR_OUT
, struct_ptr
);
2166 s2
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
2168 if (strcmp(s1
, s2
) != 0) {
2170 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1
, s2
));
2172 /* this is sometimes useful */
2173 printf("VALIDATE ERROR\n");
2174 file_save("wire.dat", s1
, strlen(s1
));
2175 file_save("gen.dat", s2
, strlen(s2
));
2176 system("diff -u wire.dat gen.dat");
2178 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
2179 "failed output validation strings doesn't match");
2180 return ndr_map_error2ntstatus(ndr_err
);
2183 return NT_STATUS_OK
;
2187 a useful function for retrieving the server name we connected to
2189 _PUBLIC_
const char *dcerpc_server_name(struct dcerpc_pipe
*p
)
2191 return p
->conn
? p
->conn
->server_name
: NULL
;
2196 get the dcerpc auth_level for a open connection
2198 uint32_t dcerpc_auth_level(struct dcecli_connection
*c
)
2202 if (c
->flags
& DCERPC_SEAL
) {
2203 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
2204 } else if (c
->flags
& DCERPC_SIGN
) {
2205 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
2206 } else if (c
->flags
& DCERPC_CONNECT
) {
2207 auth_level
= DCERPC_AUTH_LEVEL_CONNECT
;
2209 auth_level
= DCERPC_AUTH_LEVEL_NONE
;
2214 struct dcerpc_alter_context_state
{
2215 struct tevent_context
*ev
;
2216 struct dcerpc_pipe
*p
;
2219 static void dcerpc_alter_context_fail_handler(struct rpc_request
*subreq
);
2220 static void dcerpc_alter_context_recv_handler(struct rpc_request
*req
,
2221 DATA_BLOB
*raw_packet
,
2222 struct ncacn_packet
*pkt
);
2224 struct tevent_req
*dcerpc_alter_context_send(TALLOC_CTX
*mem_ctx
,
2225 struct tevent_context
*ev
,
2226 struct dcerpc_pipe
*p
,
2227 const struct ndr_syntax_id
*syntax
,
2228 const struct ndr_syntax_id
*transfer_syntax
)
2230 struct tevent_req
*req
;
2231 struct dcerpc_alter_context_state
*state
;
2232 struct ncacn_packet pkt
;
2235 struct rpc_request
*subreq
;
2238 req
= tevent_req_create(mem_ctx
, &state
,
2239 struct dcerpc_alter_context_state
);
2247 p
->syntax
= *syntax
;
2248 p
->transfer_syntax
= *transfer_syntax
;
2250 flags
= dcerpc_binding_get_flags(p
->binding
);
2252 init_ncacn_hdr(p
->conn
, &pkt
);
2254 pkt
.ptype
= DCERPC_PKT_ALTER
;
2255 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
2256 pkt
.call_id
= p
->conn
->call_id
;
2257 pkt
.auth_length
= 0;
2259 if (flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
2260 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
2263 pkt
.u
.alter
.max_xmit_frag
= p
->conn
->srv_max_xmit_frag
;
2264 pkt
.u
.alter
.max_recv_frag
= p
->conn
->srv_max_recv_frag
;
2265 pkt
.u
.alter
.assoc_group_id
= dcerpc_binding_get_assoc_group_id(p
->binding
);
2266 pkt
.u
.alter
.num_contexts
= 1;
2267 pkt
.u
.alter
.ctx_list
= talloc_array(state
, struct dcerpc_ctx_list
, 1);
2268 if (tevent_req_nomem(pkt
.u
.alter
.ctx_list
, req
)) {
2269 return tevent_req_post(req
, ev
);
2271 pkt
.u
.alter
.ctx_list
[0].context_id
= p
->context_id
;
2272 pkt
.u
.alter
.ctx_list
[0].num_transfer_syntaxes
= 1;
2273 pkt
.u
.alter
.ctx_list
[0].abstract_syntax
= p
->syntax
;
2274 pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
2275 pkt
.u
.alter
.auth_info
= data_blob(NULL
, 0);
2277 /* construct the NDR form of the packet */
2278 status
= ncacn_push_auth(&blob
, state
, &pkt
,
2279 p
->conn
->security_state
.tmp_auth_info
.out
);
2280 if (tevent_req_nterror(req
, status
)) {
2281 return tevent_req_post(req
, ev
);
2285 * we allocate a dcerpc_request so we can be in the same
2286 * request queue as normal requests
2288 subreq
= talloc_zero(state
, struct rpc_request
);
2289 if (tevent_req_nomem(subreq
, req
)) {
2290 return tevent_req_post(req
, ev
);
2293 subreq
->state
= RPC_REQUEST_PENDING
;
2294 subreq
->call_id
= pkt
.call_id
;
2295 subreq
->async
.private_data
= req
;
2296 subreq
->async
.callback
= dcerpc_alter_context_fail_handler
;
2298 subreq
->recv_handler
= dcerpc_alter_context_recv_handler
;
2299 DLIST_ADD_END(p
->conn
->pending
, subreq
, struct rpc_request
*);
2300 talloc_set_destructor(subreq
, dcerpc_req_dequeue
);
2302 status
= dcerpc_send_request(p
->conn
, &blob
, true);
2303 if (tevent_req_nterror(req
, status
)) {
2304 return tevent_req_post(req
, ev
);
2307 tevent_add_timer(ev
, subreq
,
2308 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
2309 dcerpc_timeout_handler
, subreq
);
2314 static void dcerpc_alter_context_fail_handler(struct rpc_request
*subreq
)
2316 struct tevent_req
*req
=
2317 talloc_get_type_abort(subreq
->async
.private_data
,
2319 struct dcerpc_alter_context_state
*state
=
2320 tevent_req_data(req
,
2321 struct dcerpc_alter_context_state
);
2322 NTSTATUS status
= subreq
->status
;
2324 TALLOC_FREE(subreq
);
2327 * We trigger the callback in the next event run
2328 * because the code in this file might trigger
2329 * multiple request callbacks from within a single
2332 * In order to avoid segfaults from within
2333 * dcerpc_connection_dead() we call
2334 * tevent_req_defer_callback().
2336 tevent_req_defer_callback(req
, state
->ev
);
2338 tevent_req_nterror(req
, status
);
2341 static void dcerpc_alter_context_recv_handler(struct rpc_request
*subreq
,
2342 DATA_BLOB
*raw_packet
,
2343 struct ncacn_packet
*pkt
)
2345 struct tevent_req
*req
=
2346 talloc_get_type_abort(subreq
->async
.private_data
,
2348 struct dcerpc_alter_context_state
*state
=
2349 tevent_req_data(req
,
2350 struct dcerpc_alter_context_state
);
2351 struct dcecli_connection
*conn
= state
->p
->conn
;
2352 struct dcecli_security
*sec
= &conn
->security_state
;
2356 * Note that pkt is allocated under raw_packet->data,
2357 * while raw_packet->data is a child of subreq.
2359 talloc_steal(state
, raw_packet
->data
);
2360 TALLOC_FREE(subreq
);
2363 * We trigger the callback in the next event run
2364 * because the code in this file might trigger
2365 * multiple request callbacks from within a single
2368 * In order to avoid segfaults from within
2369 * dcerpc_connection_dead() we call
2370 * tevent_req_defer_callback().
2372 tevent_req_defer_callback(req
, state
->ev
);
2374 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
2375 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2376 dcerpc_errstr(state
, pkt
->u
.fault
.status
)));
2377 if (pkt
->u
.fault
.status
== DCERPC_FAULT_ACCESS_DENIED
) {
2378 state
->p
->last_fault_code
= pkt
->u
.fault
.status
;
2379 tevent_req_nterror(req
, NT_STATUS_LOGON_FAILURE
);
2380 } else if (pkt
->u
.fault
.status
== DCERPC_FAULT_SEC_PKG_ERROR
) {
2381 state
->p
->last_fault_code
= pkt
->u
.fault
.status
;
2382 tevent_req_nterror(req
, NT_STATUS_LOGON_FAILURE
);
2384 state
->p
->last_fault_code
= pkt
->u
.fault
.status
;
2385 status
= dcerpc_fault_to_nt_status(pkt
->u
.fault
.status
);
2386 tevent_req_nterror(req
, status
);
2391 status
= dcerpc_verify_ncacn_packet_header(pkt
,
2392 DCERPC_PKT_ALTER_RESP
,
2393 pkt
->u
.alter_resp
.auth_info
.length
,
2394 DCERPC_PFC_FLAG_FIRST
|
2395 DCERPC_PFC_FLAG_LAST
,
2396 DCERPC_PFC_FLAG_CONC_MPX
|
2397 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
);
2398 if (!NT_STATUS_IS_OK(status
)) {
2399 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
2400 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
2404 if (pkt
->u
.alter_resp
.num_results
!= 1) {
2405 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
2406 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
2410 if (pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
2411 status
= dcerpc_map_ack_reason(&pkt
->u
.alter_resp
.ctx_list
[0]);
2412 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2413 pkt
->u
.alter_resp
.ctx_list
[0].reason
.value
,
2414 nt_errstr(status
)));
2415 tevent_req_nterror(req
, status
);
2419 /* the alter_resp might contain a reply set of credentials */
2420 if (pkt
->auth_length
!= 0 && sec
->tmp_auth_info
.in
!= NULL
) {
2421 uint32_t auth_length
;
2423 status
= dcerpc_pull_auth_trailer(pkt
, sec
->tmp_auth_info
.mem
,
2424 &pkt
->u
.alter_resp
.auth_info
,
2425 sec
->tmp_auth_info
.in
,
2426 &auth_length
, true);
2427 if (tevent_req_nterror(req
, status
)) {
2432 tevent_req_done(req
);
2435 NTSTATUS
dcerpc_alter_context_recv(struct tevent_req
*req
)
2437 return tevent_req_simple_recv_ntstatus(req
);
2441 send a dcerpc alter_context request
2443 _PUBLIC_ NTSTATUS
dcerpc_alter_context(struct dcerpc_pipe
*p
,
2444 TALLOC_CTX
*mem_ctx
,
2445 const struct ndr_syntax_id
*syntax
,
2446 const struct ndr_syntax_id
*transfer_syntax
)
2448 struct tevent_req
*subreq
;
2449 struct tevent_context
*ev
= p
->conn
->event_ctx
;
2452 /* TODO: create a new event context here */
2454 subreq
= dcerpc_alter_context_send(mem_ctx
, ev
,
2455 p
, syntax
, transfer_syntax
);
2456 if (subreq
== NULL
) {
2457 return NT_STATUS_NO_MEMORY
;
2460 ok
= tevent_req_poll(subreq
, ev
);
2463 status
= map_nt_error_from_unix_common(errno
);
2467 return dcerpc_alter_context_recv(subreq
);
2470 static void dcerpc_transport_dead(struct dcecli_connection
*c
, NTSTATUS status
)
2472 if (c
->transport
.stream
== NULL
) {
2476 tevent_queue_stop(c
->transport
.write_queue
);
2477 TALLOC_FREE(c
->transport
.read_subreq
);
2478 TALLOC_FREE(c
->transport
.stream
);
2480 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL
, status
)) {
2481 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
2484 if (NT_STATUS_EQUAL(NT_STATUS_OK
, status
)) {
2485 status
= NT_STATUS_END_OF_FILE
;
2488 dcerpc_recv_data(c
, NULL
, status
);
2493 shutdown SMB pipe connection
2495 struct dcerpc_shutdown_pipe_state
{
2496 struct dcecli_connection
*c
;
2500 static void dcerpc_shutdown_pipe_done(struct tevent_req
*subreq
);
2502 static NTSTATUS
dcerpc_shutdown_pipe(struct dcecli_connection
*c
, NTSTATUS status
)
2504 struct dcerpc_shutdown_pipe_state
*state
;
2505 struct tevent_req
*subreq
;
2507 if (c
->transport
.stream
== NULL
) {
2508 return NT_STATUS_OK
;
2511 state
= talloc_zero(c
, struct dcerpc_shutdown_pipe_state
);
2512 if (state
== NULL
) {
2513 return NT_STATUS_NO_MEMORY
;
2516 state
->status
= status
;
2518 subreq
= tstream_disconnect_send(state
, c
->event_ctx
, c
->transport
.stream
);
2519 if (subreq
== NULL
) {
2520 return NT_STATUS_NO_MEMORY
;
2522 tevent_req_set_callback(subreq
, dcerpc_shutdown_pipe_done
, state
);
2527 static void dcerpc_shutdown_pipe_done(struct tevent_req
*subreq
)
2529 struct dcerpc_shutdown_pipe_state
*state
=
2530 tevent_req_callback_data(subreq
, struct dcerpc_shutdown_pipe_state
);
2531 struct dcecli_connection
*c
= state
->c
;
2532 NTSTATUS status
= state
->status
;
2536 * here we ignore the return values...
2538 tstream_disconnect_recv(subreq
, &error
);
2539 TALLOC_FREE(subreq
);
2543 dcerpc_transport_dead(c
, status
);
2548 struct dcerpc_send_read_state
{
2549 struct dcecli_connection
*p
;
2552 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state
*state
)
2554 struct dcecli_connection
*p
= state
->p
;
2556 p
->transport
.read_subreq
= NULL
;
2561 static void dcerpc_send_read_done(struct tevent_req
*subreq
);
2563 static NTSTATUS
dcerpc_send_read(struct dcecli_connection
*p
)
2565 struct dcerpc_send_read_state
*state
;
2567 if (p
->transport
.read_subreq
!= NULL
) {
2568 p
->transport
.pending_reads
++;
2569 return NT_STATUS_OK
;
2572 state
= talloc_zero(p
, struct dcerpc_send_read_state
);
2573 if (state
== NULL
) {
2574 return NT_STATUS_NO_MEMORY
;
2578 talloc_set_destructor(state
, dcerpc_send_read_state_destructor
);
2580 p
->transport
.read_subreq
= dcerpc_read_ncacn_packet_send(state
,
2582 p
->transport
.stream
);
2583 if (p
->transport
.read_subreq
== NULL
) {
2584 return NT_STATUS_NO_MEMORY
;
2586 tevent_req_set_callback(p
->transport
.read_subreq
, dcerpc_send_read_done
, state
);
2588 return NT_STATUS_OK
;
2591 static void dcerpc_send_read_done(struct tevent_req
*subreq
)
2593 struct dcerpc_send_read_state
*state
=
2594 tevent_req_callback_data(subreq
,
2595 struct dcerpc_send_read_state
);
2596 struct dcecli_connection
*p
= state
->p
;
2598 struct ncacn_packet
*pkt
;
2601 status
= dcerpc_read_ncacn_packet_recv(subreq
, state
,
2603 TALLOC_FREE(subreq
);
2604 if (!NT_STATUS_IS_OK(status
)) {
2606 dcerpc_transport_dead(p
, status
);
2611 * here we steal into thet connection context,
2612 * but p->transport.recv_data() will steal or free it again
2614 talloc_steal(p
, blob
.data
);
2617 if (p
->transport
.pending_reads
> 0) {
2618 p
->transport
.pending_reads
--;
2620 status
= dcerpc_send_read(p
);
2621 if (!NT_STATUS_IS_OK(status
)) {
2622 dcerpc_transport_dead(p
, status
);
2627 dcerpc_recv_data(p
, &blob
, NT_STATUS_OK
);
2630 struct dcerpc_send_request_state
{
2631 struct dcecli_connection
*p
;
2636 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state
*state
)
2638 struct dcecli_connection
*p
= state
->p
;
2640 p
->transport
.read_subreq
= NULL
;
2645 static void dcerpc_send_request_wait_done(struct tevent_req
*subreq
);
2646 static void dcerpc_send_request_done(struct tevent_req
*subreq
);
2648 static NTSTATUS
dcerpc_send_request(struct dcecli_connection
*p
, DATA_BLOB
*data
,
2651 struct dcerpc_send_request_state
*state
;
2652 struct tevent_req
*subreq
;
2653 bool use_trans
= trigger_read
;
2655 if (p
->transport
.stream
== NULL
) {
2656 return NT_STATUS_CONNECTION_DISCONNECTED
;
2659 state
= talloc_zero(p
, struct dcerpc_send_request_state
);
2660 if (state
== NULL
) {
2661 return NT_STATUS_NO_MEMORY
;
2665 state
->blob
= data_blob_talloc(state
, data
->data
, data
->length
);
2666 if (state
->blob
.data
== NULL
) {
2668 return NT_STATUS_NO_MEMORY
;
2670 state
->iov
.iov_base
= (void *)state
->blob
.data
;
2671 state
->iov
.iov_len
= state
->blob
.length
;
2673 if (p
->transport
.read_subreq
!= NULL
) {
2677 if (!tstream_is_smbXcli_np(p
->transport
.stream
)) {
2683 * we need to block reads until our write is
2684 * the next in the write queue.
2686 p
->transport
.read_subreq
= tevent_queue_wait_send(state
, p
->event_ctx
,
2687 p
->transport
.write_queue
);
2688 if (p
->transport
.read_subreq
== NULL
) {
2690 return NT_STATUS_NO_MEMORY
;
2692 tevent_req_set_callback(p
->transport
.read_subreq
,
2693 dcerpc_send_request_wait_done
,
2696 talloc_set_destructor(state
, dcerpc_send_request_state_destructor
);
2698 trigger_read
= false;
2701 subreq
= tstream_writev_queue_send(state
, p
->event_ctx
,
2702 p
->transport
.stream
,
2703 p
->transport
.write_queue
,
2705 if (subreq
== NULL
) {
2707 return NT_STATUS_NO_MEMORY
;
2709 tevent_req_set_callback(subreq
, dcerpc_send_request_done
, state
);
2712 dcerpc_send_read(p
);
2715 return NT_STATUS_OK
;
2718 static void dcerpc_send_request_wait_done(struct tevent_req
*subreq
)
2720 struct dcerpc_send_request_state
*state
=
2721 tevent_req_callback_data(subreq
,
2722 struct dcerpc_send_request_state
);
2723 struct dcecli_connection
*p
= state
->p
;
2727 p
->transport
.read_subreq
= NULL
;
2728 talloc_set_destructor(state
, NULL
);
2730 ok
= tevent_queue_wait_recv(subreq
);
2733 dcerpc_transport_dead(p
, NT_STATUS_NO_MEMORY
);
2737 if (tevent_queue_length(p
->transport
.write_queue
) <= 2) {
2738 status
= tstream_smbXcli_np_use_trans(p
->transport
.stream
);
2739 if (!NT_STATUS_IS_OK(status
)) {
2741 dcerpc_transport_dead(p
, status
);
2746 /* we free subreq after tstream_cli_np_use_trans */
2747 TALLOC_FREE(subreq
);
2749 dcerpc_send_read(p
);
2752 static void dcerpc_send_request_done(struct tevent_req
*subreq
)
2754 struct dcerpc_send_request_state
*state
=
2755 tevent_req_callback_data(subreq
,
2756 struct dcerpc_send_request_state
);
2760 ret
= tstream_writev_queue_recv(subreq
, &error
);
2761 TALLOC_FREE(subreq
);
2763 struct dcecli_connection
*p
= state
->p
;
2764 NTSTATUS status
= map_nt_error_from_unix_common(error
);
2767 dcerpc_transport_dead(p
, status
);