2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.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"
36 enum rpc_request_state
{
43 handle for an async dcerpc request
46 struct rpc_request
*next
, *prev
;
47 struct dcerpc_pipe
*p
;
50 enum rpc_request_state state
;
55 /* this is used to distinguish bind and alter_context requests
56 from normal requests */
57 void (*recv_handler
)(struct rpc_request
*conn
,
58 DATA_BLOB
*blob
, struct ncacn_packet
*pkt
);
60 const struct GUID
*object
;
62 DATA_BLOB request_data
;
65 /* use by the ndr level async recv call */
67 const struct ndr_interface_table
*table
;
74 void (*callback
)(struct rpc_request
*);
79 _PUBLIC_ NTSTATUS
dcerpc_init(void)
84 static void dcerpc_connection_dead(struct dcecli_connection
*conn
, NTSTATUS status
);
85 static void dcerpc_ship_next_request(struct dcecli_connection
*c
);
87 static struct rpc_request
*dcerpc_request_send(struct dcerpc_pipe
*p
,
88 const struct GUID
*object
,
90 DATA_BLOB
*stub_data
);
91 static NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
93 DATA_BLOB
*stub_data
);
94 static NTSTATUS
dcerpc_ndr_validate_in(struct dcecli_connection
*c
,
98 ndr_push_flags_fn_t ndr_push
,
99 ndr_pull_flags_fn_t ndr_pull
);
100 static NTSTATUS
dcerpc_ndr_validate_out(struct dcecli_connection
*c
,
101 struct ndr_pull
*pull_in
,
104 ndr_push_flags_fn_t ndr_push
,
105 ndr_pull_flags_fn_t ndr_pull
,
106 ndr_print_function_t ndr_print
);
108 /* destroy a dcerpc connection */
109 static int dcerpc_connection_destructor(struct dcecli_connection
*conn
)
112 conn
->free_skipped
= true;
115 dcerpc_connection_dead(conn
, NT_STATUS_LOCAL_DISCONNECT
);
120 /* initialise a dcerpc connection.
121 the event context is optional
123 static struct dcecli_connection
*dcerpc_connection_init(TALLOC_CTX
*mem_ctx
,
124 struct tevent_context
*ev
)
126 struct dcecli_connection
*c
;
128 c
= talloc_zero(mem_ctx
, struct dcecli_connection
);
135 if (c
->event_ctx
== NULL
) {
141 c
->security_state
.auth_info
= NULL
;
142 c
->security_state
.session_key
= dcerpc_generic_session_key
;
143 c
->security_state
.generic_state
= NULL
;
144 c
->binding_string
= NULL
;
146 c
->srv_max_xmit_frag
= 0;
147 c
->srv_max_recv_frag
= 0;
150 talloc_set_destructor(c
, dcerpc_connection_destructor
);
155 struct dcerpc_bh_state
{
156 struct dcerpc_pipe
*p
;
159 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle
*h
)
161 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
162 struct dcerpc_bh_state
);
171 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle
*h
,
174 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
175 struct dcerpc_bh_state
);
179 return DCERPC_REQUEST_TIMEOUT
;
182 old
= hs
->p
->request_timeout
;
183 hs
->p
->request_timeout
= timeout
;
188 struct dcerpc_bh_raw_call_state
{
189 struct dcerpc_binding_handle
*h
;
195 static void dcerpc_bh_raw_call_done(struct rpc_request
*subreq
);
197 static struct tevent_req
*dcerpc_bh_raw_call_send(TALLOC_CTX
*mem_ctx
,
198 struct tevent_context
*ev
,
199 struct dcerpc_binding_handle
*h
,
200 const struct GUID
*object
,
203 const uint8_t *in_data
,
206 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
207 struct dcerpc_bh_state
);
208 struct tevent_req
*req
;
209 struct dcerpc_bh_raw_call_state
*state
;
211 struct rpc_request
*subreq
;
213 req
= tevent_req_create(mem_ctx
, &state
,
214 struct dcerpc_bh_raw_call_state
);
219 state
->in_data
.data
= discard_const_p(uint8_t, in_data
);
220 state
->in_data
.length
= in_length
;
222 ok
= dcerpc_bh_is_connected(h
);
224 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
225 return tevent_req_post(req
, ev
);
228 subreq
= dcerpc_request_send(hs
->p
,
232 if (tevent_req_nomem(subreq
, req
)) {
233 return tevent_req_post(req
, ev
);
235 subreq
->async
.callback
= dcerpc_bh_raw_call_done
;
236 subreq
->async
.private_data
= req
;
241 static void dcerpc_bh_raw_call_done(struct rpc_request
*subreq
)
243 struct tevent_req
*req
=
244 talloc_get_type_abort(subreq
->async
.private_data
,
246 struct dcerpc_bh_raw_call_state
*state
=
248 struct dcerpc_bh_raw_call_state
);
252 state
->out_flags
= 0;
253 if (subreq
->flags
& DCERPC_PULL_BIGENDIAN
) {
254 state
->out_flags
|= LIBNDR_FLAG_BIGENDIAN
;
257 fault_code
= subreq
->fault_code
;
259 status
= dcerpc_request_recv(subreq
, state
, &state
->out_data
);
260 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
261 status
= dcerpc_fault_to_nt_status(fault_code
);
263 if (!NT_STATUS_IS_OK(status
)) {
264 tevent_req_nterror(req
, status
);
268 tevent_req_done(req
);
271 static NTSTATUS
dcerpc_bh_raw_call_recv(struct tevent_req
*req
,
277 struct dcerpc_bh_raw_call_state
*state
=
279 struct dcerpc_bh_raw_call_state
);
282 if (tevent_req_is_nterror(req
, &status
)) {
283 tevent_req_received(req
);
287 *out_data
= talloc_move(mem_ctx
, &state
->out_data
.data
);
288 *out_length
= state
->out_data
.length
;
289 *out_flags
= state
->out_flags
;
290 tevent_req_received(req
);
294 struct dcerpc_bh_disconnect_state
{
298 static struct tevent_req
*dcerpc_bh_disconnect_send(TALLOC_CTX
*mem_ctx
,
299 struct tevent_context
*ev
,
300 struct dcerpc_binding_handle
*h
)
302 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
303 struct dcerpc_bh_state
);
304 struct tevent_req
*req
;
305 struct dcerpc_bh_disconnect_state
*state
;
308 req
= tevent_req_create(mem_ctx
, &state
,
309 struct dcerpc_bh_disconnect_state
);
314 ok
= dcerpc_bh_is_connected(h
);
316 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
317 return tevent_req_post(req
, ev
);
320 /* TODO: do a real disconnect ... */
323 tevent_req_done(req
);
324 return tevent_req_post(req
, ev
);
327 static NTSTATUS
dcerpc_bh_disconnect_recv(struct tevent_req
*req
)
331 if (tevent_req_is_nterror(req
, &status
)) {
332 tevent_req_received(req
);
336 tevent_req_received(req
);
340 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle
*h
)
342 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
343 struct dcerpc_bh_state
);
345 if (hs
->p
->conn
->flags
& DCERPC_PUSH_BIGENDIAN
) {
352 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle
*h
)
354 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
355 struct dcerpc_bh_state
);
357 if (hs
->p
->conn
->flags
& DCERPC_NDR_REF_ALLOC
) {
364 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle
*h
)
366 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
367 struct dcerpc_bh_state
);
369 if (hs
->p
->conn
->flags
& DCERPC_NDR64
) {
376 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle
*h
,
378 const void *_struct_ptr
,
379 const struct ndr_interface_call
*call
)
381 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
382 struct dcerpc_bh_state
);
383 void *struct_ptr
= discard_const(_struct_ptr
);
385 if (ndr_flags
& NDR_IN
) {
386 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_PRINT_IN
) {
387 ndr_print_function_debug(call
->ndr_print
,
393 if (ndr_flags
& NDR_OUT
) {
394 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_PRINT_OUT
) {
395 ndr_print_function_debug(call
->ndr_print
,
403 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle
*h
,
405 const void *struct_ptr
,
406 const struct ndr_interface_call
*call
)
408 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
409 call
->name
, nt_errstr(error
)));
412 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle
*h
,
414 const DATA_BLOB
*blob
,
415 const struct ndr_interface_call
*call
)
417 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
418 struct dcerpc_bh_state
);
419 const uint32_t num_examples
= 20;
422 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
423 call
->name
, nt_errstr(error
)));
425 if (hs
->p
->conn
->packet_log_dir
== NULL
) return;
427 for (i
=0;i
<num_examples
;i
++) {
429 asprintf(&name
, "%s/rpclog/%s-out.%d",
430 hs
->p
->conn
->packet_log_dir
,
435 if (!file_exist(name
)) {
436 if (file_save(name
, blob
->data
, blob
->length
)) {
437 DEBUG(10,("Logged rpc packet to %s\n", name
));
446 static NTSTATUS
dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle
*h
,
448 const DATA_BLOB
*blob
,
449 const struct ndr_interface_call
*call
)
451 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
452 struct dcerpc_bh_state
);
454 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_IN
) {
457 status
= dcerpc_ndr_validate_in(hs
->p
->conn
,
463 if (!NT_STATUS_IS_OK(status
)) {
464 DEBUG(0,("Validation [in] failed for %s - %s\n",
465 call
->name
, nt_errstr(status
)));
470 DEBUG(10,("rpc request data:\n"));
471 dump_data(10, blob
->data
, blob
->length
);
476 static NTSTATUS
dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle
*h
,
477 struct ndr_pull
*pull_in
,
478 const void *_struct_ptr
,
479 const struct ndr_interface_call
*call
)
481 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
482 struct dcerpc_bh_state
);
483 void *struct_ptr
= discard_const(_struct_ptr
);
485 DEBUG(10,("rpc reply data:\n"));
486 dump_data(10, pull_in
->data
, pull_in
->data_size
);
488 if (pull_in
->offset
!= pull_in
->data_size
) {
489 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
490 pull_in
->data_size
- pull_in
->offset
,
491 pull_in
->offset
, pull_in
->offset
,
493 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
494 but it turns out that early versions of NT
495 (specifically NT3.1) add junk onto the end of rpc
496 packets, so if we want to interoperate at all with
497 those versions then we need to ignore this error */
500 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_OUT
) {
503 status
= dcerpc_ndr_validate_out(hs
->p
->conn
,
510 if (!NT_STATUS_IS_OK(status
)) {
511 DEBUG(2,("Validation [out] failed for %s - %s\n",
512 call
->name
, nt_errstr(status
)));
520 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops
= {
522 .is_connected
= dcerpc_bh_is_connected
,
523 .set_timeout
= dcerpc_bh_set_timeout
,
524 .raw_call_send
= dcerpc_bh_raw_call_send
,
525 .raw_call_recv
= dcerpc_bh_raw_call_recv
,
526 .disconnect_send
= dcerpc_bh_disconnect_send
,
527 .disconnect_recv
= dcerpc_bh_disconnect_recv
,
529 .push_bigendian
= dcerpc_bh_push_bigendian
,
530 .ref_alloc
= dcerpc_bh_ref_alloc
,
531 .use_ndr64
= dcerpc_bh_use_ndr64
,
532 .do_ndr_print
= dcerpc_bh_do_ndr_print
,
533 .ndr_push_failed
= dcerpc_bh_ndr_push_failed
,
534 .ndr_pull_failed
= dcerpc_bh_ndr_pull_failed
,
535 .ndr_validate_in
= dcerpc_bh_ndr_validate_in
,
536 .ndr_validate_out
= dcerpc_bh_ndr_validate_out
,
539 /* initialise a dcerpc pipe. */
540 struct dcerpc_binding_handle
*dcerpc_pipe_binding_handle(struct dcerpc_pipe
*p
)
542 struct dcerpc_binding_handle
*h
;
543 struct dcerpc_bh_state
*hs
;
545 h
= dcerpc_binding_handle_create(p
,
550 struct dcerpc_bh_state
,
557 dcerpc_binding_handle_set_sync_ev(h
, p
->conn
->event_ctx
);
562 /* initialise a dcerpc pipe. */
563 _PUBLIC_
struct dcerpc_pipe
*dcerpc_pipe_init(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
)
565 struct dcerpc_pipe
*p
;
567 p
= talloc_zero(mem_ctx
, struct dcerpc_pipe
);
572 p
->conn
= dcerpc_connection_init(p
, ev
);
573 if (p
->conn
== NULL
) {
578 p
->last_fault_code
= 0;
580 p
->request_timeout
= DCERPC_REQUEST_TIMEOUT
;
583 ZERO_STRUCT(p
->syntax
);
584 ZERO_STRUCT(p
->transfer_syntax
);
587 p
->conn
->flags
|= DCERPC_DEBUG_PRINT_BOTH
;
590 p
->binding_handle
= dcerpc_pipe_binding_handle(p
);
591 if (p
->binding_handle
== NULL
) {
601 choose the next call id to use
603 static uint32_t next_call_id(struct dcecli_connection
*c
)
606 if (c
->call_id
== 0) {
613 setup for a ndr pull, also setting up any flags from the binding string
615 static struct ndr_pull
*ndr_pull_init_flags(struct dcecli_connection
*c
,
616 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
618 struct ndr_pull
*ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
620 if (ndr
== NULL
) return ndr
;
622 if (c
->flags
& DCERPC_DEBUG_PAD_CHECK
) {
623 ndr
->flags
|= LIBNDR_FLAG_PAD_CHECK
;
626 if (c
->flags
& DCERPC_NDR_REF_ALLOC
) {
627 ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
630 if (c
->flags
& DCERPC_NDR64
) {
631 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
638 parse a data blob into a ncacn_packet structure. This handles both
639 input and output packets
641 static NTSTATUS
ncacn_pull(struct dcecli_connection
*c
, DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
642 struct ncacn_packet
*pkt
)
644 struct ndr_pull
*ndr
;
645 enum ndr_err_code ndr_err
;
647 ndr
= ndr_pull_init_flags(c
, blob
, mem_ctx
);
649 return NT_STATUS_NO_MEMORY
;
652 if (! (CVAL(blob
->data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
653 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
656 ndr_err
= ndr_pull_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
657 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
658 return ndr_map_error2ntstatus(ndr_err
);
665 parse the authentication information on a dcerpc response packet
667 static NTSTATUS
ncacn_pull_request_auth(struct dcecli_connection
*c
, TALLOC_CTX
*mem_ctx
,
668 DATA_BLOB
*raw_packet
,
669 struct ncacn_packet
*pkt
)
672 struct dcerpc_auth auth
;
673 uint32_t auth_length
;
675 if (!c
->security_state
.auth_info
||
676 !c
->security_state
.generic_state
) {
680 switch (c
->security_state
.auth_info
->auth_level
) {
681 case DCERPC_AUTH_LEVEL_PRIVACY
:
682 case DCERPC_AUTH_LEVEL_INTEGRITY
:
685 case DCERPC_AUTH_LEVEL_CONNECT
:
686 if (pkt
->auth_length
!= 0) {
690 case DCERPC_AUTH_LEVEL_NONE
:
691 if (pkt
->auth_length
!= 0) {
692 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
697 return NT_STATUS_INVALID_LEVEL
;
700 status
= dcerpc_pull_auth_trailer(pkt
, mem_ctx
,
701 &pkt
->u
.response
.stub_and_verifier
,
702 &auth
, &auth_length
, false);
703 NT_STATUS_NOT_OK_RETURN(status
);
705 pkt
->u
.response
.stub_and_verifier
.length
-= auth_length
;
707 /* check signature or unseal the packet */
708 switch (c
->security_state
.auth_info
->auth_level
) {
709 case DCERPC_AUTH_LEVEL_PRIVACY
:
710 status
= gensec_unseal_packet(c
->security_state
.generic_state
,
711 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
712 pkt
->u
.response
.stub_and_verifier
.length
,
714 raw_packet
->length
- auth
.credentials
.length
,
716 memcpy(pkt
->u
.response
.stub_and_verifier
.data
,
717 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
718 pkt
->u
.response
.stub_and_verifier
.length
);
721 case DCERPC_AUTH_LEVEL_INTEGRITY
:
722 status
= gensec_check_packet(c
->security_state
.generic_state
,
723 pkt
->u
.response
.stub_and_verifier
.data
,
724 pkt
->u
.response
.stub_and_verifier
.length
,
726 raw_packet
->length
- auth
.credentials
.length
,
730 case DCERPC_AUTH_LEVEL_CONNECT
:
731 /* for now we ignore possible signatures here */
732 status
= NT_STATUS_OK
;
736 status
= NT_STATUS_INVALID_LEVEL
;
740 /* remove the indicated amount of padding */
741 if (pkt
->u
.response
.stub_and_verifier
.length
< auth
.auth_pad_length
) {
742 return NT_STATUS_INFO_LENGTH_MISMATCH
;
744 pkt
->u
.response
.stub_and_verifier
.length
-= auth
.auth_pad_length
;
751 push a dcerpc request packet into a blob, possibly signing it.
753 static NTSTATUS
ncacn_push_request_sign(struct dcecli_connection
*c
,
754 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
756 struct ncacn_packet
*pkt
)
759 struct ndr_push
*ndr
;
761 size_t payload_length
;
762 enum ndr_err_code ndr_err
;
763 size_t hdr_size
= DCERPC_REQUEST_LENGTH
;
765 /* non-signed packets are simpler */
767 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
770 switch (c
->security_state
.auth_info
->auth_level
) {
771 case DCERPC_AUTH_LEVEL_PRIVACY
:
772 case DCERPC_AUTH_LEVEL_INTEGRITY
:
775 case DCERPC_AUTH_LEVEL_CONNECT
:
776 /* TODO: let the gensec mech decide if it wants to generate a signature */
777 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
779 case DCERPC_AUTH_LEVEL_NONE
:
780 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
783 return NT_STATUS_INVALID_LEVEL
;
786 ndr
= ndr_push_init_ctx(mem_ctx
);
788 return NT_STATUS_NO_MEMORY
;
791 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
792 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
795 if (c
->flags
& DCERPC_NDR64
) {
796 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
799 if (pkt
->pfc_flags
& DCERPC_PFC_FLAG_OBJECT_UUID
) {
800 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
804 ndr_err
= ndr_push_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
805 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
806 return ndr_map_error2ntstatus(ndr_err
);
809 /* pad to 16 byte multiple in the payload portion of the
810 packet. This matches what w2k3 does. Note that we can't use
811 ndr_push_align() as that is relative to the start of the
812 whole packet, whereas w2k8 wants it relative to the start
814 c
->security_state
.auth_info
->auth_pad_length
=
815 (16 - (pkt
->u
.request
.stub_and_verifier
.length
& 15)) & 15;
816 ndr_err
= ndr_push_zero(ndr
, c
->security_state
.auth_info
->auth_pad_length
);
817 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
818 return ndr_map_error2ntstatus(ndr_err
);
821 payload_length
= pkt
->u
.request
.stub_and_verifier
.length
+
822 c
->security_state
.auth_info
->auth_pad_length
;
824 /* we start without signature, it will appended later */
825 c
->security_state
.auth_info
->credentials
= data_blob(NULL
,0);
827 /* add the auth verifier */
828 ndr_err
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, c
->security_state
.auth_info
);
829 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
830 return ndr_map_error2ntstatus(ndr_err
);
833 /* extract the whole packet as a blob */
834 *blob
= ndr_push_blob(ndr
);
837 * Setup the frag and auth length in the packet buffer.
838 * This is needed if the GENSEC mech does AEAD signing
839 * of the packet headers. The signature itself will be
842 dcerpc_set_frag_length(blob
, blob
->length
+ sig_size
);
843 dcerpc_set_auth_length(blob
, sig_size
);
845 /* sign or seal the packet */
846 switch (c
->security_state
.auth_info
->auth_level
) {
847 case DCERPC_AUTH_LEVEL_PRIVACY
:
848 status
= gensec_seal_packet(c
->security_state
.generic_state
,
850 blob
->data
+ hdr_size
,
855 if (!NT_STATUS_IS_OK(status
)) {
860 case DCERPC_AUTH_LEVEL_INTEGRITY
:
861 status
= gensec_sign_packet(c
->security_state
.generic_state
,
863 blob
->data
+ hdr_size
,
868 if (!NT_STATUS_IS_OK(status
)) {
874 status
= NT_STATUS_INVALID_LEVEL
;
878 if (creds2
.length
!= sig_size
) {
879 /* this means the sig_size estimate for the signature
880 was incorrect. We have to correct the packet
881 sizes. That means we could go over the max fragment
883 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
884 (unsigned) creds2
.length
,
886 (unsigned) c
->security_state
.auth_info
->auth_pad_length
,
887 (unsigned) pkt
->u
.request
.stub_and_verifier
.length
));
888 dcerpc_set_frag_length(blob
, blob
->length
+ creds2
.length
);
889 dcerpc_set_auth_length(blob
, creds2
.length
);
892 if (!data_blob_append(mem_ctx
, blob
, creds2
.data
, creds2
.length
)) {
893 return NT_STATUS_NO_MEMORY
;
901 fill in the fixed values in a dcerpc header
903 static void init_ncacn_hdr(struct dcecli_connection
*c
, struct ncacn_packet
*pkt
)
906 pkt
->rpc_vers_minor
= 0;
907 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
910 pkt
->drep
[0] = DCERPC_DREP_LE
;
918 map a bind nak reason to a NTSTATUS
920 static NTSTATUS
dcerpc_map_reason(uint16_t reason
)
923 case DCERPC_BIND_REASON_ASYNTAX
:
924 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX
;
925 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE
:
926 return NT_STATUS_INVALID_PARAMETER
;
928 return NT_STATUS_UNSUCCESSFUL
;
932 a bind or alter context has failed
934 static void dcerpc_composite_fail(struct rpc_request
*req
)
936 struct composite_context
*c
= talloc_get_type(req
->async
.private_data
,
937 struct composite_context
);
938 composite_error(c
, req
->status
);
942 remove requests from the pending or queued queues
944 static int dcerpc_req_dequeue(struct rpc_request
*req
)
946 switch (req
->state
) {
947 case RPC_REQUEST_QUEUED
:
948 DLIST_REMOVE(req
->p
->conn
->request_queue
, req
);
950 case RPC_REQUEST_PENDING
:
951 DLIST_REMOVE(req
->p
->conn
->pending
, req
);
953 case RPC_REQUEST_DONE
:
961 mark the dcerpc connection dead. All outstanding requests get an error
963 static void dcerpc_connection_dead(struct dcecli_connection
*conn
, NTSTATUS status
)
965 if (conn
->dead
) return;
969 if (conn
->transport
.shutdown_pipe
) {
970 conn
->transport
.shutdown_pipe(conn
, status
);
973 /* all pending requests get the error */
974 while (conn
->pending
) {
975 struct rpc_request
*req
= conn
->pending
;
976 dcerpc_req_dequeue(req
);
977 req
->state
= RPC_REQUEST_DONE
;
978 req
->status
= status
;
979 if (req
->async
.callback
) {
980 req
->async
.callback(req
);
984 talloc_set_destructor(conn
, NULL
);
985 if (conn
->free_skipped
) {
991 forward declarations of the recv_data handlers for the types of
992 packets we need to handle
994 static void dcerpc_request_recv_data(struct dcecli_connection
*c
,
995 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
);
998 receive a dcerpc reply from the transport. Here we work out what
999 type of reply it is (normal request, bind or alter context) and
1000 dispatch to the appropriate handler
1002 static void dcerpc_recv_data(struct dcecli_connection
*conn
, DATA_BLOB
*blob
, NTSTATUS status
)
1004 struct ncacn_packet pkt
;
1006 if (NT_STATUS_IS_OK(status
) && blob
->length
== 0) {
1007 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
1010 /* the transport may be telling us of a severe error, such as
1012 if (!NT_STATUS_IS_OK(status
)) {
1013 data_blob_free(blob
);
1014 dcerpc_connection_dead(conn
, status
);
1018 /* parse the basic packet to work out what type of response this is */
1019 status
= ncacn_pull(conn
, blob
, blob
->data
, &pkt
);
1020 if (!NT_STATUS_IS_OK(status
)) {
1021 data_blob_free(blob
);
1022 dcerpc_connection_dead(conn
, status
);
1025 dcerpc_request_recv_data(conn
, blob
, &pkt
);
1029 Receive a bind reply from the transport
1031 static void dcerpc_bind_recv_handler(struct rpc_request
*req
,
1032 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
1034 struct composite_context
*c
;
1035 struct dcecli_connection
*conn
;
1037 c
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
1039 if (pkt
->ptype
== DCERPC_PKT_BIND_NAK
) {
1040 DEBUG(2,("dcerpc: bind_nak reason %d\n",
1041 pkt
->u
.bind_nak
.reject_reason
));
1042 composite_error(c
, dcerpc_map_reason(pkt
->u
.bind_nak
.
1047 if ((pkt
->ptype
!= DCERPC_PKT_BIND_ACK
) ||
1048 (pkt
->u
.bind_ack
.num_results
== 0) ||
1049 (pkt
->u
.bind_ack
.ctx_list
[0].result
!= 0)) {
1050 req
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1051 composite_error(c
, NT_STATUS_NET_WRITE_FAULT
);
1055 conn
= req
->p
->conn
;
1057 conn
->srv_max_xmit_frag
= pkt
->u
.bind_ack
.max_xmit_frag
;
1058 conn
->srv_max_recv_frag
= pkt
->u
.bind_ack
.max_recv_frag
;
1060 if ((req
->p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) &&
1061 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_CONC_MPX
)) {
1062 conn
->flags
|= DCERPC_CONCURRENT_MULTIPLEX
;
1065 if ((req
->p
->binding
->flags
& DCERPC_HEADER_SIGNING
) &&
1066 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
)) {
1067 conn
->flags
|= DCERPC_HEADER_SIGNING
;
1070 /* the bind_ack might contain a reply set of credentials */
1071 if (conn
->security_state
.auth_info
&& pkt
->u
.bind_ack
.auth_info
.length
) {
1073 uint32_t auth_length
;
1074 status
= dcerpc_pull_auth_trailer(pkt
, conn
, &pkt
->u
.bind_ack
.auth_info
,
1075 conn
->security_state
.auth_info
, &auth_length
, true);
1076 if (!NT_STATUS_IS_OK(status
)) {
1077 composite_error(c
, status
);
1082 req
->p
->assoc_group_id
= pkt
->u
.bind_ack
.assoc_group_id
;
1088 handle timeouts of individual dcerpc requests
1090 static void dcerpc_timeout_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
1091 struct timeval t
, void *private_data
)
1093 struct rpc_request
*req
= talloc_get_type(private_data
, struct rpc_request
);
1095 if (req
->ignore_timeout
) {
1096 dcerpc_req_dequeue(req
);
1097 req
->state
= RPC_REQUEST_DONE
;
1098 req
->status
= NT_STATUS_IO_TIMEOUT
;
1099 if (req
->async
.callback
) {
1100 req
->async
.callback(req
);
1105 dcerpc_connection_dead(req
->p
->conn
, NT_STATUS_IO_TIMEOUT
);
1109 send a async dcerpc bind request
1111 struct composite_context
*dcerpc_bind_send(struct dcerpc_pipe
*p
,
1112 TALLOC_CTX
*mem_ctx
,
1113 const struct ndr_syntax_id
*syntax
,
1114 const struct ndr_syntax_id
*transfer_syntax
)
1116 struct composite_context
*c
;
1117 struct ncacn_packet pkt
;
1119 struct rpc_request
*req
;
1121 c
= composite_create(mem_ctx
,p
->conn
->event_ctx
);
1122 if (c
== NULL
) return NULL
;
1124 c
->private_data
= p
;
1126 p
->syntax
= *syntax
;
1127 p
->transfer_syntax
= *transfer_syntax
;
1129 init_ncacn_hdr(p
->conn
, &pkt
);
1131 pkt
.ptype
= DCERPC_PKT_BIND
;
1132 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1133 pkt
.call_id
= p
->conn
->call_id
;
1134 pkt
.auth_length
= 0;
1136 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1137 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1140 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
1141 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
1144 pkt
.u
.bind
.max_xmit_frag
= 5840;
1145 pkt
.u
.bind
.max_recv_frag
= 5840;
1146 pkt
.u
.bind
.assoc_group_id
= p
->binding
->assoc_group_id
;
1147 pkt
.u
.bind
.num_contexts
= 1;
1148 pkt
.u
.bind
.ctx_list
= talloc_array(mem_ctx
, struct dcerpc_ctx_list
, 1);
1149 if (composite_nomem(pkt
.u
.bind
.ctx_list
, c
)) return c
;
1150 pkt
.u
.bind
.ctx_list
[0].context_id
= p
->context_id
;
1151 pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
= 1;
1152 pkt
.u
.bind
.ctx_list
[0].abstract_syntax
= p
->syntax
;
1153 pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
1154 pkt
.u
.bind
.auth_info
= data_blob(NULL
, 0);
1156 /* construct the NDR form of the packet */
1157 c
->status
= ncacn_push_auth(&blob
, c
, &pkt
,
1158 p
->conn
->security_state
.auth_info
);
1159 if (!composite_is_ok(c
)) return c
;
1161 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1164 * we allocate a dcerpc_request so we can be in the same
1165 * request queue as normal requests
1167 req
= talloc_zero(c
, struct rpc_request
);
1168 if (composite_nomem(req
, c
)) return c
;
1170 req
->state
= RPC_REQUEST_PENDING
;
1171 req
->call_id
= pkt
.call_id
;
1172 req
->async
.private_data
= c
;
1173 req
->async
.callback
= dcerpc_composite_fail
;
1175 req
->recv_handler
= dcerpc_bind_recv_handler
;
1176 DLIST_ADD_END(p
->conn
->pending
, req
, struct rpc_request
*);
1177 talloc_set_destructor(req
, dcerpc_req_dequeue
);
1179 c
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
,
1181 if (!composite_is_ok(c
)) return c
;
1183 tevent_add_timer(c
->event_ctx
, req
,
1184 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
1185 dcerpc_timeout_handler
, req
);
1191 recv side of async dcerpc bind request
1193 NTSTATUS
dcerpc_bind_recv(struct composite_context
*ctx
)
1195 NTSTATUS result
= composite_wait(ctx
);
1201 perform a continued bind (and auth3)
1203 NTSTATUS
dcerpc_auth3(struct dcerpc_pipe
*p
,
1204 TALLOC_CTX
*mem_ctx
)
1206 struct ncacn_packet pkt
;
1210 init_ncacn_hdr(p
->conn
, &pkt
);
1212 pkt
.ptype
= DCERPC_PKT_AUTH3
;
1213 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1214 pkt
.call_id
= next_call_id(p
->conn
);
1215 pkt
.auth_length
= 0;
1216 pkt
.u
.auth3
.auth_info
= data_blob(NULL
, 0);
1218 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1219 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1222 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
1223 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
1226 /* construct the NDR form of the packet */
1227 status
= ncacn_push_auth(&blob
, mem_ctx
,
1229 p
->conn
->security_state
.auth_info
);
1230 if (!NT_STATUS_IS_OK(status
)) {
1234 /* send it on its way */
1235 status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, false);
1236 if (!NT_STATUS_IS_OK(status
)) {
1240 return NT_STATUS_OK
;
1245 process a fragment received from the transport layer during a
1248 This function frees the data
1250 static void dcerpc_request_recv_data(struct dcecli_connection
*c
,
1251 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
1253 struct rpc_request
*req
;
1254 unsigned int length
;
1255 NTSTATUS status
= NT_STATUS_OK
;
1258 if this is an authenticated connection then parse and check
1259 the auth info. We have to do this before finding the
1260 matching packet, as the request structure might have been
1261 removed due to a timeout, but if it has been we still need
1262 to run the auth routines so that we don't get the sign/seal
1263 info out of step with the server
1265 if (c
->security_state
.auth_info
&& c
->security_state
.generic_state
&&
1266 pkt
->ptype
== DCERPC_PKT_RESPONSE
) {
1267 status
= ncacn_pull_request_auth(c
, raw_packet
->data
, raw_packet
, pkt
);
1270 /* find the matching request */
1271 for (req
=c
->pending
;req
;req
=req
->next
) {
1272 if (pkt
->call_id
== req
->call_id
) break;
1276 /* useful for testing certain vendors RPC servers */
1277 if (req
== NULL
&& c
->pending
&& pkt
->call_id
== 0) {
1278 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1284 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt
->call_id
));
1285 data_blob_free(raw_packet
);
1289 talloc_steal(req
, raw_packet
->data
);
1291 if (req
->recv_handler
!= NULL
) {
1292 dcerpc_req_dequeue(req
);
1293 req
->state
= RPC_REQUEST_DONE
;
1294 req
->recv_handler(req
, raw_packet
, pkt
);
1298 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
1299 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c
, pkt
->u
.fault
.status
)));
1300 req
->fault_code
= pkt
->u
.fault
.status
;
1301 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
1305 if (pkt
->ptype
!= DCERPC_PKT_RESPONSE
) {
1306 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1308 req
->fault_code
= DCERPC_FAULT_OTHER
;
1309 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
1313 /* now check the status from the auth routines, and if it failed then fail
1314 this request accordingly */
1315 if (!NT_STATUS_IS_OK(status
)) {
1316 req
->status
= status
;
1320 length
= pkt
->u
.response
.stub_and_verifier
.length
;
1323 req
->payload
.data
= talloc_realloc(req
,
1326 req
->payload
.length
+ length
);
1327 if (!req
->payload
.data
) {
1328 req
->status
= NT_STATUS_NO_MEMORY
;
1331 memcpy(req
->payload
.data
+req
->payload
.length
,
1332 pkt
->u
.response
.stub_and_verifier
.data
, length
);
1333 req
->payload
.length
+= length
;
1336 if (!(pkt
->pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
1337 c
->transport
.send_read(c
);
1341 if (!(pkt
->drep
[0] & DCERPC_DREP_LE
)) {
1342 req
->flags
|= DCERPC_PULL_BIGENDIAN
;
1344 req
->flags
&= ~DCERPC_PULL_BIGENDIAN
;
1349 /* we've got the full payload */
1350 req
->state
= RPC_REQUEST_DONE
;
1351 DLIST_REMOVE(c
->pending
, req
);
1353 if (c
->request_queue
!= NULL
) {
1354 /* We have to look at shipping further requests before calling
1355 * the async function, that one might close the pipe */
1356 dcerpc_ship_next_request(c
);
1359 if (req
->async
.callback
) {
1360 req
->async
.callback(req
);
1365 perform the send side of a async dcerpc request
1367 static struct rpc_request
*dcerpc_request_send(struct dcerpc_pipe
*p
,
1368 const struct GUID
*object
,
1370 DATA_BLOB
*stub_data
)
1372 struct rpc_request
*req
;
1374 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1376 req
= talloc(p
, struct rpc_request
);
1382 req
->call_id
= next_call_id(p
->conn
);
1383 req
->status
= NT_STATUS_OK
;
1384 req
->state
= RPC_REQUEST_QUEUED
;
1385 req
->payload
= data_blob(NULL
, 0);
1387 req
->fault_code
= 0;
1388 req
->ignore_timeout
= false;
1389 req
->async
.callback
= NULL
;
1390 req
->async
.private_data
= NULL
;
1391 req
->recv_handler
= NULL
;
1393 if (object
!= NULL
) {
1394 req
->object
= (struct GUID
*)talloc_memdup(req
, (const void *)object
, sizeof(*object
));
1395 if (req
->object
== NULL
) {
1404 req
->request_data
.length
= stub_data
->length
;
1405 req
->request_data
.data
= talloc_reference(req
, stub_data
->data
);
1406 if (req
->request_data
.length
&& req
->request_data
.data
== NULL
) {
1410 DLIST_ADD_END(p
->conn
->request_queue
, req
, struct rpc_request
*);
1411 talloc_set_destructor(req
, dcerpc_req_dequeue
);
1413 dcerpc_ship_next_request(p
->conn
);
1415 if (p
->request_timeout
) {
1416 tevent_add_timer(dcerpc_event_context(p
), req
,
1417 timeval_current_ofs(p
->request_timeout
, 0),
1418 dcerpc_timeout_handler
, req
);
1425 Send a request using the transport
1428 static void dcerpc_ship_next_request(struct dcecli_connection
*c
)
1430 struct rpc_request
*req
;
1431 struct dcerpc_pipe
*p
;
1432 DATA_BLOB
*stub_data
;
1433 struct ncacn_packet pkt
;
1435 uint32_t remaining
, chunk_size
;
1436 bool first_packet
= true;
1437 size_t sig_size
= 0;
1438 bool need_async
= false;
1440 req
= c
->request_queue
;
1446 stub_data
= &req
->request_data
;
1452 DLIST_REMOVE(c
->request_queue
, req
);
1453 DLIST_ADD(c
->pending
, req
);
1454 req
->state
= RPC_REQUEST_PENDING
;
1456 init_ncacn_hdr(p
->conn
, &pkt
);
1458 remaining
= stub_data
->length
;
1460 /* we can write a full max_recv_frag size, minus the dcerpc
1461 request header size */
1462 chunk_size
= p
->conn
->srv_max_recv_frag
;
1463 chunk_size
-= DCERPC_REQUEST_LENGTH
;
1464 if (c
->security_state
.auth_info
&&
1465 c
->security_state
.generic_state
) {
1466 sig_size
= gensec_sig_size(c
->security_state
.generic_state
,
1467 p
->conn
->srv_max_recv_frag
);
1469 chunk_size
-= DCERPC_AUTH_TRAILER_LENGTH
;
1470 chunk_size
-= sig_size
;
1473 chunk_size
-= (chunk_size
% 16);
1475 pkt
.ptype
= DCERPC_PKT_REQUEST
;
1476 pkt
.call_id
= req
->call_id
;
1477 pkt
.auth_length
= 0;
1479 pkt
.u
.request
.alloc_hint
= remaining
;
1480 pkt
.u
.request
.context_id
= p
->context_id
;
1481 pkt
.u
.request
.opnum
= req
->opnum
;
1484 pkt
.u
.request
.object
.object
= *req
->object
;
1485 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_OBJECT_UUID
;
1486 chunk_size
-= ndr_size_GUID(req
->object
,0);
1489 /* we send a series of pdus without waiting for a reply */
1490 while (remaining
> 0 || first_packet
) {
1491 uint32_t chunk
= MIN(chunk_size
, remaining
);
1492 bool last_frag
= false;
1493 bool do_trans
= false;
1495 first_packet
= false;
1496 pkt
.pfc_flags
&= ~(DCERPC_PFC_FLAG_FIRST
|DCERPC_PFC_FLAG_LAST
);
1498 if (remaining
== stub_data
->length
) {
1499 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_FIRST
;
1501 if (chunk
== remaining
) {
1502 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_LAST
;
1506 pkt
.u
.request
.stub_and_verifier
.data
= stub_data
->data
+
1507 (stub_data
->length
- remaining
);
1508 pkt
.u
.request
.stub_and_verifier
.length
= chunk
;
1510 req
->status
= ncacn_push_request_sign(p
->conn
, &blob
, req
, sig_size
, &pkt
);
1511 if (!NT_STATUS_IS_OK(req
->status
)) {
1512 req
->state
= RPC_REQUEST_DONE
;
1513 DLIST_REMOVE(p
->conn
->pending
, req
);
1517 if (last_frag
&& !need_async
) {
1521 req
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, do_trans
);
1522 if (!NT_STATUS_IS_OK(req
->status
)) {
1523 req
->state
= RPC_REQUEST_DONE
;
1524 DLIST_REMOVE(p
->conn
->pending
, req
);
1528 if (last_frag
&& !do_trans
) {
1529 req
->status
= p
->conn
->transport
.send_read(p
->conn
);
1530 if (!NT_STATUS_IS_OK(req
->status
)) {
1531 req
->state
= RPC_REQUEST_DONE
;
1532 DLIST_REMOVE(p
->conn
->pending
, req
);
1542 return the event context for a dcerpc pipe
1543 used by callers who wish to operate asynchronously
1545 _PUBLIC_
struct tevent_context
*dcerpc_event_context(struct dcerpc_pipe
*p
)
1547 return p
->conn
->event_ctx
;
1553 perform the receive side of a async dcerpc request
1555 static NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
1556 TALLOC_CTX
*mem_ctx
,
1557 DATA_BLOB
*stub_data
)
1561 while (req
->state
!= RPC_REQUEST_DONE
) {
1562 struct tevent_context
*ctx
= dcerpc_event_context(req
->p
);
1563 if (tevent_loop_once(ctx
) != 0) {
1564 return NT_STATUS_CONNECTION_DISCONNECTED
;
1567 *stub_data
= req
->payload
;
1568 status
= req
->status
;
1569 if (stub_data
->data
) {
1570 stub_data
->data
= talloc_steal(mem_ctx
, stub_data
->data
);
1572 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
1573 req
->p
->last_fault_code
= req
->fault_code
;
1575 talloc_unlink(talloc_parent(req
), req
);
1580 this is a paranoid NDR validator. For every packet we push onto the wire
1581 we pull it back again, then push it again. Then we compare the raw NDR data
1582 for that to the NDR we initially generated. If they don't match then we know
1583 we must have a bug in either the pull or push side of our code
1585 static NTSTATUS
dcerpc_ndr_validate_in(struct dcecli_connection
*c
,
1586 TALLOC_CTX
*mem_ctx
,
1589 ndr_push_flags_fn_t ndr_push
,
1590 ndr_pull_flags_fn_t ndr_pull
)
1593 struct ndr_pull
*pull
;
1594 struct ndr_push
*push
;
1596 enum ndr_err_code ndr_err
;
1598 st
= talloc_size(mem_ctx
, struct_size
);
1600 return NT_STATUS_NO_MEMORY
;
1603 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1605 return NT_STATUS_NO_MEMORY
;
1607 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1609 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1610 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1613 if (c
->flags
& DCERPC_NDR64
) {
1614 pull
->flags
|= LIBNDR_FLAG_NDR64
;
1617 ndr_err
= ndr_pull(pull
, NDR_IN
, st
);
1618 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1619 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1620 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1621 "failed input validation pull - %s",
1623 return ndr_map_error2ntstatus(ndr_err
);
1626 push
= ndr_push_init_ctx(mem_ctx
);
1628 return NT_STATUS_NO_MEMORY
;
1631 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1632 push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1635 if (c
->flags
& DCERPC_NDR64
) {
1636 push
->flags
|= LIBNDR_FLAG_NDR64
;
1639 ndr_err
= ndr_push(push
, NDR_IN
, st
);
1640 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1641 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1642 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1643 "failed input validation push - %s",
1645 return ndr_map_error2ntstatus(ndr_err
);
1648 blob2
= ndr_push_blob(push
);
1650 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1651 DEBUG(3,("original:\n"));
1652 dump_data(3, blob
.data
, blob
.length
);
1653 DEBUG(3,("secondary:\n"));
1654 dump_data(3, blob2
.data
, blob2
.length
);
1655 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1656 "failed input validation blobs doesn't match");
1657 return ndr_map_error2ntstatus(ndr_err
);
1660 return NT_STATUS_OK
;
1664 this is a paranoid NDR input validator. For every packet we pull
1665 from the wire we push it back again then pull and push it
1666 again. Then we compare the raw NDR data for that to the NDR we
1667 initially generated. If they don't match then we know we must have a
1668 bug in either the pull or push side of our code
1670 static NTSTATUS
dcerpc_ndr_validate_out(struct dcecli_connection
*c
,
1671 struct ndr_pull
*pull_in
,
1674 ndr_push_flags_fn_t ndr_push
,
1675 ndr_pull_flags_fn_t ndr_pull
,
1676 ndr_print_function_t ndr_print
)
1679 struct ndr_pull
*pull
;
1680 struct ndr_push
*push
;
1681 DATA_BLOB blob
, blob2
;
1682 TALLOC_CTX
*mem_ctx
= pull_in
;
1684 enum ndr_err_code ndr_err
;
1686 st
= talloc_size(mem_ctx
, struct_size
);
1688 return NT_STATUS_NO_MEMORY
;
1690 memcpy(st
, struct_ptr
, struct_size
);
1692 push
= ndr_push_init_ctx(mem_ctx
);
1694 return NT_STATUS_NO_MEMORY
;
1697 ndr_err
= ndr_push(push
, NDR_OUT
, struct_ptr
);
1698 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1699 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1700 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1701 "failed output validation push - %s",
1703 return ndr_map_error2ntstatus(ndr_err
);
1706 blob
= ndr_push_blob(push
);
1708 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1710 return NT_STATUS_NO_MEMORY
;
1713 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1714 ndr_err
= ndr_pull(pull
, NDR_OUT
, st
);
1715 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1716 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1717 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1718 "failed output validation pull - %s",
1720 return ndr_map_error2ntstatus(ndr_err
);
1723 push
= ndr_push_init_ctx(mem_ctx
);
1725 return NT_STATUS_NO_MEMORY
;
1728 ndr_err
= ndr_push(push
, NDR_OUT
, st
);
1729 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1730 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1731 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1732 "failed output validation push2 - %s",
1734 return ndr_map_error2ntstatus(ndr_err
);
1737 blob2
= ndr_push_blob(push
);
1739 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1740 DEBUG(3,("original:\n"));
1741 dump_data(3, blob
.data
, blob
.length
);
1742 DEBUG(3,("secondary:\n"));
1743 dump_data(3, blob2
.data
, blob2
.length
);
1744 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1745 "failed output validation blobs doesn't match");
1746 return ndr_map_error2ntstatus(ndr_err
);
1749 /* this checks the printed forms of the two structures, which effectively
1750 tests all of the value() attributes */
1751 s1
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1752 NDR_OUT
, struct_ptr
);
1753 s2
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1755 if (strcmp(s1
, s2
) != 0) {
1757 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1
, s2
));
1759 /* this is sometimes useful */
1760 printf("VALIDATE ERROR\n");
1761 file_save("wire.dat", s1
, strlen(s1
));
1762 file_save("gen.dat", s2
, strlen(s2
));
1763 system("diff -u wire.dat gen.dat");
1765 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1766 "failed output validation strings doesn't match");
1767 return ndr_map_error2ntstatus(ndr_err
);
1770 return NT_STATUS_OK
;
1774 a useful function for retrieving the server name we connected to
1776 _PUBLIC_
const char *dcerpc_server_name(struct dcerpc_pipe
*p
)
1778 if (!p
->conn
->transport
.target_hostname
) {
1779 if (!p
->conn
->transport
.peer_name
) {
1782 return p
->conn
->transport
.peer_name(p
->conn
);
1784 return p
->conn
->transport
.target_hostname(p
->conn
);
1789 get the dcerpc auth_level for a open connection
1791 uint32_t dcerpc_auth_level(struct dcecli_connection
*c
)
1795 if (c
->flags
& DCERPC_SEAL
) {
1796 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
1797 } else if (c
->flags
& DCERPC_SIGN
) {
1798 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
1799 } else if (c
->flags
& DCERPC_CONNECT
) {
1800 auth_level
= DCERPC_AUTH_LEVEL_CONNECT
;
1802 auth_level
= DCERPC_AUTH_LEVEL_NONE
;
1808 Receive an alter reply from the transport
1810 static void dcerpc_alter_recv_handler(struct rpc_request
*req
,
1811 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
1813 struct composite_context
*c
;
1814 struct dcerpc_pipe
*recv_pipe
;
1816 c
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
1817 recv_pipe
= talloc_get_type(c
->private_data
, struct dcerpc_pipe
);
1819 if (pkt
->ptype
== DCERPC_PKT_ALTER_RESP
&&
1820 pkt
->u
.alter_resp
.num_results
== 1 &&
1821 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
1822 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1823 pkt
->u
.alter_resp
.ctx_list
[0].reason
));
1824 composite_error(c
, dcerpc_map_reason(pkt
->u
.alter_resp
.ctx_list
[0].reason
));
1828 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
1829 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c
, pkt
->u
.fault
.status
)));
1830 recv_pipe
->last_fault_code
= pkt
->u
.fault
.status
;
1831 composite_error(c
, NT_STATUS_NET_WRITE_FAULT
);
1835 if (pkt
->ptype
!= DCERPC_PKT_ALTER_RESP
||
1836 pkt
->u
.alter_resp
.num_results
== 0 ||
1837 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
1838 recv_pipe
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1839 composite_error(c
, NT_STATUS_NET_WRITE_FAULT
);
1843 /* the alter_resp might contain a reply set of credentials */
1844 if (recv_pipe
->conn
->security_state
.auth_info
&&
1845 pkt
->u
.alter_resp
.auth_info
.length
) {
1846 struct dcecli_connection
*conn
= recv_pipe
->conn
;
1848 uint32_t auth_length
;
1849 status
= dcerpc_pull_auth_trailer(pkt
, conn
, &pkt
->u
.alter_resp
.auth_info
,
1850 conn
->security_state
.auth_info
, &auth_length
, true);
1851 if (!NT_STATUS_IS_OK(status
)) {
1852 composite_error(c
, status
);
1861 send a dcerpc alter_context request
1863 struct composite_context
*dcerpc_alter_context_send(struct dcerpc_pipe
*p
,
1864 TALLOC_CTX
*mem_ctx
,
1865 const struct ndr_syntax_id
*syntax
,
1866 const struct ndr_syntax_id
*transfer_syntax
)
1868 struct composite_context
*c
;
1869 struct ncacn_packet pkt
;
1871 struct rpc_request
*req
;
1873 c
= composite_create(mem_ctx
, p
->conn
->event_ctx
);
1874 if (c
== NULL
) return NULL
;
1876 c
->private_data
= p
;
1878 p
->syntax
= *syntax
;
1879 p
->transfer_syntax
= *transfer_syntax
;
1881 init_ncacn_hdr(p
->conn
, &pkt
);
1883 pkt
.ptype
= DCERPC_PKT_ALTER
;
1884 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1885 pkt
.call_id
= p
->conn
->call_id
;
1886 pkt
.auth_length
= 0;
1888 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1889 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1892 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
1893 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
1896 pkt
.u
.alter
.max_xmit_frag
= 5840;
1897 pkt
.u
.alter
.max_recv_frag
= 5840;
1898 pkt
.u
.alter
.assoc_group_id
= p
->binding
->assoc_group_id
;
1899 pkt
.u
.alter
.num_contexts
= 1;
1900 pkt
.u
.alter
.ctx_list
= talloc_array(c
, struct dcerpc_ctx_list
, 1);
1901 if (composite_nomem(pkt
.u
.alter
.ctx_list
, c
)) return c
;
1902 pkt
.u
.alter
.ctx_list
[0].context_id
= p
->context_id
;
1903 pkt
.u
.alter
.ctx_list
[0].num_transfer_syntaxes
= 1;
1904 pkt
.u
.alter
.ctx_list
[0].abstract_syntax
= p
->syntax
;
1905 pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
1906 pkt
.u
.alter
.auth_info
= data_blob(NULL
, 0);
1908 /* construct the NDR form of the packet */
1909 c
->status
= ncacn_push_auth(&blob
, mem_ctx
, &pkt
,
1910 p
->conn
->security_state
.auth_info
);
1911 if (!composite_is_ok(c
)) return c
;
1913 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1916 * we allocate a dcerpc_request so we can be in the same
1917 * request queue as normal requests
1919 req
= talloc_zero(c
, struct rpc_request
);
1920 if (composite_nomem(req
, c
)) return c
;
1922 req
->state
= RPC_REQUEST_PENDING
;
1923 req
->call_id
= pkt
.call_id
;
1924 req
->async
.private_data
= c
;
1925 req
->async
.callback
= dcerpc_composite_fail
;
1927 req
->recv_handler
= dcerpc_alter_recv_handler
;
1928 DLIST_ADD_END(p
->conn
->pending
, req
, struct rpc_request
*);
1929 talloc_set_destructor(req
, dcerpc_req_dequeue
);
1931 c
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, true);
1932 if (!composite_is_ok(c
)) return c
;
1934 tevent_add_timer(c
->event_ctx
, req
,
1935 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
1936 dcerpc_timeout_handler
, req
);
1941 NTSTATUS
dcerpc_alter_context_recv(struct composite_context
*ctx
)
1943 NTSTATUS result
= composite_wait(ctx
);
1949 send a dcerpc alter_context request
1951 _PUBLIC_ NTSTATUS
dcerpc_alter_context(struct dcerpc_pipe
*p
,
1952 TALLOC_CTX
*mem_ctx
,
1953 const struct ndr_syntax_id
*syntax
,
1954 const struct ndr_syntax_id
*transfer_syntax
)
1956 struct composite_context
*creq
;
1957 creq
= dcerpc_alter_context_send(p
, mem_ctx
, syntax
, transfer_syntax
);
1958 return dcerpc_alter_context_recv(creq
);