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
;
121 p
->binding_handle
= talloc(p
, struct dcerpc_binding_handle
);
122 if (p
->binding_handle
== NULL
) {
126 p
->binding_handle
->private_data
= p
;
133 choose the next call id to use
135 static uint32_t next_call_id(struct dcerpc_connection
*c
)
138 if (c
->call_id
== 0) {
144 /* we need to be able to get/set the fragment length without doing a full
146 void dcerpc_set_frag_length(DATA_BLOB
*blob
, uint16_t v
)
148 if (CVAL(blob
->data
,DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
) {
149 SSVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
, v
);
151 RSSVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
, v
);
155 uint16_t dcerpc_get_frag_length(const DATA_BLOB
*blob
)
157 if (CVAL(blob
->data
,DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
) {
158 return SVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
);
160 return RSVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
);
164 void dcerpc_set_auth_length(DATA_BLOB
*blob
, uint16_t v
)
166 if (CVAL(blob
->data
,DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
) {
167 SSVAL(blob
->data
, DCERPC_AUTH_LEN_OFFSET
, v
);
169 RSSVAL(blob
->data
, DCERPC_AUTH_LEN_OFFSET
, v
);
175 setup for a ndr pull, also setting up any flags from the binding string
177 static struct ndr_pull
*ndr_pull_init_flags(struct dcerpc_connection
*c
,
178 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
180 struct ndr_pull
*ndr
= ndr_pull_init_blob(blob
, mem_ctx
, c
->iconv_convenience
);
182 if (ndr
== NULL
) return ndr
;
184 if (c
->flags
& DCERPC_DEBUG_PAD_CHECK
) {
185 ndr
->flags
|= LIBNDR_FLAG_PAD_CHECK
;
188 if (c
->flags
& DCERPC_NDR_REF_ALLOC
) {
189 ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
192 if (c
->flags
& DCERPC_NDR64
) {
193 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
200 parse a data blob into a ncacn_packet structure. This handles both
201 input and output packets
203 static NTSTATUS
ncacn_pull(struct dcerpc_connection
*c
, DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
204 struct ncacn_packet
*pkt
)
206 struct ndr_pull
*ndr
;
207 enum ndr_err_code ndr_err
;
209 ndr
= ndr_pull_init_flags(c
, blob
, mem_ctx
);
211 return NT_STATUS_NO_MEMORY
;
214 if (! (CVAL(blob
->data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
215 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
218 ndr_err
= ndr_pull_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
219 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
220 return ndr_map_error2ntstatus(ndr_err
);
227 parse the authentication information on a dcerpc response packet
229 static NTSTATUS
ncacn_pull_request_auth(struct dcerpc_connection
*c
, TALLOC_CTX
*mem_ctx
,
230 DATA_BLOB
*raw_packet
,
231 struct ncacn_packet
*pkt
)
234 struct dcerpc_auth auth
;
235 uint32_t auth_length
;
237 if (!c
->security_state
.auth_info
||
238 !c
->security_state
.generic_state
) {
242 switch (c
->security_state
.auth_info
->auth_level
) {
243 case DCERPC_AUTH_LEVEL_PRIVACY
:
244 case DCERPC_AUTH_LEVEL_INTEGRITY
:
247 case DCERPC_AUTH_LEVEL_CONNECT
:
248 if (pkt
->auth_length
!= 0) {
252 case DCERPC_AUTH_LEVEL_NONE
:
253 if (pkt
->auth_length
!= 0) {
254 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
259 return NT_STATUS_INVALID_LEVEL
;
262 status
= dcerpc_pull_auth_trailer(pkt
, mem_ctx
,
263 &pkt
->u
.response
.stub_and_verifier
,
264 &auth
, &auth_length
, false);
265 NT_STATUS_NOT_OK_RETURN(status
);
267 pkt
->u
.response
.stub_and_verifier
.length
-= auth_length
;
269 /* check signature or unseal the packet */
270 switch (c
->security_state
.auth_info
->auth_level
) {
271 case DCERPC_AUTH_LEVEL_PRIVACY
:
272 status
= gensec_unseal_packet(c
->security_state
.generic_state
,
274 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
275 pkt
->u
.response
.stub_and_verifier
.length
,
277 raw_packet
->length
- auth
.credentials
.length
,
279 memcpy(pkt
->u
.response
.stub_and_verifier
.data
,
280 raw_packet
->data
+ DCERPC_REQUEST_LENGTH
,
281 pkt
->u
.response
.stub_and_verifier
.length
);
284 case DCERPC_AUTH_LEVEL_INTEGRITY
:
285 status
= gensec_check_packet(c
->security_state
.generic_state
,
287 pkt
->u
.response
.stub_and_verifier
.data
,
288 pkt
->u
.response
.stub_and_verifier
.length
,
290 raw_packet
->length
- auth
.credentials
.length
,
294 case DCERPC_AUTH_LEVEL_CONNECT
:
295 /* for now we ignore possible signatures here */
296 status
= NT_STATUS_OK
;
300 status
= NT_STATUS_INVALID_LEVEL
;
304 /* remove the indicated amount of padding */
305 if (pkt
->u
.response
.stub_and_verifier
.length
< auth
.auth_pad_length
) {
306 return NT_STATUS_INFO_LENGTH_MISMATCH
;
308 pkt
->u
.response
.stub_and_verifier
.length
-= auth
.auth_pad_length
;
315 push a dcerpc request packet into a blob, possibly signing it.
317 static NTSTATUS
ncacn_push_request_sign(struct dcerpc_connection
*c
,
318 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
320 struct ncacn_packet
*pkt
)
323 struct ndr_push
*ndr
;
325 size_t payload_length
;
326 enum ndr_err_code ndr_err
;
327 size_t hdr_size
= DCERPC_REQUEST_LENGTH
;
329 /* non-signed packets are simpler */
331 return ncacn_push_auth(blob
, mem_ctx
, c
->iconv_convenience
, pkt
, NULL
);
334 switch (c
->security_state
.auth_info
->auth_level
) {
335 case DCERPC_AUTH_LEVEL_PRIVACY
:
336 case DCERPC_AUTH_LEVEL_INTEGRITY
:
339 case DCERPC_AUTH_LEVEL_CONNECT
:
340 /* TODO: let the gensec mech decide if it wants to generate a signature */
341 return ncacn_push_auth(blob
, mem_ctx
, c
->iconv_convenience
, pkt
, NULL
);
343 case DCERPC_AUTH_LEVEL_NONE
:
344 return ncacn_push_auth(blob
, mem_ctx
, c
->iconv_convenience
, pkt
, NULL
);
347 return NT_STATUS_INVALID_LEVEL
;
350 ndr
= ndr_push_init_ctx(mem_ctx
, c
->iconv_convenience
);
352 return NT_STATUS_NO_MEMORY
;
355 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
356 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
359 if (c
->flags
& DCERPC_NDR64
) {
360 ndr
->flags
|= LIBNDR_FLAG_NDR64
;
363 if (pkt
->pfc_flags
& DCERPC_PFC_FLAG_OBJECT_UUID
) {
364 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
368 ndr_err
= ndr_push_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
369 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
370 return ndr_map_error2ntstatus(ndr_err
);
373 /* pad to 16 byte multiple in the payload portion of the
374 packet. This matches what w2k3 does. Note that we can't use
375 ndr_push_align() as that is relative to the start of the
376 whole packet, whereas w2k8 wants it relative to the start
378 c
->security_state
.auth_info
->auth_pad_length
=
379 (16 - (pkt
->u
.request
.stub_and_verifier
.length
& 15)) & 15;
380 ndr_err
= ndr_push_zero(ndr
, c
->security_state
.auth_info
->auth_pad_length
);
381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
382 return ndr_map_error2ntstatus(ndr_err
);
385 payload_length
= pkt
->u
.request
.stub_and_verifier
.length
+
386 c
->security_state
.auth_info
->auth_pad_length
;
388 /* we start without signature, it will appended later */
389 c
->security_state
.auth_info
->credentials
= data_blob(NULL
,0);
391 /* add the auth verifier */
392 ndr_err
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, c
->security_state
.auth_info
);
393 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
394 return ndr_map_error2ntstatus(ndr_err
);
397 /* extract the whole packet as a blob */
398 *blob
= ndr_push_blob(ndr
);
401 * Setup the frag and auth length in the packet buffer.
402 * This is needed if the GENSEC mech does AEAD signing
403 * of the packet headers. The signature itself will be
406 dcerpc_set_frag_length(blob
, blob
->length
+ sig_size
);
407 dcerpc_set_auth_length(blob
, sig_size
);
409 /* sign or seal the packet */
410 switch (c
->security_state
.auth_info
->auth_level
) {
411 case DCERPC_AUTH_LEVEL_PRIVACY
:
412 status
= gensec_seal_packet(c
->security_state
.generic_state
,
414 blob
->data
+ hdr_size
,
419 if (!NT_STATUS_IS_OK(status
)) {
424 case DCERPC_AUTH_LEVEL_INTEGRITY
:
425 status
= gensec_sign_packet(c
->security_state
.generic_state
,
427 blob
->data
+ hdr_size
,
432 if (!NT_STATUS_IS_OK(status
)) {
438 status
= NT_STATUS_INVALID_LEVEL
;
442 if (creds2
.length
!= sig_size
) {
443 /* this means the sig_size estimate for the signature
444 was incorrect. We have to correct the packet
445 sizes. That means we could go over the max fragment
447 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
448 (unsigned) creds2
.length
,
450 (unsigned) c
->security_state
.auth_info
->auth_pad_length
,
451 (unsigned) pkt
->u
.request
.stub_and_verifier
.length
));
452 dcerpc_set_frag_length(blob
, blob
->length
+ creds2
.length
);
453 dcerpc_set_auth_length(blob
, creds2
.length
);
456 if (!data_blob_append(mem_ctx
, blob
, creds2
.data
, creds2
.length
)) {
457 return NT_STATUS_NO_MEMORY
;
465 fill in the fixed values in a dcerpc header
467 static void init_ncacn_hdr(struct dcerpc_connection
*c
, struct ncacn_packet
*pkt
)
470 pkt
->rpc_vers_minor
= 0;
471 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
474 pkt
->drep
[0] = DCERPC_DREP_LE
;
482 map a bind nak reason to a NTSTATUS
484 static NTSTATUS
dcerpc_map_reason(uint16_t reason
)
487 case DCERPC_BIND_REASON_ASYNTAX
:
488 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX
;
489 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE
:
490 return NT_STATUS_INVALID_PARAMETER
;
492 return NT_STATUS_UNSUCCESSFUL
;
496 a bind or alter context has failed
498 static void dcerpc_composite_fail(struct rpc_request
*req
)
500 struct composite_context
*c
= talloc_get_type(req
->async
.private_data
,
501 struct composite_context
);
502 composite_error(c
, req
->status
);
506 remove requests from the pending or queued queues
508 static int dcerpc_req_dequeue(struct rpc_request
*req
)
510 switch (req
->state
) {
511 case RPC_REQUEST_QUEUED
:
512 DLIST_REMOVE(req
->p
->conn
->request_queue
, req
);
514 case RPC_REQUEST_PENDING
:
515 DLIST_REMOVE(req
->p
->conn
->pending
, req
);
517 case RPC_REQUEST_DONE
:
525 mark the dcerpc connection dead. All outstanding requests get an error
527 static void dcerpc_connection_dead(struct dcerpc_connection
*conn
, NTSTATUS status
)
529 if (conn
->dead
) return;
533 if (conn
->transport
.shutdown_pipe
) {
534 conn
->transport
.shutdown_pipe(conn
, status
);
537 /* all pending requests get the error */
538 while (conn
->pending
) {
539 struct rpc_request
*req
= conn
->pending
;
540 dcerpc_req_dequeue(req
);
541 req
->state
= RPC_REQUEST_DONE
;
542 req
->status
= status
;
543 if (req
->async
.callback
) {
544 req
->async
.callback(req
);
548 talloc_set_destructor(conn
, NULL
);
549 if (conn
->free_skipped
) {
555 forward declarations of the recv_data handlers for the types of
556 packets we need to handle
558 static void dcerpc_request_recv_data(struct dcerpc_connection
*c
,
559 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
);
562 receive a dcerpc reply from the transport. Here we work out what
563 type of reply it is (normal request, bind or alter context) and
564 dispatch to the appropriate handler
566 static void dcerpc_recv_data(struct dcerpc_connection
*conn
, DATA_BLOB
*blob
, NTSTATUS status
)
568 struct ncacn_packet pkt
;
570 if (NT_STATUS_IS_OK(status
) && blob
->length
== 0) {
571 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
574 /* the transport may be telling us of a severe error, such as
576 if (!NT_STATUS_IS_OK(status
)) {
577 data_blob_free(blob
);
578 dcerpc_connection_dead(conn
, status
);
582 /* parse the basic packet to work out what type of response this is */
583 status
= ncacn_pull(conn
, blob
, blob
->data
, &pkt
);
584 if (!NT_STATUS_IS_OK(status
)) {
585 data_blob_free(blob
);
586 dcerpc_connection_dead(conn
, status
);
589 dcerpc_request_recv_data(conn
, blob
, &pkt
);
593 Receive a bind reply from the transport
595 static void dcerpc_bind_recv_handler(struct rpc_request
*req
,
596 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
598 struct composite_context
*c
;
599 struct dcerpc_connection
*conn
;
601 c
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
603 if (pkt
->ptype
== DCERPC_PKT_BIND_NAK
) {
604 DEBUG(2,("dcerpc: bind_nak reason %d\n",
605 pkt
->u
.bind_nak
.reject_reason
));
606 composite_error(c
, dcerpc_map_reason(pkt
->u
.bind_nak
.
611 if ((pkt
->ptype
!= DCERPC_PKT_BIND_ACK
) ||
612 (pkt
->u
.bind_ack
.num_results
== 0) ||
613 (pkt
->u
.bind_ack
.ctx_list
[0].result
!= 0)) {
614 composite_error(c
, NT_STATUS_NET_WRITE_FAULT
);
620 conn
->srv_max_xmit_frag
= pkt
->u
.bind_ack
.max_xmit_frag
;
621 conn
->srv_max_recv_frag
= pkt
->u
.bind_ack
.max_recv_frag
;
623 if ((req
->p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) &&
624 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_CONC_MPX
)) {
625 conn
->flags
|= DCERPC_CONCURRENT_MULTIPLEX
;
628 if ((req
->p
->binding
->flags
& DCERPC_HEADER_SIGNING
) &&
629 (pkt
->pfc_flags
& DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
)) {
630 conn
->flags
|= DCERPC_HEADER_SIGNING
;
633 /* the bind_ack might contain a reply set of credentials */
634 if (conn
->security_state
.auth_info
&& pkt
->u
.bind_ack
.auth_info
.length
) {
636 uint32_t auth_length
;
637 status
= dcerpc_pull_auth_trailer(pkt
, conn
, &pkt
->u
.bind_ack
.auth_info
,
638 conn
->security_state
.auth_info
, &auth_length
, true);
639 if (!NT_STATUS_IS_OK(status
)) {
640 composite_error(c
, status
);
645 req
->p
->assoc_group_id
= pkt
->u
.bind_ack
.assoc_group_id
;
651 handle timeouts of individual dcerpc requests
653 static void dcerpc_timeout_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
654 struct timeval t
, void *private_data
)
656 struct rpc_request
*req
= talloc_get_type(private_data
, struct rpc_request
);
658 if (req
->ignore_timeout
) {
659 dcerpc_req_dequeue(req
);
660 req
->state
= RPC_REQUEST_DONE
;
661 req
->status
= NT_STATUS_IO_TIMEOUT
;
662 if (req
->async
.callback
) {
663 req
->async
.callback(req
);
668 dcerpc_connection_dead(req
->p
->conn
, NT_STATUS_IO_TIMEOUT
);
672 send a async dcerpc bind request
674 struct composite_context
*dcerpc_bind_send(struct dcerpc_pipe
*p
,
676 const struct ndr_syntax_id
*syntax
,
677 const struct ndr_syntax_id
*transfer_syntax
)
679 struct composite_context
*c
;
680 struct ncacn_packet pkt
;
682 struct rpc_request
*req
;
684 c
= composite_create(mem_ctx
,p
->conn
->event_ctx
);
685 if (c
== NULL
) return NULL
;
690 p
->transfer_syntax
= *transfer_syntax
;
692 init_ncacn_hdr(p
->conn
, &pkt
);
694 pkt
.ptype
= DCERPC_PKT_BIND
;
695 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
696 pkt
.call_id
= p
->conn
->call_id
;
699 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
700 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
703 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
704 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
707 pkt
.u
.bind
.max_xmit_frag
= 5840;
708 pkt
.u
.bind
.max_recv_frag
= 5840;
709 pkt
.u
.bind
.assoc_group_id
= p
->binding
->assoc_group_id
;
710 pkt
.u
.bind
.num_contexts
= 1;
711 pkt
.u
.bind
.ctx_list
= talloc_array(mem_ctx
, struct dcerpc_ctx_list
, 1);
712 if (composite_nomem(pkt
.u
.bind
.ctx_list
, c
)) return c
;
713 pkt
.u
.bind
.ctx_list
[0].context_id
= p
->context_id
;
714 pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
= 1;
715 pkt
.u
.bind
.ctx_list
[0].abstract_syntax
= p
->syntax
;
716 pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
717 pkt
.u
.bind
.auth_info
= data_blob(NULL
, 0);
719 /* construct the NDR form of the packet */
720 c
->status
= ncacn_push_auth(&blob
, c
, p
->conn
->iconv_convenience
, &pkt
,
721 p
->conn
->security_state
.auth_info
);
722 if (!composite_is_ok(c
)) return c
;
724 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
727 * we allocate a dcerpc_request so we can be in the same
728 * request queue as normal requests
730 req
= talloc_zero(c
, struct rpc_request
);
731 if (composite_nomem(req
, c
)) return c
;
733 req
->state
= RPC_REQUEST_PENDING
;
734 req
->call_id
= pkt
.call_id
;
735 req
->async
.private_data
= c
;
736 req
->async
.callback
= dcerpc_composite_fail
;
738 req
->recv_handler
= dcerpc_bind_recv_handler
;
739 DLIST_ADD_END(p
->conn
->pending
, req
, struct rpc_request
*);
740 talloc_set_destructor(req
, dcerpc_req_dequeue
);
742 c
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
,
744 if (!composite_is_ok(c
)) return c
;
746 event_add_timed(c
->event_ctx
, req
,
747 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
748 dcerpc_timeout_handler
, req
);
754 recv side of async dcerpc bind request
756 NTSTATUS
dcerpc_bind_recv(struct composite_context
*ctx
)
758 NTSTATUS result
= composite_wait(ctx
);
764 perform a continued bind (and auth3)
766 NTSTATUS
dcerpc_auth3(struct dcerpc_pipe
*p
,
769 struct ncacn_packet pkt
;
773 init_ncacn_hdr(p
->conn
, &pkt
);
775 pkt
.ptype
= DCERPC_PKT_AUTH3
;
776 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
777 pkt
.call_id
= next_call_id(p
->conn
);
779 pkt
.u
.auth3
.auth_info
= data_blob(NULL
, 0);
781 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
782 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
785 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
786 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
789 /* construct the NDR form of the packet */
790 status
= ncacn_push_auth(&blob
, mem_ctx
,
791 p
->conn
->iconv_convenience
,
793 p
->conn
->security_state
.auth_info
);
794 if (!NT_STATUS_IS_OK(status
)) {
798 /* send it on its way */
799 status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, false);
800 if (!NT_STATUS_IS_OK(status
)) {
809 process a fragment received from the transport layer during a
812 This function frees the data
814 static void dcerpc_request_recv_data(struct dcerpc_connection
*c
,
815 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
817 struct rpc_request
*req
;
819 NTSTATUS status
= NT_STATUS_OK
;
822 if this is an authenticated connection then parse and check
823 the auth info. We have to do this before finding the
824 matching packet, as the request structure might have been
825 removed due to a timeout, but if it has been we still need
826 to run the auth routines so that we don't get the sign/seal
827 info out of step with the server
829 if (c
->security_state
.auth_info
&& c
->security_state
.generic_state
&&
830 pkt
->ptype
== DCERPC_PKT_RESPONSE
) {
831 status
= ncacn_pull_request_auth(c
, raw_packet
->data
, raw_packet
, pkt
);
834 /* find the matching request */
835 for (req
=c
->pending
;req
;req
=req
->next
) {
836 if (pkt
->call_id
== req
->call_id
) break;
840 /* useful for testing certain vendors RPC servers */
841 if (req
== NULL
&& c
->pending
&& pkt
->call_id
== 0) {
842 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
848 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt
->call_id
));
849 data_blob_free(raw_packet
);
853 talloc_steal(req
, raw_packet
->data
);
855 if (req
->recv_handler
!= NULL
) {
856 dcerpc_req_dequeue(req
);
857 req
->state
= RPC_REQUEST_DONE
;
858 req
->recv_handler(req
, raw_packet
, pkt
);
862 if (pkt
->ptype
== DCERPC_PKT_FAULT
) {
863 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c
, pkt
->u
.fault
.status
)));
864 req
->fault_code
= pkt
->u
.fault
.status
;
865 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
869 if (pkt
->ptype
!= DCERPC_PKT_RESPONSE
) {
870 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
872 req
->fault_code
= DCERPC_FAULT_OTHER
;
873 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
877 /* now check the status from the auth routines, and if it failed then fail
878 this request accordingly */
879 if (!NT_STATUS_IS_OK(status
)) {
880 req
->status
= status
;
884 length
= pkt
->u
.response
.stub_and_verifier
.length
;
887 req
->payload
.data
= talloc_realloc(req
,
890 req
->payload
.length
+ length
);
891 if (!req
->payload
.data
) {
892 req
->status
= NT_STATUS_NO_MEMORY
;
895 memcpy(req
->payload
.data
+req
->payload
.length
,
896 pkt
->u
.response
.stub_and_verifier
.data
, length
);
897 req
->payload
.length
+= length
;
900 if (!(pkt
->pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
901 c
->transport
.send_read(c
);
905 if (!(pkt
->drep
[0] & DCERPC_DREP_LE
)) {
906 req
->flags
|= DCERPC_PULL_BIGENDIAN
;
908 req
->flags
&= ~DCERPC_PULL_BIGENDIAN
;
913 /* we've got the full payload */
914 req
->state
= RPC_REQUEST_DONE
;
915 DLIST_REMOVE(c
->pending
, req
);
917 if (c
->request_queue
!= NULL
) {
918 /* We have to look at shipping further requests before calling
919 * the async function, that one might close the pipe */
920 dcerpc_ship_next_request(c
);
923 if (req
->async
.callback
) {
924 req
->async
.callback(req
);
929 perform the send side of a async dcerpc request
931 static struct rpc_request
*dcerpc_request_send(struct dcerpc_pipe
*p
,
932 const struct GUID
*object
,
935 DATA_BLOB
*stub_data
)
937 struct rpc_request
*req
;
939 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
941 req
= talloc(p
, struct rpc_request
);
947 req
->call_id
= next_call_id(p
->conn
);
948 req
->status
= NT_STATUS_OK
;
949 req
->state
= RPC_REQUEST_QUEUED
;
950 req
->payload
= data_blob(NULL
, 0);
953 req
->async_call
= async
;
954 req
->ignore_timeout
= false;
955 req
->async
.callback
= NULL
;
956 req
->async
.private_data
= NULL
;
957 req
->recv_handler
= NULL
;
959 if (object
!= NULL
) {
960 req
->object
= (struct GUID
*)talloc_memdup(req
, (const void *)object
, sizeof(*object
));
961 if (req
->object
== NULL
) {
970 req
->request_data
.length
= stub_data
->length
;
971 req
->request_data
.data
= talloc_reference(req
, stub_data
->data
);
972 if (req
->request_data
.length
&& req
->request_data
.data
== NULL
) {
976 DLIST_ADD_END(p
->conn
->request_queue
, req
, struct rpc_request
*);
977 talloc_set_destructor(req
, dcerpc_req_dequeue
);
979 dcerpc_ship_next_request(p
->conn
);
981 if (p
->request_timeout
) {
982 event_add_timed(dcerpc_event_context(p
), req
,
983 timeval_current_ofs(p
->request_timeout
, 0),
984 dcerpc_timeout_handler
, req
);
991 Send a request using the transport
994 static void dcerpc_ship_next_request(struct dcerpc_connection
*c
)
996 struct rpc_request
*req
;
997 struct dcerpc_pipe
*p
;
998 DATA_BLOB
*stub_data
;
999 struct ncacn_packet pkt
;
1001 uint32_t remaining
, chunk_size
;
1002 bool first_packet
= true;
1003 size_t sig_size
= 0;
1005 req
= c
->request_queue
;
1011 stub_data
= &req
->request_data
;
1013 if (!req
->async_call
&& (c
->pending
!= NULL
)) {
1017 DLIST_REMOVE(c
->request_queue
, req
);
1018 DLIST_ADD(c
->pending
, req
);
1019 req
->state
= RPC_REQUEST_PENDING
;
1021 init_ncacn_hdr(p
->conn
, &pkt
);
1023 remaining
= stub_data
->length
;
1025 /* we can write a full max_recv_frag size, minus the dcerpc
1026 request header size */
1027 chunk_size
= p
->conn
->srv_max_recv_frag
;
1028 chunk_size
-= DCERPC_REQUEST_LENGTH
;
1029 if (c
->security_state
.auth_info
&&
1030 c
->security_state
.generic_state
) {
1031 sig_size
= gensec_sig_size(c
->security_state
.generic_state
,
1032 p
->conn
->srv_max_recv_frag
);
1034 chunk_size
-= DCERPC_AUTH_TRAILER_LENGTH
;
1035 chunk_size
-= sig_size
;
1038 chunk_size
-= (chunk_size
% 16);
1040 pkt
.ptype
= DCERPC_PKT_REQUEST
;
1041 pkt
.call_id
= req
->call_id
;
1042 pkt
.auth_length
= 0;
1044 pkt
.u
.request
.alloc_hint
= remaining
;
1045 pkt
.u
.request
.context_id
= p
->context_id
;
1046 pkt
.u
.request
.opnum
= req
->opnum
;
1049 pkt
.u
.request
.object
.object
= *req
->object
;
1050 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_OBJECT_UUID
;
1051 chunk_size
-= ndr_size_GUID(req
->object
,NULL
,0);
1054 /* we send a series of pdus without waiting for a reply */
1055 while (remaining
> 0 || first_packet
) {
1056 uint32_t chunk
= MIN(chunk_size
, remaining
);
1057 bool last_frag
= false;
1058 bool do_trans
= false;
1060 first_packet
= false;
1061 pkt
.pfc_flags
&= ~(DCERPC_PFC_FLAG_FIRST
|DCERPC_PFC_FLAG_LAST
);
1063 if (remaining
== stub_data
->length
) {
1064 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_FIRST
;
1066 if (chunk
== remaining
) {
1067 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_LAST
;
1071 pkt
.u
.request
.stub_and_verifier
.data
= stub_data
->data
+
1072 (stub_data
->length
- remaining
);
1073 pkt
.u
.request
.stub_and_verifier
.length
= chunk
;
1075 req
->status
= ncacn_push_request_sign(p
->conn
, &blob
, req
, sig_size
, &pkt
);
1076 if (!NT_STATUS_IS_OK(req
->status
)) {
1077 req
->state
= RPC_REQUEST_DONE
;
1078 DLIST_REMOVE(p
->conn
->pending
, req
);
1082 if (last_frag
&& !req
->async_call
) {
1086 req
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, do_trans
);
1087 if (!NT_STATUS_IS_OK(req
->status
)) {
1088 req
->state
= RPC_REQUEST_DONE
;
1089 DLIST_REMOVE(p
->conn
->pending
, req
);
1093 if (last_frag
&& !do_trans
) {
1094 req
->status
= p
->conn
->transport
.send_read(p
->conn
);
1095 if (!NT_STATUS_IS_OK(req
->status
)) {
1096 req
->state
= RPC_REQUEST_DONE
;
1097 DLIST_REMOVE(p
->conn
->pending
, req
);
1107 return the event context for a dcerpc pipe
1108 used by callers who wish to operate asynchronously
1110 _PUBLIC_
struct tevent_context
*dcerpc_event_context(struct dcerpc_pipe
*p
)
1112 return p
->conn
->event_ctx
;
1118 perform the receive side of a async dcerpc request
1120 NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
1121 TALLOC_CTX
*mem_ctx
,
1122 DATA_BLOB
*stub_data
)
1126 while (req
->state
!= RPC_REQUEST_DONE
) {
1127 struct tevent_context
*ctx
= dcerpc_event_context(req
->p
);
1128 if (event_loop_once(ctx
) != 0) {
1129 return NT_STATUS_CONNECTION_DISCONNECTED
;
1132 *stub_data
= req
->payload
;
1133 status
= req
->status
;
1134 if (stub_data
->data
) {
1135 stub_data
->data
= talloc_steal(mem_ctx
, stub_data
->data
);
1137 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
1138 req
->p
->last_fault_code
= req
->fault_code
;
1140 talloc_unlink(talloc_parent(req
), req
);
1145 perform a full request/response pair on a dcerpc pipe
1147 NTSTATUS
dcerpc_request(struct dcerpc_pipe
*p
,
1148 struct GUID
*object
,
1150 TALLOC_CTX
*mem_ctx
,
1151 DATA_BLOB
*stub_data_in
,
1152 DATA_BLOB
*stub_data_out
)
1154 struct rpc_request
*req
;
1156 req
= dcerpc_request_send(p
, object
, opnum
, false, stub_data_in
);
1158 return NT_STATUS_NO_MEMORY
;
1161 return dcerpc_request_recv(req
, mem_ctx
, stub_data_out
);
1166 this is a paranoid NDR validator. For every packet we push onto the wire
1167 we pull it back again, then push it again. Then we compare the raw NDR data
1168 for that to the NDR we initially generated. If they don't match then we know
1169 we must have a bug in either the pull or push side of our code
1171 static NTSTATUS
dcerpc_ndr_validate_in(struct dcerpc_connection
*c
,
1172 TALLOC_CTX
*mem_ctx
,
1175 ndr_push_flags_fn_t ndr_push
,
1176 ndr_pull_flags_fn_t ndr_pull
)
1179 struct ndr_pull
*pull
;
1180 struct ndr_push
*push
;
1182 enum ndr_err_code ndr_err
;
1184 st
= talloc_size(mem_ctx
, struct_size
);
1186 return NT_STATUS_NO_MEMORY
;
1189 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1191 return NT_STATUS_NO_MEMORY
;
1193 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1195 ndr_err
= ndr_pull(pull
, NDR_IN
, st
);
1196 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1197 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1198 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1199 "failed input validation pull - %s",
1201 return ndr_map_error2ntstatus(ndr_err
);
1204 push
= ndr_push_init_ctx(mem_ctx
, c
->iconv_convenience
);
1206 return NT_STATUS_NO_MEMORY
;
1209 ndr_err
= ndr_push(push
, NDR_IN
, st
);
1210 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1211 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1212 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1213 "failed input validation push - %s",
1215 return ndr_map_error2ntstatus(ndr_err
);
1218 blob2
= ndr_push_blob(push
);
1220 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1221 DEBUG(3,("original:\n"));
1222 dump_data(3, blob
.data
, blob
.length
);
1223 DEBUG(3,("secondary:\n"));
1224 dump_data(3, blob2
.data
, blob2
.length
);
1225 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1226 "failed input validation blobs doesn't match");
1227 return ndr_map_error2ntstatus(ndr_err
);
1230 return NT_STATUS_OK
;
1234 this is a paranoid NDR input validator. For every packet we pull
1235 from the wire we push it back again then pull and push it
1236 again. Then we compare the raw NDR data for that to the NDR we
1237 initially generated. If they don't match then we know we must have a
1238 bug in either the pull or push side of our code
1240 static NTSTATUS
dcerpc_ndr_validate_out(struct dcerpc_connection
*c
,
1241 struct ndr_pull
*pull_in
,
1244 ndr_push_flags_fn_t ndr_push
,
1245 ndr_pull_flags_fn_t ndr_pull
,
1246 ndr_print_function_t ndr_print
)
1249 struct ndr_pull
*pull
;
1250 struct ndr_push
*push
;
1251 DATA_BLOB blob
, blob2
;
1252 TALLOC_CTX
*mem_ctx
= pull_in
;
1254 enum ndr_err_code ndr_err
;
1256 st
= talloc_size(mem_ctx
, struct_size
);
1258 return NT_STATUS_NO_MEMORY
;
1260 memcpy(st
, struct_ptr
, struct_size
);
1262 push
= ndr_push_init_ctx(mem_ctx
, c
->iconv_convenience
);
1264 return NT_STATUS_NO_MEMORY
;
1267 ndr_err
= ndr_push(push
, NDR_OUT
, struct_ptr
);
1268 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1269 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1270 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1271 "failed output validation push - %s",
1273 return ndr_map_error2ntstatus(ndr_err
);
1276 blob
= ndr_push_blob(push
);
1278 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1280 return NT_STATUS_NO_MEMORY
;
1283 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1284 ndr_err
= ndr_pull(pull
, NDR_OUT
, st
);
1285 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1286 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1287 ndr_err
= ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1288 "failed output validation pull - %s",
1290 return ndr_map_error2ntstatus(ndr_err
);
1293 push
= ndr_push_init_ctx(mem_ctx
, c
->iconv_convenience
);
1295 return NT_STATUS_NO_MEMORY
;
1298 ndr_err
= ndr_push(push
, NDR_OUT
, st
);
1299 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1300 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
1301 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1302 "failed output validation push2 - %s",
1304 return ndr_map_error2ntstatus(ndr_err
);
1307 blob2
= ndr_push_blob(push
);
1309 if (data_blob_cmp(&blob
, &blob2
) != 0) {
1310 DEBUG(3,("original:\n"));
1311 dump_data(3, blob
.data
, blob
.length
);
1312 DEBUG(3,("secondary:\n"));
1313 dump_data(3, blob2
.data
, blob2
.length
);
1314 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1315 "failed output validation blobs doesn't match");
1316 return ndr_map_error2ntstatus(ndr_err
);
1319 /* this checks the printed forms of the two structures, which effectively
1320 tests all of the value() attributes */
1321 s1
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1322 NDR_OUT
, struct_ptr
);
1323 s2
= ndr_print_function_string(mem_ctx
, ndr_print
, "VALIDATE",
1325 if (strcmp(s1
, s2
) != 0) {
1327 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1
, s2
));
1329 /* this is sometimes useful */
1330 printf("VALIDATE ERROR\n");
1331 file_save("wire.dat", s1
, strlen(s1
));
1332 file_save("gen.dat", s2
, strlen(s2
));
1333 system("diff -u wire.dat gen.dat");
1335 ndr_err
= ndr_push_error(push
, NDR_ERR_VALIDATE
,
1336 "failed output validation strings doesn't match");
1337 return ndr_map_error2ntstatus(ndr_err
);
1340 return NT_STATUS_OK
;
1345 send a rpc request given a dcerpc_call structure
1347 struct rpc_request
*dcerpc_ndr_request_send(struct dcerpc_pipe
*p
,
1348 const struct GUID
*object
,
1349 const struct ndr_interface_table
*table
,
1352 TALLOC_CTX
*mem_ctx
,
1355 const struct ndr_interface_call
*call
;
1356 struct ndr_push
*push
;
1359 struct rpc_request
*req
;
1360 enum ndr_err_code ndr_err
;
1362 call
= &table
->calls
[opnum
];
1364 /* setup for a ndr_push_* call */
1365 push
= ndr_push_init_ctx(mem_ctx
, p
->conn
->iconv_convenience
);
1370 if (p
->conn
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1371 push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1374 if (p
->conn
->flags
& DCERPC_NDR64
) {
1375 push
->flags
|= LIBNDR_FLAG_NDR64
;
1378 /* push the structure into a blob */
1379 ndr_err
= call
->ndr_push(push
, NDR_IN
, r
);
1380 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1381 status
= ndr_map_error2ntstatus(ndr_err
);
1382 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1383 nt_errstr(status
)));
1388 /* retrieve the blob */
1389 request
= ndr_push_blob(push
);
1391 if (p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_IN
) {
1392 status
= dcerpc_ndr_validate_in(p
->conn
, push
, request
, call
->struct_size
,
1393 call
->ndr_push
, call
->ndr_pull
);
1394 if (!NT_STATUS_IS_OK(status
)) {
1395 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1396 nt_errstr(status
)));
1402 DEBUG(10,("rpc request data:\n"));
1403 dump_data(10, request
.data
, request
.length
);
1405 /* make the actual dcerpc request */
1406 req
= dcerpc_request_send(p
, object
, opnum
, async
, &request
);
1409 req
->ndr
.table
= table
;
1410 req
->ndr
.opnum
= opnum
;
1411 req
->ndr
.struct_ptr
= r
;
1412 req
->ndr
.mem_ctx
= mem_ctx
;
1421 receive the answer from a dcerpc_ndr_request_send()
1423 _PUBLIC_ NTSTATUS
dcerpc_ndr_request_recv(struct rpc_request
*req
)
1425 struct dcerpc_pipe
*p
= req
->p
;
1428 struct ndr_pull
*pull
;
1430 TALLOC_CTX
*mem_ctx
= req
->ndr
.mem_ctx
;
1431 void *r
= req
->ndr
.struct_ptr
;
1432 uint32_t opnum
= req
->ndr
.opnum
;
1433 const struct ndr_interface_table
*table
= req
->ndr
.table
;
1434 const struct ndr_interface_call
*call
= &table
->calls
[opnum
];
1435 enum ndr_err_code ndr_err
;
1437 /* make sure the recv code doesn't free the request, as we
1438 need to grab the flags element before it is freed */
1439 if (talloc_reference(p
, req
) == NULL
) {
1440 return NT_STATUS_NO_MEMORY
;
1443 status
= dcerpc_request_recv(req
, mem_ctx
, &response
);
1444 if (!NT_STATUS_IS_OK(status
)) {
1445 talloc_unlink(p
, req
);
1451 /* prepare for ndr_pull_* */
1452 pull
= ndr_pull_init_flags(p
->conn
, &response
, mem_ctx
);
1454 talloc_unlink(p
, req
);
1455 return NT_STATUS_NO_MEMORY
;
1459 pull
->data
= talloc_steal(pull
, pull
->data
);
1461 talloc_unlink(p
, req
);
1463 if (flags
& DCERPC_PULL_BIGENDIAN
) {
1464 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1467 DEBUG(10,("rpc reply data:\n"));
1468 dump_data(10, pull
->data
, pull
->data_size
);
1470 /* pull the structure from the blob */
1471 ndr_err
= call
->ndr_pull(pull
, NDR_OUT
, r
);
1472 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1473 status
= ndr_map_error2ntstatus(ndr_err
);
1474 dcerpc_log_packet(p
->conn
->packet_log_dir
,
1475 table
, opnum
, NDR_OUT
,
1480 if (p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_OUT
) {
1481 status
= dcerpc_ndr_validate_out(p
->conn
, pull
, r
, call
->struct_size
,
1482 call
->ndr_push
, call
->ndr_pull
,
1484 if (!NT_STATUS_IS_OK(status
)) {
1485 dcerpc_log_packet(p
->conn
->packet_log_dir
,
1486 table
, opnum
, NDR_OUT
,
1492 if (pull
->offset
!= pull
->data_size
) {
1493 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1494 pull
->data_size
- pull
->offset
));
1495 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1496 but it turns out that early versions of NT
1497 (specifically NT3.1) add junk onto the end of rpc
1498 packets, so if we want to interoperate at all with
1499 those versions then we need to ignore this error */
1502 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1504 return NT_STATUS_OK
;
1509 a useful helper function for synchronous rpc requests
1511 this can be used when you have ndr push/pull functions in the
1514 _PUBLIC_ NTSTATUS
dcerpc_ndr_request(struct dcerpc_pipe
*p
,
1515 const struct GUID
*object
,
1516 const struct ndr_interface_table
*table
,
1518 TALLOC_CTX
*mem_ctx
,
1521 struct rpc_request
*req
;
1523 req
= dcerpc_ndr_request_send(p
, object
, table
, opnum
, false, mem_ctx
, r
);
1525 return NT_STATUS_NO_MEMORY
;
1528 return dcerpc_ndr_request_recv(req
);
1533 a useful function for retrieving the server name we connected to
1535 _PUBLIC_
const char *dcerpc_server_name(struct dcerpc_pipe
*p
)
1537 if (!p
->conn
->transport
.target_hostname
) {
1538 if (!p
->conn
->transport
.peer_name
) {
1541 return p
->conn
->transport
.peer_name(p
->conn
);
1543 return p
->conn
->transport
.target_hostname(p
->conn
);
1548 get the dcerpc auth_level for a open connection
1550 uint32_t dcerpc_auth_level(struct dcerpc_connection
*c
)
1554 if (c
->flags
& DCERPC_SEAL
) {
1555 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
1556 } else if (c
->flags
& DCERPC_SIGN
) {
1557 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
1558 } else if (c
->flags
& DCERPC_CONNECT
) {
1559 auth_level
= DCERPC_AUTH_LEVEL_CONNECT
;
1561 auth_level
= DCERPC_AUTH_LEVEL_NONE
;
1567 Receive an alter reply from the transport
1569 static void dcerpc_alter_recv_handler(struct rpc_request
*req
,
1570 DATA_BLOB
*raw_packet
, struct ncacn_packet
*pkt
)
1572 struct composite_context
*c
;
1573 struct dcerpc_pipe
*recv_pipe
;
1575 c
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
1576 recv_pipe
= talloc_get_type(c
->private_data
, struct dcerpc_pipe
);
1578 if (pkt
->ptype
== DCERPC_PKT_ALTER_RESP
&&
1579 pkt
->u
.alter_resp
.num_results
== 1 &&
1580 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
1581 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1582 pkt
->u
.alter_resp
.ctx_list
[0].reason
));
1583 composite_error(c
, dcerpc_map_reason(pkt
->u
.alter_resp
.ctx_list
[0].reason
));
1587 if (pkt
->ptype
!= DCERPC_PKT_ALTER_RESP
||
1588 pkt
->u
.alter_resp
.num_results
== 0 ||
1589 pkt
->u
.alter_resp
.ctx_list
[0].result
!= 0) {
1590 composite_error(c
, NT_STATUS_NET_WRITE_FAULT
);
1594 /* the alter_resp might contain a reply set of credentials */
1595 if (recv_pipe
->conn
->security_state
.auth_info
&&
1596 pkt
->u
.alter_resp
.auth_info
.length
) {
1597 struct dcerpc_connection
*conn
= recv_pipe
->conn
;
1599 uint32_t auth_length
;
1600 status
= dcerpc_pull_auth_trailer(pkt
, conn
, &pkt
->u
.alter_resp
.auth_info
,
1601 conn
->security_state
.auth_info
, &auth_length
, true);
1602 if (!NT_STATUS_IS_OK(status
)) {
1603 composite_error(c
, status
);
1612 send a dcerpc alter_context request
1614 struct composite_context
*dcerpc_alter_context_send(struct dcerpc_pipe
*p
,
1615 TALLOC_CTX
*mem_ctx
,
1616 const struct ndr_syntax_id
*syntax
,
1617 const struct ndr_syntax_id
*transfer_syntax
)
1619 struct composite_context
*c
;
1620 struct ncacn_packet pkt
;
1622 struct rpc_request
*req
;
1624 c
= composite_create(mem_ctx
, p
->conn
->event_ctx
);
1625 if (c
== NULL
) return NULL
;
1627 c
->private_data
= p
;
1629 p
->syntax
= *syntax
;
1630 p
->transfer_syntax
= *transfer_syntax
;
1632 init_ncacn_hdr(p
->conn
, &pkt
);
1634 pkt
.ptype
= DCERPC_PKT_ALTER
;
1635 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1636 pkt
.call_id
= p
->conn
->call_id
;
1637 pkt
.auth_length
= 0;
1639 if (p
->binding
->flags
& DCERPC_CONCURRENT_MULTIPLEX
) {
1640 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_CONC_MPX
;
1643 if (p
->binding
->flags
& DCERPC_HEADER_SIGNING
) {
1644 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN
;
1647 pkt
.u
.alter
.max_xmit_frag
= 5840;
1648 pkt
.u
.alter
.max_recv_frag
= 5840;
1649 pkt
.u
.alter
.assoc_group_id
= p
->binding
->assoc_group_id
;
1650 pkt
.u
.alter
.num_contexts
= 1;
1651 pkt
.u
.alter
.ctx_list
= talloc_array(c
, struct dcerpc_ctx_list
, 1);
1652 if (composite_nomem(pkt
.u
.alter
.ctx_list
, c
)) return c
;
1653 pkt
.u
.alter
.ctx_list
[0].context_id
= p
->context_id
;
1654 pkt
.u
.alter
.ctx_list
[0].num_transfer_syntaxes
= 1;
1655 pkt
.u
.alter
.ctx_list
[0].abstract_syntax
= p
->syntax
;
1656 pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
1657 pkt
.u
.alter
.auth_info
= data_blob(NULL
, 0);
1659 /* construct the NDR form of the packet */
1660 c
->status
= ncacn_push_auth(&blob
, mem_ctx
, p
->conn
->iconv_convenience
, &pkt
,
1661 p
->conn
->security_state
.auth_info
);
1662 if (!composite_is_ok(c
)) return c
;
1664 p
->conn
->transport
.recv_data
= dcerpc_recv_data
;
1667 * we allocate a dcerpc_request so we can be in the same
1668 * request queue as normal requests
1670 req
= talloc_zero(c
, struct rpc_request
);
1671 if (composite_nomem(req
, c
)) return c
;
1673 req
->state
= RPC_REQUEST_PENDING
;
1674 req
->call_id
= pkt
.call_id
;
1675 req
->async
.private_data
= c
;
1676 req
->async
.callback
= dcerpc_composite_fail
;
1678 req
->recv_handler
= dcerpc_alter_recv_handler
;
1679 DLIST_ADD_END(p
->conn
->pending
, req
, struct rpc_request
*);
1680 talloc_set_destructor(req
, dcerpc_req_dequeue
);
1682 c
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, true);
1683 if (!composite_is_ok(c
)) return c
;
1685 event_add_timed(c
->event_ctx
, req
,
1686 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT
, 0),
1687 dcerpc_timeout_handler
, req
);
1692 NTSTATUS
dcerpc_alter_context_recv(struct composite_context
*ctx
)
1694 NTSTATUS result
= composite_wait(ctx
);
1700 send a dcerpc alter_context request
1702 _PUBLIC_ NTSTATUS
dcerpc_alter_context(struct dcerpc_pipe
*p
,
1703 TALLOC_CTX
*mem_ctx
,
1704 const struct ndr_syntax_id
*syntax
,
1705 const struct ndr_syntax_id
*transfer_syntax
)
1707 struct composite_context
*creq
;
1708 creq
= dcerpc_alter_context_send(p
, mem_ctx
, syntax
, transfer_syntax
);
1709 return dcerpc_alter_context_recv(creq
);