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"
34 _PUBLIC_ NTSTATUS
dcerpc_init(struct loadparm_context
*lp_ctx
)
36 return gensec_init(lp_ctx
);
39 static void dcerpc_connection_dead(struct dcerpc_connection
*conn
, NTSTATUS status
);
40 static void dcerpc_ship_next_request(struct dcerpc_connection
*c
);
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection
*conn
)
46 conn
->free_skipped
= true;
49 dcerpc_connection_dead(conn
, NT_STATUS_LOCAL_DISCONNECT
);
54 /* initialise a dcerpc connection.
55 the event context is optional
57 static struct dcerpc_connection
*dcerpc_connection_init(TALLOC_CTX
*mem_ctx
,
58 struct tevent_context
*ev
,
59 struct smb_iconv_convenience
*ic
)
61 struct dcerpc_connection
*c
;
63 c
= talloc_zero(mem_ctx
, struct dcerpc_connection
);
68 c
->iconv_convenience
= talloc_reference(c
, ic
);
72 if (c
->event_ctx
== NULL
) {
78 c
->security_state
.auth_info
= NULL
;
79 c
->security_state
.session_key
= dcerpc_generic_session_key
;
80 c
->security_state
.generic_state
= NULL
;
81 c
->binding_string
= NULL
;
83 c
->srv_max_xmit_frag
= 0;
84 c
->srv_max_recv_frag
= 0;
87 talloc_set_destructor(c
, dcerpc_connection_destructor
);
92 /* initialise a dcerpc pipe. */
93 _PUBLIC_
struct dcerpc_pipe
*dcerpc_pipe_init(TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
94 struct smb_iconv_convenience
*ic
)
96 struct dcerpc_pipe
*p
;
98 p
= talloc(mem_ctx
, struct dcerpc_pipe
);
103 p
->conn
= dcerpc_connection_init(p
, ev
, ic
);
104 if (p
->conn
== NULL
) {
109 p
->last_fault_code
= 0;
111 p
->request_timeout
= DCERPC_REQUEST_TIMEOUT
;
114 ZERO_STRUCT(p
->syntax
);
115 ZERO_STRUCT(p
->transfer_syntax
);
118 p
->conn
->flags
|= DCERPC_DEBUG_PRINT_BOTH
;
126 choose the next call id to use
128 static uint32_t next_call_id(struct dcerpc_connection
*c
)
131 if (c
->call_id
== 0) {
137 /* we need to be able to get/set the fragment length without doing a full
139 void dcerpc_set_frag_length(DATA_BLOB
*blob
, uint16_t v
)
141 if (CVAL(blob
->data
,DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
) {
142 SSVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
, v
);
144 RSSVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
, v
);
148 uint16_t dcerpc_get_frag_length(const DATA_BLOB
*blob
)
150 if (CVAL(blob
->data
,DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
) {
151 return SVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
);
153 return RSVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
);
157 void dcerpc_set_auth_length(DATA_BLOB
*blob
, uint16_t v
)
159 if (CVAL(blob
->data
,DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
) {
160 SSVAL(blob
->data
, DCERPC_AUTH_LEN_OFFSET
, v
);
162 RSSVAL(blob
->data
, DCERPC_AUTH_LEN_OFFSET
, v
);
168 setup for a ndr pull, also setting up any flags from the binding string
170 static struct ndr_pull
*ndr_pull_init_flags(struct dcerpc_connection
*c
,
171 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
173 struct ndr_pull
*ndr
= ndr_pull_init_blob(blob
, mem_ctx
, c
->iconv_convenience
);
175 if (ndr
== NULL
) return ndr
;
177 if (c
->flags
& DCERPC_DEBUG_PAD_CHECK
) {
178 ndr
->flags
|= LIBNDR_FLAG_PAD_CHECK
;
181 if (c
->flags
& DCERPC_NDR_REF_ALLOC
) {
182 ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
185 if (c
->flags
& DCERPC_NDR64
) {
186 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
193 parse a data blob into a ncacn_packet structure. This handles both
194 input and output packets
196 static NTSTATUS
ncacn_pull(struct dcerpc_connection
*c
, DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
197 struct ncacn_packet
*pkt
)
199 struct ndr_pull
*ndr
;
200 enum ndr_err_code ndr_err
;
202 ndr
= ndr_pull_init_flags(c
, blob
, mem_ctx
);
204 return NT_STATUS_NO_MEMORY
;
207 if (! (CVAL(blob
->data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
208 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
211 ndr_err
= ndr_pull_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
212 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
213 return ndr_map_error2ntstatus(ndr_err
);
220 parse the authentication information on a dcerpc response packet
222 static NTSTATUS
ncacn_pull_request_auth(struct dcerpc_connection
*c
, TALLOC_CTX
*mem_ctx
,
223 DATA_BLOB
*raw_packet
,
224 struct ncacn_packet
*pkt
)
226 struct ndr_pull
*ndr
;
228 struct dcerpc_auth auth
;
230 enum ndr_err_code ndr_err
;
232 if (!c
->security_state
.auth_info
||
233 !c
->security_state
.generic_state
) {
237 switch (c
->security_state
.auth_info
->auth_level
) {
238 case DCERPC_AUTH_LEVEL_PRIVACY
:
239 case DCERPC_AUTH_LEVEL_INTEGRITY
:
242 case DCERPC_AUTH_LEVEL_CONNECT
:
243 if (pkt
->auth_length
!= 0) {
247 case DCERPC_AUTH_LEVEL_NONE
:
248 if (pkt
->auth_length
!= 0) {
249 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
254 return NT_STATUS_INVALID_LEVEL
;
257 auth_blob
.length
= 8 + pkt
->auth_length
;
259 /* check for a valid length */
260 if (pkt
->u
.response
.stub_and_verifier
.length
< auth_blob
.length
) {
261 return NT_STATUS_INFO_LENGTH_MISMATCH
;
265 pkt
->u
.response
.stub_and_verifier
.data
+
266 pkt
->u
.response
.stub_and_verifier
.length
- auth_blob
.length
;
267 pkt
->u
.response
.stub_and_verifier
.length
-= auth_blob
.length
;
269 /* pull the auth structure */
270 ndr
= ndr_pull_init_flags(c
, &auth_blob
, mem_ctx
);
272 return NT_STATUS_NO_MEMORY
;
275 if (!(pkt
->drep
[0] & DCERPC_DREP_LE
)) {
276 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
279 ndr_err
= ndr_pull_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, &auth
);
280 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
281 return ndr_map_error2ntstatus(ndr_err
);
283 status
= NT_STATUS_OK
;
285 /* check signature or unseal the packet */
286 switch (c
->security_state
.auth_info
->auth_level
) {
287 case DCERPC_AUTH_LEVEL_PRIVACY
:
288 status
= gensec_unseal_packet(c
->security_state
.generic_state
,
290 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
291 pkt
->u
.response
.stub_and_verifier
.length
,
293 raw_packet
->length
- auth
.credentials
.length
,
295 memcpy(pkt
->u
.response
.stub_and_verifier
.data
,
296 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
297 pkt
->u
.response
.stub_and_verifier
.length
);
300 case DCERPC_AUTH_LEVEL_INTEGRITY
:
301 status
= gensec_check_packet(c
->security_state
.generic_state
,
303 pkt
->u
.response
.stub_and_verifier
.data
,
304 pkt
->u
.response
.stub_and_verifier
.length
,
306 raw_packet
->length
- auth
.credentials
.length
,
310 case DCERPC_AUTH_LEVEL_CONNECT
:
311 /* for now we ignore possible signatures here */
312 status
= NT_STATUS_OK
;
316 status
= NT_STATUS_INVALID_LEVEL
;
320 /* remove the indicated amount of paddiing */
321 if (pkt
->u
.response
.stub_and_verifier
.length
< auth
.auth_pad_length
) {
322 return NT_STATUS_INFO_LENGTH_MISMATCH
;
324 pkt
->u
.response
.stub_and_verifier
.length
-= auth
.auth_pad_length
;
331 push a dcerpc request packet into a blob, possibly signing it.
333 static NTSTATUS
ncacn_push_request_sign(struct dcerpc_connection
*c
,
334 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
336 struct ncacn_packet
*pkt
)
339 struct ndr_push
*ndr
;
341 size_t payload_length
;
342 enum ndr_err_code ndr_err
;
343 size_t hdr_size
= DCERPC_REQUEST_LENGTH
;
345 /* non-signed packets are simpler */
347 return ncacn_push_auth(blob
, mem_ctx
, c
->iconv_convenience
, pkt
, NULL
);
350 switch (c
->security_state
.auth_info
->auth_level
) {
351 case DCERPC_AUTH_LEVEL_PRIVACY
:
352 case DCERPC_AUTH_LEVEL_INTEGRITY
:
355 case DCERPC_AUTH_LEVEL_CONNECT
:
356 /* TODO: let the gensec mech decide if it wants to generate a signature */
357 return ncacn_push_auth(blob
, mem_ctx
, c
->iconv_convenience
, pkt
, NULL
);
359 case DCERPC_AUTH_LEVEL_NONE
:
360 return ncacn_push_auth(blob
, mem_ctx
, c
->iconv_convenience
, pkt
, NULL
);
363 return NT_STATUS_INVALID_LEVEL
;
366 ndr
= ndr_push_init_ctx(mem_ctx
, c
->iconv_convenience
);
368 return NT_STATUS_NO_MEMORY
;
371 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
372 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
375 if (c
->flags
& DCERPC_NDR64
) {
376 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
379 if (pkt
->pfc_flags
& DCERPC_PFC_FLAG_OBJECT_UUID
) {
380 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
384 ndr_err
= ndr_push_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
385 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
386 return ndr_map_error2ntstatus(ndr_err
);
388 status
= NT_STATUS_OK
;
390 /* pad to 16 byte multiple in the payload portion of the
391 packet. This matches what w2k3 does */
392 c
->security_state
.auth_info
->auth_pad_length
=
393 (16 - (pkt
->u
.request
.stub_and_verifier
.length
& 15)) & 15;
394 ndr_err
= ndr_push_zero(ndr
, c
->security_state
.auth_info
->auth_pad_length
);
395 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
396 return ndr_map_error2ntstatus(ndr_err
);
398 status
= NT_STATUS_OK
;
400 payload_length
= pkt
->u
.request
.stub_and_verifier
.length
+
401 c
->security_state
.auth_info
->auth_pad_length
;
403 /* we start without signature, it will appended later */
404 c
->security_state
.auth_info
->credentials
= data_blob(NULL
,0);
406 /* add the auth verifier */
407 ndr_err
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, c
->security_state
.auth_info
);
408 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
409 return ndr_map_error2ntstatus(ndr_err
);
411 status
= NT_STATUS_OK
;
413 /* extract the whole packet as a blob */
414 *blob
= ndr_push_blob(ndr
);
417 * Setup the frag and auth length in the packet buffer.
418 * This is needed if the GENSEC mech does AEAD signing
419 * of the packet headers. The signature itself will be
422 dcerpc_set_frag_length(blob
, blob
->length
+ sig_size
);
423 dcerpc_set_auth_length(blob
, sig_size
);
425 /* sign or seal the packet */
426 switch (c
->security_state
.auth_info
->auth_level
) {
427 case DCERPC_AUTH_LEVEL_PRIVACY
:
428 status
= gensec_seal_packet(c
->security_state
.generic_state
,
430 blob
->data
+ hdr_size
,
435 if (!NT_STATUS_IS_OK(status
)) {
440 case DCERPC_AUTH_LEVEL_INTEGRITY
:
441 status
= gensec_sign_packet(c
->security_state
.generic_state
,
443 blob
->data
+ hdr_size
,
448 if (!NT_STATUS_IS_OK(status
)) {
454 status
= NT_STATUS_INVALID_LEVEL
;
458 if (creds2
.length
!= sig_size
) {
459 DEBUG(0,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
460 creds2
.length
, (uint32_t)sig_size
,
461 c
->security_state
.auth_info
->auth_pad_length
,
462 pkt
->u
.request
.stub_and_verifier
.length
));
463 return NT_STATUS_INTERNAL_ERROR
;
466 if (!data_blob_append(mem_ctx
, blob
, creds2
.data
, creds2
.length
)) {
467 return NT_STATUS_NO_MEMORY
;
475 fill in the fixed values in a dcerpc header
477 static void init_ncacn_hdr(struct dcerpc_connection
*c
, struct ncacn_packet
*pkt
)
480 pkt
->rpc_vers_minor
= 0;
481 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
484 pkt
->drep
[0] = DCERPC_DREP_LE
;
492 map a bind nak reason to a NTSTATUS
494 static NTSTATUS
dcerpc_map_reason(uint16_t reason
)
497 case DCERPC_BIND_REASON_ASYNTAX
:
498 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX
;
499 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE
:
500 return NT_STATUS_INVALID_PARAMETER
;
502 return NT_STATUS_UNSUCCESSFUL
;
506 a bind or alter context has failed
508 static void dcerpc_composite_fail(struct rpc_request
*req
)
510 struct composite_context
*c
= talloc_get_type(req
->async
.private_data
,
511 struct composite_context
);
512 composite_error(c
, req
->status
);
516 remove requests from the pending or queued queues
518 static int dcerpc_req_dequeue(struct rpc_request
*req
)
520 switch (req
->state
) {
521 case RPC_REQUEST_QUEUED
:
522 DLIST_REMOVE(req
->p
->conn
->request_queue
, req
);
524 case RPC_REQUEST_PENDING
:
525 DLIST_REMOVE(req
->p
->conn
->pending
, req
);
527 case RPC_REQUEST_DONE
:
535 mark the dcerpc connection dead. All outstanding requests get an error
537 static void dcerpc_connection_dead(struct dcerpc_connection
*conn
, NTSTATUS status
)
539 if (conn
->dead
) return;
543 if (conn
->transport
.shutdown_pipe
) {
544 conn
->transport
.shutdown_pipe(conn
, status
);
547 /* all pending requests get the error */
548 while (conn
->pending
) {
549 struct rpc_request
*req
= conn
->pending
;
550 dcerpc_req_dequeue(req
);
551 req
->state
= RPC_REQUEST_DONE
;
552 req
->status
= status
;
553 if (req
->async
.callback
) {
554 req
->async
.callback(req
);
558 talloc_set_destructor(conn
, NULL
);
559 if (conn
->free_skipped
) {
565 forward declarations of the recv_data handlers for the types of
566 packets we need to handle
568 static void dcerpc_request_recv_data(struct dcerpc_connection
*c
,
569 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
);
572 receive a dcerpc reply from the transport. Here we work out what
573 type of reply it is (normal request, bind or alter context) and
574 dispatch to the appropriate handler
576 static void dcerpc_recv_data(struct dcerpc_connection
*conn
, DATA_BLOB
*blob
, NTSTATUS status
)
578 struct ncacn_packet pkt
;
580 if (NT_STATUS_IS_OK(status
) && blob
->length
== 0) {
581 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
584 /* the transport may be telling us of a severe error, such as
586 if (!NT_STATUS_IS_OK(status
)) {
587 data_blob_free(blob
);
588 dcerpc_connection_dead(conn
, status
);
592 /* parse the basic packet to work out what type of response this is */
593 status
= ncacn_pull(conn
, blob
, blob
->data
, &pkt
);
594 if (!NT_STATUS_IS_OK(status
)) {
595 data_blob_free(blob
);
596 dcerpc_connection_dead(conn
, status
);
599 dcerpc_request_recv_data(conn
, blob
, &pkt
);
604 Receive a bind reply from the transport
606 static void dcerpc_bind_recv_handler(struct rpc_request
*req
,
607 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
609 struct composite_context
*c
;
610 struct dcerpc_connection
*conn
;
612 c
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
614 if (pkt
->ptype
== DCERPC_PKT_BIND_NAK
) {
615 DEBUG(2,("dcerpc: bind_nak reason %d\n",
616 pkt
->u
.bind_nak
.reject_reason
));
617 composite_error(c
, dcerpc_map_reason(pkt
->u
.bind_nak
.
622 if ((pkt
->ptype
!= DCERPC_PKT_BIND_ACK
) ||
623 (pkt
->u
.bind_ack
.num_results
== 0) ||
624 (pkt
->u
.bind_ack
.ctx_list
[0].result
!= 0)) {
625 composite_error(c
, NT_STATUS_NET_WRITE_FAULT
);
631 conn
->srv_max_xmit_frag
= pkt
->u
.bind_ack
.max_xmit_frag
;
632 conn
->srv_max_recv_frag
= pkt
->u
.bind_ack
.max_recv_frag
;
634 if ((req
->p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) &&
635 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_CONC_MPX
)) {
636 conn
->flags
|= DCERPC_CONCURRENT_MULTIPLEX
;
639 if ((req
->p
->binding
->flags
& DCERPC_HEADER_SIGNING
) &&
640 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
)) {
641 conn
->flags
|= DCERPC_HEADER_SIGNING
;
644 /* the bind_ack might contain a reply set of credentials */
645 if (conn
->security_state
.auth_info
&&
646 pkt
->u
.bind_ack
.auth_info
.length
) {
647 enum ndr_err_code ndr_err
;
648 ndr_err
= ndr_pull_struct_blob(
649 &pkt
->u
.bind_ack
.auth_info
, conn
,
651 conn
->security_state
.auth_info
,
652 (ndr_pull_flags_fn_t
)ndr_pull_dcerpc_auth
);
653 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
654 c
->status
= ndr_map_error2ntstatus(ndr_err
);
655 if (!composite_is_ok(c
)) return;
659 req
->p
->assoc_group_id
= pkt
->u
.bind_ack
.assoc_group_id
;
665 handle timeouts of individual dcerpc requests
667 static void dcerpc_timeout_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
668 struct timeval t
, void *private_data
)
670 struct rpc_request
*req
= talloc_get_type(private_data
, struct rpc_request
);
672 if (req
->ignore_timeout
) {
673 dcerpc_req_dequeue(req
);
674 req
->state
= RPC_REQUEST_DONE
;
675 req
->status
= NT_STATUS_IO_TIMEOUT
;
676 if (req
->async
.callback
) {
677 req
->async
.callback(req
);
682 dcerpc_connection_dead(req
->p
->conn
, NT_STATUS_IO_TIMEOUT
);
686 send a async dcerpc bind request
688 struct composite_context
*dcerpc_bind_send(struct dcerpc_pipe
*p
,
690 const struct ndr_syntax_id
*syntax
,
691 const struct ndr_syntax_id
*transfer_syntax
)
693 struct composite_context
*c
;
694 struct ncacn_packet pkt
;
696 struct rpc_request
*req
;
698 c
= composite_create(mem_ctx
,p
->conn
->event_ctx
);
699 if (c
== NULL
) return NULL
;
704 p
->transfer_syntax
= *transfer_syntax
;
706 init_ncacn_hdr(p
->conn
, &pkt
);
708 pkt
.ptype
= DCERPC_PKT_BIND
;
709 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
710 pkt
.call_id
= p
->conn
->call_id
;
713 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
714 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
717 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
718 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
721 pkt
.u
.bind
.max_xmit_frag
= 5840;
722 pkt
.u
.bind
.max_recv_frag
= 5840;
723 pkt
.u
.bind
.assoc_group_id
= p
->binding
->assoc_group_id
;
724 pkt
.u
.bind
.num_contexts
= 1;
725 pkt
.u
.bind
.ctx_list
= talloc_array(mem_ctx
, struct dcerpc_ctx_list
, 1);
726 if (composite_nomem(pkt
.u
.bind
.ctx_list
, c
)) return c
;
727 pkt
.u
.bind
.ctx_list
[0].context_id
= p
->context_id
;
728 pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
= 1;
729 pkt
.u
.bind
.ctx_list
[0].abstract_syntax
= p
->syntax
;
730 pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
731 pkt
.u
.bind
.auth_info
= data_blob(NULL
, 0);
733 /* construct the NDR form of the packet */
734 c
->status
= ncacn_push_auth(&blob
, c
, p
->conn
->iconv_convenience
, &pkt
,
735 p
->conn
->security_state
.auth_info
);
736 if (!composite_is_ok(c
)) return c
;
738 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
741 * we allocate a dcerpc_request so we can be in the same
742 * request queue as normal requests
744 req
= talloc_zero(c
, struct rpc_request
);
745 if (composite_nomem(req
, c
)) return c
;
747 req
->state
= RPC_REQUEST_PENDING
;
748 req
->call_id
= pkt
.call_id
;
749 req
->async
.private_data
= c
;
750 req
->async
.callback
= dcerpc_composite_fail
;
752 req
->recv_handler
= dcerpc_bind_recv_handler
;
753 DLIST_ADD_END(p
->conn
->pending
, req
, struct rpc_request
*);
754 talloc_set_destructor(req
, dcerpc_req_dequeue
);
756 c
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
,
758 if (!composite_is_ok(c
)) return c
;
760 event_add_timed(c
->event_ctx
, req
,
761 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
762 dcerpc_timeout_handler
, req
);
768 recv side of async dcerpc bind request
770 NTSTATUS
dcerpc_bind_recv(struct composite_context
*ctx
)
772 NTSTATUS result
= composite_wait(ctx
);
778 perform a continued bind (and auth3)
780 NTSTATUS
dcerpc_auth3(struct dcerpc_pipe
*p
,
783 struct ncacn_packet pkt
;
787 init_ncacn_hdr(p
->conn
, &pkt
);
789 pkt
.ptype
= DCERPC_PKT_AUTH3
;
790 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
791 pkt
.call_id
= next_call_id(p
->conn
);
793 pkt
.u
.auth3
._pad
= 0;
794 pkt
.u
.auth3
.auth_info
= data_blob(NULL
, 0);
796 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
797 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
800 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
801 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
804 /* construct the NDR form of the packet */
805 status
= ncacn_push_auth(&blob
, mem_ctx
,
806 p
->conn
->iconv_convenience
,
808 p
->conn
->security_state
.auth_info
);
809 if (!NT_STATUS_IS_OK(status
)) {
813 /* send it on its way */
814 status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, false);
815 if (!NT_STATUS_IS_OK(status
)) {
824 process a fragment received from the transport layer during a
827 This function frees the data
829 static void dcerpc_request_recv_data(struct dcerpc_connection
*c
,
830 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
832 struct rpc_request
*req
;
834 NTSTATUS status
= NT_STATUS_OK
;
837 if this is an authenticated connection then parse and check
838 the auth info. We have to do this before finding the
839 matching packet, as the request structure might have been
840 removed due to a timeout, but if it has been we still need
841 to run the auth routines so that we don't get the sign/seal
842 info out of step with the server
844 if (c
->security_state
.auth_info
&& c
->security_state
.generic_state
&&
845 pkt
->ptype
== DCERPC_PKT_RESPONSE
) {
846 status
= ncacn_pull_request_auth(c
, raw_packet
->data
, raw_packet
, pkt
);
849 /* find the matching request */
850 for (req
=c
->pending
;req
;req
=req
->next
) {
851 if (pkt
->call_id
== req
->call_id
) break;
855 /* useful for testing certain vendors RPC servers */
856 if (req
== NULL
&& c
->pending
&& pkt
->call_id
== 0) {
857 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
863 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt
->call_id
));
864 data_blob_free(raw_packet
);
868 talloc_steal(req
, raw_packet
->data
);
870 if (req
->recv_handler
!= NULL
) {
871 dcerpc_req_dequeue(req
);
872 req
->state
= RPC_REQUEST_DONE
;
873 req
->recv_handler(req
, raw_packet
, pkt
);
877 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
878 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c
, pkt
->u
.fault
.status
)));
879 req
->fault_code
= pkt
->u
.fault
.status
;
880 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
884 if (pkt
->ptype
!= DCERPC_PKT_RESPONSE
) {
885 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
887 req
->fault_code
= DCERPC_FAULT_OTHER
;
888 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
892 /* now check the status from the auth routines, and if it failed then fail
893 this request accordingly */
894 if (!NT_STATUS_IS_OK(status
)) {
895 req
->status
= status
;
899 length
= pkt
->u
.response
.stub_and_verifier
.length
;
902 req
->payload
.data
= talloc_realloc(req
,
905 req
->payload
.length
+ length
);
906 if (!req
->payload
.data
) {
907 req
->status
= NT_STATUS_NO_MEMORY
;
910 memcpy(req
->payload
.data
+req
->payload
.length
,
911 pkt
->u
.response
.stub_and_verifier
.data
, length
);
912 req
->payload
.length
+= length
;
915 if (!(pkt
->pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
916 c
->transport
.send_read(c
);
920 if (!(pkt
->drep
[0] & DCERPC_DREP_LE
)) {
921 req
->flags
|= DCERPC_PULL_BIGENDIAN
;
923 req
->flags
&= ~DCERPC_PULL_BIGENDIAN
;
928 /* we've got the full payload */
929 req
->state
= RPC_REQUEST_DONE
;
930 DLIST_REMOVE(c
->pending
, req
);
932 if (c
->request_queue
!= NULL
) {
933 /* We have to look at shipping further requests before calling
934 * the async function, that one might close the pipe */
935 dcerpc_ship_next_request(c
);
938 if (req
->async
.callback
) {
939 req
->async
.callback(req
);
944 perform the send side of a async dcerpc request
946 static struct rpc_request
*dcerpc_request_send(struct dcerpc_pipe
*p
,
947 const struct GUID
*object
,
950 DATA_BLOB
*stub_data
)
952 struct rpc_request
*req
;
954 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
956 req
= talloc(p
, struct rpc_request
);
962 req
->call_id
= next_call_id(p
->conn
);
963 req
->status
= NT_STATUS_OK
;
964 req
->state
= RPC_REQUEST_QUEUED
;
965 req
->payload
= data_blob(NULL
, 0);
968 req
->async_call
= async
;
969 req
->ignore_timeout
= false;
970 req
->async
.callback
= NULL
;
971 req
->async
.private_data
= NULL
;
972 req
->recv_handler
= NULL
;
974 if (object
!= NULL
) {
975 req
->object
= (struct GUID
*)talloc_memdup(req
, (const void *)object
, sizeof(*object
));
976 if (req
->object
== NULL
) {
985 req
->request_data
.length
= stub_data
->length
;
986 req
->request_data
.data
= talloc_reference(req
, stub_data
->data
);
987 if (req
->request_data
.length
&& req
->request_data
.data
== NULL
) {
991 DLIST_ADD_END(p
->conn
->request_queue
, req
, struct rpc_request
*);
992 talloc_set_destructor(req
, dcerpc_req_dequeue
);
994 dcerpc_ship_next_request(p
->conn
);
996 if (p
->request_timeout
) {
997 event_add_timed(dcerpc_event_context(p
), req
,
998 timeval_current_ofs(p
->request_timeout
, 0),
999 dcerpc_timeout_handler
, req
);
1006 Send a request using the transport
1009 static void dcerpc_ship_next_request(struct dcerpc_connection
*c
)
1011 struct rpc_request
*req
;
1012 struct dcerpc_pipe
*p
;
1013 DATA_BLOB
*stub_data
;
1014 struct ncacn_packet pkt
;
1016 uint32_t remaining
, chunk_size
;
1017 bool first_packet
= true;
1018 size_t sig_size
= 0;
1020 req
= c
->request_queue
;
1026 stub_data
= &req
->request_data
;
1028 if (!req
->async_call
&& (c
->pending
!= NULL
)) {
1032 DLIST_REMOVE(c
->request_queue
, req
);
1033 DLIST_ADD(c
->pending
, req
);
1034 req
->state
= RPC_REQUEST_PENDING
;
1036 init_ncacn_hdr(p
->conn
, &pkt
);
1038 remaining
= stub_data
->length
;
1040 /* we can write a full max_recv_frag size, minus the dcerpc
1041 request header size */
1042 chunk_size
= p
->conn
->srv_max_recv_frag
;
1043 chunk_size
-= DCERPC_REQUEST_LENGTH
;
1044 if (c
->security_state
.auth_info
&&
1045 c
->security_state
.generic_state
) {
1046 sig_size
= gensec_sig_size(c
->security_state
.generic_state
,
1047 p
->conn
->srv_max_recv_frag
);
1049 chunk_size
-= DCERPC_AUTH_TRAILER_LENGTH
;
1050 chunk_size
-= sig_size
;
1053 chunk_size
-= (chunk_size
% 16);
1055 pkt
.ptype
= DCERPC_PKT_REQUEST
;
1056 pkt
.call_id
= req
->call_id
;
1057 pkt
.auth_length
= 0;
1059 pkt
.u
.request
.alloc_hint
= remaining
;
1060 pkt
.u
.request
.context_id
= p
->context_id
;
1061 pkt
.u
.request
.opnum
= req
->opnum
;
1064 pkt
.u
.request
.object
.object
= *req
->object
;
1065 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_OBJECT_UUID
;
1066 chunk_size
-= ndr_size_GUID(req
->object
,NULL
,0);
1069 /* we send a series of pdus without waiting for a reply */
1070 while (remaining
> 0 || first_packet
) {
1071 uint32_t chunk
= MIN(chunk_size
, remaining
);
1072 bool last_frag
= false;
1073 bool do_trans
= false;
1075 first_packet
= false;
1076 pkt
.pfc_flags
&= ~(DCERPC_PFC_FLAG_FIRST
|DCERPC_PFC_FLAG_LAST
);
1078 if (remaining
== stub_data
->length
) {
1079 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_FIRST
;
1081 if (chunk
== remaining
) {
1082 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_LAST
;
1086 pkt
.u
.request
.stub_and_verifier
.data
= stub_data
->data
+
1087 (stub_data
->length
- remaining
);
1088 pkt
.u
.request
.stub_and_verifier
.length
= chunk
;
1090 req
->status
= ncacn_push_request_sign(p
->conn
, &blob
, req
, sig_size
, &pkt
);
1091 if (!NT_STATUS_IS_OK(req
->status
)) {
1092 req
->state
= RPC_REQUEST_DONE
;
1093 DLIST_REMOVE(p
->conn
->pending
, req
);
1097 if (last_frag
&& !req
->async_call
) {
1101 req
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, do_trans
);
1102 if (!NT_STATUS_IS_OK(req
->status
)) {
1103 req
->state
= RPC_REQUEST_DONE
;
1104 DLIST_REMOVE(p
->conn
->pending
, req
);
1108 if (last_frag
&& !do_trans
) {
1109 req
->status
= p
->conn
->transport
.send_read(p
->conn
);
1110 if (!NT_STATUS_IS_OK(req
->status
)) {
1111 req
->state
= RPC_REQUEST_DONE
;
1112 DLIST_REMOVE(p
->conn
->pending
, req
);
1122 return the event context for a dcerpc pipe
1123 used by callers who wish to operate asynchronously
1125 _PUBLIC_
struct tevent_context
*dcerpc_event_context(struct dcerpc_pipe
*p
)
1127 return p
->conn
->event_ctx
;
1133 perform the receive side of a async dcerpc request
1135 NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
1136 TALLOC_CTX
*mem_ctx
,
1137 DATA_BLOB
*stub_data
)
1141 while (req
->state
!= RPC_REQUEST_DONE
) {
1142 struct tevent_context
*ctx
= dcerpc_event_context(req
->p
);
1143 if (event_loop_once(ctx
) != 0) {
1144 return NT_STATUS_CONNECTION_DISCONNECTED
;
1147 *stub_data
= req
->payload
;
1148 status
= req
->status
;
1149 if (stub_data
->data
) {
1150 stub_data
->data
= talloc_steal(mem_ctx
, stub_data
->data
);
1152 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
1153 req
->p
->last_fault_code
= req
->fault_code
;
1155 talloc_unlink(talloc_parent(req
), req
);
1160 perform a full request/response pair on a dcerpc pipe
1162 NTSTATUS
dcerpc_request(struct dcerpc_pipe
*p
,
1163 struct GUID
*object
,
1165 TALLOC_CTX
*mem_ctx
,
1166 DATA_BLOB
*stub_data_in
,
1167 DATA_BLOB
*stub_data_out
)
1169 struct rpc_request
*req
;
1171 req
= dcerpc_request_send(p
, object
, opnum
, false, stub_data_in
);
1173 return NT_STATUS_NO_MEMORY
;
1176 return dcerpc_request_recv(req
, mem_ctx
, stub_data_out
);
1181 this is a paranoid NDR validator. For every packet we push onto the wire
1182 we pull it back again, then push it again. Then we compare the raw NDR data
1183 for that to the NDR we initially generated. If they don't match then we know
1184 we must have a bug in either the pull or push side of our code
1186 static NTSTATUS
dcerpc_ndr_validate_in(struct dcerpc_connection
*c
,
1187 TALLOC_CTX
*mem_ctx
,
1190 ndr_push_flags_fn_t ndr_push
,
1191 ndr_pull_flags_fn_t ndr_pull
)
1194 struct ndr_pull
*pull
;
1195 struct ndr_push
*push
;
1197 enum ndr_err_code ndr_err
;
1199 st
= talloc_size(mem_ctx
, struct_size
);
1201 return NT_STATUS_NO_MEMORY
;
1204 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1206 return NT_STATUS_NO_MEMORY
;
1208 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1210 ndr_err
= ndr_pull(pull
, NDR_IN
, st
);
1211 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1212 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1213 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1214 "failed input validation pull - %s",
1216 return ndr_map_error2ntstatus(ndr_err
);
1219 push
= ndr_push_init_ctx(mem_ctx
, c
->iconv_convenience
);
1221 return NT_STATUS_NO_MEMORY
;
1224 ndr_err
= ndr_push(push
, NDR_IN
, st
);
1225 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1226 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1227 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1228 "failed input validation push - %s",
1230 return ndr_map_error2ntstatus(ndr_err
);
1233 blob2
= ndr_push_blob(push
);
1235 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1236 DEBUG(3,("original:\n"));
1237 dump_data(3, blob
.data
, blob
.length
);
1238 DEBUG(3,("secondary:\n"));
1239 dump_data(3, blob2
.data
, blob2
.length
);
1240 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1241 "failed input validation blobs doesn't match");
1242 return ndr_map_error2ntstatus(ndr_err
);
1245 return NT_STATUS_OK
;
1249 this is a paranoid NDR input validator. For every packet we pull
1250 from the wire we push it back again then pull and push it
1251 again. Then we compare the raw NDR data for that to the NDR we
1252 initially generated. If they don't match then we know we must have a
1253 bug in either the pull or push side of our code
1255 static NTSTATUS
dcerpc_ndr_validate_out(struct dcerpc_connection
*c
,
1256 struct ndr_pull
*pull_in
,
1259 ndr_push_flags_fn_t ndr_push
,
1260 ndr_pull_flags_fn_t ndr_pull
,
1261 ndr_print_function_t ndr_print
)
1264 struct ndr_pull
*pull
;
1265 struct ndr_push
*push
;
1266 DATA_BLOB blob
, blob2
;
1267 TALLOC_CTX
*mem_ctx
= pull_in
;
1269 enum ndr_err_code ndr_err
;
1271 st
= talloc_size(mem_ctx
, struct_size
);
1273 return NT_STATUS_NO_MEMORY
;
1275 memcpy(st
, struct_ptr
, struct_size
);
1277 push
= ndr_push_init_ctx(mem_ctx
, c
->iconv_convenience
);
1279 return NT_STATUS_NO_MEMORY
;
1282 ndr_err
= ndr_push(push
, NDR_OUT
, struct_ptr
);
1283 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1284 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1285 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1286 "failed output validation push - %s",
1288 return ndr_map_error2ntstatus(ndr_err
);
1291 blob
= ndr_push_blob(push
);
1293 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1295 return NT_STATUS_NO_MEMORY
;
1298 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1299 ndr_err
= ndr_pull(pull
, NDR_OUT
, st
);
1300 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1301 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1302 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1303 "failed output validation pull - %s",
1305 return ndr_map_error2ntstatus(ndr_err
);
1308 push
= ndr_push_init_ctx(mem_ctx
, c
->iconv_convenience
);
1310 return NT_STATUS_NO_MEMORY
;
1313 ndr_err
= ndr_push(push
, NDR_OUT
, st
);
1314 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1315 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1316 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1317 "failed output validation push2 - %s",
1319 return ndr_map_error2ntstatus(ndr_err
);
1322 blob2
= ndr_push_blob(push
);
1324 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1325 DEBUG(3,("original:\n"));
1326 dump_data(3, blob
.data
, blob
.length
);
1327 DEBUG(3,("secondary:\n"));
1328 dump_data(3, blob2
.data
, blob2
.length
);
1329 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1330 "failed output validation blobs doesn't match");
1331 return ndr_map_error2ntstatus(ndr_err
);
1334 /* this checks the printed forms of the two structures, which effectively
1335 tests all of the value() attributes */
1336 s1
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1337 NDR_OUT
, struct_ptr
);
1338 s2
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1340 if (strcmp(s1
, s2
) != 0) {
1342 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1
, s2
));
1344 /* this is sometimes useful */
1345 printf("VALIDATE ERROR\n");
1346 file_save("wire.dat", s1
, strlen(s1
));
1347 file_save("gen.dat", s2
, strlen(s2
));
1348 system("diff -u wire.dat gen.dat");
1350 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1351 "failed output validation strings doesn't match");
1352 return ndr_map_error2ntstatus(ndr_err
);
1355 return NT_STATUS_OK
;
1360 send a rpc request given a dcerpc_call structure
1362 struct rpc_request
*dcerpc_ndr_request_send(struct dcerpc_pipe
*p
,
1363 const struct GUID
*object
,
1364 const struct ndr_interface_table
*table
,
1367 TALLOC_CTX
*mem_ctx
,
1370 const struct ndr_interface_call
*call
;
1371 struct ndr_push
*push
;
1374 struct rpc_request
*req
;
1375 enum ndr_err_code ndr_err
;
1377 call
= &table
->calls
[opnum
];
1379 /* setup for a ndr_push_* call */
1380 push
= ndr_push_init_ctx(mem_ctx
, p
->conn
->iconv_convenience
);
1385 if (p
->conn
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1386 push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1389 if (p
->conn
->flags
& DCERPC_NDR64
) {
1390 push
->flags
|= LIBNDR_FLAG_NDR64
;
1393 /* push the structure into a blob */
1394 ndr_err
= call
->ndr_push(push
, NDR_IN
, r
);
1395 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1396 status
= ndr_map_error2ntstatus(ndr_err
);
1397 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1398 nt_errstr(status
)));
1403 /* retrieve the blob */
1404 request
= ndr_push_blob(push
);
1406 if (p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_IN
) {
1407 status
= dcerpc_ndr_validate_in(p
->conn
, push
, request
, call
->struct_size
,
1408 call
->ndr_push
, call
->ndr_pull
);
1409 if (!NT_STATUS_IS_OK(status
)) {
1410 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1411 nt_errstr(status
)));
1417 DEBUG(10,("rpc request data:\n"));
1418 dump_data(10, request
.data
, request
.length
);
1420 /* make the actual dcerpc request */
1421 req
= dcerpc_request_send(p
, object
, opnum
, async
, &request
);
1424 req
->ndr
.table
= table
;
1425 req
->ndr
.opnum
= opnum
;
1426 req
->ndr
.struct_ptr
= r
;
1427 req
->ndr
.mem_ctx
= mem_ctx
;
1436 receive the answer from a dcerpc_ndr_request_send()
1438 _PUBLIC_ NTSTATUS
dcerpc_ndr_request_recv(struct rpc_request
*req
)
1440 struct dcerpc_pipe
*p
= req
->p
;
1443 struct ndr_pull
*pull
;
1445 TALLOC_CTX
*mem_ctx
= req
->ndr
.mem_ctx
;
1446 void *r
= req
->ndr
.struct_ptr
;
1447 uint32_t opnum
= req
->ndr
.opnum
;
1448 const struct ndr_interface_table
*table
= req
->ndr
.table
;
1449 const struct ndr_interface_call
*call
= &table
->calls
[opnum
];
1450 enum ndr_err_code ndr_err
;
1452 /* make sure the recv code doesn't free the request, as we
1453 need to grab the flags element before it is freed */
1454 if (talloc_reference(p
, req
) == NULL
) {
1455 return NT_STATUS_NO_MEMORY
;
1458 status
= dcerpc_request_recv(req
, mem_ctx
, &response
);
1459 if (!NT_STATUS_IS_OK(status
)) {
1460 talloc_unlink(p
, req
);
1466 /* prepare for ndr_pull_* */
1467 pull
= ndr_pull_init_flags(p
->conn
, &response
, mem_ctx
);
1469 talloc_unlink(p
, req
);
1470 return NT_STATUS_NO_MEMORY
;
1474 pull
->data
= talloc_steal(pull
, pull
->data
);
1476 talloc_unlink(p
, req
);
1478 if (flags
& DCERPC_PULL_BIGENDIAN
) {
1479 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1482 DEBUG(10,("rpc reply data:\n"));
1483 dump_data(10, pull
->data
, pull
->data_size
);
1485 /* pull the structure from the blob */
1486 ndr_err
= call
->ndr_pull(pull
, NDR_OUT
, r
);
1487 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1488 status
= ndr_map_error2ntstatus(ndr_err
);
1489 dcerpc_log_packet(p
->conn
->packet_log_dir
,
1490 table
, opnum
, NDR_OUT
,
1495 if (p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_OUT
) {
1496 status
= dcerpc_ndr_validate_out(p
->conn
, pull
, r
, call
->struct_size
,
1497 call
->ndr_push
, call
->ndr_pull
,
1499 if (!NT_STATUS_IS_OK(status
)) {
1500 dcerpc_log_packet(p
->conn
->packet_log_dir
,
1501 table
, opnum
, NDR_OUT
,
1507 if (pull
->offset
!= pull
->data_size
) {
1508 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1509 pull
->data_size
- pull
->offset
));
1510 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1511 but it turns out that early versions of NT
1512 (specifically NT3.1) add junk onto the end of rpc
1513 packets, so if we want to interoperate at all with
1514 those versions then we need to ignore this error */
1517 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1519 return NT_STATUS_OK
;
1524 a useful helper function for synchronous rpc requests
1526 this can be used when you have ndr push/pull functions in the
1529 _PUBLIC_ NTSTATUS
dcerpc_ndr_request(struct dcerpc_pipe
*p
,
1530 const struct GUID
*object
,
1531 const struct ndr_interface_table
*table
,
1533 TALLOC_CTX
*mem_ctx
,
1536 struct rpc_request
*req
;
1538 req
= dcerpc_ndr_request_send(p
, object
, table
, opnum
, false, mem_ctx
, r
);
1540 return NT_STATUS_NO_MEMORY
;
1543 return dcerpc_ndr_request_recv(req
);
1548 a useful function for retrieving the server name we connected to
1550 _PUBLIC_
const char *dcerpc_server_name(struct dcerpc_pipe
*p
)
1552 if (!p
->conn
->transport
.target_hostname
) {
1553 if (!p
->conn
->transport
.peer_name
) {
1556 return p
->conn
->transport
.peer_name(p
->conn
);
1558 return p
->conn
->transport
.target_hostname(p
->conn
);
1563 get the dcerpc auth_level for a open connection
1565 uint32_t dcerpc_auth_level(struct dcerpc_connection
*c
)
1569 if (c
->flags
& DCERPC_SEAL
) {
1570 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
1571 } else if (c
->flags
& DCERPC_SIGN
) {
1572 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
1573 } else if (c
->flags
& DCERPC_CONNECT
) {
1574 auth_level
= DCERPC_AUTH_LEVEL_CONNECT
;
1576 auth_level
= DCERPC_AUTH_LEVEL_NONE
;
1582 Receive an alter reply from the transport
1584 static void dcerpc_alter_recv_handler(struct rpc_request
*req
,
1585 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
1587 struct composite_context
*c
;
1588 struct dcerpc_pipe
*recv_pipe
;
1590 c
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
1591 recv_pipe
= talloc_get_type(c
->private_data
, struct dcerpc_pipe
);
1593 if (pkt
->ptype
== DCERPC_PKT_ALTER_RESP
&&
1594 pkt
->u
.alter_resp
.num_results
== 1 &&
1595 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
1596 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1597 pkt
->u
.alter_resp
.ctx_list
[0].reason
));
1598 composite_error(c
, dcerpc_map_reason(pkt
->u
.alter_resp
.ctx_list
[0].reason
));
1602 if (pkt
->ptype
!= DCERPC_PKT_ALTER_RESP
||
1603 pkt
->u
.alter_resp
.num_results
== 0 ||
1604 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
1605 composite_error(c
, NT_STATUS_NET_WRITE_FAULT
);
1609 /* the alter_resp might contain a reply set of credentials */
1610 if (recv_pipe
->conn
->security_state
.auth_info
&&
1611 pkt
->u
.alter_resp
.auth_info
.length
) {
1612 enum ndr_err_code ndr_err
;
1613 ndr_err
= ndr_pull_struct_blob(
1614 &pkt
->u
.alter_resp
.auth_info
, recv_pipe
,
1616 recv_pipe
->conn
->security_state
.auth_info
,
1617 (ndr_pull_flags_fn_t
)ndr_pull_dcerpc_auth
);
1618 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1619 c
->status
= ndr_map_error2ntstatus(ndr_err
);
1620 if (!composite_is_ok(c
)) return;
1628 send a dcerpc alter_context request
1630 struct composite_context
*dcerpc_alter_context_send(struct dcerpc_pipe
*p
,
1631 TALLOC_CTX
*mem_ctx
,
1632 const struct ndr_syntax_id
*syntax
,
1633 const struct ndr_syntax_id
*transfer_syntax
)
1635 struct composite_context
*c
;
1636 struct ncacn_packet pkt
;
1638 struct rpc_request
*req
;
1640 c
= composite_create(mem_ctx
, p
->conn
->event_ctx
);
1641 if (c
== NULL
) return NULL
;
1643 c
->private_data
= p
;
1645 p
->syntax
= *syntax
;
1646 p
->transfer_syntax
= *transfer_syntax
;
1648 init_ncacn_hdr(p
->conn
, &pkt
);
1650 pkt
.ptype
= DCERPC_PKT_ALTER
;
1651 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1652 pkt
.call_id
= p
->conn
->call_id
;
1653 pkt
.auth_length
= 0;
1655 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1656 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1659 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
1660 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
1663 pkt
.u
.alter
.max_xmit_frag
= 5840;
1664 pkt
.u
.alter
.max_recv_frag
= 5840;
1665 pkt
.u
.alter
.assoc_group_id
= p
->binding
->assoc_group_id
;
1666 pkt
.u
.alter
.num_contexts
= 1;
1667 pkt
.u
.alter
.ctx_list
= talloc_array(c
, struct dcerpc_ctx_list
, 1);
1668 if (composite_nomem(pkt
.u
.alter
.ctx_list
, c
)) return c
;
1669 pkt
.u
.alter
.ctx_list
[0].context_id
= p
->context_id
;
1670 pkt
.u
.alter
.ctx_list
[0].num_transfer_syntaxes
= 1;
1671 pkt
.u
.alter
.ctx_list
[0].abstract_syntax
= p
->syntax
;
1672 pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
1673 pkt
.u
.alter
.auth_info
= data_blob(NULL
, 0);
1675 /* construct the NDR form of the packet */
1676 c
->status
= ncacn_push_auth(&blob
, mem_ctx
, p
->conn
->iconv_convenience
, &pkt
,
1677 p
->conn
->security_state
.auth_info
);
1678 if (!composite_is_ok(c
)) return c
;
1680 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1683 * we allocate a dcerpc_request so we can be in the same
1684 * request queue as normal requests
1686 req
= talloc_zero(c
, struct rpc_request
);
1687 if (composite_nomem(req
, c
)) return c
;
1689 req
->state
= RPC_REQUEST_PENDING
;
1690 req
->call_id
= pkt
.call_id
;
1691 req
->async
.private_data
= c
;
1692 req
->async
.callback
= dcerpc_composite_fail
;
1694 req
->recv_handler
= dcerpc_alter_recv_handler
;
1695 DLIST_ADD_END(p
->conn
->pending
, req
, struct rpc_request
*);
1696 talloc_set_destructor(req
, dcerpc_req_dequeue
);
1698 c
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, true);
1699 if (!composite_is_ok(c
)) return c
;
1701 event_add_timed(c
->event_ctx
, req
,
1702 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
1703 dcerpc_timeout_handler
, req
);
1708 NTSTATUS
dcerpc_alter_context_recv(struct composite_context
*ctx
)
1710 NTSTATUS result
= composite_wait(ctx
);
1716 send a dcerpc alter_context request
1718 _PUBLIC_ NTSTATUS
dcerpc_alter_context(struct dcerpc_pipe
*p
,
1719 TALLOC_CTX
*mem_ctx
,
1720 const struct ndr_syntax_id
*syntax
,
1721 const struct ndr_syntax_id
*transfer_syntax
)
1723 struct composite_context
*creq
;
1724 creq
= dcerpc_alter_context_send(p
, mem_ctx
, syntax
, transfer_syntax
);
1725 return dcerpc_alter_context_recv(creq
);