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 c->security_state.auth_info = NULL;
77 c->security_state.session_key = dcerpc_generic_session_key;
78 c->security_state.generic_state = NULL;
79 c->binding_string = NULL;
81 c->srv_max_xmit_frag = 0;
82 c->srv_max_recv_frag = 0;
85 talloc_set_destructor(c, dcerpc_connection_destructor);
90 /* initialise a dcerpc pipe. */
91 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
93 struct dcerpc_pipe *p;
95 p = talloc(mem_ctx, struct dcerpc_pipe);
100 p->conn = dcerpc_connection_init(p, ev);
101 if (p->conn == NULL) {
106 p->last_fault_code = 0;
108 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
110 ZERO_STRUCT(p->syntax);
111 ZERO_STRUCT(p->transfer_syntax);
118 choose the next call id to use
120 static uint32_t next_call_id(struct dcerpc_connection *c)
123 if (c->call_id == 0) {
129 /* we need to be able to get/set the fragment length without doing a full
131 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
133 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
134 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
136 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
140 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
142 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
143 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
145 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
149 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
151 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
152 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
154 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
160 setup for a ndr pull, also setting up any flags from the binding string
162 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
163 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
165 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
167 if (ndr == NULL) return ndr;
169 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
170 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
173 if (c->flags & DCERPC_NDR_REF_ALLOC) {
174 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
181 parse a data blob into a ncacn_packet structure. This handles both
182 input and output packets
184 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
185 struct ncacn_packet *pkt)
187 struct ndr_pull *ndr;
189 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
191 return NT_STATUS_NO_MEMORY;
194 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
195 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
198 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
202 generate a CONNECT level verifier
204 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
206 *blob = data_blob_talloc(mem_ctx, NULL, 16);
207 if (blob->data == NULL) {
208 return NT_STATUS_NO_MEMORY;
210 SIVAL(blob->data, 0, 1);
211 memset(blob->data+4, 0, 12);
216 check a CONNECT level verifier
218 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
220 if (blob->length != 16 ||
221 IVAL(blob->data, 0) != 1) {
222 return NT_STATUS_ACCESS_DENIED;
228 parse the authentication information on a dcerpc response packet
230 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
231 DATA_BLOB *raw_packet,
232 struct ncacn_packet *pkt)
234 struct ndr_pull *ndr;
236 struct dcerpc_auth auth;
239 if (pkt->auth_length == 0 &&
240 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
244 auth_blob.length = 8 + pkt->auth_length;
246 /* check for a valid length */
247 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
248 return NT_STATUS_INFO_LENGTH_MISMATCH;
252 pkt->u.response.stub_and_verifier.data +
253 pkt->u.response.stub_and_verifier.length - auth_blob.length;
254 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
256 /* pull the auth structure */
257 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
259 return NT_STATUS_NO_MEMORY;
262 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
263 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
266 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
267 if (!NT_STATUS_IS_OK(status)) {
272 /* check signature or unseal the packet */
273 switch (c->security_state.auth_info->auth_level) {
274 case DCERPC_AUTH_LEVEL_PRIVACY:
275 status = gensec_unseal_packet(c->security_state.generic_state,
277 raw_packet->data + DCERPC_REQUEST_LENGTH,
278 pkt->u.response.stub_and_verifier.length,
280 raw_packet->length - auth.credentials.length,
282 memcpy(pkt->u.response.stub_and_verifier.data,
283 raw_packet->data + DCERPC_REQUEST_LENGTH,
284 pkt->u.response.stub_and_verifier.length);
287 case DCERPC_AUTH_LEVEL_INTEGRITY:
288 status = gensec_check_packet(c->security_state.generic_state,
290 pkt->u.response.stub_and_verifier.data,
291 pkt->u.response.stub_and_verifier.length,
293 raw_packet->length - auth.credentials.length,
297 case DCERPC_AUTH_LEVEL_CONNECT:
298 status = dcerpc_check_connect_verifier(&auth.credentials);
301 case DCERPC_AUTH_LEVEL_NONE:
305 status = NT_STATUS_INVALID_LEVEL;
309 /* remove the indicated amount of paddiing */
310 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
311 return NT_STATUS_INFO_LENGTH_MISMATCH;
313 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
320 push a dcerpc request packet into a blob, possibly signing it.
322 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
323 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
324 struct ncacn_packet *pkt)
327 struct ndr_push *ndr;
329 size_t payload_length;
331 /* non-signed packets are simpler */
332 if (!c->security_state.auth_info ||
333 !c->security_state.generic_state) {
334 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
337 ndr = ndr_push_init_ctx(mem_ctx);
339 return NT_STATUS_NO_MEMORY;
342 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
343 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
346 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
347 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
350 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
351 if (!NT_STATUS_IS_OK(status)) {
355 /* pad to 16 byte multiple in the payload portion of the
356 packet. This matches what w2k3 does */
357 c->security_state.auth_info->auth_pad_length =
358 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
359 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
361 payload_length = pkt->u.request.stub_and_verifier.length +
362 c->security_state.auth_info->auth_pad_length;
364 /* sign or seal the packet */
365 switch (c->security_state.auth_info->auth_level) {
366 case DCERPC_AUTH_LEVEL_PRIVACY:
367 case DCERPC_AUTH_LEVEL_INTEGRITY:
368 c->security_state.auth_info->credentials
369 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
371 data_blob_clear(&c->security_state.auth_info->credentials);
374 case DCERPC_AUTH_LEVEL_CONNECT:
375 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
378 case DCERPC_AUTH_LEVEL_NONE:
379 c->security_state.auth_info->credentials = data_blob(NULL, 0);
383 status = NT_STATUS_INVALID_LEVEL;
387 if (!NT_STATUS_IS_OK(status)) {
391 /* add the auth verifier */
392 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
393 if (!NT_STATUS_IS_OK(status)) {
397 /* extract the whole packet as a blob */
398 *blob = ndr_push_blob(ndr);
400 /* fill in the fragment length and auth_length, we can't fill
401 in these earlier as we don't know the signature length (it
402 could be variable length) */
403 dcerpc_set_frag_length(blob, blob->length);
404 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
406 /* sign or seal the packet */
407 switch (c->security_state.auth_info->auth_level) {
408 case DCERPC_AUTH_LEVEL_PRIVACY:
409 status = gensec_seal_packet(c->security_state.generic_state,
411 blob->data + DCERPC_REQUEST_LENGTH,
415 c->security_state.auth_info->credentials.length,
417 if (!NT_STATUS_IS_OK(status)) {
420 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
423 case DCERPC_AUTH_LEVEL_INTEGRITY:
424 status = gensec_sign_packet(c->security_state.generic_state,
426 blob->data + DCERPC_REQUEST_LENGTH,
430 c->security_state.auth_info->credentials.length,
432 if (!NT_STATUS_IS_OK(status)) {
435 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
438 case DCERPC_AUTH_LEVEL_CONNECT:
441 case DCERPC_AUTH_LEVEL_NONE:
442 c->security_state.auth_info->credentials = data_blob(NULL, 0);
446 status = NT_STATUS_INVALID_LEVEL;
450 data_blob_free(&c->security_state.auth_info->credentials);
457 fill in the fixed values in a dcerpc header
459 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
462 pkt->rpc_vers_minor = 0;
463 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
466 pkt->drep[0] = DCERPC_DREP_LE;
474 map a bind nak reason to a NTSTATUS
476 static NTSTATUS dcerpc_map_reason(uint16_t reason)
479 case DCERPC_BIND_REASON_ASYNTAX:
480 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
482 return NT_STATUS_UNSUCCESSFUL;
486 mark the dcerpc connection dead. All outstanding requests get an error
488 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
490 /* all pending requests get the error */
491 while (conn->pending) {
492 struct rpc_request *req = conn->pending;
493 req->state = RPC_REQUEST_DONE;
494 req->status = status;
495 DLIST_REMOVE(conn->pending, req);
496 if (req->async.callback) {
497 req->async.callback(req);
501 if (conn->bind_private) {
502 /* a bind was in flight - fail it */
503 struct composite_context *c = talloc_get_type(conn->bind_private, struct composite_context);
504 composite_error(c, status);
507 if (conn->alter_private) {
508 /* a alter context was in flight - fail it */
509 struct composite_context *c = talloc_get_type(conn->alter_private, struct composite_context);
510 composite_error(c, status);
515 forward declarations of the recv_data handlers for the 3 types of packets we need
518 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
519 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
520 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
521 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
524 receive a dcerpc reply from the transport. Here we work out what
525 type of reply it is (normal request, bind or alter context) and
526 dispatch to the appropriate handler
528 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
530 struct ncacn_packet pkt;
532 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
533 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
536 /* the transport may be telling us of a severe error, such as
538 if (!NT_STATUS_IS_OK(status)) {
539 data_blob_free(blob);
540 dcerpc_connection_dead(conn, status);
544 /* parse the basic packet to work out what type of response this is */
545 status = ncacn_pull(conn, blob, blob->data, &pkt);
546 if (!NT_STATUS_IS_OK(status)) {
547 data_blob_free(blob);
548 dcerpc_connection_dead(conn, status);
552 case DCERPC_PKT_BIND_NAK:
553 case DCERPC_PKT_BIND_ACK:
554 if (conn->bind_private) {
555 talloc_steal(conn->bind_private, blob->data);
556 dcerpc_bind_recv_data(conn, &pkt);
560 case DCERPC_PKT_ALTER_RESP:
561 if (conn->alter_private) {
562 talloc_steal(conn->alter_private, blob->data);
563 dcerpc_alter_recv_data(conn, &pkt);
568 /* assume its an ordinary request */
569 dcerpc_request_recv_data(conn, blob, &pkt);
576 Receive a bind reply from the transport
578 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
580 struct composite_context *c;
581 struct dcerpc_pipe *pipe;
583 c = talloc_get_type(conn->bind_private, struct composite_context);
584 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
586 /* mark the connection as not waiting for a bind reply */
587 conn->bind_private = NULL;
589 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
590 DEBUG(2,("dcerpc: bind_nak reason %d\n",
591 pkt->u.bind_nak.reject_reason));
592 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
597 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
598 (pkt->u.bind_ack.num_results == 0) ||
599 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
600 composite_error(c, NT_STATUS_UNSUCCESSFUL);
604 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
605 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
607 /* the bind_ack might contain a reply set of credentials */
608 if (conn->security_state.auth_info &&
609 pkt->u.bind_ack.auth_info.length) {
610 c->status = ndr_pull_struct_blob(
611 &pkt->u.bind_ack.auth_info, conn,
612 conn->security_state.auth_info,
613 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
614 if (!composite_is_ok(c)) return;
621 handle timeouts of dcerpc bind and alter context requests
623 static void bind_timeout_handler(struct event_context *ev,
624 struct timed_event *te,
625 struct timeval t, void *private)
627 struct composite_context *ctx =
628 talloc_get_type(private, struct composite_context);
629 struct dcerpc_pipe *pipe = talloc_get_type(ctx->private_data, struct dcerpc_pipe);
631 SMB_ASSERT(pipe->conn->bind_private != NULL);
632 pipe->conn->bind_private = NULL;
633 composite_error(ctx, NT_STATUS_IO_TIMEOUT);
637 send a async dcerpc bind request
639 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
641 const struct dcerpc_syntax_id *syntax,
642 const struct dcerpc_syntax_id *transfer_syntax)
644 struct composite_context *c;
645 struct ncacn_packet pkt;
648 c = talloc_zero(mem_ctx, struct composite_context);
649 if (c == NULL) return NULL;
651 c->state = COMPOSITE_STATE_IN_PROGRESS;
653 c->event_ctx = p->conn->event_ctx;
656 p->transfer_syntax = *transfer_syntax;
658 init_ncacn_hdr(p->conn, &pkt);
660 pkt.ptype = DCERPC_PKT_BIND;
661 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
662 pkt.call_id = p->conn->call_id;
665 pkt.u.bind.max_xmit_frag = 5840;
666 pkt.u.bind.max_recv_frag = 5840;
667 pkt.u.bind.assoc_group_id = 0;
668 pkt.u.bind.num_contexts = 1;
669 pkt.u.bind.ctx_list =
670 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
671 if (pkt.u.bind.ctx_list == NULL) {
672 c->status = NT_STATUS_NO_MEMORY;
675 pkt.u.bind.ctx_list[0].context_id = p->context_id;
676 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
677 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
678 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
679 pkt.u.bind.auth_info = data_blob(NULL, 0);
681 /* construct the NDR form of the packet */
682 c->status = ncacn_push_auth(&blob, c, &pkt,
683 p->conn->security_state.auth_info);
684 if (!NT_STATUS_IS_OK(c->status)) {
688 p->conn->transport.recv_data = dcerpc_recv_data;
689 p->conn->bind_private = c;
691 c->status = p->conn->transport.send_request(p->conn, &blob,
693 if (!NT_STATUS_IS_OK(c->status)) {
697 event_add_timed(c->event_ctx, c,
698 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
699 bind_timeout_handler, c);
704 composite_error(c, c->status);
709 recv side of async dcerpc bind request
711 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
713 NTSTATUS result = composite_wait(ctx);
719 perform a bind using the given syntax
721 the auth_info structure is updated with the reply authentication info
724 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
726 const struct dcerpc_syntax_id *syntax,
727 const struct dcerpc_syntax_id *transfer_syntax)
729 struct composite_context *creq;
730 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
731 return dcerpc_bind_recv(creq);
735 perform a continued bind (and auth3)
737 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
740 struct ncacn_packet pkt;
744 init_ncacn_hdr(c, &pkt);
746 pkt.ptype = DCERPC_PKT_AUTH3;
747 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
748 pkt.call_id = next_call_id(c);
750 pkt.u.auth3._pad = 0;
751 pkt.u.auth3.auth_info = data_blob(NULL, 0);
753 /* construct the NDR form of the packet */
754 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
755 if (!NT_STATUS_IS_OK(status)) {
759 /* send it on its way */
760 status = c->transport.send_request(c, &blob, False);
761 if (!NT_STATUS_IS_OK(status)) {
770 return the rpc syntax and transfer syntax given the pipe uuid and version
772 NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
773 struct dcerpc_syntax_id *syntax,
774 struct dcerpc_syntax_id *transfer_syntax)
776 syntax->uuid = table->uuid;
777 syntax->if_version = table->if_version;
779 *transfer_syntax = ndr_transfer_syntax;
784 /* perform a dcerpc bind, using the uuid as the key */
785 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
787 const struct dcerpc_interface_table *table)
789 struct dcerpc_syntax_id syntax;
790 struct dcerpc_syntax_id transfer_syntax;
793 status = dcerpc_init_syntaxes(table,
794 &syntax, &transfer_syntax);
795 if (!NT_STATUS_IS_OK(status)) {
796 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
800 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
805 process a fragment received from the transport layer during a
808 This function frees the data
810 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
811 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
813 struct rpc_request *req;
815 NTSTATUS status = NT_STATUS_OK;
818 if this is an authenticated connection then parse and check
819 the auth info. We have to do this before finding the
820 matching packet, as the request structure might have been
821 removed due to a timeout, but if it has been we still need
822 to run the auth routines so that we don't get the sign/seal
823 info out of step with the server
825 if (c->security_state.auth_info && c->security_state.generic_state &&
826 pkt->ptype == DCERPC_PKT_RESPONSE) {
827 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
830 /* find the matching request */
831 for (req=c->pending;req;req=req->next) {
832 if (pkt->call_id == req->call_id) break;
836 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
837 data_blob_free(raw_packet);
841 talloc_steal(req, raw_packet->data);
843 if (pkt->ptype == DCERPC_PKT_FAULT) {
844 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
845 req->fault_code = pkt->u.fault.status;
846 req->status = NT_STATUS_NET_WRITE_FAULT;
850 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
851 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
853 req->fault_code = DCERPC_FAULT_OTHER;
854 req->status = NT_STATUS_NET_WRITE_FAULT;
858 /* now check the status from the auth routines, and if it failed then fail
859 this request accordingly */
860 if (!NT_STATUS_IS_OK(status)) {
861 req->status = status;
865 length = pkt->u.response.stub_and_verifier.length;
868 req->payload.data = talloc_realloc(req,
871 req->payload.length + length);
872 if (!req->payload.data) {
873 req->status = NT_STATUS_NO_MEMORY;
876 memcpy(req->payload.data+req->payload.length,
877 pkt->u.response.stub_and_verifier.data, length);
878 req->payload.length += length;
881 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
882 c->transport.send_read(c);
886 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
887 req->flags |= DCERPC_PULL_BIGENDIAN;
889 req->flags &= ~DCERPC_PULL_BIGENDIAN;
894 /* we've got the full payload */
895 req->state = RPC_REQUEST_DONE;
896 DLIST_REMOVE(c->pending, req);
898 if (c->request_queue != NULL) {
899 /* We have to look at shipping further requests before calling
900 * the async function, that one might close the pipe */
901 dcerpc_ship_next_request(c);
904 if (req->async.callback) {
905 req->async.callback(req);
910 handle timeouts of individual dcerpc requests
912 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
913 struct timeval t, void *private)
915 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
917 if (req->state != RPC_REQUEST_PENDING) {
921 req->status = NT_STATUS_IO_TIMEOUT;
922 req->state = RPC_REQUEST_DONE;
923 DLIST_REMOVE(req->p->conn->pending, req);
924 if (req->async.callback) {
925 req->async.callback(req);
931 make sure requests are cleaned up
933 static int dcerpc_req_destructor(void *ptr)
935 struct rpc_request *req = ptr;
936 DLIST_REMOVE(req->p->conn->pending, req);
941 perform the send side of a async dcerpc request
943 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
944 const struct GUID *object,
947 DATA_BLOB *stub_data)
949 struct rpc_request *req;
951 p->conn->transport.recv_data = dcerpc_recv_data;
953 req = talloc(p, struct rpc_request);
959 req->call_id = next_call_id(p->conn);
960 req->status = NT_STATUS_OK;
961 req->state = RPC_REQUEST_PENDING;
962 req->payload = data_blob(NULL, 0);
965 req->async_call = async;
966 req->async.callback = NULL;
968 if (object != NULL) {
969 req->object = talloc_memdup(req, object, sizeof(*object));
970 if (req->object == NULL) {
979 req->request_data.length = stub_data->length;
980 req->request_data.data = talloc_reference(req, stub_data->data);
981 if (req->request_data.data == NULL) {
985 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
987 dcerpc_ship_next_request(p->conn);
989 if (p->request_timeout) {
990 event_add_timed(dcerpc_event_context(p), req,
991 timeval_current_ofs(p->request_timeout, 0),
992 dcerpc_timeout_handler, req);
995 talloc_set_destructor(req, dcerpc_req_destructor);
1000 Send a request using the transport
1003 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1005 struct rpc_request *req;
1006 struct dcerpc_pipe *p;
1007 DATA_BLOB *stub_data;
1008 struct ncacn_packet pkt;
1010 uint32_t remaining, chunk_size;
1011 BOOL first_packet = True;
1013 req = c->request_queue;
1019 stub_data = &req->request_data;
1021 if (!req->async_call && (c->pending != NULL)) {
1025 DLIST_REMOVE(c->request_queue, req);
1026 DLIST_ADD(c->pending, req);
1028 init_ncacn_hdr(p->conn, &pkt);
1030 remaining = stub_data->length;
1032 /* we can write a full max_recv_frag size, minus the dcerpc
1033 request header size */
1034 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1036 pkt.ptype = DCERPC_PKT_REQUEST;
1037 pkt.call_id = req->call_id;
1038 pkt.auth_length = 0;
1040 pkt.u.request.alloc_hint = remaining;
1041 pkt.u.request.context_id = p->context_id;
1042 pkt.u.request.opnum = req->opnum;
1045 pkt.u.request.object.object = *req->object;
1046 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1047 chunk_size -= ndr_size_GUID(req->object,0);
1050 /* we send a series of pdus without waiting for a reply */
1051 while (remaining > 0 || first_packet) {
1052 uint32_t chunk = MIN(chunk_size, remaining);
1053 BOOL last_frag = False;
1055 first_packet = False;
1056 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1058 if (remaining == stub_data->length) {
1059 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1061 if (chunk == remaining) {
1062 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1066 pkt.u.request.stub_and_verifier.data = stub_data->data +
1067 (stub_data->length - remaining);
1068 pkt.u.request.stub_and_verifier.length = chunk;
1070 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1071 if (!NT_STATUS_IS_OK(req->status)) {
1072 req->state = RPC_REQUEST_DONE;
1073 DLIST_REMOVE(p->conn->pending, req);
1077 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1078 if (!NT_STATUS_IS_OK(req->status)) {
1079 req->state = RPC_REQUEST_DONE;
1080 DLIST_REMOVE(p->conn->pending, req);
1089 return the event context for a dcerpc pipe
1090 used by callers who wish to operate asynchronously
1092 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1094 return p->conn->event_ctx;
1100 perform the receive side of a async dcerpc request
1102 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1103 TALLOC_CTX *mem_ctx,
1104 DATA_BLOB *stub_data)
1108 while (req->state == RPC_REQUEST_PENDING) {
1109 struct event_context *ctx = dcerpc_event_context(req->p);
1110 if (event_loop_once(ctx) != 0) {
1111 return NT_STATUS_CONNECTION_DISCONNECTED;
1114 *stub_data = req->payload;
1115 status = req->status;
1116 if (stub_data->data) {
1117 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1119 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1120 req->p->last_fault_code = req->fault_code;
1127 perform a full request/response pair on a dcerpc pipe
1129 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1130 struct GUID *object,
1133 TALLOC_CTX *mem_ctx,
1134 DATA_BLOB *stub_data_in,
1135 DATA_BLOB *stub_data_out)
1137 struct rpc_request *req;
1139 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1141 return NT_STATUS_NO_MEMORY;
1144 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1149 this is a paranoid NDR validator. For every packet we push onto the wire
1150 we pull it back again, then push it again. Then we compare the raw NDR data
1151 for that to the NDR we initially generated. If they don't match then we know
1152 we must have a bug in either the pull or push side of our code
1154 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1155 TALLOC_CTX *mem_ctx,
1158 ndr_push_flags_fn_t ndr_push,
1159 ndr_pull_flags_fn_t ndr_pull)
1162 struct ndr_pull *pull;
1163 struct ndr_push *push;
1167 st = talloc_size(mem_ctx, struct_size);
1169 return NT_STATUS_NO_MEMORY;
1172 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1174 return NT_STATUS_NO_MEMORY;
1176 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1178 status = ndr_pull(pull, NDR_IN, st);
1179 if (!NT_STATUS_IS_OK(status)) {
1180 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1181 "failed input validation pull - %s",
1185 push = ndr_push_init_ctx(mem_ctx);
1187 return NT_STATUS_NO_MEMORY;
1190 status = ndr_push(push, NDR_IN, st);
1191 if (!NT_STATUS_IS_OK(status)) {
1192 return ndr_push_error(push, NDR_ERR_VALIDATE,
1193 "failed input validation push - %s",
1197 blob2 = ndr_push_blob(push);
1199 if (!data_blob_equal(&blob, &blob2)) {
1200 DEBUG(3,("original:\n"));
1201 dump_data(3, blob.data, blob.length);
1202 DEBUG(3,("secondary:\n"));
1203 dump_data(3, blob2.data, blob2.length);
1204 return ndr_push_error(push, NDR_ERR_VALIDATE,
1205 "failed input validation data - %s",
1209 return NT_STATUS_OK;
1213 this is a paranoid NDR input validator. For every packet we pull
1214 from the wire we push it back again then pull and push it
1215 again. Then we compare the raw NDR data for that to the NDR we
1216 initially generated. If they don't match then we know we must have a
1217 bug in either the pull or push side of our code
1219 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1220 struct ndr_pull *pull_in,
1223 ndr_push_flags_fn_t ndr_push,
1224 ndr_pull_flags_fn_t ndr_pull,
1225 ndr_print_function_t ndr_print)
1228 struct ndr_pull *pull;
1229 struct ndr_push *push;
1231 DATA_BLOB blob, blob2;
1232 TALLOC_CTX *mem_ctx = pull_in;
1235 st = talloc_size(mem_ctx, struct_size);
1237 return NT_STATUS_NO_MEMORY;
1239 memcpy(st, struct_ptr, struct_size);
1241 push = ndr_push_init_ctx(mem_ctx);
1243 return NT_STATUS_NO_MEMORY;
1246 status = ndr_push(push, NDR_OUT, struct_ptr);
1247 if (!NT_STATUS_IS_OK(status)) {
1248 return ndr_push_error(push, NDR_ERR_VALIDATE,
1249 "failed output validation push - %s",
1253 blob = ndr_push_blob(push);
1255 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1257 return NT_STATUS_NO_MEMORY;
1260 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1261 status = ndr_pull(pull, NDR_OUT, st);
1262 if (!NT_STATUS_IS_OK(status)) {
1263 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1264 "failed output validation pull - %s",
1268 push = ndr_push_init_ctx(mem_ctx);
1270 return NT_STATUS_NO_MEMORY;
1273 status = ndr_push(push, NDR_OUT, st);
1274 if (!NT_STATUS_IS_OK(status)) {
1275 return ndr_push_error(push, NDR_ERR_VALIDATE,
1276 "failed output validation push2 - %s",
1280 blob2 = ndr_push_blob(push);
1282 if (!data_blob_equal(&blob, &blob2)) {
1283 DEBUG(3,("original:\n"));
1284 dump_data(3, blob.data, blob.length);
1285 DEBUG(3,("secondary:\n"));
1286 dump_data(3, blob2.data, blob2.length);
1287 return ndr_push_error(push, NDR_ERR_VALIDATE,
1288 "failed output validation data - %s",
1292 /* this checks the printed forms of the two structures, which effectively
1293 tests all of the value() attributes */
1294 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1295 NDR_OUT, struct_ptr);
1296 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1298 if (strcmp(s1, s2) != 0) {
1299 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1302 return NT_STATUS_OK;
1307 send a rpc request given a dcerpc_call structure
1309 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1310 const struct GUID *object,
1311 const struct dcerpc_interface_table *table,
1313 TALLOC_CTX *mem_ctx,
1316 const struct dcerpc_interface_call *call;
1317 struct ndr_push *push;
1320 struct rpc_request *req;
1322 call = &table->calls[opnum];
1324 /* setup for a ndr_push_* call */
1325 push = ndr_push_init_ctx(mem_ctx);
1330 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1331 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1334 /* push the structure into a blob */
1335 status = call->ndr_push(push, NDR_IN, r);
1336 if (!NT_STATUS_IS_OK(status)) {
1337 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1338 nt_errstr(status)));
1343 /* retrieve the blob */
1344 request = ndr_push_blob(push);
1346 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1347 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1348 call->ndr_push, call->ndr_pull);
1349 if (!NT_STATUS_IS_OK(status)) {
1350 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1351 nt_errstr(status)));
1357 DEBUG(10,("rpc request data:\n"));
1358 dump_data(10, request.data, request.length);
1360 /* make the actual dcerpc request */
1361 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1365 req->ndr.table = table;
1366 req->ndr.opnum = opnum;
1367 req->ndr.struct_ptr = r;
1368 req->ndr.mem_ctx = mem_ctx;
1377 receive the answer from a dcerpc_ndr_request_send()
1379 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1381 struct dcerpc_pipe *p = req->p;
1384 struct ndr_pull *pull;
1386 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1387 void *r = req->ndr.struct_ptr;
1388 uint32_t opnum = req->ndr.opnum;
1389 const struct dcerpc_interface_table *table = req->ndr.table;
1390 const struct dcerpc_interface_call *call = &table->calls[opnum];
1392 /* make sure the recv code doesn't free the request, as we
1393 need to grab the flags element before it is freed */
1394 talloc_increase_ref_count(req);
1396 status = dcerpc_request_recv(req, mem_ctx, &response);
1397 if (!NT_STATUS_IS_OK(status)) {
1403 /* prepare for ndr_pull_* */
1404 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1407 return NT_STATUS_NO_MEMORY;
1411 pull->data = talloc_steal(pull, pull->data);
1415 if (flags & DCERPC_PULL_BIGENDIAN) {
1416 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1419 DEBUG(10,("rpc reply data:\n"));
1420 dump_data(10, pull->data, pull->data_size);
1422 /* pull the structure from the blob */
1423 status = call->ndr_pull(pull, NDR_OUT, r);
1424 if (!NT_STATUS_IS_OK(status)) {
1425 dcerpc_log_packet(table, opnum, NDR_OUT,
1430 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1431 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1432 call->ndr_push, call->ndr_pull,
1434 if (!NT_STATUS_IS_OK(status)) {
1435 dcerpc_log_packet(table, opnum, NDR_OUT,
1441 if (pull->offset != pull->data_size) {
1442 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1443 pull->data_size - pull->offset));
1444 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1445 but it turns out that early versions of NT
1446 (specifically NT3.1) add junk onto the end of rpc
1447 packets, so if we want to interoperate at all with
1448 those versions then we need to ignore this error */
1451 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1453 return NT_STATUS_OK;
1458 a useful helper function for synchronous rpc requests
1460 this can be used when you have ndr push/pull functions in the
1463 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1464 const struct GUID *object,
1465 const struct dcerpc_interface_table *table,
1467 TALLOC_CTX *mem_ctx,
1470 struct rpc_request *req;
1472 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1474 return NT_STATUS_NO_MEMORY;
1477 return dcerpc_ndr_request_recv(req);
1482 a useful function for retrieving the server name we connected to
1484 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1486 if (!p->conn->transport.peer_name) {
1489 return p->conn->transport.peer_name(p->conn);
1494 get the dcerpc auth_level for a open connection
1496 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1500 if (c->flags & DCERPC_SEAL) {
1501 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1502 } else if (c->flags & DCERPC_SIGN) {
1503 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1504 } else if (c->flags & DCERPC_CONNECT) {
1505 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1507 auth_level = DCERPC_AUTH_LEVEL_NONE;
1513 Receive an alter reply from the transport
1515 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
1517 struct composite_context *c;
1518 struct dcerpc_pipe *pipe;
1520 c = talloc_get_type(conn->alter_private, struct composite_context);
1521 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1523 /* mark the connection as not waiting for a alter context reply */
1524 conn->alter_private = NULL;
1526 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1527 pkt->u.alter_resp.num_results == 1 &&
1528 pkt->u.alter_resp.ctx_list[0].result != 0) {
1529 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1530 pkt->u.alter_resp.ctx_list[0].reason));
1531 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1535 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1536 pkt->u.alter_resp.num_results == 0 ||
1537 pkt->u.alter_resp.ctx_list[0].result != 0) {
1538 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1542 /* the alter_resp might contain a reply set of credentials */
1543 if (pipe->conn->security_state.auth_info &&
1544 pkt->u.alter_resp.auth_info.length) {
1545 c->status = ndr_pull_struct_blob(
1546 &pkt->u.alter_resp.auth_info, pipe,
1547 pipe->conn->security_state.auth_info,
1548 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1549 if (!composite_is_ok(c)) return;
1556 send a dcerpc alter_context request
1558 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1559 TALLOC_CTX *mem_ctx,
1560 const struct dcerpc_syntax_id *syntax,
1561 const struct dcerpc_syntax_id *transfer_syntax)
1563 struct composite_context *c;
1564 struct ncacn_packet pkt;
1567 c = talloc_zero(mem_ctx, struct composite_context);
1568 if (c == NULL) return NULL;
1570 c->state = COMPOSITE_STATE_IN_PROGRESS;
1571 c->private_data = p;
1572 c->event_ctx = p->conn->event_ctx;
1574 p->syntax = *syntax;
1575 p->transfer_syntax = *transfer_syntax;
1577 init_ncacn_hdr(p->conn, &pkt);
1579 pkt.ptype = DCERPC_PKT_ALTER;
1580 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1581 pkt.call_id = p->conn->call_id;
1582 pkt.auth_length = 0;
1584 pkt.u.alter.max_xmit_frag = 5840;
1585 pkt.u.alter.max_recv_frag = 5840;
1586 pkt.u.alter.assoc_group_id = 0;
1587 pkt.u.alter.num_contexts = 1;
1588 pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1589 struct dcerpc_ctx_list, 1);
1590 if (pkt.u.alter.ctx_list == NULL) {
1591 c->status = NT_STATUS_NO_MEMORY;
1594 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1595 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1596 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1597 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1598 pkt.u.alter.auth_info = data_blob(NULL, 0);
1600 /* construct the NDR form of the packet */
1601 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1602 p->conn->security_state.auth_info);
1603 if (!NT_STATUS_IS_OK(c->status)) {
1607 p->conn->transport.recv_data = dcerpc_recv_data;
1608 p->conn->alter_private = c;
1610 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1611 if (!NT_STATUS_IS_OK(c->status)) {
1615 event_add_timed(c->event_ctx, c,
1616 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1617 bind_timeout_handler, c);
1622 composite_error(c, c->status);
1626 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1628 NTSTATUS result = composite_wait(ctx);
1634 send a dcerpc alter_context request
1636 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1637 TALLOC_CTX *mem_ctx,
1638 const struct dcerpc_syntax_id *syntax,
1639 const struct dcerpc_syntax_id *transfer_syntax)
1641 struct composite_context *creq;
1642 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1643 return dcerpc_alter_context_recv(creq);