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/gen_ndr/ndr_dcerpc.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "libcli/composite/composite.h"
30 #include "auth/gensec/gensec.h"
32 NTSTATUS dcerpc_init(void)
39 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
41 /* destroy a dcerpc connection */
42 static int dcerpc_connection_destructor(void *ptr)
44 struct dcerpc_connection *c = ptr;
45 if (c->transport.shutdown_pipe) {
46 c->transport.shutdown_pipe(c);
52 /* initialise a dcerpc connection.
53 the event context is optional
55 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
56 struct event_context *ev)
58 struct dcerpc_connection *c;
60 c = talloc_zero(mem_ctx, struct dcerpc_connection);
66 ev = event_context_init(c);
75 c->security_state.auth_info = NULL;
76 c->security_state.session_key = dcerpc_generic_session_key;
77 c->security_state.generic_state = NULL;
78 c->binding_string = NULL;
80 c->srv_max_xmit_frag = 0;
81 c->srv_max_recv_frag = 0;
84 talloc_set_destructor(c, dcerpc_connection_destructor);
89 /* initialise a dcerpc pipe. */
90 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
92 struct dcerpc_pipe *p;
94 p = talloc(mem_ctx, struct dcerpc_pipe);
99 p->conn = dcerpc_connection_init(p, ev);
100 if (p->conn == NULL) {
105 p->last_fault_code = 0;
107 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
109 ZERO_STRUCT(p->syntax);
110 ZERO_STRUCT(p->transfer_syntax);
117 choose the next call id to use
119 static uint32_t next_call_id(struct dcerpc_connection *c)
122 if (c->call_id == 0) {
128 /* we need to be able to get/set the fragment length without doing a full
130 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
132 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
133 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
135 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
139 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
141 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
142 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
144 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
148 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
150 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
151 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
153 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
159 setup for a ndr pull, also setting up any flags from the binding string
161 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
162 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
164 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
166 if (ndr == NULL) return ndr;
168 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
169 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
172 if (c->flags & DCERPC_NDR_REF_ALLOC) {
173 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
180 parse a data blob into a ncacn_packet structure. This handles both
181 input and output packets
183 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
184 struct ncacn_packet *pkt)
186 struct ndr_pull *ndr;
188 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
190 return NT_STATUS_NO_MEMORY;
193 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
194 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
197 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
201 generate a CONNECT level verifier
203 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
205 *blob = data_blob_talloc(mem_ctx, NULL, 16);
206 if (blob->data == NULL) {
207 return NT_STATUS_NO_MEMORY;
209 SIVAL(blob->data, 0, 1);
210 memset(blob->data+4, 0, 12);
215 check a CONNECT level verifier
217 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
219 if (blob->length != 16 ||
220 IVAL(blob->data, 0) != 1) {
221 return NT_STATUS_ACCESS_DENIED;
227 parse the authentication information on a dcerpc response packet
229 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
230 DATA_BLOB *raw_packet,
231 struct ncacn_packet *pkt)
233 struct ndr_pull *ndr;
235 struct dcerpc_auth auth;
238 if (pkt->auth_length == 0 &&
239 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
243 auth_blob.length = 8 + pkt->auth_length;
245 /* check for a valid length */
246 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
247 return NT_STATUS_INFO_LENGTH_MISMATCH;
251 pkt->u.response.stub_and_verifier.data +
252 pkt->u.response.stub_and_verifier.length - auth_blob.length;
253 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
255 /* pull the auth structure */
256 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
258 return NT_STATUS_NO_MEMORY;
261 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
262 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
265 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
266 if (!NT_STATUS_IS_OK(status)) {
271 /* check signature or unseal the packet */
272 switch (c->security_state.auth_info->auth_level) {
273 case DCERPC_AUTH_LEVEL_PRIVACY:
274 status = gensec_unseal_packet(c->security_state.generic_state,
276 raw_packet->data + DCERPC_REQUEST_LENGTH,
277 pkt->u.response.stub_and_verifier.length,
279 raw_packet->length - auth.credentials.length,
281 memcpy(pkt->u.response.stub_and_verifier.data,
282 raw_packet->data + DCERPC_REQUEST_LENGTH,
283 pkt->u.response.stub_and_verifier.length);
286 case DCERPC_AUTH_LEVEL_INTEGRITY:
287 status = gensec_check_packet(c->security_state.generic_state,
289 pkt->u.response.stub_and_verifier.data,
290 pkt->u.response.stub_and_verifier.length,
292 raw_packet->length - auth.credentials.length,
296 case DCERPC_AUTH_LEVEL_CONNECT:
297 status = dcerpc_check_connect_verifier(&auth.credentials);
300 case DCERPC_AUTH_LEVEL_NONE:
304 status = NT_STATUS_INVALID_LEVEL;
308 /* remove the indicated amount of paddiing */
309 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
310 return NT_STATUS_INFO_LENGTH_MISMATCH;
312 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
319 push a dcerpc request packet into a blob, possibly signing it.
321 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
322 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
323 struct ncacn_packet *pkt)
326 struct ndr_push *ndr;
328 size_t payload_length;
330 /* non-signed packets are simpler */
331 if (!c->security_state.auth_info ||
332 !c->security_state.generic_state) {
333 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
336 ndr = ndr_push_init_ctx(mem_ctx);
338 return NT_STATUS_NO_MEMORY;
341 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
342 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
345 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
346 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
349 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
350 if (!NT_STATUS_IS_OK(status)) {
354 /* pad to 16 byte multiple in the payload portion of the
355 packet. This matches what w2k3 does */
356 c->security_state.auth_info->auth_pad_length =
357 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
358 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
360 payload_length = pkt->u.request.stub_and_verifier.length +
361 c->security_state.auth_info->auth_pad_length;
363 /* sign or seal the packet */
364 switch (c->security_state.auth_info->auth_level) {
365 case DCERPC_AUTH_LEVEL_PRIVACY:
366 case DCERPC_AUTH_LEVEL_INTEGRITY:
367 c->security_state.auth_info->credentials
368 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
370 data_blob_clear(&c->security_state.auth_info->credentials);
373 case DCERPC_AUTH_LEVEL_CONNECT:
374 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
377 case DCERPC_AUTH_LEVEL_NONE:
378 c->security_state.auth_info->credentials = data_blob(NULL, 0);
382 status = NT_STATUS_INVALID_LEVEL;
386 if (!NT_STATUS_IS_OK(status)) {
390 /* add the auth verifier */
391 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
392 if (!NT_STATUS_IS_OK(status)) {
396 /* extract the whole packet as a blob */
397 *blob = ndr_push_blob(ndr);
399 /* fill in the fragment length and auth_length, we can't fill
400 in these earlier as we don't know the signature length (it
401 could be variable length) */
402 dcerpc_set_frag_length(blob, blob->length);
403 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
405 /* sign or seal the packet */
406 switch (c->security_state.auth_info->auth_level) {
407 case DCERPC_AUTH_LEVEL_PRIVACY:
408 status = gensec_seal_packet(c->security_state.generic_state,
410 blob->data + DCERPC_REQUEST_LENGTH,
414 c->security_state.auth_info->credentials.length,
416 if (!NT_STATUS_IS_OK(status)) {
419 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
422 case DCERPC_AUTH_LEVEL_INTEGRITY:
423 status = gensec_sign_packet(c->security_state.generic_state,
425 blob->data + DCERPC_REQUEST_LENGTH,
429 c->security_state.auth_info->credentials.length,
431 if (!NT_STATUS_IS_OK(status)) {
434 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
437 case DCERPC_AUTH_LEVEL_CONNECT:
440 case DCERPC_AUTH_LEVEL_NONE:
441 c->security_state.auth_info->credentials = data_blob(NULL, 0);
445 status = NT_STATUS_INVALID_LEVEL;
449 data_blob_free(&c->security_state.auth_info->credentials);
456 fill in the fixed values in a dcerpc header
458 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
461 pkt->rpc_vers_minor = 0;
462 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
465 pkt->drep[0] = DCERPC_DREP_LE;
473 map a bind nak reason to a NTSTATUS
475 static NTSTATUS dcerpc_map_reason(uint16_t reason)
478 case DCERPC_BIND_REASON_ASYNTAX:
479 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
481 return NT_STATUS_UNSUCCESSFUL;
485 mark the dcerpc connection dead. All outstanding requests get an error
487 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
489 /* all pending requests get the error */
490 while (conn->pending) {
491 struct rpc_request *req = conn->pending;
492 req->state = RPC_REQUEST_DONE;
493 req->status = status;
494 DLIST_REMOVE(conn->pending, req);
495 if (req->async.callback) {
496 req->async.callback(req);
500 if (conn->bind_private) {
501 /* a bind was in flight - fail it */
502 struct composite_context *c = talloc_get_type(conn->bind_private, struct composite_context);
503 composite_error(c, status);
506 if (conn->alter_private) {
507 /* a alter context was in flight - fail it */
508 struct composite_context *c = talloc_get_type(conn->alter_private, struct composite_context);
509 composite_error(c, status);
514 forward declarations of the recv_data handlers for the 3 types of packets we need
517 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
518 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
519 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
520 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
523 receive a dcerpc reply from the transport. Here we work out what
524 type of reply it is (normal request, bind or alter context) and
525 dispatch to the appropriate handler
527 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
529 struct ncacn_packet pkt;
531 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
532 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
535 /* the transport may be telling us of a severe error, such as
537 if (!NT_STATUS_IS_OK(status)) {
538 data_blob_free(blob);
539 dcerpc_connection_dead(conn, status);
543 /* parse the basic packet to work out what type of response this is */
544 status = ncacn_pull(conn, blob, blob->data, &pkt);
545 if (!NT_STATUS_IS_OK(status)) {
546 data_blob_free(blob);
547 dcerpc_connection_dead(conn, status);
551 case DCERPC_PKT_BIND_NAK:
552 case DCERPC_PKT_BIND_ACK:
553 if (conn->bind_private) {
554 talloc_steal(conn->bind_private, blob->data);
555 dcerpc_bind_recv_data(conn, &pkt);
559 case DCERPC_PKT_ALTER_RESP:
560 if (conn->alter_private) {
561 talloc_steal(conn->alter_private, blob->data);
562 dcerpc_alter_recv_data(conn, &pkt);
567 /* assume its an ordinary request */
568 dcerpc_request_recv_data(conn, blob, &pkt);
575 Receive a bind reply from the transport
577 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
579 struct composite_context *c;
580 struct dcerpc_pipe *pipe;
582 c = talloc_get_type(conn->bind_private, struct composite_context);
583 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
585 /* mark the connection as not waiting for a bind reply */
586 conn->bind_private = NULL;
588 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
589 DEBUG(2,("dcerpc: bind_nak reason %d\n",
590 pkt->u.bind_nak.reject_reason));
591 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
596 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
597 (pkt->u.bind_ack.num_results == 0) ||
598 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
599 composite_error(c, NT_STATUS_UNSUCCESSFUL);
603 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
604 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
606 /* the bind_ack might contain a reply set of credentials */
607 if (conn->security_state.auth_info &&
608 pkt->u.bind_ack.auth_info.length) {
609 c->status = ndr_pull_struct_blob(
610 &pkt->u.bind_ack.auth_info, conn,
611 conn->security_state.auth_info,
612 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
613 if (!composite_is_ok(c)) return;
620 handle timeouts of dcerpc bind and alter context requests
622 static void bind_timeout_handler(struct event_context *ev,
623 struct timed_event *te,
624 struct timeval t, void *private)
626 struct composite_context *ctx =
627 talloc_get_type(private, struct composite_context);
628 struct dcerpc_pipe *pipe = talloc_get_type(ctx->private_data, struct dcerpc_pipe);
630 SMB_ASSERT(pipe->conn->bind_private != NULL);
631 pipe->conn->bind_private = NULL;
632 composite_error(ctx, NT_STATUS_IO_TIMEOUT);
636 send a async dcerpc bind request
638 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
640 const struct dcerpc_syntax_id *syntax,
641 const struct dcerpc_syntax_id *transfer_syntax)
643 struct composite_context *c;
644 struct ncacn_packet pkt;
647 c = talloc_zero(mem_ctx, struct composite_context);
648 if (c == NULL) return NULL;
650 c->state = COMPOSITE_STATE_IN_PROGRESS;
652 c->event_ctx = p->conn->event_ctx;
655 p->transfer_syntax = *transfer_syntax;
657 init_ncacn_hdr(p->conn, &pkt);
659 pkt.ptype = DCERPC_PKT_BIND;
660 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
661 pkt.call_id = p->conn->call_id;
664 pkt.u.bind.max_xmit_frag = 5840;
665 pkt.u.bind.max_recv_frag = 5840;
666 pkt.u.bind.assoc_group_id = 0;
667 pkt.u.bind.num_contexts = 1;
668 pkt.u.bind.ctx_list =
669 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
670 if (pkt.u.bind.ctx_list == NULL) {
671 c->status = NT_STATUS_NO_MEMORY;
674 pkt.u.bind.ctx_list[0].context_id = p->context_id;
675 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
676 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
677 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
678 pkt.u.bind.auth_info = data_blob(NULL, 0);
680 /* construct the NDR form of the packet */
681 c->status = ncacn_push_auth(&blob, c, &pkt,
682 p->conn->security_state.auth_info);
683 if (!NT_STATUS_IS_OK(c->status)) {
687 p->conn->transport.recv_data = dcerpc_recv_data;
688 p->conn->bind_private = c;
690 c->status = p->conn->transport.send_request(p->conn, &blob,
692 if (!NT_STATUS_IS_OK(c->status)) {
696 event_add_timed(c->event_ctx, c,
697 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
698 bind_timeout_handler, c);
703 composite_error(c, c->status);
708 recv side of async dcerpc bind request
710 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
712 NTSTATUS result = composite_wait(ctx);
718 perform a bind using the given syntax
720 the auth_info structure is updated with the reply authentication info
723 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
725 const struct dcerpc_syntax_id *syntax,
726 const struct dcerpc_syntax_id *transfer_syntax)
728 struct composite_context *creq;
729 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
730 return dcerpc_bind_recv(creq);
734 perform a continued bind (and auth3)
736 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
739 struct ncacn_packet pkt;
743 init_ncacn_hdr(c, &pkt);
745 pkt.ptype = DCERPC_PKT_AUTH3;
746 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
747 pkt.call_id = next_call_id(c);
749 pkt.u.auth3._pad = 0;
750 pkt.u.auth3.auth_info = data_blob(NULL, 0);
752 /* construct the NDR form of the packet */
753 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
754 if (!NT_STATUS_IS_OK(status)) {
758 /* send it on its way */
759 status = c->transport.send_request(c, &blob, False);
760 if (!NT_STATUS_IS_OK(status)) {
769 return the rpc syntax and transfer syntax given the pipe uuid and version
771 NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
772 struct dcerpc_syntax_id *syntax,
773 struct dcerpc_syntax_id *transfer_syntax)
775 syntax->uuid = table->uuid;
776 syntax->if_version = table->if_version;
778 *transfer_syntax = ndr_transfer_syntax;
783 /* perform a dcerpc bind, using the uuid as the key */
784 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
786 const struct dcerpc_interface_table *table)
788 struct dcerpc_syntax_id syntax;
789 struct dcerpc_syntax_id transfer_syntax;
792 status = dcerpc_init_syntaxes(table,
793 &syntax, &transfer_syntax);
794 if (!NT_STATUS_IS_OK(status)) {
795 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
799 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
804 process a fragment received from the transport layer during a
807 This function frees the data
809 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
810 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
812 struct rpc_request *req;
814 NTSTATUS status = NT_STATUS_OK;
817 if this is an authenticated connection then parse and check
818 the auth info. We have to do this before finding the
819 matching packet, as the request structure might have been
820 removed due to a timeout, but if it has been we still need
821 to run the auth routines so that we don't get the sign/seal
822 info out of step with the server
824 if (c->security_state.auth_info && c->security_state.generic_state &&
825 pkt->ptype == DCERPC_PKT_RESPONSE) {
826 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
829 /* find the matching request */
830 for (req=c->pending;req;req=req->next) {
831 if (pkt->call_id == req->call_id) break;
835 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
836 data_blob_free(raw_packet);
840 talloc_steal(req, raw_packet->data);
842 if (pkt->ptype == DCERPC_PKT_FAULT) {
843 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
844 req->fault_code = pkt->u.fault.status;
845 req->status = NT_STATUS_NET_WRITE_FAULT;
849 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
850 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
852 req->fault_code = DCERPC_FAULT_OTHER;
853 req->status = NT_STATUS_NET_WRITE_FAULT;
857 /* now check the status from the auth routines, and if it failed then fail
858 this request accordingly */
859 if (!NT_STATUS_IS_OK(status)) {
860 req->status = status;
864 length = pkt->u.response.stub_and_verifier.length;
867 req->payload.data = talloc_realloc(req,
870 req->payload.length + length);
871 if (!req->payload.data) {
872 req->status = NT_STATUS_NO_MEMORY;
875 memcpy(req->payload.data+req->payload.length,
876 pkt->u.response.stub_and_verifier.data, length);
877 req->payload.length += length;
880 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
881 c->transport.send_read(c);
885 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
886 req->flags |= DCERPC_PULL_BIGENDIAN;
888 req->flags &= ~DCERPC_PULL_BIGENDIAN;
893 /* we've got the full payload */
894 req->state = RPC_REQUEST_DONE;
895 DLIST_REMOVE(c->pending, req);
897 if (c->request_queue != NULL) {
898 /* We have to look at shipping further requests before calling
899 * the async function, that one might close the pipe */
900 dcerpc_ship_next_request(c);
903 if (req->async.callback) {
904 req->async.callback(req);
909 handle timeouts of individual dcerpc requests
911 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
912 struct timeval t, void *private)
914 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
916 if (req->state != RPC_REQUEST_PENDING) {
920 req->status = NT_STATUS_IO_TIMEOUT;
921 req->state = RPC_REQUEST_DONE;
922 DLIST_REMOVE(req->p->conn->pending, req);
923 if (req->async.callback) {
924 req->async.callback(req);
930 make sure requests are cleaned up
932 static int dcerpc_req_destructor(void *ptr)
934 struct rpc_request *req = ptr;
935 DLIST_REMOVE(req->p->conn->pending, req);
940 perform the send side of a async dcerpc request
942 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
943 const struct GUID *object,
946 DATA_BLOB *stub_data)
948 struct rpc_request *req;
950 p->conn->transport.recv_data = dcerpc_recv_data;
952 req = talloc(p, struct rpc_request);
958 req->call_id = next_call_id(p->conn);
959 req->status = NT_STATUS_OK;
960 req->state = RPC_REQUEST_PENDING;
961 req->payload = data_blob(NULL, 0);
964 req->async_call = async;
965 req->async.callback = NULL;
967 if (object != NULL) {
968 req->object = talloc_memdup(req, object, sizeof(*object));
969 if (req->object == NULL) {
978 req->request_data.length = stub_data->length;
979 req->request_data.data = talloc_reference(req, stub_data->data);
980 if (req->request_data.data == NULL) {
984 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
986 dcerpc_ship_next_request(p->conn);
988 if (p->request_timeout) {
989 event_add_timed(dcerpc_event_context(p), req,
990 timeval_current_ofs(p->request_timeout, 0),
991 dcerpc_timeout_handler, req);
994 talloc_set_destructor(req, dcerpc_req_destructor);
999 Send a request using the transport
1002 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1004 struct rpc_request *req;
1005 struct dcerpc_pipe *p;
1006 DATA_BLOB *stub_data;
1007 struct ncacn_packet pkt;
1009 uint32_t remaining, chunk_size;
1010 BOOL first_packet = True;
1012 req = c->request_queue;
1018 stub_data = &req->request_data;
1020 if (!req->async_call && (c->pending != NULL)) {
1024 DLIST_REMOVE(c->request_queue, req);
1025 DLIST_ADD(c->pending, req);
1027 init_ncacn_hdr(p->conn, &pkt);
1029 remaining = stub_data->length;
1031 /* we can write a full max_recv_frag size, minus the dcerpc
1032 request header size */
1033 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1035 pkt.ptype = DCERPC_PKT_REQUEST;
1036 pkt.call_id = req->call_id;
1037 pkt.auth_length = 0;
1039 pkt.u.request.alloc_hint = remaining;
1040 pkt.u.request.context_id = p->context_id;
1041 pkt.u.request.opnum = req->opnum;
1044 pkt.u.request.object.object = *req->object;
1045 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1046 chunk_size -= ndr_size_GUID(req->object,0);
1049 /* we send a series of pdus without waiting for a reply */
1050 while (remaining > 0 || first_packet) {
1051 uint32_t chunk = MIN(chunk_size, remaining);
1052 BOOL last_frag = False;
1054 first_packet = False;
1055 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1057 if (remaining == stub_data->length) {
1058 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1060 if (chunk == remaining) {
1061 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1065 pkt.u.request.stub_and_verifier.data = stub_data->data +
1066 (stub_data->length - remaining);
1067 pkt.u.request.stub_and_verifier.length = chunk;
1069 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1070 if (!NT_STATUS_IS_OK(req->status)) {
1071 req->state = RPC_REQUEST_DONE;
1072 DLIST_REMOVE(p->conn->pending, req);
1076 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1077 if (!NT_STATUS_IS_OK(req->status)) {
1078 req->state = RPC_REQUEST_DONE;
1079 DLIST_REMOVE(p->conn->pending, req);
1088 return the event context for a dcerpc pipe
1089 used by callers who wish to operate asynchronously
1091 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1093 return p->conn->event_ctx;
1099 perform the receive side of a async dcerpc request
1101 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1102 TALLOC_CTX *mem_ctx,
1103 DATA_BLOB *stub_data)
1107 while (req->state == RPC_REQUEST_PENDING) {
1108 struct event_context *ctx = dcerpc_event_context(req->p);
1109 if (event_loop_once(ctx) != 0) {
1110 return NT_STATUS_CONNECTION_DISCONNECTED;
1113 *stub_data = req->payload;
1114 status = req->status;
1115 if (stub_data->data) {
1116 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1118 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1119 req->p->last_fault_code = req->fault_code;
1126 perform a full request/response pair on a dcerpc pipe
1128 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1129 struct GUID *object,
1132 TALLOC_CTX *mem_ctx,
1133 DATA_BLOB *stub_data_in,
1134 DATA_BLOB *stub_data_out)
1136 struct rpc_request *req;
1138 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1140 return NT_STATUS_NO_MEMORY;
1143 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1148 this is a paranoid NDR validator. For every packet we push onto the wire
1149 we pull it back again, then push it again. Then we compare the raw NDR data
1150 for that to the NDR we initially generated. If they don't match then we know
1151 we must have a bug in either the pull or push side of our code
1153 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1154 TALLOC_CTX *mem_ctx,
1157 ndr_push_flags_fn_t ndr_push,
1158 ndr_pull_flags_fn_t ndr_pull)
1161 struct ndr_pull *pull;
1162 struct ndr_push *push;
1166 st = talloc_size(mem_ctx, struct_size);
1168 return NT_STATUS_NO_MEMORY;
1171 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1173 return NT_STATUS_NO_MEMORY;
1175 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1177 status = ndr_pull(pull, NDR_IN, st);
1178 if (!NT_STATUS_IS_OK(status)) {
1179 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1180 "failed input validation pull - %s",
1184 push = ndr_push_init_ctx(mem_ctx);
1186 return NT_STATUS_NO_MEMORY;
1189 status = ndr_push(push, NDR_IN, st);
1190 if (!NT_STATUS_IS_OK(status)) {
1191 return ndr_push_error(push, NDR_ERR_VALIDATE,
1192 "failed input validation push - %s",
1196 blob2 = ndr_push_blob(push);
1198 if (!data_blob_equal(&blob, &blob2)) {
1199 DEBUG(3,("original:\n"));
1200 dump_data(3, blob.data, blob.length);
1201 DEBUG(3,("secondary:\n"));
1202 dump_data(3, blob2.data, blob2.length);
1203 return ndr_push_error(push, NDR_ERR_VALIDATE,
1204 "failed input validation data - %s",
1208 return NT_STATUS_OK;
1212 this is a paranoid NDR input validator. For every packet we pull
1213 from the wire we push it back again then pull and push it
1214 again. Then we compare the raw NDR data for that to the NDR we
1215 initially generated. If they don't match then we know we must have a
1216 bug in either the pull or push side of our code
1218 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1219 struct ndr_pull *pull_in,
1222 ndr_push_flags_fn_t ndr_push,
1223 ndr_pull_flags_fn_t ndr_pull,
1224 ndr_print_function_t ndr_print)
1227 struct ndr_pull *pull;
1228 struct ndr_push *push;
1230 DATA_BLOB blob, blob2;
1231 TALLOC_CTX *mem_ctx = pull_in;
1234 st = talloc_size(mem_ctx, struct_size);
1236 return NT_STATUS_NO_MEMORY;
1238 memcpy(st, struct_ptr, struct_size);
1240 push = ndr_push_init_ctx(mem_ctx);
1242 return NT_STATUS_NO_MEMORY;
1245 status = ndr_push(push, NDR_OUT, struct_ptr);
1246 if (!NT_STATUS_IS_OK(status)) {
1247 return ndr_push_error(push, NDR_ERR_VALIDATE,
1248 "failed output validation push - %s",
1252 blob = ndr_push_blob(push);
1254 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1256 return NT_STATUS_NO_MEMORY;
1259 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1260 status = ndr_pull(pull, NDR_OUT, st);
1261 if (!NT_STATUS_IS_OK(status)) {
1262 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1263 "failed output validation pull - %s",
1267 push = ndr_push_init_ctx(mem_ctx);
1269 return NT_STATUS_NO_MEMORY;
1272 status = ndr_push(push, NDR_OUT, st);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 return ndr_push_error(push, NDR_ERR_VALIDATE,
1275 "failed output validation push2 - %s",
1279 blob2 = ndr_push_blob(push);
1281 if (!data_blob_equal(&blob, &blob2)) {
1282 DEBUG(3,("original:\n"));
1283 dump_data(3, blob.data, blob.length);
1284 DEBUG(3,("secondary:\n"));
1285 dump_data(3, blob2.data, blob2.length);
1286 return ndr_push_error(push, NDR_ERR_VALIDATE,
1287 "failed output validation data - %s",
1291 /* this checks the printed forms of the two structures, which effectively
1292 tests all of the value() attributes */
1293 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1294 NDR_OUT, struct_ptr);
1295 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1297 if (strcmp(s1, s2) != 0) {
1298 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1301 return NT_STATUS_OK;
1306 send a rpc request given a dcerpc_call structure
1308 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1309 const struct GUID *object,
1310 const struct dcerpc_interface_table *table,
1312 TALLOC_CTX *mem_ctx,
1315 const struct dcerpc_interface_call *call;
1316 struct ndr_push *push;
1319 struct rpc_request *req;
1321 call = &table->calls[opnum];
1323 /* setup for a ndr_push_* call */
1324 push = ndr_push_init_ctx(mem_ctx);
1329 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1330 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1333 /* push the structure into a blob */
1334 status = call->ndr_push(push, NDR_IN, r);
1335 if (!NT_STATUS_IS_OK(status)) {
1336 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1337 nt_errstr(status)));
1342 /* retrieve the blob */
1343 request = ndr_push_blob(push);
1345 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1346 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1347 call->ndr_push, call->ndr_pull);
1348 if (!NT_STATUS_IS_OK(status)) {
1349 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1350 nt_errstr(status)));
1356 DEBUG(10,("rpc request data:\n"));
1357 dump_data(10, request.data, request.length);
1359 /* make the actual dcerpc request */
1360 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1364 req->ndr.table = table;
1365 req->ndr.opnum = opnum;
1366 req->ndr.struct_ptr = r;
1367 req->ndr.mem_ctx = mem_ctx;
1376 receive the answer from a dcerpc_ndr_request_send()
1378 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1380 struct dcerpc_pipe *p = req->p;
1383 struct ndr_pull *pull;
1385 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1386 void *r = req->ndr.struct_ptr;
1387 uint32_t opnum = req->ndr.opnum;
1388 const struct dcerpc_interface_table *table = req->ndr.table;
1389 const struct dcerpc_interface_call *call = &table->calls[opnum];
1391 /* make sure the recv code doesn't free the request, as we
1392 need to grab the flags element before it is freed */
1393 talloc_increase_ref_count(req);
1395 status = dcerpc_request_recv(req, mem_ctx, &response);
1396 if (!NT_STATUS_IS_OK(status)) {
1402 /* prepare for ndr_pull_* */
1403 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1406 return NT_STATUS_NO_MEMORY;
1410 pull->data = talloc_steal(pull, pull->data);
1414 if (flags & DCERPC_PULL_BIGENDIAN) {
1415 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1418 DEBUG(10,("rpc reply data:\n"));
1419 dump_data(10, pull->data, pull->data_size);
1421 /* pull the structure from the blob */
1422 status = call->ndr_pull(pull, NDR_OUT, r);
1423 if (!NT_STATUS_IS_OK(status)) {
1424 dcerpc_log_packet(table, opnum, NDR_OUT,
1429 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1430 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1431 call->ndr_push, call->ndr_pull,
1433 if (!NT_STATUS_IS_OK(status)) {
1434 dcerpc_log_packet(table, opnum, NDR_OUT,
1440 if (pull->offset != pull->data_size) {
1441 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1442 pull->data_size - pull->offset));
1443 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1444 but it turns out that early versions of NT
1445 (specifically NT3.1) add junk onto the end of rpc
1446 packets, so if we want to interoperate at all with
1447 those versions then we need to ignore this error */
1450 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1452 return NT_STATUS_OK;
1457 a useful helper function for synchronous rpc requests
1459 this can be used when you have ndr push/pull functions in the
1462 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1463 const struct GUID *object,
1464 const struct dcerpc_interface_table *table,
1466 TALLOC_CTX *mem_ctx,
1469 struct rpc_request *req;
1471 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1473 return NT_STATUS_NO_MEMORY;
1476 return dcerpc_ndr_request_recv(req);
1481 a useful function for retrieving the server name we connected to
1483 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1485 if (!p->conn->transport.peer_name) {
1488 return p->conn->transport.peer_name(p->conn);
1493 get the dcerpc auth_level for a open connection
1495 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1499 if (c->flags & DCERPC_SEAL) {
1500 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1501 } else if (c->flags & DCERPC_SIGN) {
1502 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1503 } else if (c->flags & DCERPC_CONNECT) {
1504 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1506 auth_level = DCERPC_AUTH_LEVEL_NONE;
1512 Receive an alter reply from the transport
1514 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
1516 struct composite_context *c;
1517 struct dcerpc_pipe *pipe;
1519 c = talloc_get_type(conn->alter_private, struct composite_context);
1520 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1522 /* mark the connection as not waiting for a alter context reply */
1523 conn->alter_private = NULL;
1525 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1526 pkt->u.alter_resp.num_results == 1 &&
1527 pkt->u.alter_resp.ctx_list[0].result != 0) {
1528 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1529 pkt->u.alter_resp.ctx_list[0].reason));
1530 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1534 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1535 pkt->u.alter_resp.num_results == 0 ||
1536 pkt->u.alter_resp.ctx_list[0].result != 0) {
1537 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1541 /* the alter_resp might contain a reply set of credentials */
1542 if (pipe->conn->security_state.auth_info &&
1543 pkt->u.alter_resp.auth_info.length) {
1544 c->status = ndr_pull_struct_blob(
1545 &pkt->u.alter_resp.auth_info, pipe,
1546 pipe->conn->security_state.auth_info,
1547 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1548 if (!composite_is_ok(c)) return;
1555 send a dcerpc alter_context request
1557 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1558 TALLOC_CTX *mem_ctx,
1559 const struct dcerpc_syntax_id *syntax,
1560 const struct dcerpc_syntax_id *transfer_syntax)
1562 struct composite_context *c;
1563 struct ncacn_packet pkt;
1566 c = talloc_zero(mem_ctx, struct composite_context);
1567 if (c == NULL) return NULL;
1569 c->state = COMPOSITE_STATE_IN_PROGRESS;
1570 c->private_data = p;
1571 c->event_ctx = p->conn->event_ctx;
1573 p->syntax = *syntax;
1574 p->transfer_syntax = *transfer_syntax;
1576 init_ncacn_hdr(p->conn, &pkt);
1578 pkt.ptype = DCERPC_PKT_ALTER;
1579 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1580 pkt.call_id = p->conn->call_id;
1581 pkt.auth_length = 0;
1583 pkt.u.alter.max_xmit_frag = 5840;
1584 pkt.u.alter.max_recv_frag = 5840;
1585 pkt.u.alter.assoc_group_id = 0;
1586 pkt.u.alter.num_contexts = 1;
1587 pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1588 struct dcerpc_ctx_list, 1);
1589 if (pkt.u.alter.ctx_list == NULL) {
1590 c->status = NT_STATUS_NO_MEMORY;
1593 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1594 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1595 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1596 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1597 pkt.u.alter.auth_info = data_blob(NULL, 0);
1599 /* construct the NDR form of the packet */
1600 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1601 p->conn->security_state.auth_info);
1602 if (!NT_STATUS_IS_OK(c->status)) {
1606 p->conn->transport.recv_data = dcerpc_recv_data;
1607 p->conn->alter_private = c;
1609 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1610 if (!NT_STATUS_IS_OK(c->status)) {
1614 event_add_timed(c->event_ctx, c,
1615 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1616 bind_timeout_handler, c);
1621 composite_error(c, c->status);
1625 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1627 NTSTATUS result = composite_wait(ctx);
1633 send a dcerpc alter_context request
1635 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1636 TALLOC_CTX *mem_ctx,
1637 const struct dcerpc_syntax_id *syntax,
1638 const struct dcerpc_syntax_id *transfer_syntax)
1640 struct composite_context *creq;
1641 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1642 return dcerpc_alter_context_recv(creq);