2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "auth/gensec/gensec.h"
31 #include "param/param.h"
32 #include "lib/util/tevent_ntstatus.h"
33 #include "librpc/rpc/rpc_common.h"
35 enum rpc_request_state
{
42 handle for an async dcerpc request
45 struct rpc_request
*next
, *prev
;
46 struct dcerpc_pipe
*p
;
49 enum rpc_request_state state
;
54 /* this is used to distinguish bind and alter_context requests
55 from normal requests */
56 void (*recv_handler
)(struct rpc_request
*conn
,
57 DATA_BLOB
*blob
, struct ncacn_packet
*pkt
);
59 const struct GUID
*object
;
61 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_schedule_io_trigger(struct dcecli_connection
*c
);
87 static struct rpc_request
*dcerpc_request_send(TALLOC_CTX
*mem_ctx
,
88 struct dcerpc_pipe
*p
,
89 const struct GUID
*object
,
91 DATA_BLOB
*stub_data
);
92 static NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
94 DATA_BLOB
*stub_data
);
95 static NTSTATUS
dcerpc_ndr_validate_in(struct dcecli_connection
*c
,
99 ndr_push_flags_fn_t ndr_push
,
100 ndr_pull_flags_fn_t ndr_pull
);
101 static NTSTATUS
dcerpc_ndr_validate_out(struct dcecli_connection
*c
,
102 struct ndr_pull
*pull_in
,
105 ndr_push_flags_fn_t ndr_push
,
106 ndr_pull_flags_fn_t ndr_pull
,
107 ndr_print_function_t ndr_print
);
109 /* destroy a dcerpc connection */
110 static int dcerpc_connection_destructor(struct dcecli_connection
*conn
)
113 conn
->free_skipped
= true;
116 dcerpc_connection_dead(conn
, NT_STATUS_LOCAL_DISCONNECT
);
121 /* initialise a dcerpc connection.
122 the event context is optional
124 static struct dcecli_connection
*dcerpc_connection_init(TALLOC_CTX
*mem_ctx
,
125 struct tevent_context
*ev
)
127 struct dcecli_connection
*c
;
129 c
= talloc_zero(mem_ctx
, struct dcecli_connection
);
136 if (c
->event_ctx
== NULL
) {
142 c
->security_state
.auth_info
= NULL
;
143 c
->security_state
.session_key
= dcerpc_generic_session_key
;
144 c
->security_state
.generic_state
= NULL
;
145 c
->binding_string
= NULL
;
147 c
->srv_max_xmit_frag
= 0;
148 c
->srv_max_recv_frag
= 0;
151 c
->io_trigger
= tevent_create_immediate(c
);
152 if (c
->io_trigger
== NULL
) {
157 talloc_set_destructor(c
, dcerpc_connection_destructor
);
162 struct dcerpc_bh_state
{
163 struct dcerpc_pipe
*p
;
166 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle
*h
)
168 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
169 struct dcerpc_bh_state
);
179 if (hs
->p
->conn
->dead
) {
186 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle
*h
,
189 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
190 struct dcerpc_bh_state
);
194 return DCERPC_REQUEST_TIMEOUT
;
197 old
= hs
->p
->request_timeout
;
198 hs
->p
->request_timeout
= timeout
;
203 struct dcerpc_bh_raw_call_state
{
204 struct tevent_context
*ev
;
205 struct dcerpc_binding_handle
*h
;
211 static void dcerpc_bh_raw_call_done(struct rpc_request
*subreq
);
213 static struct tevent_req
*dcerpc_bh_raw_call_send(TALLOC_CTX
*mem_ctx
,
214 struct tevent_context
*ev
,
215 struct dcerpc_binding_handle
*h
,
216 const struct GUID
*object
,
219 const uint8_t *in_data
,
222 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
223 struct dcerpc_bh_state
);
224 struct tevent_req
*req
;
225 struct dcerpc_bh_raw_call_state
*state
;
227 struct rpc_request
*subreq
;
229 req
= tevent_req_create(mem_ctx
, &state
,
230 struct dcerpc_bh_raw_call_state
);
236 state
->in_data
.data
= discard_const_p(uint8_t, in_data
);
237 state
->in_data
.length
= in_length
;
239 ok
= dcerpc_bh_is_connected(h
);
241 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
242 return tevent_req_post(req
, ev
);
245 subreq
= dcerpc_request_send(state
,
250 if (tevent_req_nomem(subreq
, req
)) {
251 return tevent_req_post(req
, ev
);
253 subreq
->async
.callback
= dcerpc_bh_raw_call_done
;
254 subreq
->async
.private_data
= req
;
259 static void dcerpc_bh_raw_call_done(struct rpc_request
*subreq
)
261 struct tevent_req
*req
=
262 talloc_get_type_abort(subreq
->async
.private_data
,
264 struct dcerpc_bh_raw_call_state
*state
=
266 struct dcerpc_bh_raw_call_state
);
270 state
->out_flags
= 0;
271 if (subreq
->flags
& DCERPC_PULL_BIGENDIAN
) {
272 state
->out_flags
|= LIBNDR_FLAG_BIGENDIAN
;
275 fault_code
= subreq
->fault_code
;
277 status
= dcerpc_request_recv(subreq
, state
, &state
->out_data
);
278 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
279 status
= dcerpc_fault_to_nt_status(fault_code
);
283 * We trigger the callback in the next event run
284 * because the code in this file might trigger
285 * multiple request callbacks from within a single
288 * In order to avoid segfaults from within
289 * dcerpc_connection_dead() we call
290 * tevent_req_defer_callback().
292 tevent_req_defer_callback(req
, state
->ev
);
294 if (!NT_STATUS_IS_OK(status
)) {
295 tevent_req_nterror(req
, status
);
299 tevent_req_done(req
);
302 static NTSTATUS
dcerpc_bh_raw_call_recv(struct tevent_req
*req
,
308 struct dcerpc_bh_raw_call_state
*state
=
310 struct dcerpc_bh_raw_call_state
);
313 if (tevent_req_is_nterror(req
, &status
)) {
314 tevent_req_received(req
);
318 *out_data
= talloc_move(mem_ctx
, &state
->out_data
.data
);
319 *out_length
= state
->out_data
.length
;
320 *out_flags
= state
->out_flags
;
321 tevent_req_received(req
);
325 struct dcerpc_bh_disconnect_state
{
329 static struct tevent_req
*dcerpc_bh_disconnect_send(TALLOC_CTX
*mem_ctx
,
330 struct tevent_context
*ev
,
331 struct dcerpc_binding_handle
*h
)
333 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
334 struct dcerpc_bh_state
);
335 struct tevent_req
*req
;
336 struct dcerpc_bh_disconnect_state
*state
;
339 req
= tevent_req_create(mem_ctx
, &state
,
340 struct dcerpc_bh_disconnect_state
);
345 ok
= dcerpc_bh_is_connected(h
);
347 tevent_req_nterror(req
, NT_STATUS_CONNECTION_DISCONNECTED
);
348 return tevent_req_post(req
, ev
);
351 /* TODO: do a real disconnect ... */
354 tevent_req_done(req
);
355 return tevent_req_post(req
, ev
);
358 static NTSTATUS
dcerpc_bh_disconnect_recv(struct tevent_req
*req
)
362 if (tevent_req_is_nterror(req
, &status
)) {
363 tevent_req_received(req
);
367 tevent_req_received(req
);
371 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle
*h
)
373 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
374 struct dcerpc_bh_state
);
376 if (hs
->p
->conn
->flags
& DCERPC_PUSH_BIGENDIAN
) {
383 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle
*h
)
385 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
386 struct dcerpc_bh_state
);
388 if (hs
->p
->conn
->flags
& DCERPC_NDR_REF_ALLOC
) {
395 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle
*h
)
397 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
398 struct dcerpc_bh_state
);
400 if (hs
->p
->conn
->flags
& DCERPC_NDR64
) {
407 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle
*h
,
409 const void *_struct_ptr
,
410 const struct ndr_interface_call
*call
)
412 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
413 struct dcerpc_bh_state
);
414 void *struct_ptr
= discard_const(_struct_ptr
);
416 if (ndr_flags
& NDR_IN
) {
417 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_PRINT_IN
) {
418 ndr_print_function_debug(call
->ndr_print
,
424 if (ndr_flags
& NDR_OUT
) {
425 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_PRINT_OUT
) {
426 ndr_print_function_debug(call
->ndr_print
,
434 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle
*h
,
436 const void *struct_ptr
,
437 const struct ndr_interface_call
*call
)
439 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
440 call
->name
, nt_errstr(error
)));
443 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle
*h
,
445 const DATA_BLOB
*blob
,
446 const struct ndr_interface_call
*call
)
448 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
449 struct dcerpc_bh_state
);
450 const uint32_t num_examples
= 20;
453 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
454 call
->name
, nt_errstr(error
)));
456 if (hs
->p
->conn
->packet_log_dir
== NULL
) return;
458 for (i
=0;i
<num_examples
;i
++) {
460 asprintf(&name
, "%s/rpclog/%s-out.%d",
461 hs
->p
->conn
->packet_log_dir
,
466 if (!file_exist(name
)) {
467 if (file_save(name
, blob
->data
, blob
->length
)) {
468 DEBUG(10,("Logged rpc packet to %s\n", name
));
477 static NTSTATUS
dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle
*h
,
479 const DATA_BLOB
*blob
,
480 const struct ndr_interface_call
*call
)
482 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
483 struct dcerpc_bh_state
);
485 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_IN
) {
488 status
= dcerpc_ndr_validate_in(hs
->p
->conn
,
494 if (!NT_STATUS_IS_OK(status
)) {
495 DEBUG(0,("Validation [in] failed for %s - %s\n",
496 call
->name
, nt_errstr(status
)));
501 DEBUG(10,("rpc request data:\n"));
502 dump_data(10, blob
->data
, blob
->length
);
507 static NTSTATUS
dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle
*h
,
508 struct ndr_pull
*pull_in
,
509 const void *_struct_ptr
,
510 const struct ndr_interface_call
*call
)
512 struct dcerpc_bh_state
*hs
= dcerpc_binding_handle_data(h
,
513 struct dcerpc_bh_state
);
514 void *struct_ptr
= discard_const(_struct_ptr
);
516 DEBUG(10,("rpc reply data:\n"));
517 dump_data(10, pull_in
->data
, pull_in
->data_size
);
519 if (pull_in
->offset
!= pull_in
->data_size
) {
520 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
521 pull_in
->data_size
- pull_in
->offset
,
522 pull_in
->offset
, pull_in
->offset
,
524 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
525 but it turns out that early versions of NT
526 (specifically NT3.1) add junk onto the end of rpc
527 packets, so if we want to interoperate at all with
528 those versions then we need to ignore this error */
531 if (hs
->p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_OUT
) {
534 status
= dcerpc_ndr_validate_out(hs
->p
->conn
,
541 if (!NT_STATUS_IS_OK(status
)) {
542 DEBUG(2,("Validation [out] failed for %s - %s\n",
543 call
->name
, nt_errstr(status
)));
551 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops
= {
553 .is_connected
= dcerpc_bh_is_connected
,
554 .set_timeout
= dcerpc_bh_set_timeout
,
555 .raw_call_send
= dcerpc_bh_raw_call_send
,
556 .raw_call_recv
= dcerpc_bh_raw_call_recv
,
557 .disconnect_send
= dcerpc_bh_disconnect_send
,
558 .disconnect_recv
= dcerpc_bh_disconnect_recv
,
560 .push_bigendian
= dcerpc_bh_push_bigendian
,
561 .ref_alloc
= dcerpc_bh_ref_alloc
,
562 .use_ndr64
= dcerpc_bh_use_ndr64
,
563 .do_ndr_print
= dcerpc_bh_do_ndr_print
,
564 .ndr_push_failed
= dcerpc_bh_ndr_push_failed
,
565 .ndr_pull_failed
= dcerpc_bh_ndr_pull_failed
,
566 .ndr_validate_in
= dcerpc_bh_ndr_validate_in
,
567 .ndr_validate_out
= dcerpc_bh_ndr_validate_out
,
570 /* initialise a dcerpc pipe. */
571 struct dcerpc_binding_handle
*dcerpc_pipe_binding_handle(struct dcerpc_pipe
*p
)
573 struct dcerpc_binding_handle
*h
;
574 struct dcerpc_bh_state
*hs
;
576 h
= dcerpc_binding_handle_create(p
,
581 struct dcerpc_bh_state
,
588 dcerpc_binding_handle_set_sync_ev(h
, p
->conn
->event_ctx
);
593 /* initialise a dcerpc pipe. */
594 _PUBLIC_
struct dcerpc_pipe
*dcerpc_pipe_init(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
)
596 struct dcerpc_pipe
*p
;
598 p
= talloc_zero(mem_ctx
, struct dcerpc_pipe
);
603 p
->conn
= dcerpc_connection_init(p
, ev
);
604 if (p
->conn
== NULL
) {
609 p
->last_fault_code
= 0;
611 p
->request_timeout
= DCERPC_REQUEST_TIMEOUT
;
614 ZERO_STRUCT(p
->syntax
);
615 ZERO_STRUCT(p
->transfer_syntax
);
618 p
->conn
->flags
|= DCERPC_DEBUG_PRINT_BOTH
;
621 p
->binding_handle
= dcerpc_pipe_binding_handle(p
);
622 if (p
->binding_handle
== NULL
) {
632 choose the next call id to use
634 static uint32_t next_call_id(struct dcecli_connection
*c
)
637 if (c
->call_id
== 0) {
644 setup for a ndr pull, also setting up any flags from the binding string
646 static struct ndr_pull
*ndr_pull_init_flags(struct dcecli_connection
*c
,
647 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
649 struct ndr_pull
*ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
651 if (ndr
== NULL
) return ndr
;
653 if (c
->flags
& DCERPC_DEBUG_PAD_CHECK
) {
654 ndr
->flags
|= LIBNDR_FLAG_PAD_CHECK
;
657 if (c
->flags
& DCERPC_NDR_REF_ALLOC
) {
658 ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
661 if (c
->flags
& DCERPC_NDR64
) {
662 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
669 parse a data blob into a ncacn_packet structure. This handles both
670 input and output packets
672 static NTSTATUS
ncacn_pull(struct dcecli_connection
*c
, DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
673 struct ncacn_packet
*pkt
)
675 struct ndr_pull
*ndr
;
676 enum ndr_err_code ndr_err
;
678 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
680 return NT_STATUS_NO_MEMORY
;
683 if (! (CVAL(blob
->data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
684 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
687 if (CVAL(blob
->data
, DCERPC_PFC_OFFSET
) & DCERPC_PFC_FLAG_OBJECT_UUID
) {
688 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
691 ndr_err
= ndr_pull_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
692 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
693 return ndr_map_error2ntstatus(ndr_err
);
700 parse the authentication information on a dcerpc response packet
702 static NTSTATUS
ncacn_pull_request_auth(struct dcecli_connection
*c
, TALLOC_CTX
*mem_ctx
,
703 DATA_BLOB
*raw_packet
,
704 struct ncacn_packet
*pkt
)
707 struct dcerpc_auth auth
;
708 uint32_t auth_length
;
710 if (!c
->security_state
.auth_info
||
711 !c
->security_state
.generic_state
) {
715 switch (c
->security_state
.auth_info
->auth_level
) {
716 case DCERPC_AUTH_LEVEL_PRIVACY
:
717 case DCERPC_AUTH_LEVEL_INTEGRITY
:
720 case DCERPC_AUTH_LEVEL_CONNECT
:
721 if (pkt
->auth_length
!= 0) {
725 case DCERPC_AUTH_LEVEL_NONE
:
726 if (pkt
->auth_length
!= 0) {
727 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
732 return NT_STATUS_INVALID_LEVEL
;
735 status
= dcerpc_pull_auth_trailer(pkt
, mem_ctx
,
736 &pkt
->u
.response
.stub_and_verifier
,
737 &auth
, &auth_length
, false);
738 NT_STATUS_NOT_OK_RETURN(status
);
740 pkt
->u
.response
.stub_and_verifier
.length
-= auth_length
;
742 /* check signature or unseal the packet */
743 switch (c
->security_state
.auth_info
->auth_level
) {
744 case DCERPC_AUTH_LEVEL_PRIVACY
:
745 status
= gensec_unseal_packet(c
->security_state
.generic_state
,
746 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
747 pkt
->u
.response
.stub_and_verifier
.length
,
749 raw_packet
->length
- auth
.credentials
.length
,
751 memcpy(pkt
->u
.response
.stub_and_verifier
.data
,
752 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
753 pkt
->u
.response
.stub_and_verifier
.length
);
756 case DCERPC_AUTH_LEVEL_INTEGRITY
:
757 status
= gensec_check_packet(c
->security_state
.generic_state
,
758 pkt
->u
.response
.stub_and_verifier
.data
,
759 pkt
->u
.response
.stub_and_verifier
.length
,
761 raw_packet
->length
- auth
.credentials
.length
,
765 case DCERPC_AUTH_LEVEL_CONNECT
:
766 /* for now we ignore possible signatures here */
767 status
= NT_STATUS_OK
;
771 status
= NT_STATUS_INVALID_LEVEL
;
775 /* remove the indicated amount of padding */
776 if (pkt
->u
.response
.stub_and_verifier
.length
< auth
.auth_pad_length
) {
777 return NT_STATUS_INFO_LENGTH_MISMATCH
;
779 pkt
->u
.response
.stub_and_verifier
.length
-= auth
.auth_pad_length
;
786 push a dcerpc request packet into a blob, possibly signing it.
788 static NTSTATUS
ncacn_push_request_sign(struct dcecli_connection
*c
,
789 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
791 struct ncacn_packet
*pkt
)
794 struct ndr_push
*ndr
;
796 size_t payload_length
;
797 enum ndr_err_code ndr_err
;
798 size_t hdr_size
= DCERPC_REQUEST_LENGTH
;
800 /* non-signed packets are simpler */
802 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
805 switch (c
->security_state
.auth_info
->auth_level
) {
806 case DCERPC_AUTH_LEVEL_PRIVACY
:
807 case DCERPC_AUTH_LEVEL_INTEGRITY
:
810 case DCERPC_AUTH_LEVEL_CONNECT
:
811 /* TODO: let the gensec mech decide if it wants to generate a signature */
812 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
814 case DCERPC_AUTH_LEVEL_NONE
:
815 return ncacn_push_auth(blob
, mem_ctx
, pkt
, NULL
);
818 return NT_STATUS_INVALID_LEVEL
;
821 ndr
= ndr_push_init_ctx(mem_ctx
);
823 return NT_STATUS_NO_MEMORY
;
826 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
827 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
830 if (c
->flags
& DCERPC_NDR64
) {
831 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
834 if (pkt
->pfc_flags
& DCERPC_PFC_FLAG_OBJECT_UUID
) {
835 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
839 ndr_err
= ndr_push_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
840 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
841 return ndr_map_error2ntstatus(ndr_err
);
844 /* pad to 16 byte multiple in the payload portion of the
845 packet. This matches what w2k3 does. Note that we can't use
846 ndr_push_align() as that is relative to the start of the
847 whole packet, whereas w2k8 wants it relative to the start
849 c
->security_state
.auth_info
->auth_pad_length
=
850 (16 - (pkt
->u
.request
.stub_and_verifier
.length
& 15)) & 15;
851 ndr_err
= ndr_push_zero(ndr
, c
->security_state
.auth_info
->auth_pad_length
);
852 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
853 return ndr_map_error2ntstatus(ndr_err
);
856 payload_length
= pkt
->u
.request
.stub_and_verifier
.length
+
857 c
->security_state
.auth_info
->auth_pad_length
;
859 /* we start without signature, it will appended later */
860 c
->security_state
.auth_info
->credentials
= data_blob(NULL
,0);
862 /* add the auth verifier */
863 ndr_err
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, c
->security_state
.auth_info
);
864 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
865 return ndr_map_error2ntstatus(ndr_err
);
868 /* extract the whole packet as a blob */
869 *blob
= ndr_push_blob(ndr
);
872 * Setup the frag and auth length in the packet buffer.
873 * This is needed if the GENSEC mech does AEAD signing
874 * of the packet headers. The signature itself will be
877 dcerpc_set_frag_length(blob
, blob
->length
+ sig_size
);
878 dcerpc_set_auth_length(blob
, sig_size
);
880 /* sign or seal the packet */
881 switch (c
->security_state
.auth_info
->auth_level
) {
882 case DCERPC_AUTH_LEVEL_PRIVACY
:
883 status
= gensec_seal_packet(c
->security_state
.generic_state
,
885 blob
->data
+ hdr_size
,
890 if (!NT_STATUS_IS_OK(status
)) {
895 case DCERPC_AUTH_LEVEL_INTEGRITY
:
896 status
= gensec_sign_packet(c
->security_state
.generic_state
,
898 blob
->data
+ hdr_size
,
903 if (!NT_STATUS_IS_OK(status
)) {
909 status
= NT_STATUS_INVALID_LEVEL
;
913 if (creds2
.length
!= sig_size
) {
914 /* this means the sig_size estimate for the signature
915 was incorrect. We have to correct the packet
916 sizes. That means we could go over the max fragment
918 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
919 (unsigned) creds2
.length
,
921 (unsigned) c
->security_state
.auth_info
->auth_pad_length
,
922 (unsigned) pkt
->u
.request
.stub_and_verifier
.length
));
923 dcerpc_set_frag_length(blob
, blob
->length
+ creds2
.length
);
924 dcerpc_set_auth_length(blob
, creds2
.length
);
927 if (!data_blob_append(mem_ctx
, blob
, creds2
.data
, creds2
.length
)) {
928 return NT_STATUS_NO_MEMORY
;
936 fill in the fixed values in a dcerpc header
938 static void init_ncacn_hdr(struct dcecli_connection
*c
, struct ncacn_packet
*pkt
)
941 pkt
->rpc_vers_minor
= 0;
942 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
945 pkt
->drep
[0] = DCERPC_DREP_LE
;
953 map a bind nak reason to a NTSTATUS
955 static NTSTATUS
dcerpc_map_reason(uint16_t reason
)
958 case DCERPC_BIND_REASON_ASYNTAX
:
959 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX
;
960 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE
:
961 return NT_STATUS_INVALID_PARAMETER
;
963 return NT_STATUS_UNSUCCESSFUL
;
967 remove requests from the pending or queued queues
969 static int dcerpc_req_dequeue(struct rpc_request
*req
)
971 switch (req
->state
) {
972 case RPC_REQUEST_QUEUED
:
973 DLIST_REMOVE(req
->p
->conn
->request_queue
, req
);
975 case RPC_REQUEST_PENDING
:
976 DLIST_REMOVE(req
->p
->conn
->pending
, req
);
978 case RPC_REQUEST_DONE
:
986 mark the dcerpc connection dead. All outstanding requests get an error
988 static void dcerpc_connection_dead(struct dcecli_connection
*conn
, NTSTATUS status
)
990 if (conn
->dead
) return;
994 TALLOC_FREE(conn
->io_trigger
);
995 conn
->io_trigger_pending
= false;
997 conn
->transport
.recv_data
= NULL
;
999 if (conn
->transport
.shutdown_pipe
) {
1000 conn
->transport
.shutdown_pipe(conn
, status
);
1003 /* all pending requests get the error */
1004 while (conn
->pending
) {
1005 struct rpc_request
*req
= conn
->pending
;
1006 dcerpc_req_dequeue(req
);
1007 req
->state
= RPC_REQUEST_DONE
;
1008 req
->status
= status
;
1009 if (req
->async
.callback
) {
1010 req
->async
.callback(req
);
1014 /* all requests, which are not shipped */
1015 while (conn
->request_queue
) {
1016 struct rpc_request
*req
= conn
->request_queue
;
1017 dcerpc_req_dequeue(req
);
1018 req
->state
= RPC_REQUEST_DONE
;
1019 req
->status
= status
;
1020 if (req
->async
.callback
) {
1021 req
->async
.callback(req
);
1025 talloc_set_destructor(conn
, NULL
);
1026 if (conn
->free_skipped
) {
1032 forward declarations of the recv_data handlers for the types of
1033 packets we need to handle
1035 static void dcerpc_request_recv_data(struct dcecli_connection
*c
,
1036 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
);
1039 receive a dcerpc reply from the transport. Here we work out what
1040 type of reply it is (normal request, bind or alter context) and
1041 dispatch to the appropriate handler
1043 static void dcerpc_recv_data(struct dcecli_connection
*conn
, DATA_BLOB
*blob
, NTSTATUS status
)
1045 struct ncacn_packet pkt
;
1047 if (NT_STATUS_IS_OK(status
) && blob
->length
== 0) {
1048 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
1051 /* the transport may be telling us of a severe error, such as
1053 if (!NT_STATUS_IS_OK(status
)) {
1054 data_blob_free(blob
);
1055 dcerpc_connection_dead(conn
, status
);
1059 /* parse the basic packet to work out what type of response this is */
1060 status
= ncacn_pull(conn
, blob
, blob
->data
, &pkt
);
1061 if (!NT_STATUS_IS_OK(status
)) {
1062 data_blob_free(blob
);
1063 dcerpc_connection_dead(conn
, status
);
1067 dcerpc_request_recv_data(conn
, blob
, &pkt
);
1071 handle timeouts of individual dcerpc requests
1073 static void dcerpc_timeout_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
1074 struct timeval t
, void *private_data
)
1076 struct rpc_request
*req
= talloc_get_type(private_data
, struct rpc_request
);
1078 if (req
->ignore_timeout
) {
1079 dcerpc_req_dequeue(req
);
1080 req
->state
= RPC_REQUEST_DONE
;
1081 req
->status
= NT_STATUS_IO_TIMEOUT
;
1082 if (req
->async
.callback
) {
1083 req
->async
.callback(req
);
1088 dcerpc_connection_dead(req
->p
->conn
, NT_STATUS_IO_TIMEOUT
);
1091 struct dcerpc_bind_state
{
1092 struct tevent_context
*ev
;
1093 struct dcerpc_pipe
*p
;
1096 static void dcerpc_bind_fail_handler(struct rpc_request
*subreq
);
1097 static void dcerpc_bind_recv_handler(struct rpc_request
*subreq
,
1098 DATA_BLOB
*raw_packet
,
1099 struct ncacn_packet
*pkt
);
1101 struct tevent_req
*dcerpc_bind_send(TALLOC_CTX
*mem_ctx
,
1102 struct tevent_context
*ev
,
1103 struct dcerpc_pipe
*p
,
1104 const struct ndr_syntax_id
*syntax
,
1105 const struct ndr_syntax_id
*transfer_syntax
)
1107 struct tevent_req
*req
;
1108 struct dcerpc_bind_state
*state
;
1109 struct ncacn_packet pkt
;
1112 struct rpc_request
*subreq
;
1114 req
= tevent_req_create(mem_ctx
, &state
,
1115 struct dcerpc_bind_state
);
1123 p
->syntax
= *syntax
;
1124 p
->transfer_syntax
= *transfer_syntax
;
1126 init_ncacn_hdr(p
->conn
, &pkt
);
1128 pkt
.ptype
= DCERPC_PKT_BIND
;
1129 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1130 pkt
.call_id
= p
->conn
->call_id
;
1131 pkt
.auth_length
= 0;
1133 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1134 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1137 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
1138 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
1141 pkt
.u
.bind
.max_xmit_frag
= 5840;
1142 pkt
.u
.bind
.max_recv_frag
= 5840;
1143 pkt
.u
.bind
.assoc_group_id
= p
->binding
->assoc_group_id
;
1144 pkt
.u
.bind
.num_contexts
= 1;
1145 pkt
.u
.bind
.ctx_list
= talloc_array(mem_ctx
, struct dcerpc_ctx_list
, 1);
1146 if (tevent_req_nomem(pkt
.u
.bind
.ctx_list
, req
)) {
1147 return tevent_req_post(req
, ev
);
1149 pkt
.u
.bind
.ctx_list
[0].context_id
= p
->context_id
;
1150 pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
= 1;
1151 pkt
.u
.bind
.ctx_list
[0].abstract_syntax
= p
->syntax
;
1152 pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
1153 pkt
.u
.bind
.auth_info
= data_blob(NULL
, 0);
1155 /* construct the NDR form of the packet */
1156 status
= ncacn_push_auth(&blob
, state
, &pkt
,
1157 p
->conn
->security_state
.auth_info
);
1158 if (tevent_req_nterror(req
, status
)) {
1159 return tevent_req_post(req
, ev
);
1162 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1165 * we allocate a dcerpc_request so we can be in the same
1166 * request queue as normal requests
1168 subreq
= talloc_zero(state
, struct rpc_request
);
1169 if (tevent_req_nomem(subreq
, req
)) {
1170 return tevent_req_post(req
, ev
);
1173 subreq
->state
= RPC_REQUEST_PENDING
;
1174 subreq
->call_id
= pkt
.call_id
;
1175 subreq
->async
.private_data
= req
;
1176 subreq
->async
.callback
= dcerpc_bind_fail_handler
;
1178 subreq
->recv_handler
= dcerpc_bind_recv_handler
;
1179 DLIST_ADD_END(p
->conn
->pending
, subreq
, struct rpc_request
*);
1180 talloc_set_destructor(subreq
, dcerpc_req_dequeue
);
1182 status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, true);
1183 if (tevent_req_nterror(req
, status
)) {
1184 return tevent_req_post(req
, ev
);
1187 tevent_add_timer(ev
, subreq
,
1188 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
1189 dcerpc_timeout_handler
, subreq
);
1194 static void dcerpc_bind_fail_handler(struct rpc_request
*subreq
)
1196 struct tevent_req
*req
=
1197 talloc_get_type_abort(subreq
->async
.private_data
,
1199 struct dcerpc_bind_state
*state
=
1200 tevent_req_data(req
,
1201 struct dcerpc_bind_state
);
1202 NTSTATUS status
= subreq
->status
;
1204 TALLOC_FREE(subreq
);
1207 * We trigger the callback in the next event run
1208 * because the code in this file might trigger
1209 * multiple request callbacks from within a single
1212 * In order to avoid segfaults from within
1213 * dcerpc_connection_dead() we call
1214 * tevent_req_defer_callback().
1216 tevent_req_defer_callback(req
, state
->ev
);
1218 tevent_req_nterror(req
, status
);
1221 static void dcerpc_bind_recv_handler(struct rpc_request
*subreq
,
1222 DATA_BLOB
*raw_packet
,
1223 struct ncacn_packet
*pkt
)
1225 struct tevent_req
*req
=
1226 talloc_get_type_abort(subreq
->async
.private_data
,
1228 struct dcerpc_bind_state
*state
=
1229 tevent_req_data(req
,
1230 struct dcerpc_bind_state
);
1231 struct dcecli_connection
*conn
= state
->p
->conn
;
1235 * Note that pkt is allocated under raw_packet->data,
1236 * while raw_packet->data is a child of subreq.
1238 talloc_steal(state
, raw_packet
->data
);
1239 TALLOC_FREE(subreq
);
1242 * We trigger the callback in the next event run
1243 * because the code in this file might trigger
1244 * multiple request callbacks from within a single
1247 * In order to avoid segfaults from within
1248 * dcerpc_connection_dead() we call
1249 * tevent_req_defer_callback().
1251 tevent_req_defer_callback(req
, state
->ev
);
1253 if (pkt
->ptype
== DCERPC_PKT_BIND_NAK
) {
1254 status
= dcerpc_map_reason(pkt
->u
.bind_nak
.reject_reason
);
1256 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1257 pkt
->u
.bind_nak
.reject_reason
, nt_errstr(status
)));
1259 tevent_req_nterror(req
, status
);
1263 if ((pkt
->ptype
!= DCERPC_PKT_BIND_ACK
) ||
1264 (pkt
->u
.bind_ack
.num_results
== 0) ||
1265 (pkt
->u
.bind_ack
.ctx_list
[0].result
!= 0)) {
1266 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
1267 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
1271 conn
->srv_max_xmit_frag
= pkt
->u
.bind_ack
.max_xmit_frag
;
1272 conn
->srv_max_recv_frag
= pkt
->u
.bind_ack
.max_recv_frag
;
1274 if ((state
->p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) &&
1275 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_CONC_MPX
)) {
1276 conn
->flags
|= DCERPC_CONCURRENT_MULTIPLEX
;
1279 if ((state
->p
->binding
->flags
& DCERPC_HEADER_SIGNING
) &&
1280 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
)) {
1281 conn
->flags
|= DCERPC_HEADER_SIGNING
;
1284 /* the bind_ack might contain a reply set of credentials */
1285 if (conn
->security_state
.auth_info
&& pkt
->u
.bind_ack
.auth_info
.length
) {
1286 uint32_t auth_length
;
1288 status
= dcerpc_pull_auth_trailer(pkt
, conn
, &pkt
->u
.bind_ack
.auth_info
,
1289 conn
->security_state
.auth_info
, &auth_length
, true);
1290 if (tevent_req_nterror(req
, status
)) {
1295 state
->p
->assoc_group_id
= pkt
->u
.bind_ack
.assoc_group_id
;
1297 tevent_req_done(req
);
1300 NTSTATUS
dcerpc_bind_recv(struct tevent_req
*req
)
1302 return tevent_req_simple_recv_ntstatus(req
);
1306 perform a continued bind (and auth3)
1308 NTSTATUS
dcerpc_auth3(struct dcerpc_pipe
*p
,
1309 TALLOC_CTX
*mem_ctx
)
1311 struct ncacn_packet pkt
;
1315 init_ncacn_hdr(p
->conn
, &pkt
);
1317 pkt
.ptype
= DCERPC_PKT_AUTH3
;
1318 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1319 pkt
.call_id
= next_call_id(p
->conn
);
1320 pkt
.auth_length
= 0;
1321 pkt
.u
.auth3
.auth_info
= data_blob(NULL
, 0);
1323 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1324 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1327 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
1328 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
1331 /* construct the NDR form of the packet */
1332 status
= ncacn_push_auth(&blob
, mem_ctx
,
1334 p
->conn
->security_state
.auth_info
);
1335 if (!NT_STATUS_IS_OK(status
)) {
1339 /* send it on its way */
1340 status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, false);
1341 if (!NT_STATUS_IS_OK(status
)) {
1345 return NT_STATUS_OK
;
1350 process a fragment received from the transport layer during a
1353 This function frees the data
1355 static void dcerpc_request_recv_data(struct dcecli_connection
*c
,
1356 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
1358 struct rpc_request
*req
;
1359 unsigned int length
;
1360 NTSTATUS status
= NT_STATUS_OK
;
1363 if this is an authenticated connection then parse and check
1364 the auth info. We have to do this before finding the
1365 matching packet, as the request structure might have been
1366 removed due to a timeout, but if it has been we still need
1367 to run the auth routines so that we don't get the sign/seal
1368 info out of step with the server
1370 if (c
->security_state
.auth_info
&& c
->security_state
.generic_state
&&
1371 pkt
->ptype
== DCERPC_PKT_RESPONSE
) {
1372 status
= ncacn_pull_request_auth(c
, raw_packet
->data
, raw_packet
, pkt
);
1375 /* find the matching request */
1376 for (req
=c
->pending
;req
;req
=req
->next
) {
1377 if (pkt
->call_id
== req
->call_id
) break;
1381 /* useful for testing certain vendors RPC servers */
1382 if (req
== NULL
&& c
->pending
&& pkt
->call_id
== 0) {
1383 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1389 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt
->call_id
));
1390 data_blob_free(raw_packet
);
1394 talloc_steal(req
, raw_packet
->data
);
1396 if (req
->recv_handler
!= NULL
) {
1397 dcerpc_req_dequeue(req
);
1398 req
->state
= RPC_REQUEST_DONE
;
1401 * We have to look at shipping further requests before calling
1402 * the async function, that one might close the pipe
1404 dcerpc_schedule_io_trigger(c
);
1406 req
->recv_handler(req
, raw_packet
, pkt
);
1410 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
1411 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c
, pkt
->u
.fault
.status
)));
1412 req
->fault_code
= pkt
->u
.fault
.status
;
1413 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
1417 if (pkt
->ptype
!= DCERPC_PKT_RESPONSE
) {
1418 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1420 req
->fault_code
= DCERPC_FAULT_OTHER
;
1421 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
1425 /* now check the status from the auth routines, and if it failed then fail
1426 this request accordingly */
1427 if (!NT_STATUS_IS_OK(status
)) {
1428 req
->status
= status
;
1432 length
= pkt
->u
.response
.stub_and_verifier
.length
;
1435 req
->payload
.data
= talloc_realloc(req
,
1438 req
->payload
.length
+ length
);
1439 if (!req
->payload
.data
) {
1440 req
->status
= NT_STATUS_NO_MEMORY
;
1443 memcpy(req
->payload
.data
+req
->payload
.length
,
1444 pkt
->u
.response
.stub_and_verifier
.data
, length
);
1445 req
->payload
.length
+= length
;
1448 if (!(pkt
->pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
1449 c
->transport
.send_read(c
);
1453 if (!(pkt
->drep
[0] & DCERPC_DREP_LE
)) {
1454 req
->flags
|= DCERPC_PULL_BIGENDIAN
;
1456 req
->flags
&= ~DCERPC_PULL_BIGENDIAN
;
1461 /* we've got the full payload */
1462 dcerpc_req_dequeue(req
);
1463 req
->state
= RPC_REQUEST_DONE
;
1466 * We have to look at shipping further requests before calling
1467 * the async function, that one might close the pipe
1469 dcerpc_schedule_io_trigger(c
);
1471 if (req
->async
.callback
) {
1472 req
->async
.callback(req
);
1477 perform the send side of a async dcerpc request
1479 static struct rpc_request
*dcerpc_request_send(TALLOC_CTX
*mem_ctx
,
1480 struct dcerpc_pipe
*p
,
1481 const struct GUID
*object
,
1483 DATA_BLOB
*stub_data
)
1485 struct rpc_request
*req
;
1487 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1489 req
= talloc_zero(mem_ctx
, struct rpc_request
);
1495 req
->call_id
= next_call_id(p
->conn
);
1496 req
->state
= RPC_REQUEST_QUEUED
;
1498 if (object
!= NULL
) {
1499 req
->object
= (struct GUID
*)talloc_memdup(req
, (const void *)object
, sizeof(*object
));
1500 if (req
->object
== NULL
) {
1507 req
->request_data
.length
= stub_data
->length
;
1508 req
->request_data
.data
= stub_data
->data
;
1510 DLIST_ADD_END(p
->conn
->request_queue
, req
, struct rpc_request
*);
1511 talloc_set_destructor(req
, dcerpc_req_dequeue
);
1513 dcerpc_schedule_io_trigger(p
->conn
);
1515 if (p
->request_timeout
) {
1516 tevent_add_timer(dcerpc_event_context(p
), req
,
1517 timeval_current_ofs(p
->request_timeout
, 0),
1518 dcerpc_timeout_handler
, req
);
1525 Send a request using the transport
1528 static void dcerpc_ship_next_request(struct dcecli_connection
*c
)
1530 struct rpc_request
*req
;
1531 struct dcerpc_pipe
*p
;
1532 DATA_BLOB
*stub_data
;
1533 struct ncacn_packet pkt
;
1535 uint32_t remaining
, chunk_size
;
1536 bool first_packet
= true;
1537 size_t sig_size
= 0;
1538 bool need_async
= false;
1539 bool can_async
= true;
1541 req
= c
->request_queue
;
1547 stub_data
= &req
->request_data
;
1553 if (c
->security_state
.auth_info
&&
1554 c
->security_state
.generic_state
)
1556 struct gensec_security
*gensec
= c
->security_state
.generic_state
;
1558 switch (c
->security_state
.auth_info
->auth_level
) {
1559 case DCERPC_AUTH_LEVEL_PRIVACY
:
1560 case DCERPC_AUTH_LEVEL_INTEGRITY
:
1561 can_async
= gensec_have_feature(gensec
,
1562 GENSEC_FEATURE_ASYNC_REPLIES
);
1564 case DCERPC_AUTH_LEVEL_CONNECT
:
1565 case DCERPC_AUTH_LEVEL_NONE
:
1574 if (need_async
&& !can_async
) {
1575 req
->wait_for_sync
= true;
1579 DLIST_REMOVE(c
->request_queue
, req
);
1580 DLIST_ADD(c
->pending
, req
);
1581 req
->state
= RPC_REQUEST_PENDING
;
1583 init_ncacn_hdr(p
->conn
, &pkt
);
1585 remaining
= stub_data
->length
;
1587 /* we can write a full max_recv_frag size, minus the dcerpc
1588 request header size */
1589 chunk_size
= p
->conn
->srv_max_recv_frag
;
1590 chunk_size
-= DCERPC_REQUEST_LENGTH
;
1591 if (c
->security_state
.auth_info
&&
1592 c
->security_state
.generic_state
) {
1593 sig_size
= gensec_sig_size(c
->security_state
.generic_state
,
1594 p
->conn
->srv_max_recv_frag
);
1596 chunk_size
-= DCERPC_AUTH_TRAILER_LENGTH
;
1597 chunk_size
-= sig_size
;
1600 chunk_size
-= (chunk_size
% 16);
1602 pkt
.ptype
= DCERPC_PKT_REQUEST
;
1603 pkt
.call_id
= req
->call_id
;
1604 pkt
.auth_length
= 0;
1606 pkt
.u
.request
.alloc_hint
= remaining
;
1607 pkt
.u
.request
.context_id
= p
->context_id
;
1608 pkt
.u
.request
.opnum
= req
->opnum
;
1611 pkt
.u
.request
.object
.object
= *req
->object
;
1612 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_OBJECT_UUID
;
1613 chunk_size
-= ndr_size_GUID(req
->object
,0);
1616 /* we send a series of pdus without waiting for a reply */
1617 while (remaining
> 0 || first_packet
) {
1618 uint32_t chunk
= MIN(chunk_size
, remaining
);
1619 bool last_frag
= false;
1620 bool do_trans
= false;
1622 first_packet
= false;
1623 pkt
.pfc_flags
&= ~(DCERPC_PFC_FLAG_FIRST
|DCERPC_PFC_FLAG_LAST
);
1625 if (remaining
== stub_data
->length
) {
1626 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_FIRST
;
1628 if (chunk
== remaining
) {
1629 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_LAST
;
1633 pkt
.u
.request
.stub_and_verifier
.data
= stub_data
->data
+
1634 (stub_data
->length
- remaining
);
1635 pkt
.u
.request
.stub_and_verifier
.length
= chunk
;
1637 req
->status
= ncacn_push_request_sign(p
->conn
, &blob
, req
, sig_size
, &pkt
);
1638 if (!NT_STATUS_IS_OK(req
->status
)) {
1639 req
->state
= RPC_REQUEST_DONE
;
1640 DLIST_REMOVE(p
->conn
->pending
, req
);
1644 if (last_frag
&& !need_async
) {
1648 req
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, do_trans
);
1649 if (!NT_STATUS_IS_OK(req
->status
)) {
1650 req
->state
= RPC_REQUEST_DONE
;
1651 DLIST_REMOVE(p
->conn
->pending
, req
);
1655 if (last_frag
&& !do_trans
) {
1656 req
->status
= p
->conn
->transport
.send_read(p
->conn
);
1657 if (!NT_STATUS_IS_OK(req
->status
)) {
1658 req
->state
= RPC_REQUEST_DONE
;
1659 DLIST_REMOVE(p
->conn
->pending
, req
);
1668 static void dcerpc_io_trigger(struct tevent_context
*ctx
,
1669 struct tevent_immediate
*im
,
1672 struct dcecli_connection
*c
=
1673 talloc_get_type_abort(private_data
,
1674 struct dcecli_connection
);
1676 c
->io_trigger_pending
= false;
1678 dcerpc_schedule_io_trigger(c
);
1680 dcerpc_ship_next_request(c
);
1683 static void dcerpc_schedule_io_trigger(struct dcecli_connection
*c
)
1689 if (c
->request_queue
== NULL
) {
1693 if (c
->request_queue
->wait_for_sync
&& c
->pending
) {
1697 if (c
->io_trigger_pending
) {
1701 c
->io_trigger_pending
= true;
1703 tevent_schedule_immediate(c
->io_trigger
,
1710 return the event context for a dcerpc pipe
1711 used by callers who wish to operate asynchronously
1713 _PUBLIC_
struct tevent_context
*dcerpc_event_context(struct dcerpc_pipe
*p
)
1715 return p
->conn
->event_ctx
;
1721 perform the receive side of a async dcerpc request
1723 static NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
1724 TALLOC_CTX
*mem_ctx
,
1725 DATA_BLOB
*stub_data
)
1729 while (req
->state
!= RPC_REQUEST_DONE
) {
1730 struct tevent_context
*ctx
= dcerpc_event_context(req
->p
);
1731 if (tevent_loop_once(ctx
) != 0) {
1732 return NT_STATUS_CONNECTION_DISCONNECTED
;
1735 *stub_data
= req
->payload
;
1736 status
= req
->status
;
1737 if (stub_data
->data
) {
1738 stub_data
->data
= talloc_steal(mem_ctx
, stub_data
->data
);
1740 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
1741 req
->p
->last_fault_code
= req
->fault_code
;
1743 talloc_unlink(talloc_parent(req
), req
);
1748 this is a paranoid NDR validator. For every packet we push onto the wire
1749 we pull it back again, then push it again. Then we compare the raw NDR data
1750 for that to the NDR we initially generated. If they don't match then we know
1751 we must have a bug in either the pull or push side of our code
1753 static NTSTATUS
dcerpc_ndr_validate_in(struct dcecli_connection
*c
,
1754 TALLOC_CTX
*mem_ctx
,
1757 ndr_push_flags_fn_t ndr_push
,
1758 ndr_pull_flags_fn_t ndr_pull
)
1761 struct ndr_pull
*pull
;
1762 struct ndr_push
*push
;
1764 enum ndr_err_code ndr_err
;
1766 st
= talloc_size(mem_ctx
, struct_size
);
1768 return NT_STATUS_NO_MEMORY
;
1771 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1773 return NT_STATUS_NO_MEMORY
;
1775 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1777 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1778 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1781 if (c
->flags
& DCERPC_NDR64
) {
1782 pull
->flags
|= LIBNDR_FLAG_NDR64
;
1785 ndr_err
= ndr_pull(pull
, NDR_IN
, st
);
1786 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1787 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1788 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1789 "failed input validation pull - %s",
1791 return ndr_map_error2ntstatus(ndr_err
);
1794 push
= ndr_push_init_ctx(mem_ctx
);
1796 return NT_STATUS_NO_MEMORY
;
1799 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1800 push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1803 if (c
->flags
& DCERPC_NDR64
) {
1804 push
->flags
|= LIBNDR_FLAG_NDR64
;
1807 ndr_err
= ndr_push(push
, NDR_IN
, st
);
1808 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1809 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1810 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1811 "failed input validation push - %s",
1813 return ndr_map_error2ntstatus(ndr_err
);
1816 blob2
= ndr_push_blob(push
);
1818 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1819 DEBUG(3,("original:\n"));
1820 dump_data(3, blob
.data
, blob
.length
);
1821 DEBUG(3,("secondary:\n"));
1822 dump_data(3, blob2
.data
, blob2
.length
);
1823 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1824 "failed input validation blobs doesn't match");
1825 return ndr_map_error2ntstatus(ndr_err
);
1828 return NT_STATUS_OK
;
1832 this is a paranoid NDR input validator. For every packet we pull
1833 from the wire we push it back again then pull and push it
1834 again. Then we compare the raw NDR data for that to the NDR we
1835 initially generated. If they don't match then we know we must have a
1836 bug in either the pull or push side of our code
1838 static NTSTATUS
dcerpc_ndr_validate_out(struct dcecli_connection
*c
,
1839 struct ndr_pull
*pull_in
,
1842 ndr_push_flags_fn_t ndr_push
,
1843 ndr_pull_flags_fn_t ndr_pull
,
1844 ndr_print_function_t ndr_print
)
1847 struct ndr_pull
*pull
;
1848 struct ndr_push
*push
;
1849 DATA_BLOB blob
, blob2
;
1850 TALLOC_CTX
*mem_ctx
= pull_in
;
1852 enum ndr_err_code ndr_err
;
1854 st
= talloc_size(mem_ctx
, struct_size
);
1856 return NT_STATUS_NO_MEMORY
;
1858 memcpy(st
, struct_ptr
, struct_size
);
1860 push
= ndr_push_init_ctx(mem_ctx
);
1862 return NT_STATUS_NO_MEMORY
;
1865 ndr_err
= ndr_push(push
, NDR_OUT
, struct_ptr
);
1866 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1867 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1868 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1869 "failed output validation push - %s",
1871 return ndr_map_error2ntstatus(ndr_err
);
1874 blob
= ndr_push_blob(push
);
1876 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1878 return NT_STATUS_NO_MEMORY
;
1881 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1882 ndr_err
= ndr_pull(pull
, NDR_OUT
, st
);
1883 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1884 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1885 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1886 "failed output validation pull - %s",
1888 return ndr_map_error2ntstatus(ndr_err
);
1891 push
= ndr_push_init_ctx(mem_ctx
);
1893 return NT_STATUS_NO_MEMORY
;
1896 ndr_err
= ndr_push(push
, NDR_OUT
, st
);
1897 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1898 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1899 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1900 "failed output validation push2 - %s",
1902 return ndr_map_error2ntstatus(ndr_err
);
1905 blob2
= ndr_push_blob(push
);
1907 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1908 DEBUG(3,("original:\n"));
1909 dump_data(3, blob
.data
, blob
.length
);
1910 DEBUG(3,("secondary:\n"));
1911 dump_data(3, blob2
.data
, blob2
.length
);
1912 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1913 "failed output validation blobs doesn't match");
1914 return ndr_map_error2ntstatus(ndr_err
);
1917 /* this checks the printed forms of the two structures, which effectively
1918 tests all of the value() attributes */
1919 s1
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1920 NDR_OUT
, struct_ptr
);
1921 s2
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1923 if (strcmp(s1
, s2
) != 0) {
1925 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1
, s2
));
1927 /* this is sometimes useful */
1928 printf("VALIDATE ERROR\n");
1929 file_save("wire.dat", s1
, strlen(s1
));
1930 file_save("gen.dat", s2
, strlen(s2
));
1931 system("diff -u wire.dat gen.dat");
1933 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1934 "failed output validation strings doesn't match");
1935 return ndr_map_error2ntstatus(ndr_err
);
1938 return NT_STATUS_OK
;
1942 a useful function for retrieving the server name we connected to
1944 _PUBLIC_
const char *dcerpc_server_name(struct dcerpc_pipe
*p
)
1946 if (!p
->conn
->transport
.target_hostname
) {
1947 if (!p
->conn
->transport
.peer_name
) {
1950 return p
->conn
->transport
.peer_name(p
->conn
);
1952 return p
->conn
->transport
.target_hostname(p
->conn
);
1957 get the dcerpc auth_level for a open connection
1959 uint32_t dcerpc_auth_level(struct dcecli_connection
*c
)
1963 if (c
->flags
& DCERPC_SEAL
) {
1964 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
1965 } else if (c
->flags
& DCERPC_SIGN
) {
1966 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
1967 } else if (c
->flags
& DCERPC_CONNECT
) {
1968 auth_level
= DCERPC_AUTH_LEVEL_CONNECT
;
1970 auth_level
= DCERPC_AUTH_LEVEL_NONE
;
1975 struct dcerpc_alter_context_state
{
1976 struct tevent_context
*ev
;
1977 struct dcerpc_pipe
*p
;
1980 static void dcerpc_alter_context_fail_handler(struct rpc_request
*subreq
);
1981 static void dcerpc_alter_context_recv_handler(struct rpc_request
*req
,
1982 DATA_BLOB
*raw_packet
,
1983 struct ncacn_packet
*pkt
);
1985 struct tevent_req
*dcerpc_alter_context_send(TALLOC_CTX
*mem_ctx
,
1986 struct tevent_context
*ev
,
1987 struct dcerpc_pipe
*p
,
1988 const struct ndr_syntax_id
*syntax
,
1989 const struct ndr_syntax_id
*transfer_syntax
)
1991 struct tevent_req
*req
;
1992 struct dcerpc_alter_context_state
*state
;
1993 struct ncacn_packet pkt
;
1996 struct rpc_request
*subreq
;
1998 req
= tevent_req_create(mem_ctx
, &state
,
1999 struct dcerpc_alter_context_state
);
2007 p
->syntax
= *syntax
;
2008 p
->transfer_syntax
= *transfer_syntax
;
2010 init_ncacn_hdr(p
->conn
, &pkt
);
2012 pkt
.ptype
= DCERPC_PKT_ALTER
;
2013 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
2014 pkt
.call_id
= p
->conn
->call_id
;
2015 pkt
.auth_length
= 0;
2017 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
2018 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
2021 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
2022 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
2025 pkt
.u
.alter
.max_xmit_frag
= 5840;
2026 pkt
.u
.alter
.max_recv_frag
= 5840;
2027 pkt
.u
.alter
.assoc_group_id
= p
->binding
->assoc_group_id
;
2028 pkt
.u
.alter
.num_contexts
= 1;
2029 pkt
.u
.alter
.ctx_list
= talloc_array(state
, struct dcerpc_ctx_list
, 1);
2030 if (tevent_req_nomem(pkt
.u
.alter
.ctx_list
, req
)) {
2031 return tevent_req_post(req
, ev
);
2033 pkt
.u
.alter
.ctx_list
[0].context_id
= p
->context_id
;
2034 pkt
.u
.alter
.ctx_list
[0].num_transfer_syntaxes
= 1;
2035 pkt
.u
.alter
.ctx_list
[0].abstract_syntax
= p
->syntax
;
2036 pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
2037 pkt
.u
.alter
.auth_info
= data_blob(NULL
, 0);
2039 /* construct the NDR form of the packet */
2040 status
= ncacn_push_auth(&blob
, state
, &pkt
,
2041 p
->conn
->security_state
.auth_info
);
2042 if (tevent_req_nterror(req
, status
)) {
2043 return tevent_req_post(req
, ev
);
2046 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
2049 * we allocate a dcerpc_request so we can be in the same
2050 * request queue as normal requests
2052 subreq
= talloc_zero(state
, struct rpc_request
);
2053 if (tevent_req_nomem(subreq
, req
)) {
2054 return tevent_req_post(req
, ev
);
2057 subreq
->state
= RPC_REQUEST_PENDING
;
2058 subreq
->call_id
= pkt
.call_id
;
2059 subreq
->async
.private_data
= req
;
2060 subreq
->async
.callback
= dcerpc_alter_context_fail_handler
;
2062 subreq
->recv_handler
= dcerpc_alter_context_recv_handler
;
2063 DLIST_ADD_END(p
->conn
->pending
, subreq
, struct rpc_request
*);
2064 talloc_set_destructor(subreq
, dcerpc_req_dequeue
);
2066 status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, true);
2067 if (tevent_req_nterror(req
, status
)) {
2068 return tevent_req_post(req
, ev
);
2071 tevent_add_timer(ev
, subreq
,
2072 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
2073 dcerpc_timeout_handler
, subreq
);
2078 static void dcerpc_alter_context_fail_handler(struct rpc_request
*subreq
)
2080 struct tevent_req
*req
=
2081 talloc_get_type_abort(subreq
->async
.private_data
,
2083 struct dcerpc_alter_context_state
*state
=
2084 tevent_req_data(req
,
2085 struct dcerpc_alter_context_state
);
2086 NTSTATUS status
= subreq
->status
;
2088 TALLOC_FREE(subreq
);
2091 * We trigger the callback in the next event run
2092 * because the code in this file might trigger
2093 * multiple request callbacks from within a single
2096 * In order to avoid segfaults from within
2097 * dcerpc_connection_dead() we call
2098 * tevent_req_defer_callback().
2100 tevent_req_defer_callback(req
, state
->ev
);
2102 tevent_req_nterror(req
, status
);
2105 static void dcerpc_alter_context_recv_handler(struct rpc_request
*subreq
,
2106 DATA_BLOB
*raw_packet
,
2107 struct ncacn_packet
*pkt
)
2109 struct tevent_req
*req
=
2110 talloc_get_type_abort(subreq
->async
.private_data
,
2112 struct dcerpc_alter_context_state
*state
=
2113 tevent_req_data(req
,
2114 struct dcerpc_alter_context_state
);
2115 struct dcecli_connection
*conn
= state
->p
->conn
;
2119 * Note that pkt is allocated under raw_packet->data,
2120 * while raw_packet->data is a child of subreq.
2122 talloc_steal(state
, raw_packet
->data
);
2123 TALLOC_FREE(subreq
);
2126 * We trigger the callback in the next event run
2127 * because the code in this file might trigger
2128 * multiple request callbacks from within a single
2131 * In order to avoid segfaults from within
2132 * dcerpc_connection_dead() we call
2133 * tevent_req_defer_callback().
2135 tevent_req_defer_callback(req
, state
->ev
);
2137 if (pkt
->ptype
== DCERPC_PKT_ALTER_RESP
&&
2138 pkt
->u
.alter_resp
.num_results
== 1 &&
2139 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
2140 status
= dcerpc_map_reason(pkt
->u
.alter_resp
.ctx_list
[0].reason
);
2141 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2142 pkt
->u
.alter_resp
.ctx_list
[0].reason
,
2143 nt_errstr(status
)));
2144 tevent_req_nterror(req
, status
);
2148 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
2149 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2150 dcerpc_errstr(state
, pkt
->u
.fault
.status
)));
2151 state
->p
->last_fault_code
= pkt
->u
.fault
.status
;
2152 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
2156 if (pkt
->ptype
!= DCERPC_PKT_ALTER_RESP
||
2157 pkt
->u
.alter_resp
.num_results
== 0 ||
2158 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
2159 state
->p
->last_fault_code
= DCERPC_NCA_S_PROTO_ERROR
;
2160 tevent_req_nterror(req
, NT_STATUS_NET_WRITE_FAULT
);
2164 /* the alter_resp might contain a reply set of credentials */
2165 if (conn
->security_state
.auth_info
&&
2166 pkt
->u
.alter_resp
.auth_info
.length
) {
2167 uint32_t auth_length
;
2169 status
= dcerpc_pull_auth_trailer(pkt
, conn
, &pkt
->u
.alter_resp
.auth_info
,
2170 conn
->security_state
.auth_info
, &auth_length
, true);
2171 if (tevent_req_nterror(req
, status
)) {
2176 tevent_req_done(req
);
2179 NTSTATUS
dcerpc_alter_context_recv(struct tevent_req
*req
)
2181 return tevent_req_simple_recv_ntstatus(req
);
2185 send a dcerpc alter_context request
2187 _PUBLIC_ NTSTATUS
dcerpc_alter_context(struct dcerpc_pipe
*p
,
2188 TALLOC_CTX
*mem_ctx
,
2189 const struct ndr_syntax_id
*syntax
,
2190 const struct ndr_syntax_id
*transfer_syntax
)
2192 struct tevent_req
*subreq
;
2193 struct tevent_context
*ev
= p
->conn
->event_ctx
;
2196 /* TODO: create a new event context here */
2198 subreq
= dcerpc_alter_context_send(mem_ctx
, p
->conn
->event_ctx
,
2199 p
, syntax
, transfer_syntax
);
2200 if (subreq
== NULL
) {
2201 return NT_STATUS_NO_MEMORY
;
2204 ok
= tevent_req_poll(subreq
, ev
);
2207 status
= map_nt_error_from_unix_common(errno
);
2211 return dcerpc_alter_context_recv(subreq
);