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 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/rpc/dcerpc.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"
33 NTSTATUS dcerpc_init(void)
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(void *ptr)
45 struct dcerpc_connection *c = ptr;
46 if (c->transport.shutdown_pipe) {
47 c->transport.shutdown_pipe(c);
53 /* initialise a dcerpc connection.
54 the event context is optional
56 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
57 struct event_context *ev)
59 struct dcerpc_connection *c;
61 c = talloc_zero(mem_ctx, struct dcerpc_connection);
67 ev = event_context_init(c);
76 if (!talloc_reference(c, ev)) {
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, struct event_context *ev)
98 struct dcerpc_pipe *p;
100 p = talloc(mem_ctx, struct dcerpc_pipe);
105 p->conn = dcerpc_connection_init(p, ev);
106 if (p->conn == NULL) {
111 p->last_fault_code = 0;
113 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
115 ZERO_STRUCT(p->syntax);
116 ZERO_STRUCT(p->transfer_syntax);
123 choose the next call id to use
125 static uint32_t next_call_id(struct dcerpc_connection *c)
128 if (c->call_id == 0) {
134 /* we need to be able to get/set the fragment length without doing a full
136 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
138 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
139 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
141 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
145 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
147 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
148 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
150 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
154 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
156 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
157 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
159 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
165 setup for a ndr pull, also setting up any flags from the binding string
167 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
168 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
170 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
172 if (ndr == NULL) return ndr;
174 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
175 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
178 if (c->flags & DCERPC_NDR_REF_ALLOC) {
179 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
186 parse a data blob into a ncacn_packet structure. This handles both
187 input and output packets
189 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
190 struct ncacn_packet *pkt)
192 struct ndr_pull *ndr;
194 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
196 return NT_STATUS_NO_MEMORY;
199 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
200 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
203 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
207 generate a CONNECT level verifier
209 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
211 *blob = data_blob_talloc(mem_ctx, NULL, 16);
212 if (blob->data == NULL) {
213 return NT_STATUS_NO_MEMORY;
215 SIVAL(blob->data, 0, 1);
216 memset(blob->data+4, 0, 12);
221 check a CONNECT level verifier
223 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
225 if (blob->length != 16 ||
226 IVAL(blob->data, 0) != 1) {
227 return NT_STATUS_ACCESS_DENIED;
233 parse the authentication information on a dcerpc response packet
235 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
236 DATA_BLOB *raw_packet,
237 struct ncacn_packet *pkt)
239 struct ndr_pull *ndr;
241 struct dcerpc_auth auth;
244 if (pkt->auth_length == 0 &&
245 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
249 auth_blob.length = 8 + pkt->auth_length;
251 /* check for a valid length */
252 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
253 return NT_STATUS_INFO_LENGTH_MISMATCH;
257 pkt->u.response.stub_and_verifier.data +
258 pkt->u.response.stub_and_verifier.length - auth_blob.length;
259 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
261 /* pull the auth structure */
262 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
264 return NT_STATUS_NO_MEMORY;
267 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
268 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
271 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
272 if (!NT_STATUS_IS_OK(status)) {
277 /* check signature or unseal the packet */
278 switch (c->security_state.auth_info->auth_level) {
279 case DCERPC_AUTH_LEVEL_PRIVACY:
280 status = gensec_unseal_packet(c->security_state.generic_state,
282 raw_packet->data + DCERPC_REQUEST_LENGTH,
283 pkt->u.response.stub_and_verifier.length,
285 raw_packet->length - auth.credentials.length,
287 memcpy(pkt->u.response.stub_and_verifier.data,
288 raw_packet->data + DCERPC_REQUEST_LENGTH,
289 pkt->u.response.stub_and_verifier.length);
292 case DCERPC_AUTH_LEVEL_INTEGRITY:
293 status = gensec_check_packet(c->security_state.generic_state,
295 pkt->u.response.stub_and_verifier.data,
296 pkt->u.response.stub_and_verifier.length,
298 raw_packet->length - auth.credentials.length,
302 case DCERPC_AUTH_LEVEL_CONNECT:
303 status = dcerpc_check_connect_verifier(&auth.credentials);
306 case DCERPC_AUTH_LEVEL_NONE:
310 status = NT_STATUS_INVALID_LEVEL;
314 /* remove the indicated amount of paddiing */
315 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
316 return NT_STATUS_INFO_LENGTH_MISMATCH;
318 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
325 push a dcerpc request packet into a blob, possibly signing it.
327 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
328 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
329 struct ncacn_packet *pkt)
332 struct ndr_push *ndr;
334 size_t payload_length;
336 /* non-signed packets are simpler */
337 if (!c->security_state.auth_info ||
338 !c->security_state.generic_state) {
339 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
342 ndr = ndr_push_init_ctx(mem_ctx);
344 return NT_STATUS_NO_MEMORY;
347 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
348 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
351 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
352 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
355 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
356 if (!NT_STATUS_IS_OK(status)) {
360 /* pad to 16 byte multiple in the payload portion of the
361 packet. This matches what w2k3 does */
362 c->security_state.auth_info->auth_pad_length =
363 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
364 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
366 payload_length = pkt->u.request.stub_and_verifier.length +
367 c->security_state.auth_info->auth_pad_length;
369 /* sign or seal the packet */
370 switch (c->security_state.auth_info->auth_level) {
371 case DCERPC_AUTH_LEVEL_PRIVACY:
372 case DCERPC_AUTH_LEVEL_INTEGRITY:
373 c->security_state.auth_info->credentials
374 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
376 data_blob_clear(&c->security_state.auth_info->credentials);
379 case DCERPC_AUTH_LEVEL_CONNECT:
380 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
383 case DCERPC_AUTH_LEVEL_NONE:
384 c->security_state.auth_info->credentials = data_blob(NULL, 0);
388 status = NT_STATUS_INVALID_LEVEL;
392 if (!NT_STATUS_IS_OK(status)) {
396 /* add the auth verifier */
397 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
398 if (!NT_STATUS_IS_OK(status)) {
402 /* extract the whole packet as a blob */
403 *blob = ndr_push_blob(ndr);
405 /* fill in the fragment length and auth_length, we can't fill
406 in these earlier as we don't know the signature length (it
407 could be variable length) */
408 dcerpc_set_frag_length(blob, blob->length);
409 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
411 /* sign or seal the packet */
412 switch (c->security_state.auth_info->auth_level) {
413 case DCERPC_AUTH_LEVEL_PRIVACY:
414 status = gensec_seal_packet(c->security_state.generic_state,
416 blob->data + DCERPC_REQUEST_LENGTH,
420 c->security_state.auth_info->credentials.length,
422 if (!NT_STATUS_IS_OK(status)) {
425 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
428 case DCERPC_AUTH_LEVEL_INTEGRITY:
429 status = gensec_sign_packet(c->security_state.generic_state,
431 blob->data + DCERPC_REQUEST_LENGTH,
435 c->security_state.auth_info->credentials.length,
437 if (!NT_STATUS_IS_OK(status)) {
440 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
443 case DCERPC_AUTH_LEVEL_CONNECT:
446 case DCERPC_AUTH_LEVEL_NONE:
447 c->security_state.auth_info->credentials = data_blob(NULL, 0);
451 status = NT_STATUS_INVALID_LEVEL;
455 data_blob_free(&c->security_state.auth_info->credentials);
462 fill in the fixed values in a dcerpc header
464 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
467 pkt->rpc_vers_minor = 0;
468 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
471 pkt->drep[0] = DCERPC_DREP_LE;
479 map a bind nak reason to a NTSTATUS
481 static NTSTATUS dcerpc_map_reason(uint16_t reason)
484 case DCERPC_BIND_REASON_ASYNTAX:
485 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
486 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
487 return NT_STATUS_INVALID_PARAMETER;
489 return NT_STATUS_UNSUCCESSFUL;
493 mark the dcerpc connection dead. All outstanding requests get an error
495 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
497 /* all pending requests get the error */
498 while (conn->pending) {
499 struct rpc_request *req = conn->pending;
500 req->state = RPC_REQUEST_DONE;
501 req->status = status;
502 DLIST_REMOVE(conn->pending, req);
503 if (req->async.callback) {
504 req->async.callback(req);
508 if (conn->bind_private) {
509 /* a bind was in flight - fail it */
510 struct composite_context *c = talloc_get_type(conn->bind_private, struct composite_context);
511 composite_error(c, status);
514 if (conn->alter_private) {
515 /* a alter context was in flight - fail it */
516 struct composite_context *c = talloc_get_type(conn->alter_private, struct composite_context);
517 composite_error(c, status);
522 forward declarations of the recv_data handlers for the 3 types of packets we need
525 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
526 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
527 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
528 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
531 receive a dcerpc reply from the transport. Here we work out what
532 type of reply it is (normal request, bind or alter context) and
533 dispatch to the appropriate handler
535 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
537 struct ncacn_packet pkt;
539 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
540 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
543 /* the transport may be telling us of a severe error, such as
545 if (!NT_STATUS_IS_OK(status)) {
546 data_blob_free(blob);
547 dcerpc_connection_dead(conn, status);
551 /* parse the basic packet to work out what type of response this is */
552 status = ncacn_pull(conn, blob, blob->data, &pkt);
553 if (!NT_STATUS_IS_OK(status)) {
554 data_blob_free(blob);
555 dcerpc_connection_dead(conn, status);
559 case DCERPC_PKT_BIND_NAK:
560 case DCERPC_PKT_BIND_ACK:
561 if (conn->bind_private) {
562 talloc_steal(conn->bind_private, blob->data);
563 dcerpc_bind_recv_data(conn, &pkt);
567 case DCERPC_PKT_ALTER_RESP:
568 if (conn->alter_private) {
569 talloc_steal(conn->alter_private, blob->data);
570 dcerpc_alter_recv_data(conn, &pkt);
575 /* assume its an ordinary request */
576 dcerpc_request_recv_data(conn, blob, &pkt);
583 Receive a bind reply from the transport
585 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
587 struct composite_context *c;
589 c = talloc_get_type(conn->bind_private, struct composite_context);
591 /* mark the connection as not waiting for a bind reply */
592 conn->bind_private = NULL;
594 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
595 DEBUG(2,("dcerpc: bind_nak reason %d\n",
596 pkt->u.bind_nak.reject_reason));
597 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
602 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
603 (pkt->u.bind_ack.num_results == 0) ||
604 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
605 composite_error(c, NT_STATUS_UNSUCCESSFUL);
609 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
610 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
612 /* the bind_ack might contain a reply set of credentials */
613 if (conn->security_state.auth_info &&
614 pkt->u.bind_ack.auth_info.length) {
615 c->status = ndr_pull_struct_blob(
616 &pkt->u.bind_ack.auth_info, conn,
617 conn->security_state.auth_info,
618 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
619 if (!composite_is_ok(c)) return;
626 handle timeouts of dcerpc bind and alter context requests
628 static void bind_timeout_handler(struct event_context *ev,
629 struct timed_event *te,
630 struct timeval t, void *private)
632 struct composite_context *ctx =
633 talloc_get_type(private, struct composite_context);
634 struct dcerpc_pipe *timeout_pipe = talloc_get_type(ctx->private_data, struct dcerpc_pipe);
636 SMB_ASSERT(timeout_pipe->conn->bind_private != NULL);
637 timeout_pipe->conn->bind_private = NULL;
638 composite_error(ctx, NT_STATUS_IO_TIMEOUT);
642 send a async dcerpc bind request
644 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
646 const struct dcerpc_syntax_id *syntax,
647 const struct dcerpc_syntax_id *transfer_syntax)
649 struct composite_context *c;
650 struct ncacn_packet pkt;
653 c = talloc_zero(mem_ctx, struct composite_context);
654 if (c == NULL) return NULL;
656 c->state = COMPOSITE_STATE_IN_PROGRESS;
658 c->event_ctx = p->conn->event_ctx;
661 p->transfer_syntax = *transfer_syntax;
663 init_ncacn_hdr(p->conn, &pkt);
665 pkt.ptype = DCERPC_PKT_BIND;
666 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
667 pkt.call_id = p->conn->call_id;
670 pkt.u.bind.max_xmit_frag = 5840;
671 pkt.u.bind.max_recv_frag = 5840;
672 pkt.u.bind.assoc_group_id = 0;
673 pkt.u.bind.num_contexts = 1;
674 pkt.u.bind.ctx_list =
675 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
676 if (pkt.u.bind.ctx_list == NULL) {
677 c->status = NT_STATUS_NO_MEMORY;
680 pkt.u.bind.ctx_list[0].context_id = p->context_id;
681 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
682 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
683 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
684 pkt.u.bind.auth_info = data_blob(NULL, 0);
686 /* construct the NDR form of the packet */
687 c->status = ncacn_push_auth(&blob, c, &pkt,
688 p->conn->security_state.auth_info);
689 if (!NT_STATUS_IS_OK(c->status)) {
693 p->conn->transport.recv_data = dcerpc_recv_data;
694 p->conn->bind_private = c;
696 c->status = p->conn->transport.send_request(p->conn, &blob,
698 if (!NT_STATUS_IS_OK(c->status)) {
702 event_add_timed(c->event_ctx, c,
703 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
704 bind_timeout_handler, c);
709 composite_error(c, c->status);
714 recv side of async dcerpc bind request
716 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
718 NTSTATUS result = composite_wait(ctx);
724 perform a bind using the given syntax
726 the auth_info structure is updated with the reply authentication info
729 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
731 const struct dcerpc_syntax_id *syntax,
732 const struct dcerpc_syntax_id *transfer_syntax)
734 struct composite_context *creq;
735 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
736 return dcerpc_bind_recv(creq);
740 perform a continued bind (and auth3)
742 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
745 struct ncacn_packet pkt;
749 init_ncacn_hdr(c, &pkt);
751 pkt.ptype = DCERPC_PKT_AUTH3;
752 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
753 pkt.call_id = next_call_id(c);
755 pkt.u.auth3._pad = 0;
756 pkt.u.auth3.auth_info = data_blob(NULL, 0);
758 /* construct the NDR form of the packet */
759 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
760 if (!NT_STATUS_IS_OK(status)) {
764 /* send it on its way */
765 status = c->transport.send_request(c, &blob, False);
766 if (!NT_STATUS_IS_OK(status)) {
775 return the rpc syntax and transfer syntax given the pipe uuid and version
777 NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
778 struct dcerpc_syntax_id *syntax,
779 struct dcerpc_syntax_id *transfer_syntax)
781 syntax->uuid = table->syntax_id.uuid;
782 syntax->if_version = table->syntax_id.if_version;
784 *transfer_syntax = ndr_transfer_syntax;
789 /* perform a dcerpc bind, using the uuid as the key */
790 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
792 const struct dcerpc_interface_table *table)
794 struct dcerpc_syntax_id syntax;
795 struct dcerpc_syntax_id transfer_syntax;
798 status = dcerpc_init_syntaxes(table,
799 &syntax, &transfer_syntax);
800 if (!NT_STATUS_IS_OK(status)) {
801 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
805 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
810 process a fragment received from the transport layer during a
813 This function frees the data
815 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
816 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
818 struct rpc_request *req;
820 NTSTATUS status = NT_STATUS_OK;
823 if this is an authenticated connection then parse and check
824 the auth info. We have to do this before finding the
825 matching packet, as the request structure might have been
826 removed due to a timeout, but if it has been we still need
827 to run the auth routines so that we don't get the sign/seal
828 info out of step with the server
830 if (c->security_state.auth_info && c->security_state.generic_state &&
831 pkt->ptype == DCERPC_PKT_RESPONSE) {
832 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
835 /* find the matching request */
836 for (req=c->pending;req;req=req->next) {
837 if (pkt->call_id == req->call_id) break;
841 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
842 data_blob_free(raw_packet);
846 talloc_steal(req, raw_packet->data);
848 if (pkt->ptype == DCERPC_PKT_FAULT) {
849 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
850 req->fault_code = pkt->u.fault.status;
851 req->status = NT_STATUS_NET_WRITE_FAULT;
855 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
856 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
858 req->fault_code = DCERPC_FAULT_OTHER;
859 req->status = NT_STATUS_NET_WRITE_FAULT;
863 /* now check the status from the auth routines, and if it failed then fail
864 this request accordingly */
865 if (!NT_STATUS_IS_OK(status)) {
866 req->status = status;
870 length = pkt->u.response.stub_and_verifier.length;
873 req->payload.data = talloc_realloc(req,
876 req->payload.length + length);
877 if (!req->payload.data) {
878 req->status = NT_STATUS_NO_MEMORY;
881 memcpy(req->payload.data+req->payload.length,
882 pkt->u.response.stub_and_verifier.data, length);
883 req->payload.length += length;
886 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
887 c->transport.send_read(c);
891 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
892 req->flags |= DCERPC_PULL_BIGENDIAN;
894 req->flags &= ~DCERPC_PULL_BIGENDIAN;
899 /* we've got the full payload */
900 req->state = RPC_REQUEST_DONE;
901 DLIST_REMOVE(c->pending, req);
903 if (c->request_queue != NULL) {
904 /* We have to look at shipping further requests before calling
905 * the async function, that one might close the pipe */
906 dcerpc_ship_next_request(c);
909 if (req->async.callback) {
910 req->async.callback(req);
915 handle timeouts of individual dcerpc requests
917 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
918 struct timeval t, void *private)
920 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
922 if (req->state != RPC_REQUEST_PENDING) {
926 req->status = NT_STATUS_IO_TIMEOUT;
927 req->state = RPC_REQUEST_DONE;
928 DLIST_REMOVE(req->p->conn->pending, req);
929 if (req->async.callback) {
930 req->async.callback(req);
936 make sure requests are cleaned up
938 static int dcerpc_req_destructor(void *ptr)
940 struct rpc_request *req = ptr;
941 DLIST_REMOVE(req->p->conn->pending, req);
946 perform the send side of a async dcerpc request
948 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
949 const struct GUID *object,
952 DATA_BLOB *stub_data)
954 struct rpc_request *req;
956 p->conn->transport.recv_data = dcerpc_recv_data;
958 req = talloc(p, struct rpc_request);
964 req->call_id = next_call_id(p->conn);
965 req->status = NT_STATUS_OK;
966 req->state = RPC_REQUEST_PENDING;
967 req->payload = data_blob(NULL, 0);
970 req->async_call = async;
971 req->async.callback = NULL;
973 if (object != NULL) {
974 req->object = talloc_memdup(req, object, sizeof(*object));
975 if (req->object == NULL) {
984 req->request_data.length = stub_data->length;
985 req->request_data.data = talloc_reference(req, stub_data->data);
986 if (req->request_data.data == NULL) {
990 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
992 dcerpc_ship_next_request(p->conn);
994 if (p->request_timeout) {
995 event_add_timed(dcerpc_event_context(p), req,
996 timeval_current_ofs(p->request_timeout, 0),
997 dcerpc_timeout_handler, req);
1000 talloc_set_destructor(req, dcerpc_req_destructor);
1005 Send a request using the transport
1008 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1010 struct rpc_request *req;
1011 struct dcerpc_pipe *p;
1012 DATA_BLOB *stub_data;
1013 struct ncacn_packet pkt;
1015 uint32_t remaining, chunk_size;
1016 BOOL first_packet = True;
1018 req = c->request_queue;
1024 stub_data = &req->request_data;
1026 if (!req->async_call && (c->pending != NULL)) {
1030 DLIST_REMOVE(c->request_queue, req);
1031 DLIST_ADD(c->pending, req);
1033 init_ncacn_hdr(p->conn, &pkt);
1035 remaining = stub_data->length;
1037 /* we can write a full max_recv_frag size, minus the dcerpc
1038 request header size */
1039 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1041 pkt.ptype = DCERPC_PKT_REQUEST;
1042 pkt.call_id = req->call_id;
1043 pkt.auth_length = 0;
1045 pkt.u.request.alloc_hint = remaining;
1046 pkt.u.request.context_id = p->context_id;
1047 pkt.u.request.opnum = req->opnum;
1050 pkt.u.request.object.object = *req->object;
1051 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1052 chunk_size -= ndr_size_GUID(req->object,0);
1055 /* we send a series of pdus without waiting for a reply */
1056 while (remaining > 0 || first_packet) {
1057 uint32_t chunk = MIN(chunk_size, remaining);
1058 BOOL last_frag = 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, &pkt);
1076 if (!NT_STATUS_IS_OK(req->status)) {
1077 req->state = RPC_REQUEST_DONE;
1078 DLIST_REMOVE(p->conn->pending, req);
1082 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1083 if (!NT_STATUS_IS_OK(req->status)) {
1084 req->state = RPC_REQUEST_DONE;
1085 DLIST_REMOVE(p->conn->pending, req);
1094 return the event context for a dcerpc pipe
1095 used by callers who wish to operate asynchronously
1097 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1099 return p->conn->event_ctx;
1105 perform the receive side of a async dcerpc request
1107 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1108 TALLOC_CTX *mem_ctx,
1109 DATA_BLOB *stub_data)
1113 while (req->state == RPC_REQUEST_PENDING) {
1114 struct event_context *ctx = dcerpc_event_context(req->p);
1115 if (event_loop_once(ctx) != 0) {
1116 return NT_STATUS_CONNECTION_DISCONNECTED;
1119 *stub_data = req->payload;
1120 status = req->status;
1121 if (stub_data->data) {
1122 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1124 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1125 req->p->last_fault_code = req->fault_code;
1132 perform a full request/response pair on a dcerpc pipe
1134 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1135 struct GUID *object,
1138 TALLOC_CTX *mem_ctx,
1139 DATA_BLOB *stub_data_in,
1140 DATA_BLOB *stub_data_out)
1142 struct rpc_request *req;
1144 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1146 return NT_STATUS_NO_MEMORY;
1149 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1154 this is a paranoid NDR validator. For every packet we push onto the wire
1155 we pull it back again, then push it again. Then we compare the raw NDR data
1156 for that to the NDR we initially generated. If they don't match then we know
1157 we must have a bug in either the pull or push side of our code
1159 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1160 TALLOC_CTX *mem_ctx,
1163 ndr_push_flags_fn_t ndr_push,
1164 ndr_pull_flags_fn_t ndr_pull)
1167 struct ndr_pull *pull;
1168 struct ndr_push *push;
1172 st = talloc_size(mem_ctx, struct_size);
1174 return NT_STATUS_NO_MEMORY;
1177 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1179 return NT_STATUS_NO_MEMORY;
1181 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1183 status = ndr_pull(pull, NDR_IN, st);
1184 if (!NT_STATUS_IS_OK(status)) {
1185 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1186 "failed input validation pull - %s",
1190 push = ndr_push_init_ctx(mem_ctx);
1192 return NT_STATUS_NO_MEMORY;
1195 status = ndr_push(push, NDR_IN, st);
1196 if (!NT_STATUS_IS_OK(status)) {
1197 return ndr_push_error(push, NDR_ERR_VALIDATE,
1198 "failed input validation push - %s",
1202 blob2 = ndr_push_blob(push);
1204 if (!data_blob_equal(&blob, &blob2)) {
1205 DEBUG(3,("original:\n"));
1206 dump_data(3, blob.data, blob.length);
1207 DEBUG(3,("secondary:\n"));
1208 dump_data(3, blob2.data, blob2.length);
1209 return ndr_push_error(push, NDR_ERR_VALIDATE,
1210 "failed input validation data - %s",
1214 return NT_STATUS_OK;
1218 this is a paranoid NDR input validator. For every packet we pull
1219 from the wire we push it back again then pull and push it
1220 again. Then we compare the raw NDR data for that to the NDR we
1221 initially generated. If they don't match then we know we must have a
1222 bug in either the pull or push side of our code
1224 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1225 struct ndr_pull *pull_in,
1228 ndr_push_flags_fn_t ndr_push,
1229 ndr_pull_flags_fn_t ndr_pull,
1230 ndr_print_function_t ndr_print)
1233 struct ndr_pull *pull;
1234 struct ndr_push *push;
1236 DATA_BLOB blob, blob2;
1237 TALLOC_CTX *mem_ctx = pull_in;
1240 st = talloc_size(mem_ctx, struct_size);
1242 return NT_STATUS_NO_MEMORY;
1244 memcpy(st, struct_ptr, struct_size);
1246 push = ndr_push_init_ctx(mem_ctx);
1248 return NT_STATUS_NO_MEMORY;
1251 status = ndr_push(push, NDR_OUT, struct_ptr);
1252 if (!NT_STATUS_IS_OK(status)) {
1253 return ndr_push_error(push, NDR_ERR_VALIDATE,
1254 "failed output validation push - %s",
1258 blob = ndr_push_blob(push);
1260 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1262 return NT_STATUS_NO_MEMORY;
1265 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1266 status = ndr_pull(pull, NDR_OUT, st);
1267 if (!NT_STATUS_IS_OK(status)) {
1268 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1269 "failed output validation pull - %s",
1273 push = ndr_push_init_ctx(mem_ctx);
1275 return NT_STATUS_NO_MEMORY;
1278 status = ndr_push(push, NDR_OUT, st);
1279 if (!NT_STATUS_IS_OK(status)) {
1280 return ndr_push_error(push, NDR_ERR_VALIDATE,
1281 "failed output validation push2 - %s",
1285 blob2 = ndr_push_blob(push);
1287 if (!data_blob_equal(&blob, &blob2)) {
1288 DEBUG(3,("original:\n"));
1289 dump_data(3, blob.data, blob.length);
1290 DEBUG(3,("secondary:\n"));
1291 dump_data(3, blob2.data, blob2.length);
1292 return ndr_push_error(push, NDR_ERR_VALIDATE,
1293 "failed output validation data - %s",
1297 /* this checks the printed forms of the two structures, which effectively
1298 tests all of the value() attributes */
1299 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1300 NDR_OUT, struct_ptr);
1301 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1303 if (strcmp(s1, s2) != 0) {
1304 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1307 return NT_STATUS_OK;
1312 send a rpc request given a dcerpc_call structure
1314 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1315 const struct GUID *object,
1316 const struct dcerpc_interface_table *table,
1318 TALLOC_CTX *mem_ctx,
1321 const struct dcerpc_interface_call *call;
1322 struct ndr_push *push;
1325 struct rpc_request *req;
1327 call = &table->calls[opnum];
1329 /* setup for a ndr_push_* call */
1330 push = ndr_push_init_ctx(mem_ctx);
1335 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1336 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1339 /* push the structure into a blob */
1340 status = call->ndr_push(push, NDR_IN, r);
1341 if (!NT_STATUS_IS_OK(status)) {
1342 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1343 nt_errstr(status)));
1348 /* retrieve the blob */
1349 request = ndr_push_blob(push);
1351 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1352 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1353 call->ndr_push, call->ndr_pull);
1354 if (!NT_STATUS_IS_OK(status)) {
1355 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1356 nt_errstr(status)));
1362 DEBUG(10,("rpc request data:\n"));
1363 dump_data(10, request.data, request.length);
1365 /* make the actual dcerpc request */
1366 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1370 req->ndr.table = table;
1371 req->ndr.opnum = opnum;
1372 req->ndr.struct_ptr = r;
1373 req->ndr.mem_ctx = mem_ctx;
1382 receive the answer from a dcerpc_ndr_request_send()
1384 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1386 struct dcerpc_pipe *p = req->p;
1389 struct ndr_pull *pull;
1391 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1392 void *r = req->ndr.struct_ptr;
1393 uint32_t opnum = req->ndr.opnum;
1394 const struct dcerpc_interface_table *table = req->ndr.table;
1395 const struct dcerpc_interface_call *call = &table->calls[opnum];
1397 /* make sure the recv code doesn't free the request, as we
1398 need to grab the flags element before it is freed */
1399 talloc_increase_ref_count(req);
1401 status = dcerpc_request_recv(req, mem_ctx, &response);
1402 if (!NT_STATUS_IS_OK(status)) {
1408 /* prepare for ndr_pull_* */
1409 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1412 return NT_STATUS_NO_MEMORY;
1416 pull->data = talloc_steal(pull, pull->data);
1420 if (flags & DCERPC_PULL_BIGENDIAN) {
1421 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1424 DEBUG(10,("rpc reply data:\n"));
1425 dump_data(10, pull->data, pull->data_size);
1427 /* pull the structure from the blob */
1428 status = call->ndr_pull(pull, NDR_OUT, r);
1429 if (!NT_STATUS_IS_OK(status)) {
1430 dcerpc_log_packet(table, opnum, NDR_OUT,
1435 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1436 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1437 call->ndr_push, call->ndr_pull,
1439 if (!NT_STATUS_IS_OK(status)) {
1440 dcerpc_log_packet(table, opnum, NDR_OUT,
1446 if (pull->offset != pull->data_size) {
1447 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1448 pull->data_size - pull->offset));
1449 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1450 but it turns out that early versions of NT
1451 (specifically NT3.1) add junk onto the end of rpc
1452 packets, so if we want to interoperate at all with
1453 those versions then we need to ignore this error */
1456 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1458 return NT_STATUS_OK;
1463 a useful helper function for synchronous rpc requests
1465 this can be used when you have ndr push/pull functions in the
1468 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1469 const struct GUID *object,
1470 const struct dcerpc_interface_table *table,
1472 TALLOC_CTX *mem_ctx,
1475 struct rpc_request *req;
1477 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1479 return NT_STATUS_NO_MEMORY;
1482 return dcerpc_ndr_request_recv(req);
1487 a useful function for retrieving the server name we connected to
1489 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1491 if (!p->conn->transport.peer_name) {
1494 return p->conn->transport.peer_name(p->conn);
1499 get the dcerpc auth_level for a open connection
1501 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1505 if (c->flags & DCERPC_SEAL) {
1506 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1507 } else if (c->flags & DCERPC_SIGN) {
1508 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1509 } else if (c->flags & DCERPC_CONNECT) {
1510 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1512 auth_level = DCERPC_AUTH_LEVEL_NONE;
1518 Receive an alter reply from the transport
1520 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
1522 struct composite_context *c;
1523 struct dcerpc_pipe *recv_pipe;
1525 c = talloc_get_type(conn->alter_private, struct composite_context);
1526 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1528 /* mark the connection as not waiting for a alter context reply */
1529 conn->alter_private = NULL;
1531 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1532 pkt->u.alter_resp.num_results == 1 &&
1533 pkt->u.alter_resp.ctx_list[0].result != 0) {
1534 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1535 pkt->u.alter_resp.ctx_list[0].reason));
1536 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1540 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1541 pkt->u.alter_resp.num_results == 0 ||
1542 pkt->u.alter_resp.ctx_list[0].result != 0) {
1543 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1547 /* the alter_resp might contain a reply set of credentials */
1548 if (recv_pipe->conn->security_state.auth_info &&
1549 pkt->u.alter_resp.auth_info.length) {
1550 c->status = ndr_pull_struct_blob(
1551 &pkt->u.alter_resp.auth_info, recv_pipe,
1552 recv_pipe->conn->security_state.auth_info,
1553 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1554 if (!composite_is_ok(c)) return;
1561 send a dcerpc alter_context request
1563 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1564 TALLOC_CTX *mem_ctx,
1565 const struct dcerpc_syntax_id *syntax,
1566 const struct dcerpc_syntax_id *transfer_syntax)
1568 struct composite_context *c;
1569 struct ncacn_packet pkt;
1572 c = talloc_zero(mem_ctx, struct composite_context);
1573 if (c == NULL) return NULL;
1575 c->state = COMPOSITE_STATE_IN_PROGRESS;
1576 c->private_data = p;
1577 c->event_ctx = p->conn->event_ctx;
1579 p->syntax = *syntax;
1580 p->transfer_syntax = *transfer_syntax;
1582 init_ncacn_hdr(p->conn, &pkt);
1584 pkt.ptype = DCERPC_PKT_ALTER;
1585 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1586 pkt.call_id = p->conn->call_id;
1587 pkt.auth_length = 0;
1589 pkt.u.alter.max_xmit_frag = 5840;
1590 pkt.u.alter.max_recv_frag = 5840;
1591 pkt.u.alter.assoc_group_id = 0;
1592 pkt.u.alter.num_contexts = 1;
1593 pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1594 struct dcerpc_ctx_list, 1);
1595 if (pkt.u.alter.ctx_list == NULL) {
1596 c->status = NT_STATUS_NO_MEMORY;
1599 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1600 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1601 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1602 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1603 pkt.u.alter.auth_info = data_blob(NULL, 0);
1605 /* construct the NDR form of the packet */
1606 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1607 p->conn->security_state.auth_info);
1608 if (!NT_STATUS_IS_OK(c->status)) {
1612 p->conn->transport.recv_data = dcerpc_recv_data;
1613 p->conn->alter_private = c;
1615 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1616 if (!NT_STATUS_IS_OK(c->status)) {
1620 event_add_timed(c->event_ctx, c,
1621 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1622 bind_timeout_handler, c);
1627 composite_error(c, c->status);
1631 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1633 NTSTATUS result = composite_wait(ctx);
1639 send a dcerpc alter_context request
1641 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1642 TALLOC_CTX *mem_ctx,
1643 const struct dcerpc_syntax_id *syntax,
1644 const struct dcerpc_syntax_id *transfer_syntax)
1646 struct composite_context *creq;
1647 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1648 return dcerpc_alter_context_recv(creq);