2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004
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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/gen_ndr/ndr_epmapper.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 static struct dcerpc_interface_list
*dcerpc_pipes
= NULL
;
33 register a dcerpc client interface
35 NTSTATUS
librpc_register_interface(const struct dcerpc_interface_table
*interface
)
37 struct dcerpc_interface_list
*l
= talloc(talloc_autofree_context(),
38 struct dcerpc_interface_list
);
40 if (idl_iface_by_name (interface
->name
) != NULL
) {
41 DEBUG(0, ("Attempt to register interface %s twice\n", interface
->name
));
42 return NT_STATUS_OBJECT_NAME_COLLISION
;
46 DLIST_ADD(dcerpc_pipes
, l
);
52 return the list of registered dcerpc_pipes
54 const struct dcerpc_interface_list
*librpc_dcerpc_pipes(void)
59 /* destroy a dcerpc connection */
60 static int dcerpc_connection_destructor(void *ptr
)
62 struct dcerpc_connection
*c
= ptr
;
63 if (c
->transport
.shutdown_pipe
) {
64 c
->transport
.shutdown_pipe(c
);
70 /* initialise a dcerpc connection. */
71 struct dcerpc_connection
*dcerpc_connection_init(TALLOC_CTX
*mem_ctx
)
73 struct dcerpc_connection
*c
;
75 c
= talloc_zero(mem_ctx
, struct dcerpc_connection
);
81 c
->security_state
.auth_info
= NULL
;
82 c
->security_state
.session_key
= dcerpc_generic_session_key
;
83 c
->security_state
.generic_state
= NULL
;
84 c
->binding_string
= NULL
;
86 c
->srv_max_xmit_frag
= 0;
87 c
->srv_max_recv_frag
= 0;
90 talloc_set_destructor(c
, dcerpc_connection_destructor
);
95 /* initialise a dcerpc pipe. */
96 struct dcerpc_pipe
*dcerpc_pipe_init(TALLOC_CTX
*mem_ctx
)
98 struct dcerpc_pipe
*p
;
100 p
= talloc(mem_ctx
, struct dcerpc_pipe
);
105 p
->conn
= dcerpc_connection_init(p
);
106 if (p
->conn
== NULL
) {
111 p
->last_fault_code
= 0;
114 ZERO_STRUCT(p
->syntax
);
115 ZERO_STRUCT(p
->transfer_syntax
);
122 choose the next call id to use
124 static uint32_t next_call_id(struct dcerpc_connection
*c
)
127 if (c
->call_id
== 0) {
133 /* close down a dcerpc over SMB pipe */
134 void dcerpc_pipe_close(struct dcerpc_pipe
*p
)
139 /* we need to be able to get/set the fragment length without doing a full
141 void dcerpc_set_frag_length(DATA_BLOB
*blob
, uint16_t v
)
143 if (CVAL(blob
->data
,DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
) {
144 SSVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
, v
);
146 RSSVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
, v
);
150 uint16_t dcerpc_get_frag_length(const DATA_BLOB
*blob
)
152 if (CVAL(blob
->data
,DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
) {
153 return SVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
);
155 return RSVAL(blob
->data
, DCERPC_FRAG_LEN_OFFSET
);
159 void dcerpc_set_auth_length(DATA_BLOB
*blob
, uint16_t v
)
161 if (CVAL(blob
->data
,DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
) {
162 SSVAL(blob
->data
, DCERPC_AUTH_LEN_OFFSET
, v
);
164 RSSVAL(blob
->data
, DCERPC_AUTH_LEN_OFFSET
, v
);
170 setup for a ndr pull, also setting up any flags from the binding string
172 static struct ndr_pull
*ndr_pull_init_flags(struct dcerpc_connection
*c
,
173 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
175 struct ndr_pull
*ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
177 if (ndr
== NULL
) return ndr
;
179 if (c
->flags
& DCERPC_DEBUG_PAD_CHECK
) {
180 ndr
->flags
|= LIBNDR_FLAG_PAD_CHECK
;
183 if (c
->flags
& DCERPC_NDR_REF_ALLOC
) {
184 ndr
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
191 parse a data blob into a dcerpc_packet structure. This handles both
192 input and output packets
194 static NTSTATUS
dcerpc_pull(struct dcerpc_connection
*c
, DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
195 struct dcerpc_packet
*pkt
)
197 struct ndr_pull
*ndr
;
199 ndr
= ndr_pull_init_flags(c
, blob
, mem_ctx
);
201 return NT_STATUS_NO_MEMORY
;
204 if (! (CVAL(blob
->data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
205 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
208 return ndr_pull_dcerpc_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
212 generate a CONNECT level verifier
214 static NTSTATUS
dcerpc_connect_verifier(TALLOC_CTX
*mem_ctx
, DATA_BLOB
*blob
)
216 *blob
= data_blob_talloc(mem_ctx
, NULL
, 16);
217 if (blob
->data
== NULL
) {
218 return NT_STATUS_NO_MEMORY
;
220 SIVAL(blob
->data
, 0, 1);
221 memset(blob
->data
+4, 0, 12);
226 check a CONNECT level verifier
228 static NTSTATUS
dcerpc_check_connect_verifier(DATA_BLOB
*blob
)
230 if (blob
->length
!= 16 ||
231 IVAL(blob
->data
, 0) != 1) {
232 return NT_STATUS_ACCESS_DENIED
;
238 parse a possibly signed blob into a dcerpc request packet structure
240 static NTSTATUS
dcerpc_pull_request_sign(struct dcerpc_connection
*c
,
241 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
242 struct dcerpc_packet
*pkt
)
244 struct ndr_pull
*ndr
;
246 struct dcerpc_auth auth
;
249 /* non-signed packets are simpler */
250 if (!c
->security_state
.auth_info
||
251 !c
->security_state
.generic_state
) {
252 return dcerpc_pull(c
, blob
, mem_ctx
, pkt
);
255 ndr
= ndr_pull_init_flags(c
, blob
, mem_ctx
);
257 return NT_STATUS_NO_MEMORY
;
260 if (! (CVAL(blob
->data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
261 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
264 /* pull the basic packet */
265 status
= ndr_pull_dcerpc_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
266 if (!NT_STATUS_IS_OK(status
)) {
270 if (pkt
->ptype
!= DCERPC_PKT_RESPONSE
) {
274 if (pkt
->auth_length
== 0 &&
275 c
->security_state
.auth_info
->auth_level
== DCERPC_AUTH_LEVEL_CONNECT
) {
279 auth_blob
.length
= 8 + pkt
->auth_length
;
281 /* check for a valid length */
282 if (pkt
->u
.response
.stub_and_verifier
.length
< auth_blob
.length
) {
283 return NT_STATUS_INFO_LENGTH_MISMATCH
;
287 pkt
->u
.response
.stub_and_verifier
.data
+
288 pkt
->u
.response
.stub_and_verifier
.length
- auth_blob
.length
;
289 pkt
->u
.response
.stub_and_verifier
.length
-= auth_blob
.length
;
291 /* pull the auth structure */
292 ndr
= ndr_pull_init_flags(c
, &auth_blob
, mem_ctx
);
294 return NT_STATUS_NO_MEMORY
;
297 if (! (CVAL(blob
->data
, DCERPC_DREP_OFFSET
) & DCERPC_DREP_LE
)) {
298 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
301 status
= ndr_pull_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, &auth
);
302 if (!NT_STATUS_IS_OK(status
)) {
307 /* check signature or unseal the packet */
308 switch (c
->security_state
.auth_info
->auth_level
) {
309 case DCERPC_AUTH_LEVEL_PRIVACY
:
310 status
= gensec_unseal_packet(c
->security_state
.generic_state
,
312 blob
->data
+ DCERPC_REQUEST_LENGTH
,
313 pkt
->u
.response
.stub_and_verifier
.length
,
315 blob
->length
- auth
.credentials
.length
,
317 memcpy(pkt
->u
.response
.stub_and_verifier
.data
,
318 blob
->data
+ DCERPC_REQUEST_LENGTH
,
319 pkt
->u
.response
.stub_and_verifier
.length
);
322 case DCERPC_AUTH_LEVEL_INTEGRITY
:
323 status
= gensec_check_packet(c
->security_state
.generic_state
,
325 pkt
->u
.response
.stub_and_verifier
.data
,
326 pkt
->u
.response
.stub_and_verifier
.length
,
328 blob
->length
- auth
.credentials
.length
,
332 case DCERPC_AUTH_LEVEL_CONNECT
:
333 status
= dcerpc_check_connect_verifier(&auth
.credentials
);
336 case DCERPC_AUTH_LEVEL_NONE
:
340 status
= NT_STATUS_INVALID_LEVEL
;
344 /* remove the indicated amount of paddiing */
345 if (pkt
->u
.response
.stub_and_verifier
.length
< auth
.auth_pad_length
) {
346 return NT_STATUS_INFO_LENGTH_MISMATCH
;
348 pkt
->u
.response
.stub_and_verifier
.length
-= auth
.auth_pad_length
;
355 push a dcerpc request packet into a blob, possibly signing it.
357 static NTSTATUS
dcerpc_push_request_sign(struct dcerpc_connection
*c
,
358 DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
359 struct dcerpc_packet
*pkt
)
362 struct ndr_push
*ndr
;
365 /* non-signed packets are simpler */
366 if (!c
->security_state
.auth_info
||
367 !c
->security_state
.generic_state
) {
368 return dcerpc_push_auth(blob
, mem_ctx
, pkt
, c
->security_state
.auth_info
);
371 ndr
= ndr_push_init_ctx(mem_ctx
);
373 return NT_STATUS_NO_MEMORY
;
376 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
377 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
380 if (pkt
->pfc_flags
& DCERPC_PFC_FLAG_ORPC
) {
381 ndr
->flags
|= LIBNDR_FLAG_OBJECT_PRESENT
;
384 status
= ndr_push_dcerpc_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
385 if (!NT_STATUS_IS_OK(status
)) {
389 /* pad to 16 byte multiple in the payload portion of the
390 packet. This matches what w2k3 does */
391 c
->security_state
.auth_info
->auth_pad_length
=
392 (16 - (pkt
->u
.request
.stub_and_verifier
.length
& 15)) & 15;
393 ndr_push_zero(ndr
, c
->security_state
.auth_info
->auth_pad_length
);
395 /* sign or seal the packet */
396 switch (c
->security_state
.auth_info
->auth_level
) {
397 case DCERPC_AUTH_LEVEL_PRIVACY
:
398 case DCERPC_AUTH_LEVEL_INTEGRITY
:
399 c
->security_state
.auth_info
->credentials
400 = data_blob_talloc(mem_ctx
, NULL
, gensec_sig_size(c
->security_state
.generic_state
));
401 data_blob_clear(&c
->security_state
.auth_info
->credentials
);
404 case DCERPC_AUTH_LEVEL_CONNECT
:
405 status
= dcerpc_connect_verifier(mem_ctx
, &c
->security_state
.auth_info
->credentials
);
408 case DCERPC_AUTH_LEVEL_NONE
:
409 c
->security_state
.auth_info
->credentials
= data_blob(NULL
, 0);
413 status
= NT_STATUS_INVALID_LEVEL
;
417 if (!NT_STATUS_IS_OK(status
)) {
421 /* add the auth verifier */
422 status
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, c
->security_state
.auth_info
);
423 if (!NT_STATUS_IS_OK(status
)) {
427 /* extract the whole packet as a blob */
428 *blob
= ndr_push_blob(ndr
);
430 /* fill in the fragment length and auth_length, we can't fill
431 in these earlier as we don't know the signature length (it
432 could be variable length) */
433 dcerpc_set_frag_length(blob
, blob
->length
);
434 dcerpc_set_auth_length(blob
, c
->security_state
.auth_info
->credentials
.length
);
436 /* sign or seal the packet */
437 switch (c
->security_state
.auth_info
->auth_level
) {
438 case DCERPC_AUTH_LEVEL_PRIVACY
:
439 status
= gensec_seal_packet(c
->security_state
.generic_state
,
441 blob
->data
+ DCERPC_REQUEST_LENGTH
,
442 pkt
->u
.request
.stub_and_verifier
.length
+
443 c
->security_state
.auth_info
->auth_pad_length
,
446 c
->security_state
.auth_info
->credentials
.length
,
448 if (!NT_STATUS_IS_OK(status
)) {
451 memcpy(blob
->data
+ blob
->length
- creds2
.length
, creds2
.data
, creds2
.length
);
454 case DCERPC_AUTH_LEVEL_INTEGRITY
:
455 status
= gensec_sign_packet(c
->security_state
.generic_state
,
457 blob
->data
+ DCERPC_REQUEST_LENGTH
,
458 pkt
->u
.request
.stub_and_verifier
.length
+
459 c
->security_state
.auth_info
->auth_pad_length
,
462 c
->security_state
.auth_info
->credentials
.length
,
464 if (!NT_STATUS_IS_OK(status
)) {
467 memcpy(blob
->data
+ blob
->length
- creds2
.length
, creds2
.data
, creds2
.length
);
470 case DCERPC_AUTH_LEVEL_CONNECT
:
473 case DCERPC_AUTH_LEVEL_NONE
:
474 c
->security_state
.auth_info
->credentials
= data_blob(NULL
, 0);
478 status
= NT_STATUS_INVALID_LEVEL
;
482 data_blob_free(&c
->security_state
.auth_info
->credentials
);
489 fill in the fixed values in a dcerpc header
491 static void init_dcerpc_hdr(struct dcerpc_connection
*c
, struct dcerpc_packet
*pkt
)
494 pkt
->rpc_vers_minor
= 0;
495 if (c
->flags
& DCERPC_PUSH_BIGENDIAN
) {
498 pkt
->drep
[0] = DCERPC_DREP_LE
;
506 hold the state of pending full requests
508 struct full_request_state
{
509 DATA_BLOB
*reply_blob
;
514 receive a reply to a full request
516 static void full_request_recv(struct dcerpc_connection
*c
, DATA_BLOB
*blob
,
519 struct full_request_state
*state
= c
->full_request_private
;
521 if (!NT_STATUS_IS_OK(status
)) {
522 state
->status
= status
;
525 state
->reply_blob
[0] = data_blob_talloc(state
, blob
->data
, blob
->length
);
526 state
->reply_blob
= NULL
;
530 perform a single pdu synchronous request - used for the bind code
531 this cannot be mixed with normal async requests
533 static NTSTATUS
full_request(struct dcerpc_connection
*c
,
535 DATA_BLOB
*request_blob
,
536 DATA_BLOB
*reply_blob
)
538 struct full_request_state
*state
= talloc(mem_ctx
, struct full_request_state
);
542 return NT_STATUS_NO_MEMORY
;
545 state
->reply_blob
= reply_blob
;
546 state
->status
= NT_STATUS_OK
;
548 c
->transport
.recv_data
= full_request_recv
;
549 c
->full_request_private
= state
;
551 status
= c
->transport
.send_request(c
, request_blob
, True
);
552 if (!NT_STATUS_IS_OK(status
)) {
556 while (NT_STATUS_IS_OK(state
->status
) && state
->reply_blob
) {
557 struct event_context
*ctx
= c
->transport
.event_context(c
);
558 if (event_loop_once(ctx
) != 0) {
559 return NT_STATUS_CONNECTION_DISCONNECTED
;
563 return state
->status
;
567 map a bind nak reason to a NTSTATUS
569 static NTSTATUS
dcerpc_map_reason(uint16_t reason
)
572 case DCERPC_BIND_REASON_ASYNTAX
:
573 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX
;
575 return NT_STATUS_UNSUCCESSFUL
;
580 perform a bind using the given syntax
582 the auth_info structure is updated with the reply authentication info
585 NTSTATUS
dcerpc_bind(struct dcerpc_pipe
*p
,
587 const struct dcerpc_syntax_id
*syntax
,
588 const struct dcerpc_syntax_id
*transfer_syntax
)
590 struct dcerpc_packet pkt
;
595 p
->transfer_syntax
= *transfer_syntax
;
597 init_dcerpc_hdr(p
->conn
, &pkt
);
599 pkt
.ptype
= DCERPC_PKT_BIND
;
600 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
601 pkt
.call_id
= p
->conn
->call_id
;
604 pkt
.u
.bind
.max_xmit_frag
= 5840;
605 pkt
.u
.bind
.max_recv_frag
= 5840;
606 pkt
.u
.bind
.assoc_group_id
= 0;
607 pkt
.u
.bind
.num_contexts
= 1;
608 pkt
.u
.bind
.ctx_list
= talloc_array(mem_ctx
, struct dcerpc_ctx_list
, 1);
609 if (!pkt
.u
.bind
.ctx_list
) {
610 return NT_STATUS_NO_MEMORY
;
612 pkt
.u
.bind
.ctx_list
[0].context_id
= p
->context_id
;
613 pkt
.u
.bind
.ctx_list
[0].num_transfer_syntaxes
= 1;
614 pkt
.u
.bind
.ctx_list
[0].abstract_syntax
= p
->syntax
;
615 pkt
.u
.bind
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
616 pkt
.u
.bind
.auth_info
= data_blob(NULL
, 0);
618 /* construct the NDR form of the packet */
619 status
= dcerpc_push_auth(&blob
, mem_ctx
, &pkt
, p
->conn
->security_state
.auth_info
);
620 if (!NT_STATUS_IS_OK(status
)) {
624 /* send it on its way */
625 status
= full_request(p
->conn
, mem_ctx
, &blob
, &blob
);
626 if (!NT_STATUS_IS_OK(status
)) {
630 /* unmarshall the NDR */
631 status
= dcerpc_pull(p
->conn
, &blob
, mem_ctx
, &pkt
);
632 if (!NT_STATUS_IS_OK(status
)) {
636 if (pkt
.ptype
== DCERPC_PKT_BIND_NAK
) {
637 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt
.u
.bind_nak
.reject_reason
));
638 return dcerpc_map_reason(pkt
.u
.bind_nak
.reject_reason
);
641 if ((pkt
.ptype
!= DCERPC_PKT_BIND_ACK
) ||
642 pkt
.u
.bind_ack
.num_results
== 0 ||
643 pkt
.u
.bind_ack
.ctx_list
[0].result
!= 0) {
644 return NT_STATUS_UNSUCCESSFUL
;
647 p
->conn
->srv_max_xmit_frag
= pkt
.u
.bind_ack
.max_xmit_frag
;
648 p
->conn
->srv_max_recv_frag
= pkt
.u
.bind_ack
.max_recv_frag
;
650 /* the bind_ack might contain a reply set of credentials */
651 if (p
->conn
->security_state
.auth_info
&& pkt
.u
.bind_ack
.auth_info
.length
) {
652 status
= ndr_pull_struct_blob(&pkt
.u
.bind_ack
.auth_info
,
654 p
->conn
->security_state
.auth_info
,
655 (ndr_pull_flags_fn_t
)ndr_pull_dcerpc_auth
);
663 perform a continued bind (and auth3)
665 NTSTATUS
dcerpc_auth3(struct dcerpc_connection
*c
,
668 struct dcerpc_packet pkt
;
672 init_dcerpc_hdr(c
, &pkt
);
674 pkt
.ptype
= DCERPC_PKT_AUTH3
;
675 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
676 pkt
.call_id
= next_call_id(c
);
678 pkt
.u
.auth3
._pad
= 0;
679 pkt
.u
.auth3
.auth_info
= data_blob(NULL
, 0);
681 /* construct the NDR form of the packet */
682 status
= dcerpc_push_auth(&blob
, mem_ctx
, &pkt
, c
->security_state
.auth_info
);
683 if (!NT_STATUS_IS_OK(status
)) {
687 /* send it on its way */
688 status
= c
->transport
.send_request(c
, &blob
, False
);
689 if (!NT_STATUS_IS_OK(status
)) {
697 /* perform a dcerpc bind, using the uuid as the key */
698 NTSTATUS
dcerpc_bind_byuuid(struct dcerpc_pipe
*p
,
700 const char *uuid
, uint_t version
)
702 struct dcerpc_syntax_id syntax
;
703 struct dcerpc_syntax_id transfer_syntax
;
706 status
= GUID_from_string(uuid
, &syntax
.uuid
);
707 if (!NT_STATUS_IS_OK(status
)) {
708 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
711 syntax
.if_version
= version
;
713 status
= GUID_from_string(NDR_GUID
, &transfer_syntax
.uuid
);
714 if (!NT_STATUS_IS_OK(status
)) {
717 transfer_syntax
.if_version
= NDR_GUID_VERSION
;
719 return dcerpc_bind(p
, mem_ctx
, &syntax
, &transfer_syntax
);
723 process a fragment received from the transport layer during a
726 static void dcerpc_request_recv_data(struct dcerpc_connection
*c
,
730 struct dcerpc_packet pkt
;
731 struct rpc_request
*req
;
734 if (!NT_STATUS_IS_OK(status
)) {
735 /* all pending requests get the error */
738 req
->state
= RPC_REQUEST_DONE
;
739 req
->status
= status
;
740 DLIST_REMOVE(c
->pending
, req
);
741 if (req
->async
.callback
) {
742 req
->async
.callback(req
);
750 status
= dcerpc_pull_request_sign(c
, data
, (TALLOC_CTX
*)data
->data
, &pkt
);
752 /* find the matching request. Notice we match before we check
753 the status. this is ok as a pending call_id can never be
755 for (req
=c
->pending
;req
;req
=req
->next
) {
756 if (pkt
.call_id
== req
->call_id
) break;
760 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt
.call_id
));
764 if (!NT_STATUS_IS_OK(status
)) {
765 req
->status
= status
;
766 req
->state
= RPC_REQUEST_DONE
;
767 DLIST_REMOVE(c
->pending
, req
);
768 if (req
->async
.callback
) {
769 req
->async
.callback(req
);
774 if (pkt
.ptype
== DCERPC_PKT_FAULT
) {
775 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c
, pkt
.u
.fault
.status
)));
776 req
->fault_code
= pkt
.u
.fault
.status
;
777 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
778 req
->state
= RPC_REQUEST_DONE
;
779 DLIST_REMOVE(c
->pending
, req
);
780 if (req
->async
.callback
) {
781 req
->async
.callback(req
);
786 if (pkt
.ptype
!= DCERPC_PKT_RESPONSE
) {
787 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
789 req
->fault_code
= DCERPC_FAULT_OTHER
;
790 req
->status
= NT_STATUS_NET_WRITE_FAULT
;
791 req
->state
= RPC_REQUEST_DONE
;
792 DLIST_REMOVE(c
->pending
, req
);
793 if (req
->async
.callback
) {
794 req
->async
.callback(req
);
799 length
= pkt
.u
.response
.stub_and_verifier
.length
;
802 req
->payload
.data
= talloc_realloc(req
,
805 req
->payload
.length
+ length
);
806 if (!req
->payload
.data
) {
807 req
->status
= NT_STATUS_NO_MEMORY
;
808 req
->state
= RPC_REQUEST_DONE
;
809 DLIST_REMOVE(c
->pending
, req
);
810 if (req
->async
.callback
) {
811 req
->async
.callback(req
);
815 memcpy(req
->payload
.data
+req
->payload
.length
,
816 pkt
.u
.response
.stub_and_verifier
.data
, length
);
817 req
->payload
.length
+= length
;
820 if (!(pkt
.pfc_flags
& DCERPC_PFC_FLAG_LAST
)) {
821 c
->transport
.send_read(c
);
825 /* we've got the full payload */
826 req
->state
= RPC_REQUEST_DONE
;
827 DLIST_REMOVE(c
->pending
, req
);
829 if (!(pkt
.drep
[0] & DCERPC_DREP_LE
)) {
830 req
->flags
|= DCERPC_PULL_BIGENDIAN
;
832 req
->flags
&= ~DCERPC_PULL_BIGENDIAN
;
835 if (req
->async
.callback
) {
836 req
->async
.callback(req
);
842 make sure requests are cleaned up
844 static int dcerpc_req_destructor(void *ptr
)
846 struct rpc_request
*req
= ptr
;
847 DLIST_REMOVE(req
->p
->conn
->pending
, req
);
852 perform the send side of a async dcerpc request
854 struct rpc_request
*dcerpc_request_send(struct dcerpc_pipe
*p
,
855 const struct GUID
*object
,
858 DATA_BLOB
*stub_data
)
860 struct rpc_request
*req
;
861 struct dcerpc_packet pkt
;
863 uint32_t remaining
, chunk_size
;
864 BOOL first_packet
= True
;
866 p
->conn
->transport
.recv_data
= dcerpc_request_recv_data
;
868 req
= talloc(mem_ctx
, struct rpc_request
);
874 req
->call_id
= next_call_id(p
->conn
);
875 req
->status
= NT_STATUS_OK
;
876 req
->state
= RPC_REQUEST_PENDING
;
877 req
->payload
= data_blob(NULL
, 0);
880 req
->async
.callback
= NULL
;
882 init_dcerpc_hdr(p
->conn
, &pkt
);
884 remaining
= stub_data
->length
;
886 /* we can write a full max_recv_frag size, minus the dcerpc
887 request header size */
888 chunk_size
= p
->conn
->srv_max_recv_frag
- (DCERPC_MAX_SIGN_SIZE
+DCERPC_REQUEST_LENGTH
);
890 pkt
.ptype
= DCERPC_PKT_REQUEST
;
891 pkt
.call_id
= req
->call_id
;
894 pkt
.u
.request
.alloc_hint
= remaining
;
895 pkt
.u
.request
.context_id
= p
->context_id
;
896 pkt
.u
.request
.opnum
= opnum
;
899 pkt
.u
.request
.object
.object
= *object
;
900 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_ORPC
;
901 chunk_size
-= ndr_size_GUID(object
,0);
904 DLIST_ADD(p
->conn
->pending
, req
);
906 /* we send a series of pdus without waiting for a reply */
907 while (remaining
> 0 || first_packet
) {
908 uint32_t chunk
= MIN(chunk_size
, remaining
);
909 BOOL last_frag
= False
;
911 first_packet
= False
;
912 pkt
.pfc_flags
&= ~(DCERPC_PFC_FLAG_FIRST
|DCERPC_PFC_FLAG_LAST
);
914 if (remaining
== stub_data
->length
) {
915 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_FIRST
;
917 if (chunk
== remaining
) {
918 pkt
.pfc_flags
|= DCERPC_PFC_FLAG_LAST
;
922 pkt
.u
.request
.stub_and_verifier
.data
= stub_data
->data
+
923 (stub_data
->length
- remaining
);
924 pkt
.u
.request
.stub_and_verifier
.length
= chunk
;
926 req
->status
= dcerpc_push_request_sign(p
->conn
, &blob
, mem_ctx
, &pkt
);
927 if (!NT_STATUS_IS_OK(req
->status
)) {
928 req
->state
= RPC_REQUEST_DONE
;
929 DLIST_REMOVE(p
->conn
->pending
, req
);
933 req
->status
= p
->conn
->transport
.send_request(p
->conn
, &blob
, last_frag
);
934 if (!NT_STATUS_IS_OK(req
->status
)) {
935 req
->state
= RPC_REQUEST_DONE
;
936 DLIST_REMOVE(p
->conn
->pending
, req
);
943 talloc_set_destructor(req
, dcerpc_req_destructor
);
949 return the event context for a dcerpc pipe
950 used by callers who wish to operate asynchronously
952 struct event_context
*dcerpc_event_context(struct dcerpc_pipe
*p
)
954 return p
->conn
->transport
.event_context(p
->conn
);
960 perform the receive side of a async dcerpc request
962 NTSTATUS
dcerpc_request_recv(struct rpc_request
*req
,
964 DATA_BLOB
*stub_data
)
968 while (req
->state
== RPC_REQUEST_PENDING
) {
969 struct event_context
*ctx
= dcerpc_event_context(req
->p
);
970 if (event_loop_once(ctx
) != 0) {
971 return NT_STATUS_CONNECTION_DISCONNECTED
;
974 *stub_data
= req
->payload
;
975 status
= req
->status
;
976 if (stub_data
->data
) {
977 stub_data
->data
= talloc_steal(mem_ctx
, stub_data
->data
);
979 if (NT_STATUS_EQUAL(status
, NT_STATUS_NET_WRITE_FAULT
)) {
980 req
->p
->last_fault_code
= req
->fault_code
;
987 perform a full request/response pair on a dcerpc pipe
989 NTSTATUS
dcerpc_request(struct dcerpc_pipe
*p
,
993 DATA_BLOB
*stub_data_in
,
994 DATA_BLOB
*stub_data_out
)
996 struct rpc_request
*req
;
998 req
= dcerpc_request_send(p
, object
, opnum
, mem_ctx
, stub_data_in
);
1000 return NT_STATUS_NO_MEMORY
;
1003 return dcerpc_request_recv(req
, mem_ctx
, stub_data_out
);
1008 this is a paranoid NDR validator. For every packet we push onto the wire
1009 we pull it back again, then push it again. Then we compare the raw NDR data
1010 for that to the NDR we initially generated. If they don't match then we know
1011 we must have a bug in either the pull or push side of our code
1013 static NTSTATUS
dcerpc_ndr_validate_in(struct dcerpc_connection
*c
,
1014 TALLOC_CTX
*mem_ctx
,
1017 NTSTATUS (*ndr_push
)(struct ndr_push
*, int, void *),
1018 NTSTATUS (*ndr_pull
)(struct ndr_pull
*, int, void *))
1021 struct ndr_pull
*pull
;
1022 struct ndr_push
*push
;
1026 st
= talloc_size(mem_ctx
, struct_size
);
1028 return NT_STATUS_NO_MEMORY
;
1031 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1033 return NT_STATUS_NO_MEMORY
;
1036 status
= ndr_pull(pull
, NDR_IN
, st
);
1037 if (!NT_STATUS_IS_OK(status
)) {
1038 return ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1039 "failed input validation pull - %s",
1043 push
= ndr_push_init_ctx(mem_ctx
);
1045 return NT_STATUS_NO_MEMORY
;
1048 status
= ndr_push(push
, NDR_IN
, st
);
1049 if (!NT_STATUS_IS_OK(status
)) {
1050 return ndr_push_error(push
, NDR_ERR_VALIDATE
,
1051 "failed input validation push - %s",
1055 blob2
= ndr_push_blob(push
);
1057 if (!data_blob_equal(&blob
, &blob2
)) {
1058 DEBUG(3,("original:\n"));
1059 dump_data(3, blob
.data
, blob
.length
);
1060 DEBUG(3,("secondary:\n"));
1061 dump_data(3, blob2
.data
, blob2
.length
);
1062 return ndr_push_error(push
, NDR_ERR_VALIDATE
,
1063 "failed input validation data - %s",
1067 return NT_STATUS_OK
;
1071 this is a paranoid NDR input validator. For every packet we pull
1072 from the wire we push it back again then pull and push it
1073 again. Then we compare the raw NDR data for that to the NDR we
1074 initially generated. If they don't match then we know we must have a
1075 bug in either the pull or push side of our code
1077 static NTSTATUS
dcerpc_ndr_validate_out(struct dcerpc_connection
*c
,
1078 TALLOC_CTX
*mem_ctx
,
1081 NTSTATUS (*ndr_push
)(struct ndr_push
*, int, void *),
1082 NTSTATUS (*ndr_pull
)(struct ndr_pull
*, int, void *))
1085 struct ndr_pull
*pull
;
1086 struct ndr_push
*push
;
1088 DATA_BLOB blob
, blob2
;
1090 st
= talloc_size(mem_ctx
, struct_size
);
1092 return NT_STATUS_NO_MEMORY
;
1094 memcpy(st
, struct_ptr
, struct_size
);
1096 push
= ndr_push_init_ctx(mem_ctx
);
1098 return NT_STATUS_NO_MEMORY
;
1101 status
= ndr_push(push
, NDR_OUT
, struct_ptr
);
1102 if (!NT_STATUS_IS_OK(status
)) {
1103 return ndr_push_error(push
, NDR_ERR_VALIDATE
,
1104 "failed output validation push - %s",
1108 blob
= ndr_push_blob(push
);
1110 pull
= ndr_pull_init_flags(c
, &blob
, mem_ctx
);
1112 return NT_STATUS_NO_MEMORY
;
1115 pull
->flags
|= LIBNDR_FLAG_REF_ALLOC
;
1116 status
= ndr_pull(pull
, NDR_OUT
, st
);
1117 if (!NT_STATUS_IS_OK(status
)) {
1118 return ndr_pull_error(pull
, NDR_ERR_VALIDATE
,
1119 "failed output validation pull - %s",
1123 push
= ndr_push_init_ctx(mem_ctx
);
1125 return NT_STATUS_NO_MEMORY
;
1128 status
= ndr_push(push
, NDR_OUT
, st
);
1129 if (!NT_STATUS_IS_OK(status
)) {
1130 return ndr_push_error(push
, NDR_ERR_VALIDATE
,
1131 "failed output validation push2 - %s",
1135 blob2
= ndr_push_blob(push
);
1137 if (!data_blob_equal(&blob
, &blob2
)) {
1138 DEBUG(3,("original:\n"));
1139 dump_data(3, blob
.data
, blob
.length
);
1140 DEBUG(3,("secondary:\n"));
1141 dump_data(3, blob2
.data
, blob2
.length
);
1142 return ndr_push_error(push
, NDR_ERR_VALIDATE
,
1143 "failed output validation data - %s",
1147 return NT_STATUS_OK
;
1152 send a rpc request given a dcerpc_call structure
1154 struct rpc_request
*dcerpc_ndr_request_send(struct dcerpc_pipe
*p
,
1155 const struct GUID
*object
,
1156 const struct dcerpc_interface_table
*table
,
1158 TALLOC_CTX
*mem_ctx
,
1161 const struct dcerpc_interface_call
*call
;
1162 struct ndr_push
*push
;
1165 struct rpc_request
*req
;
1167 call
= &table
->calls
[opnum
];
1169 /* setup for a ndr_push_* call */
1170 push
= ndr_push_init();
1175 if (p
->conn
->flags
& DCERPC_PUSH_BIGENDIAN
) {
1176 push
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1179 /* push the structure into a blob */
1180 status
= call
->ndr_push(push
, NDR_IN
, r
);
1181 if (!NT_STATUS_IS_OK(status
)) {
1182 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1183 nt_errstr(status
)));
1184 ndr_push_free(push
);
1188 /* retrieve the blob */
1189 request
= ndr_push_blob(push
);
1191 if (p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_IN
) {
1192 status
= dcerpc_ndr_validate_in(p
->conn
, mem_ctx
, request
, call
->struct_size
,
1193 call
->ndr_push
, call
->ndr_pull
);
1194 if (!NT_STATUS_IS_OK(status
)) {
1195 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1196 nt_errstr(status
)));
1197 ndr_push_free(push
);
1202 DEBUG(10,("rpc request data:\n"));
1203 dump_data(10, request
.data
, request
.length
);
1205 /* make the actual dcerpc request */
1206 req
= dcerpc_request_send(p
, object
, opnum
, mem_ctx
, &request
);
1209 req
->ndr
.table
= table
;
1210 req
->ndr
.opnum
= opnum
;
1211 req
->ndr
.struct_ptr
= r
;
1212 req
->ndr
.mem_ctx
= mem_ctx
;
1215 ndr_push_free(push
);
1221 receive the answer from a dcerpc_ndr_request_send()
1223 NTSTATUS
dcerpc_ndr_request_recv(struct rpc_request
*req
)
1225 struct dcerpc_pipe
*p
= req
->p
;
1228 struct ndr_pull
*pull
;
1230 TALLOC_CTX
*mem_ctx
= req
->ndr
.mem_ctx
;
1231 void *r
= req
->ndr
.struct_ptr
;
1232 uint32_t opnum
= req
->ndr
.opnum
;
1233 const struct dcerpc_interface_table
*table
= req
->ndr
.table
;
1234 const struct dcerpc_interface_call
*call
= &table
->calls
[opnum
];
1236 /* make sure the recv code doesn't free the request, as we
1237 need to grab the flags element before it is freed */
1238 talloc_increase_ref_count(req
);
1240 status
= dcerpc_request_recv(req
, mem_ctx
, &response
);
1241 if (!NT_STATUS_IS_OK(status
)) {
1248 /* prepare for ndr_pull_* */
1249 pull
= ndr_pull_init_flags(p
->conn
, &response
, mem_ctx
);
1251 return NT_STATUS_NO_MEMORY
;
1254 if (flags
& DCERPC_PULL_BIGENDIAN
) {
1255 pull
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
1258 DEBUG(10,("rpc reply data:\n"));
1259 dump_data(10, pull
->data
, pull
->data_size
);
1261 /* pull the structure from the blob */
1262 status
= call
->ndr_pull(pull
, NDR_OUT
, r
);
1263 if (!NT_STATUS_IS_OK(status
)) {
1264 dcerpc_log_packet(table
, opnum
, NDR_OUT
,
1269 if (p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_OUT
) {
1270 status
= dcerpc_ndr_validate_out(p
->conn
, mem_ctx
, r
, call
->struct_size
,
1271 call
->ndr_push
, call
->ndr_pull
);
1272 if (!NT_STATUS_IS_OK(status
)) {
1273 dcerpc_log_packet(table
, opnum
, NDR_OUT
,
1279 if (pull
->offset
!= pull
->data_size
) {
1280 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1281 pull
->data_size
- pull
->offset
));
1282 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1283 but it turns out that early versions of NT
1284 (specifically NT3.1) add junk onto the end of rpc
1285 packets, so if we want to interoperate at all with
1286 those versions then we need to ignore this error */
1289 return NT_STATUS_OK
;
1294 a useful helper function for synchronous rpc requests
1296 this can be used when you have ndr push/pull functions in the
1299 NTSTATUS
dcerpc_ndr_request(struct dcerpc_pipe
*p
,
1300 const struct GUID
*object
,
1301 const struct dcerpc_interface_table
*table
,
1303 TALLOC_CTX
*mem_ctx
,
1306 struct rpc_request
*req
;
1308 req
= dcerpc_ndr_request_send(p
, object
, table
, opnum
, mem_ctx
, r
);
1310 return NT_STATUS_NO_MEMORY
;
1313 return dcerpc_ndr_request_recv(req
);
1318 a useful function for retrieving the server name we connected to
1320 const char *dcerpc_server_name(struct dcerpc_pipe
*p
)
1322 if (!p
->conn
->transport
.peer_name
) {
1325 return p
->conn
->transport
.peer_name(p
->conn
);
1330 get the dcerpc auth_level for a open connection
1332 uint32_t dcerpc_auth_level(struct dcerpc_connection
*c
)
1336 if (c
->flags
& DCERPC_SEAL
) {
1337 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
1338 } else if (c
->flags
& DCERPC_SIGN
) {
1339 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
1340 } else if (c
->flags
& DCERPC_CONNECT
) {
1341 auth_level
= DCERPC_AUTH_LEVEL_CONNECT
;
1343 auth_level
= DCERPC_AUTH_LEVEL_NONE
;
1350 send a dcerpc alter_context request
1352 NTSTATUS
dcerpc_alter_context(struct dcerpc_pipe
*p
,
1353 TALLOC_CTX
*mem_ctx
,
1354 const struct dcerpc_syntax_id
*syntax
,
1355 const struct dcerpc_syntax_id
*transfer_syntax
)
1357 struct dcerpc_packet pkt
;
1361 p
->syntax
= *syntax
;
1362 p
->transfer_syntax
= *transfer_syntax
;
1364 init_dcerpc_hdr(p
->conn
, &pkt
);
1366 pkt
.ptype
= DCERPC_PKT_ALTER
;
1367 pkt
.pfc_flags
= DCERPC_PFC_FLAG_FIRST
| DCERPC_PFC_FLAG_LAST
;
1368 pkt
.call_id
= p
->conn
->call_id
;
1369 pkt
.auth_length
= 0;
1371 pkt
.u
.alter
.max_xmit_frag
= 5840;
1372 pkt
.u
.alter
.max_recv_frag
= 5840;
1373 pkt
.u
.alter
.assoc_group_id
= 0;
1374 pkt
.u
.alter
.num_contexts
= 1;
1375 pkt
.u
.alter
.ctx_list
= talloc_array(mem_ctx
, struct dcerpc_ctx_list
, 1);
1376 if (!pkt
.u
.alter
.ctx_list
) {
1377 return NT_STATUS_NO_MEMORY
;
1379 pkt
.u
.alter
.ctx_list
[0].context_id
= p
->context_id
;
1380 pkt
.u
.alter
.ctx_list
[0].num_transfer_syntaxes
= 1;
1381 pkt
.u
.alter
.ctx_list
[0].abstract_syntax
= p
->syntax
;
1382 pkt
.u
.alter
.ctx_list
[0].transfer_syntaxes
= &p
->transfer_syntax
;
1383 pkt
.u
.alter
.auth_info
= data_blob(NULL
, 0);
1385 /* construct the NDR form of the packet */
1386 status
= dcerpc_push_auth(&blob
, mem_ctx
, &pkt
, p
->conn
->security_state
.auth_info
);
1387 if (!NT_STATUS_IS_OK(status
)) {
1391 /* send it on its way */
1392 status
= full_request(p
->conn
, mem_ctx
, &blob
, &blob
);
1393 if (!NT_STATUS_IS_OK(status
)) {
1397 /* unmarshall the NDR */
1398 status
= dcerpc_pull(p
->conn
, &blob
, mem_ctx
, &pkt
);
1399 if (!NT_STATUS_IS_OK(status
)) {
1403 if (pkt
.ptype
== DCERPC_PKT_ALTER_RESP
&&
1404 pkt
.u
.alter_resp
.num_results
== 1 &&
1405 pkt
.u
.alter_resp
.ctx_list
[0].result
!= 0) {
1406 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1407 pkt
.u
.alter_resp
.ctx_list
[0].reason
));
1408 return dcerpc_map_reason(pkt
.u
.alter_resp
.ctx_list
[0].reason
);
1411 if (pkt
.ptype
!= DCERPC_PKT_ALTER_RESP
||
1412 pkt
.u
.alter_resp
.num_results
== 0 ||
1413 pkt
.u
.alter_resp
.ctx_list
[0].result
!= 0) {
1414 return NT_STATUS_UNSUCCESSFUL
;
1417 /* the alter_resp might contain a reply set of credentials */
1418 if (p
->conn
->security_state
.auth_info
&& pkt
.u
.alter_resp
.auth_info
.length
) {
1419 status
= ndr_pull_struct_blob(&pkt
.u
.alter_resp
.auth_info
,
1421 p
->conn
->security_state
.auth_info
,
1422 (ndr_pull_flags_fn_t
)ndr_pull_dcerpc_auth
);