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_epmapper.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
33 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
35 /* destroy a dcerpc connection */
36 static int dcerpc_connection_destructor(void *ptr)
38 struct dcerpc_connection *c = ptr;
39 if (c->transport.shutdown_pipe) {
40 c->transport.shutdown_pipe(c);
46 /* initialise a dcerpc connection.
47 the event context is optional
49 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
50 struct event_context *ev)
52 struct dcerpc_connection *c;
54 c = talloc_zero(mem_ctx, struct dcerpc_connection);
60 ev = event_context_init(c);
69 c->security_state.auth_info = NULL;
70 c->security_state.session_key = dcerpc_generic_session_key;
71 c->security_state.generic_state = NULL;
72 c->binding_string = NULL;
74 c->srv_max_xmit_frag = 0;
75 c->srv_max_recv_frag = 0;
78 talloc_set_destructor(c, dcerpc_connection_destructor);
83 /* initialise a dcerpc pipe. */
84 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
86 struct dcerpc_pipe *p;
88 p = talloc(mem_ctx, struct dcerpc_pipe);
93 p->conn = dcerpc_connection_init(p, ev);
94 if (p->conn == NULL) {
99 p->last_fault_code = 0;
101 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
103 ZERO_STRUCT(p->syntax);
104 ZERO_STRUCT(p->transfer_syntax);
111 choose the next call id to use
113 static uint32_t next_call_id(struct dcerpc_connection *c)
116 if (c->call_id == 0) {
122 /* we need to be able to get/set the fragment length without doing a full
124 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
126 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
127 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
129 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
133 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
135 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
136 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
138 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
142 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
144 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
145 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
147 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
153 setup for a ndr pull, also setting up any flags from the binding string
155 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
156 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
158 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
160 if (ndr == NULL) return ndr;
162 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
163 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
166 if (c->flags & DCERPC_NDR_REF_ALLOC) {
167 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
174 parse a data blob into a ncacn_packet structure. This handles both
175 input and output packets
177 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
178 struct ncacn_packet *pkt)
180 struct ndr_pull *ndr;
182 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
184 return NT_STATUS_NO_MEMORY;
187 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
188 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
191 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
195 generate a CONNECT level verifier
197 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
199 *blob = data_blob_talloc(mem_ctx, NULL, 16);
200 if (blob->data == NULL) {
201 return NT_STATUS_NO_MEMORY;
203 SIVAL(blob->data, 0, 1);
204 memset(blob->data+4, 0, 12);
209 check a CONNECT level verifier
211 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
213 if (blob->length != 16 ||
214 IVAL(blob->data, 0) != 1) {
215 return NT_STATUS_ACCESS_DENIED;
221 parse the authentication information on a dcerpc response packet
223 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
224 DATA_BLOB *raw_packet,
225 struct ncacn_packet *pkt)
227 struct ndr_pull *ndr;
229 struct dcerpc_auth auth;
232 if (pkt->auth_length == 0 &&
233 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
237 auth_blob.length = 8 + pkt->auth_length;
239 /* check for a valid length */
240 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
241 return NT_STATUS_INFO_LENGTH_MISMATCH;
245 pkt->u.response.stub_and_verifier.data +
246 pkt->u.response.stub_and_verifier.length - auth_blob.length;
247 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
249 /* pull the auth structure */
250 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
252 return NT_STATUS_NO_MEMORY;
255 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
256 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
259 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
260 if (!NT_STATUS_IS_OK(status)) {
265 /* check signature or unseal the packet */
266 switch (c->security_state.auth_info->auth_level) {
267 case DCERPC_AUTH_LEVEL_PRIVACY:
268 status = gensec_unseal_packet(c->security_state.generic_state,
270 raw_packet->data + DCERPC_REQUEST_LENGTH,
271 pkt->u.response.stub_and_verifier.length,
273 raw_packet->length - auth.credentials.length,
275 memcpy(pkt->u.response.stub_and_verifier.data,
276 raw_packet->data + DCERPC_REQUEST_LENGTH,
277 pkt->u.response.stub_and_verifier.length);
280 case DCERPC_AUTH_LEVEL_INTEGRITY:
281 status = gensec_check_packet(c->security_state.generic_state,
283 pkt->u.response.stub_and_verifier.data,
284 pkt->u.response.stub_and_verifier.length,
286 raw_packet->length - auth.credentials.length,
290 case DCERPC_AUTH_LEVEL_CONNECT:
291 status = dcerpc_check_connect_verifier(&auth.credentials);
294 case DCERPC_AUTH_LEVEL_NONE:
298 status = NT_STATUS_INVALID_LEVEL;
302 /* remove the indicated amount of paddiing */
303 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
304 return NT_STATUS_INFO_LENGTH_MISMATCH;
306 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
313 push a dcerpc request packet into a blob, possibly signing it.
315 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
316 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
317 struct ncacn_packet *pkt)
320 struct ndr_push *ndr;
322 size_t payload_length;
324 /* non-signed packets are simpler */
325 if (!c->security_state.auth_info ||
326 !c->security_state.generic_state) {
327 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
330 ndr = ndr_push_init_ctx(mem_ctx);
332 return NT_STATUS_NO_MEMORY;
335 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
336 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
339 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
340 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
343 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
344 if (!NT_STATUS_IS_OK(status)) {
348 /* pad to 16 byte multiple in the payload portion of the
349 packet. This matches what w2k3 does */
350 c->security_state.auth_info->auth_pad_length =
351 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
352 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
354 payload_length = pkt->u.request.stub_and_verifier.length +
355 c->security_state.auth_info->auth_pad_length;
357 /* sign or seal the packet */
358 switch (c->security_state.auth_info->auth_level) {
359 case DCERPC_AUTH_LEVEL_PRIVACY:
360 case DCERPC_AUTH_LEVEL_INTEGRITY:
361 c->security_state.auth_info->credentials
362 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
364 data_blob_clear(&c->security_state.auth_info->credentials);
367 case DCERPC_AUTH_LEVEL_CONNECT:
368 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
371 case DCERPC_AUTH_LEVEL_NONE:
372 c->security_state.auth_info->credentials = data_blob(NULL, 0);
376 status = NT_STATUS_INVALID_LEVEL;
380 if (!NT_STATUS_IS_OK(status)) {
384 /* add the auth verifier */
385 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
386 if (!NT_STATUS_IS_OK(status)) {
390 /* extract the whole packet as a blob */
391 *blob = ndr_push_blob(ndr);
393 /* fill in the fragment length and auth_length, we can't fill
394 in these earlier as we don't know the signature length (it
395 could be variable length) */
396 dcerpc_set_frag_length(blob, blob->length);
397 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
399 /* sign or seal the packet */
400 switch (c->security_state.auth_info->auth_level) {
401 case DCERPC_AUTH_LEVEL_PRIVACY:
402 status = gensec_seal_packet(c->security_state.generic_state,
404 blob->data + DCERPC_REQUEST_LENGTH,
408 c->security_state.auth_info->credentials.length,
410 if (!NT_STATUS_IS_OK(status)) {
413 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
416 case DCERPC_AUTH_LEVEL_INTEGRITY:
417 status = gensec_sign_packet(c->security_state.generic_state,
419 blob->data + DCERPC_REQUEST_LENGTH,
423 c->security_state.auth_info->credentials.length,
425 if (!NT_STATUS_IS_OK(status)) {
428 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
431 case DCERPC_AUTH_LEVEL_CONNECT:
434 case DCERPC_AUTH_LEVEL_NONE:
435 c->security_state.auth_info->credentials = data_blob(NULL, 0);
439 status = NT_STATUS_INVALID_LEVEL;
443 data_blob_free(&c->security_state.auth_info->credentials);
450 fill in the fixed values in a dcerpc header
452 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
455 pkt->rpc_vers_minor = 0;
456 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
459 pkt->drep[0] = DCERPC_DREP_LE;
467 map a bind nak reason to a NTSTATUS
469 static NTSTATUS dcerpc_map_reason(uint16_t reason)
472 case DCERPC_BIND_REASON_ASYNTAX:
473 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
475 return NT_STATUS_UNSUCCESSFUL;
479 mark the dcerpc connection dead. All outstanding requests get an error
481 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
483 /* all pending requests get the error */
484 while (conn->pending) {
485 struct rpc_request *req = conn->pending;
486 req->state = RPC_REQUEST_DONE;
487 req->status = status;
488 DLIST_REMOVE(conn->pending, req);
489 if (req->async.callback) {
490 req->async.callback(req);
494 if (conn->bind_private) {
495 /* a bind was in flight - fail it */
496 struct composite_context *c = talloc_get_type(conn->bind_private, struct composite_context);
497 composite_error(c, status);
500 if (conn->alter_private) {
501 /* a alter context was in flight - fail it */
502 struct composite_context *c = talloc_get_type(conn->alter_private, struct composite_context);
503 composite_error(c, status);
508 forward declarations of the recv_data handlers for the 3 types of packets we need
511 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
512 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
513 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
514 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
517 receive a dcerpc reply from the transport. Here we work out what
518 type of reply it is (normal request, bind or alter context) and
519 dispatch to the appropriate handler
521 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
523 struct ncacn_packet pkt;
525 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
526 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
529 /* the transport may be telling us of a severe error, such as
531 if (!NT_STATUS_IS_OK(status)) {
532 data_blob_free(blob);
533 dcerpc_connection_dead(conn, status);
537 /* parse the basic packet to work out what type of response this is */
538 status = ncacn_pull(conn, blob, blob->data, &pkt);
539 if (!NT_STATUS_IS_OK(status)) {
540 data_blob_free(blob);
541 dcerpc_connection_dead(conn, status);
545 case DCERPC_PKT_BIND_NAK:
546 case DCERPC_PKT_BIND_ACK:
547 if (conn->bind_private) {
548 talloc_steal(conn->bind_private, blob->data);
549 dcerpc_bind_recv_data(conn, &pkt);
553 case DCERPC_PKT_ALTER_RESP:
554 if (conn->alter_private) {
555 talloc_steal(conn->alter_private, blob->data);
556 dcerpc_alter_recv_data(conn, &pkt);
561 /* assume its an ordinary request */
562 dcerpc_request_recv_data(conn, blob, &pkt);
569 Receive a bind reply from the transport
571 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
573 struct composite_context *c;
574 struct dcerpc_pipe *pipe;
576 c = talloc_get_type(conn->bind_private, struct composite_context);
577 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
579 /* mark the connection as not waiting for a bind reply */
580 conn->bind_private = NULL;
582 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
583 DEBUG(2,("dcerpc: bind_nak reason %d\n",
584 pkt->u.bind_nak.reject_reason));
585 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
590 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
591 (pkt->u.bind_ack.num_results == 0) ||
592 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
593 composite_error(c, NT_STATUS_UNSUCCESSFUL);
597 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
598 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
600 /* the bind_ack might contain a reply set of credentials */
601 if (conn->security_state.auth_info &&
602 pkt->u.bind_ack.auth_info.length) {
603 c->status = ndr_pull_struct_blob(
604 &pkt->u.bind_ack.auth_info, conn,
605 conn->security_state.auth_info,
606 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
607 if (!composite_is_ok(c)) return;
614 handle timeouts of dcerpc bind and alter context requests
616 static void bind_timeout_handler(struct event_context *ev,
617 struct timed_event *te,
618 struct timeval t, void *private)
620 struct composite_context *ctx =
621 talloc_get_type(private, struct composite_context);
622 struct dcerpc_pipe *pipe = talloc_get_type(ctx->private_data, struct dcerpc_pipe);
624 SMB_ASSERT(pipe->conn->bind_private != NULL);
625 pipe->conn->bind_private = NULL;
626 composite_error(ctx, NT_STATUS_IO_TIMEOUT);
630 send a async dcerpc bind request
632 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
634 const struct dcerpc_syntax_id *syntax,
635 const struct dcerpc_syntax_id *transfer_syntax)
637 struct composite_context *c;
638 struct ncacn_packet pkt;
641 c = talloc_zero(mem_ctx, struct composite_context);
642 if (c == NULL) return NULL;
644 c->state = COMPOSITE_STATE_IN_PROGRESS;
646 c->event_ctx = p->conn->event_ctx;
649 p->transfer_syntax = *transfer_syntax;
651 init_ncacn_hdr(p->conn, &pkt);
653 pkt.ptype = DCERPC_PKT_BIND;
654 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
655 pkt.call_id = p->conn->call_id;
658 pkt.u.bind.max_xmit_frag = 5840;
659 pkt.u.bind.max_recv_frag = 5840;
660 pkt.u.bind.assoc_group_id = 0;
661 pkt.u.bind.num_contexts = 1;
662 pkt.u.bind.ctx_list =
663 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
664 if (pkt.u.bind.ctx_list == NULL) {
665 c->status = NT_STATUS_NO_MEMORY;
668 pkt.u.bind.ctx_list[0].context_id = p->context_id;
669 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
670 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
671 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
672 pkt.u.bind.auth_info = data_blob(NULL, 0);
674 /* construct the NDR form of the packet */
675 c->status = ncacn_push_auth(&blob, c, &pkt,
676 p->conn->security_state.auth_info);
677 if (!NT_STATUS_IS_OK(c->status)) {
681 p->conn->transport.recv_data = dcerpc_recv_data;
682 p->conn->bind_private = c;
684 c->status = p->conn->transport.send_request(p->conn, &blob,
686 if (!NT_STATUS_IS_OK(c->status)) {
690 event_add_timed(c->event_ctx, c,
691 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
692 bind_timeout_handler, c);
697 composite_error(c, c->status);
702 recv side of async dcerpc bind request
704 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
706 NTSTATUS result = composite_wait(ctx);
712 perform a bind using the given syntax
714 the auth_info structure is updated with the reply authentication info
717 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
719 const struct dcerpc_syntax_id *syntax,
720 const struct dcerpc_syntax_id *transfer_syntax)
722 struct composite_context *creq;
723 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
724 return dcerpc_bind_recv(creq);
728 perform a continued bind (and auth3)
730 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
733 struct ncacn_packet pkt;
737 init_ncacn_hdr(c, &pkt);
739 pkt.ptype = DCERPC_PKT_AUTH3;
740 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
741 pkt.call_id = next_call_id(c);
743 pkt.u.auth3._pad = 0;
744 pkt.u.auth3.auth_info = data_blob(NULL, 0);
746 /* construct the NDR form of the packet */
747 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
748 if (!NT_STATUS_IS_OK(status)) {
752 /* send it on its way */
753 status = c->transport.send_request(c, &blob, False);
754 if (!NT_STATUS_IS_OK(status)) {
763 return the rpc syntax and transfer syntax given the pipe uuid and version
765 NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
766 struct dcerpc_syntax_id *syntax,
767 struct dcerpc_syntax_id *transfer_syntax)
769 syntax->uuid = table->uuid;
770 syntax->if_version = table->if_version;
772 *transfer_syntax = ndr_transfer_syntax;
777 /* perform a dcerpc bind, using the uuid as the key */
778 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
780 const struct dcerpc_interface_table *table)
782 struct dcerpc_syntax_id syntax;
783 struct dcerpc_syntax_id transfer_syntax;
786 status = dcerpc_init_syntaxes(table,
787 &syntax, &transfer_syntax);
788 if (!NT_STATUS_IS_OK(status)) {
789 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
793 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
798 process a fragment received from the transport layer during a
801 This function frees the data
803 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
804 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
806 struct rpc_request *req;
808 NTSTATUS status = NT_STATUS_OK;
811 if this is an authenticated connection then parse and check
812 the auth info. We have to do this before finding the
813 matching packet, as the request structure might have been
814 removed due to a timeout, but if it has been we still need
815 to run the auth routines so that we don't get the sign/seal
816 info out of step with the server
818 if (c->security_state.auth_info && c->security_state.generic_state &&
819 pkt->ptype == DCERPC_PKT_RESPONSE) {
820 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
823 /* find the matching request */
824 for (req=c->pending;req;req=req->next) {
825 if (pkt->call_id == req->call_id) break;
829 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
830 data_blob_free(raw_packet);
834 talloc_steal(req, raw_packet->data);
836 if (pkt->ptype == DCERPC_PKT_FAULT) {
837 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
838 req->fault_code = pkt->u.fault.status;
839 req->status = NT_STATUS_NET_WRITE_FAULT;
843 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
844 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
846 req->fault_code = DCERPC_FAULT_OTHER;
847 req->status = NT_STATUS_NET_WRITE_FAULT;
851 /* now check the status from the auth routines, and if it failed then fail
852 this request accordingly */
853 if (!NT_STATUS_IS_OK(status)) {
854 req->status = status;
858 length = pkt->u.response.stub_and_verifier.length;
861 req->payload.data = talloc_realloc(req,
864 req->payload.length + length);
865 if (!req->payload.data) {
866 req->status = NT_STATUS_NO_MEMORY;
869 memcpy(req->payload.data+req->payload.length,
870 pkt->u.response.stub_and_verifier.data, length);
871 req->payload.length += length;
874 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
875 c->transport.send_read(c);
879 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
880 req->flags |= DCERPC_PULL_BIGENDIAN;
882 req->flags &= ~DCERPC_PULL_BIGENDIAN;
887 /* we've got the full payload */
888 req->state = RPC_REQUEST_DONE;
889 DLIST_REMOVE(c->pending, req);
891 if (c->request_queue != NULL) {
892 /* We have to look at shipping further requests before calling
893 * the async function, that one might close the pipe */
894 dcerpc_ship_next_request(c);
897 if (req->async.callback) {
898 req->async.callback(req);
903 handle timeouts of individual dcerpc requests
905 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
906 struct timeval t, void *private)
908 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
910 if (req->state != RPC_REQUEST_PENDING) {
914 req->status = NT_STATUS_IO_TIMEOUT;
915 req->state = RPC_REQUEST_DONE;
916 DLIST_REMOVE(req->p->conn->pending, req);
917 if (req->async.callback) {
918 req->async.callback(req);
924 make sure requests are cleaned up
926 static int dcerpc_req_destructor(void *ptr)
928 struct rpc_request *req = ptr;
929 DLIST_REMOVE(req->p->conn->pending, req);
934 perform the send side of a async dcerpc request
936 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
937 const struct GUID *object,
940 DATA_BLOB *stub_data)
942 struct rpc_request *req;
944 p->conn->transport.recv_data = dcerpc_recv_data;
946 req = talloc(p, struct rpc_request);
952 req->call_id = next_call_id(p->conn);
953 req->status = NT_STATUS_OK;
954 req->state = RPC_REQUEST_PENDING;
955 req->payload = data_blob(NULL, 0);
958 req->async_call = async;
959 req->async.callback = NULL;
961 if (object != NULL) {
962 req->object = talloc_memdup(req, object, sizeof(*object));
963 if (req->object == NULL) {
972 req->request_data.length = stub_data->length;
973 req->request_data.data = talloc_reference(req, stub_data->data);
974 if (req->request_data.data == NULL) {
978 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
980 dcerpc_ship_next_request(p->conn);
982 if (p->request_timeout) {
983 event_add_timed(dcerpc_event_context(p), req,
984 timeval_current_ofs(p->request_timeout, 0),
985 dcerpc_timeout_handler, req);
988 talloc_set_destructor(req, dcerpc_req_destructor);
993 Send a request using the transport
996 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
998 struct rpc_request *req;
999 struct dcerpc_pipe *p;
1000 DATA_BLOB *stub_data;
1001 struct ncacn_packet pkt;
1003 uint32_t remaining, chunk_size;
1004 BOOL first_packet = True;
1006 req = c->request_queue;
1012 stub_data = &req->request_data;
1014 if (!req->async_call && (c->pending != NULL)) {
1018 DLIST_REMOVE(c->request_queue, req);
1019 DLIST_ADD(c->pending, req);
1021 init_ncacn_hdr(p->conn, &pkt);
1023 remaining = stub_data->length;
1025 /* we can write a full max_recv_frag size, minus the dcerpc
1026 request header size */
1027 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1029 pkt.ptype = DCERPC_PKT_REQUEST;
1030 pkt.call_id = req->call_id;
1031 pkt.auth_length = 0;
1033 pkt.u.request.alloc_hint = remaining;
1034 pkt.u.request.context_id = p->context_id;
1035 pkt.u.request.opnum = req->opnum;
1038 pkt.u.request.object.object = *req->object;
1039 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1040 chunk_size -= ndr_size_GUID(req->object,0);
1043 /* we send a series of pdus without waiting for a reply */
1044 while (remaining > 0 || first_packet) {
1045 uint32_t chunk = MIN(chunk_size, remaining);
1046 BOOL last_frag = False;
1048 first_packet = False;
1049 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1051 if (remaining == stub_data->length) {
1052 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1054 if (chunk == remaining) {
1055 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1059 pkt.u.request.stub_and_verifier.data = stub_data->data +
1060 (stub_data->length - remaining);
1061 pkt.u.request.stub_and_verifier.length = chunk;
1063 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1064 if (!NT_STATUS_IS_OK(req->status)) {
1065 req->state = RPC_REQUEST_DONE;
1066 DLIST_REMOVE(p->conn->pending, req);
1070 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1071 if (!NT_STATUS_IS_OK(req->status)) {
1072 req->state = RPC_REQUEST_DONE;
1073 DLIST_REMOVE(p->conn->pending, req);
1082 return the event context for a dcerpc pipe
1083 used by callers who wish to operate asynchronously
1085 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1087 return p->conn->event_ctx;
1093 perform the receive side of a async dcerpc request
1095 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1096 TALLOC_CTX *mem_ctx,
1097 DATA_BLOB *stub_data)
1101 while (req->state == RPC_REQUEST_PENDING) {
1102 struct event_context *ctx = dcerpc_event_context(req->p);
1103 if (event_loop_once(ctx) != 0) {
1104 return NT_STATUS_CONNECTION_DISCONNECTED;
1107 *stub_data = req->payload;
1108 status = req->status;
1109 if (stub_data->data) {
1110 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1112 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1113 req->p->last_fault_code = req->fault_code;
1120 perform a full request/response pair on a dcerpc pipe
1122 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1123 struct GUID *object,
1126 TALLOC_CTX *mem_ctx,
1127 DATA_BLOB *stub_data_in,
1128 DATA_BLOB *stub_data_out)
1130 struct rpc_request *req;
1132 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1134 return NT_STATUS_NO_MEMORY;
1137 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1142 this is a paranoid NDR validator. For every packet we push onto the wire
1143 we pull it back again, then push it again. Then we compare the raw NDR data
1144 for that to the NDR we initially generated. If they don't match then we know
1145 we must have a bug in either the pull or push side of our code
1147 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1148 TALLOC_CTX *mem_ctx,
1151 ndr_push_flags_fn_t ndr_push,
1152 ndr_pull_flags_fn_t ndr_pull)
1155 struct ndr_pull *pull;
1156 struct ndr_push *push;
1160 st = talloc_size(mem_ctx, struct_size);
1162 return NT_STATUS_NO_MEMORY;
1165 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1167 return NT_STATUS_NO_MEMORY;
1169 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1171 status = ndr_pull(pull, NDR_IN, st);
1172 if (!NT_STATUS_IS_OK(status)) {
1173 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1174 "failed input validation pull - %s",
1178 push = ndr_push_init_ctx(mem_ctx);
1180 return NT_STATUS_NO_MEMORY;
1183 status = ndr_push(push, NDR_IN, st);
1184 if (!NT_STATUS_IS_OK(status)) {
1185 return ndr_push_error(push, NDR_ERR_VALIDATE,
1186 "failed input validation push - %s",
1190 blob2 = ndr_push_blob(push);
1192 if (!data_blob_equal(&blob, &blob2)) {
1193 DEBUG(3,("original:\n"));
1194 dump_data(3, blob.data, blob.length);
1195 DEBUG(3,("secondary:\n"));
1196 dump_data(3, blob2.data, blob2.length);
1197 return ndr_push_error(push, NDR_ERR_VALIDATE,
1198 "failed input validation data - %s",
1202 return NT_STATUS_OK;
1206 this is a paranoid NDR input validator. For every packet we pull
1207 from the wire we push it back again then pull and push it
1208 again. Then we compare the raw NDR data for that to the NDR we
1209 initially generated. If they don't match then we know we must have a
1210 bug in either the pull or push side of our code
1212 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1213 TALLOC_CTX *mem_ctx,
1216 ndr_push_flags_fn_t ndr_push,
1217 ndr_pull_flags_fn_t ndr_pull)
1220 struct ndr_pull *pull;
1221 struct ndr_push *push;
1223 DATA_BLOB blob, blob2;
1225 st = talloc_size(mem_ctx, struct_size);
1227 return NT_STATUS_NO_MEMORY;
1229 memcpy(st, struct_ptr, struct_size);
1231 push = ndr_push_init_ctx(mem_ctx);
1233 return NT_STATUS_NO_MEMORY;
1236 status = ndr_push(push, NDR_OUT, struct_ptr);
1237 if (!NT_STATUS_IS_OK(status)) {
1238 return ndr_push_error(push, NDR_ERR_VALIDATE,
1239 "failed output validation push - %s",
1243 blob = ndr_push_blob(push);
1245 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1247 return NT_STATUS_NO_MEMORY;
1250 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1251 status = ndr_pull(pull, NDR_OUT, st);
1252 if (!NT_STATUS_IS_OK(status)) {
1253 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1254 "failed output validation pull - %s",
1258 push = ndr_push_init_ctx(mem_ctx);
1260 return NT_STATUS_NO_MEMORY;
1263 status = ndr_push(push, NDR_OUT, st);
1264 if (!NT_STATUS_IS_OK(status)) {
1265 return ndr_push_error(push, NDR_ERR_VALIDATE,
1266 "failed output validation push2 - %s",
1270 blob2 = ndr_push_blob(push);
1272 if (!data_blob_equal(&blob, &blob2)) {
1273 DEBUG(3,("original:\n"));
1274 dump_data(3, blob.data, blob.length);
1275 DEBUG(3,("secondary:\n"));
1276 dump_data(3, blob2.data, blob2.length);
1277 return ndr_push_error(push, NDR_ERR_VALIDATE,
1278 "failed output validation data - %s",
1282 return NT_STATUS_OK;
1287 send a rpc request given a dcerpc_call structure
1289 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1290 const struct GUID *object,
1291 const struct dcerpc_interface_table *table,
1293 TALLOC_CTX *mem_ctx,
1296 const struct dcerpc_interface_call *call;
1297 struct ndr_push *push;
1300 struct rpc_request *req;
1302 call = &table->calls[opnum];
1304 /* setup for a ndr_push_* call */
1305 push = ndr_push_init_ctx(mem_ctx);
1310 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1311 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1314 /* push the structure into a blob */
1315 status = call->ndr_push(push, NDR_IN, r);
1316 if (!NT_STATUS_IS_OK(status)) {
1317 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1318 nt_errstr(status)));
1323 /* retrieve the blob */
1324 request = ndr_push_blob(push);
1326 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1327 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1328 call->ndr_push, call->ndr_pull);
1329 if (!NT_STATUS_IS_OK(status)) {
1330 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1331 nt_errstr(status)));
1337 DEBUG(10,("rpc request data:\n"));
1338 dump_data(10, request.data, request.length);
1340 /* make the actual dcerpc request */
1341 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1345 req->ndr.table = table;
1346 req->ndr.opnum = opnum;
1347 req->ndr.struct_ptr = r;
1348 req->ndr.mem_ctx = mem_ctx;
1357 receive the answer from a dcerpc_ndr_request_send()
1359 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1361 struct dcerpc_pipe *p = req->p;
1364 struct ndr_pull *pull;
1366 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1367 void *r = req->ndr.struct_ptr;
1368 uint32_t opnum = req->ndr.opnum;
1369 const struct dcerpc_interface_table *table = req->ndr.table;
1370 const struct dcerpc_interface_call *call = &table->calls[opnum];
1372 /* make sure the recv code doesn't free the request, as we
1373 need to grab the flags element before it is freed */
1374 talloc_increase_ref_count(req);
1376 status = dcerpc_request_recv(req, mem_ctx, &response);
1377 if (!NT_STATUS_IS_OK(status)) {
1383 /* prepare for ndr_pull_* */
1384 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1387 return NT_STATUS_NO_MEMORY;
1391 pull->data = talloc_steal(pull, pull->data);
1395 if (flags & DCERPC_PULL_BIGENDIAN) {
1396 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1399 DEBUG(10,("rpc reply data:\n"));
1400 dump_data(10, pull->data, pull->data_size);
1402 /* pull the structure from the blob */
1403 status = call->ndr_pull(pull, NDR_OUT, r);
1404 if (!NT_STATUS_IS_OK(status)) {
1405 dcerpc_log_packet(table, opnum, NDR_OUT,
1410 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1411 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1412 call->ndr_push, call->ndr_pull);
1413 if (!NT_STATUS_IS_OK(status)) {
1414 dcerpc_log_packet(table, opnum, NDR_OUT,
1420 if (pull->offset != pull->data_size) {
1421 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1422 pull->data_size - pull->offset));
1423 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1424 but it turns out that early versions of NT
1425 (specifically NT3.1) add junk onto the end of rpc
1426 packets, so if we want to interoperate at all with
1427 those versions then we need to ignore this error */
1430 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1432 return NT_STATUS_OK;
1437 a useful helper function for synchronous rpc requests
1439 this can be used when you have ndr push/pull functions in the
1442 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1443 const struct GUID *object,
1444 const struct dcerpc_interface_table *table,
1446 TALLOC_CTX *mem_ctx,
1449 struct rpc_request *req;
1451 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1453 return NT_STATUS_NO_MEMORY;
1456 return dcerpc_ndr_request_recv(req);
1461 a useful function for retrieving the server name we connected to
1463 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1465 if (!p->conn->transport.peer_name) {
1468 return p->conn->transport.peer_name(p->conn);
1473 get the dcerpc auth_level for a open connection
1475 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1479 if (c->flags & DCERPC_SEAL) {
1480 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1481 } else if (c->flags & DCERPC_SIGN) {
1482 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1483 } else if (c->flags & DCERPC_CONNECT) {
1484 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1486 auth_level = DCERPC_AUTH_LEVEL_NONE;
1492 Receive an alter reply from the transport
1494 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
1496 struct composite_context *c;
1497 struct dcerpc_pipe *pipe;
1499 c = talloc_get_type(conn->alter_private, struct composite_context);
1500 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1502 /* mark the connection as not waiting for a alter context reply */
1503 conn->alter_private = NULL;
1505 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1506 pkt->u.alter_resp.num_results == 1 &&
1507 pkt->u.alter_resp.ctx_list[0].result != 0) {
1508 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1509 pkt->u.alter_resp.ctx_list[0].reason));
1510 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1514 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1515 pkt->u.alter_resp.num_results == 0 ||
1516 pkt->u.alter_resp.ctx_list[0].result != 0) {
1517 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1521 /* the alter_resp might contain a reply set of credentials */
1522 if (pipe->conn->security_state.auth_info &&
1523 pkt->u.alter_resp.auth_info.length) {
1524 c->status = ndr_pull_struct_blob(
1525 &pkt->u.alter_resp.auth_info, pipe,
1526 pipe->conn->security_state.auth_info,
1527 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1528 if (!composite_is_ok(c)) return;
1535 send a dcerpc alter_context request
1537 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1538 TALLOC_CTX *mem_ctx,
1539 const struct dcerpc_syntax_id *syntax,
1540 const struct dcerpc_syntax_id *transfer_syntax)
1542 struct composite_context *c;
1543 struct ncacn_packet pkt;
1546 c = talloc_zero(mem_ctx, struct composite_context);
1547 if (c == NULL) return NULL;
1549 c->state = COMPOSITE_STATE_IN_PROGRESS;
1550 c->private_data = p;
1551 c->event_ctx = p->conn->event_ctx;
1553 p->syntax = *syntax;
1554 p->transfer_syntax = *transfer_syntax;
1556 init_ncacn_hdr(p->conn, &pkt);
1558 pkt.ptype = DCERPC_PKT_ALTER;
1559 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1560 pkt.call_id = p->conn->call_id;
1561 pkt.auth_length = 0;
1563 pkt.u.alter.max_xmit_frag = 5840;
1564 pkt.u.alter.max_recv_frag = 5840;
1565 pkt.u.alter.assoc_group_id = 0;
1566 pkt.u.alter.num_contexts = 1;
1567 pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1568 struct dcerpc_ctx_list, 1);
1569 if (pkt.u.alter.ctx_list == NULL) {
1570 c->status = NT_STATUS_NO_MEMORY;
1573 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1574 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1575 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1576 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1577 pkt.u.alter.auth_info = data_blob(NULL, 0);
1579 /* construct the NDR form of the packet */
1580 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1581 p->conn->security_state.auth_info);
1582 if (!NT_STATUS_IS_OK(c->status)) {
1586 p->conn->transport.recv_data = dcerpc_recv_data;
1587 p->conn->alter_private = c;
1589 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1590 if (!NT_STATUS_IS_OK(c->status)) {
1594 event_add_timed(c->event_ctx, c,
1595 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1596 bind_timeout_handler, c);
1601 composite_error(c, c->status);
1605 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1607 NTSTATUS result = composite_wait(ctx);
1613 send a dcerpc alter_context request
1615 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1616 TALLOC_CTX *mem_ctx,
1617 const struct dcerpc_syntax_id *syntax,
1618 const struct dcerpc_syntax_id *transfer_syntax)
1620 struct composite_context *creq;
1621 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1622 return dcerpc_alter_context_recv(creq);