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"
32 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
34 struct dcerpc_interface_list *dcerpc_pipes = NULL;
37 register a dcerpc client interface
39 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
41 struct dcerpc_interface_list *l;
43 for (l = dcerpc_pipes; l; l = l->next) {
44 if (GUID_equal(&interface->uuid, &l->table->uuid)) {
45 DEBUG(0, ("Attempt to register interface %s which has the "
46 "same UUID as already registered interface %s\n",
47 interface->name, l->table->name));
48 return NT_STATUS_OBJECT_NAME_COLLISION;
52 l = talloc(talloc_autofree_context(), struct dcerpc_interface_list);
55 DLIST_ADD(dcerpc_pipes, l);
60 /* destroy a dcerpc connection */
61 static int dcerpc_connection_destructor(void *ptr)
63 struct dcerpc_connection *c = ptr;
64 if (c->transport.shutdown_pipe) {
65 c->transport.shutdown_pipe(c);
71 /* initialise a dcerpc connection.
72 the event context is optional
74 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
75 struct event_context *ev)
77 struct dcerpc_connection *c;
79 c = talloc_zero(mem_ctx, struct dcerpc_connection);
85 ev = event_context_init(c);
94 c->security_state.auth_info = NULL;
95 c->security_state.session_key = dcerpc_generic_session_key;
96 c->security_state.generic_state = NULL;
97 c->binding_string = NULL;
99 c->srv_max_xmit_frag = 0;
100 c->srv_max_recv_frag = 0;
103 talloc_set_destructor(c, dcerpc_connection_destructor);
108 /* initialise a dcerpc pipe. */
109 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
111 struct dcerpc_pipe *p;
113 p = talloc(mem_ctx, struct dcerpc_pipe);
118 p->conn = dcerpc_connection_init(p, ev);
119 if (p->conn == NULL) {
124 p->last_fault_code = 0;
126 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
128 ZERO_STRUCT(p->syntax);
129 ZERO_STRUCT(p->transfer_syntax);
136 choose the next call id to use
138 static uint32_t next_call_id(struct dcerpc_connection *c)
141 if (c->call_id == 0) {
147 /* we need to be able to get/set the fragment length without doing a full
149 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
151 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
152 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
154 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
158 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
160 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
161 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
163 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
167 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
169 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
170 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
172 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
178 setup for a ndr pull, also setting up any flags from the binding string
180 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
181 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
183 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
185 if (ndr == NULL) return ndr;
187 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
188 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
191 if (c->flags & DCERPC_NDR_REF_ALLOC) {
192 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
199 parse a data blob into a ncacn_packet structure. This handles both
200 input and output packets
202 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
203 struct ncacn_packet *pkt)
205 struct ndr_pull *ndr;
207 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
209 return NT_STATUS_NO_MEMORY;
212 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
213 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
216 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
220 generate a CONNECT level verifier
222 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
224 *blob = data_blob_talloc(mem_ctx, NULL, 16);
225 if (blob->data == NULL) {
226 return NT_STATUS_NO_MEMORY;
228 SIVAL(blob->data, 0, 1);
229 memset(blob->data+4, 0, 12);
234 check a CONNECT level verifier
236 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
238 if (blob->length != 16 ||
239 IVAL(blob->data, 0) != 1) {
240 return NT_STATUS_ACCESS_DENIED;
246 parse the authentication information on a dcerpc response packet
248 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
249 DATA_BLOB *raw_packet,
250 struct ncacn_packet *pkt)
252 struct ndr_pull *ndr;
254 struct dcerpc_auth auth;
257 if (pkt->auth_length == 0 &&
258 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
262 auth_blob.length = 8 + pkt->auth_length;
264 /* check for a valid length */
265 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
266 return NT_STATUS_INFO_LENGTH_MISMATCH;
270 pkt->u.response.stub_and_verifier.data +
271 pkt->u.response.stub_and_verifier.length - auth_blob.length;
272 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
274 /* pull the auth structure */
275 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
277 return NT_STATUS_NO_MEMORY;
280 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
281 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
284 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
285 if (!NT_STATUS_IS_OK(status)) {
290 /* check signature or unseal the packet */
291 switch (c->security_state.auth_info->auth_level) {
292 case DCERPC_AUTH_LEVEL_PRIVACY:
293 status = gensec_unseal_packet(c->security_state.generic_state,
295 raw_packet->data + DCERPC_REQUEST_LENGTH,
296 pkt->u.response.stub_and_verifier.length,
298 raw_packet->length - auth.credentials.length,
300 memcpy(pkt->u.response.stub_and_verifier.data,
301 raw_packet->data + DCERPC_REQUEST_LENGTH,
302 pkt->u.response.stub_and_verifier.length);
305 case DCERPC_AUTH_LEVEL_INTEGRITY:
306 status = gensec_check_packet(c->security_state.generic_state,
308 pkt->u.response.stub_and_verifier.data,
309 pkt->u.response.stub_and_verifier.length,
311 raw_packet->length - auth.credentials.length,
315 case DCERPC_AUTH_LEVEL_CONNECT:
316 status = dcerpc_check_connect_verifier(&auth.credentials);
319 case DCERPC_AUTH_LEVEL_NONE:
323 status = NT_STATUS_INVALID_LEVEL;
327 /* remove the indicated amount of paddiing */
328 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
329 return NT_STATUS_INFO_LENGTH_MISMATCH;
331 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
338 push a dcerpc request packet into a blob, possibly signing it.
340 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
341 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
342 struct ncacn_packet *pkt)
345 struct ndr_push *ndr;
347 size_t payload_length;
349 /* non-signed packets are simpler */
350 if (!c->security_state.auth_info ||
351 !c->security_state.generic_state) {
352 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
355 ndr = ndr_push_init_ctx(mem_ctx);
357 return NT_STATUS_NO_MEMORY;
360 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
361 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
364 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
365 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
368 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
369 if (!NT_STATUS_IS_OK(status)) {
373 /* pad to 16 byte multiple in the payload portion of the
374 packet. This matches what w2k3 does */
375 c->security_state.auth_info->auth_pad_length =
376 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
377 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
379 payload_length = pkt->u.request.stub_and_verifier.length +
380 c->security_state.auth_info->auth_pad_length;
382 /* sign or seal the packet */
383 switch (c->security_state.auth_info->auth_level) {
384 case DCERPC_AUTH_LEVEL_PRIVACY:
385 case DCERPC_AUTH_LEVEL_INTEGRITY:
386 c->security_state.auth_info->credentials
387 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
389 data_blob_clear(&c->security_state.auth_info->credentials);
392 case DCERPC_AUTH_LEVEL_CONNECT:
393 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
396 case DCERPC_AUTH_LEVEL_NONE:
397 c->security_state.auth_info->credentials = data_blob(NULL, 0);
401 status = NT_STATUS_INVALID_LEVEL;
405 if (!NT_STATUS_IS_OK(status)) {
409 /* add the auth verifier */
410 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
411 if (!NT_STATUS_IS_OK(status)) {
415 /* extract the whole packet as a blob */
416 *blob = ndr_push_blob(ndr);
418 /* fill in the fragment length and auth_length, we can't fill
419 in these earlier as we don't know the signature length (it
420 could be variable length) */
421 dcerpc_set_frag_length(blob, blob->length);
422 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
424 /* sign or seal the packet */
425 switch (c->security_state.auth_info->auth_level) {
426 case DCERPC_AUTH_LEVEL_PRIVACY:
427 status = gensec_seal_packet(c->security_state.generic_state,
429 blob->data + DCERPC_REQUEST_LENGTH,
433 c->security_state.auth_info->credentials.length,
435 if (!NT_STATUS_IS_OK(status)) {
438 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
441 case DCERPC_AUTH_LEVEL_INTEGRITY:
442 status = gensec_sign_packet(c->security_state.generic_state,
444 blob->data + DCERPC_REQUEST_LENGTH,
448 c->security_state.auth_info->credentials.length,
450 if (!NT_STATUS_IS_OK(status)) {
453 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
456 case DCERPC_AUTH_LEVEL_CONNECT:
459 case DCERPC_AUTH_LEVEL_NONE:
460 c->security_state.auth_info->credentials = data_blob(NULL, 0);
464 status = NT_STATUS_INVALID_LEVEL;
468 data_blob_free(&c->security_state.auth_info->credentials);
475 fill in the fixed values in a dcerpc header
477 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
480 pkt->rpc_vers_minor = 0;
481 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
484 pkt->drep[0] = DCERPC_DREP_LE;
492 map a bind nak reason to a NTSTATUS
494 static NTSTATUS dcerpc_map_reason(uint16_t reason)
497 case DCERPC_BIND_REASON_ASYNTAX:
498 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
500 return NT_STATUS_UNSUCCESSFUL;
504 mark the dcerpc connection dead. All outstanding requests get an error
506 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
508 /* all pending requests get the error */
509 while (conn->pending) {
510 struct rpc_request *req = conn->pending;
511 req->state = RPC_REQUEST_DONE;
512 req->status = status;
513 DLIST_REMOVE(conn->pending, req);
514 if (req->async.callback) {
515 req->async.callback(req);
519 if (conn->bind_private) {
520 /* a bind was in flight - fail it */
521 struct composite_context *c = talloc_get_type(conn->bind_private, struct composite_context);
522 composite_error(c, status);
525 if (conn->alter_private) {
526 /* a alter context was in flight - fail it */
527 struct composite_context *c = talloc_get_type(conn->alter_private, struct composite_context);
528 composite_error(c, status);
533 forward declarations of the recv_data handlers for the 3 types of packets we need
536 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
537 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
538 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
539 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
542 receive a dcerpc reply from the transport. Here we work out what
543 type of reply it is (normal request, bind or alter context) and
544 dispatch to the appropriate handler
546 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
548 struct ncacn_packet pkt;
550 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
551 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
554 /* the transport may be telling us of a severe error, such as
556 if (!NT_STATUS_IS_OK(status)) {
557 data_blob_free(blob);
558 dcerpc_connection_dead(conn, status);
562 /* parse the basic packet to work out what type of response this is */
563 status = ncacn_pull(conn, blob, blob->data, &pkt);
564 if (!NT_STATUS_IS_OK(status)) {
565 data_blob_free(blob);
566 dcerpc_connection_dead(conn, status);
570 case DCERPC_PKT_BIND_NAK:
571 case DCERPC_PKT_BIND_ACK:
572 if (conn->bind_private) {
573 talloc_steal(conn->bind_private, blob->data);
574 dcerpc_bind_recv_data(conn, &pkt);
578 case DCERPC_PKT_ALTER_RESP:
579 if (conn->alter_private) {
580 talloc_steal(conn->alter_private, blob->data);
581 dcerpc_alter_recv_data(conn, &pkt);
586 /* assume its an ordinary request */
587 dcerpc_request_recv_data(conn, blob, &pkt);
594 Receive a bind reply from the transport
596 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
598 struct composite_context *c;
599 struct dcerpc_pipe *pipe;
601 c = talloc_get_type(conn->bind_private, struct composite_context);
602 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
604 /* mark the connection as not waiting for a bind reply */
605 conn->bind_private = NULL;
607 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
608 DEBUG(2,("dcerpc: bind_nak reason %d\n",
609 pkt->u.bind_nak.reject_reason));
610 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
615 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
616 (pkt->u.bind_ack.num_results == 0) ||
617 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
618 composite_error(c, NT_STATUS_UNSUCCESSFUL);
622 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
623 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
625 /* the bind_ack might contain a reply set of credentials */
626 if (conn->security_state.auth_info &&
627 pkt->u.bind_ack.auth_info.length) {
628 c->status = ndr_pull_struct_blob(
629 &pkt->u.bind_ack.auth_info, conn,
630 conn->security_state.auth_info,
631 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
632 if (!composite_is_ok(c)) return;
639 handle timeouts of dcerpc bind and alter context requests
641 static void bind_timeout_handler(struct event_context *ev,
642 struct timed_event *te,
643 struct timeval t, void *private)
645 struct composite_context *ctx =
646 talloc_get_type(private, struct composite_context);
647 struct dcerpc_pipe *pipe = talloc_get_type(ctx->private_data, struct dcerpc_pipe);
649 SMB_ASSERT(pipe->conn->bind_private != NULL);
650 pipe->conn->bind_private = NULL;
651 composite_error(ctx, NT_STATUS_IO_TIMEOUT);
655 send a async dcerpc bind request
657 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
659 const struct dcerpc_syntax_id *syntax,
660 const struct dcerpc_syntax_id *transfer_syntax)
662 struct composite_context *c;
663 struct ncacn_packet pkt;
666 c = talloc_zero(mem_ctx, struct composite_context);
667 if (c == NULL) return NULL;
669 c->state = COMPOSITE_STATE_IN_PROGRESS;
671 c->event_ctx = p->conn->event_ctx;
674 p->transfer_syntax = *transfer_syntax;
676 init_ncacn_hdr(p->conn, &pkt);
678 pkt.ptype = DCERPC_PKT_BIND;
679 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
680 pkt.call_id = p->conn->call_id;
683 pkt.u.bind.max_xmit_frag = 5840;
684 pkt.u.bind.max_recv_frag = 5840;
685 pkt.u.bind.assoc_group_id = 0;
686 pkt.u.bind.num_contexts = 1;
687 pkt.u.bind.ctx_list =
688 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
689 if (pkt.u.bind.ctx_list == NULL) {
690 c->status = NT_STATUS_NO_MEMORY;
693 pkt.u.bind.ctx_list[0].context_id = p->context_id;
694 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
695 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
696 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
697 pkt.u.bind.auth_info = data_blob(NULL, 0);
699 /* construct the NDR form of the packet */
700 c->status = ncacn_push_auth(&blob, c, &pkt,
701 p->conn->security_state.auth_info);
702 if (!NT_STATUS_IS_OK(c->status)) {
706 p->conn->transport.recv_data = dcerpc_recv_data;
707 p->conn->bind_private = c;
709 c->status = p->conn->transport.send_request(p->conn, &blob,
711 if (!NT_STATUS_IS_OK(c->status)) {
715 event_add_timed(c->event_ctx, c,
716 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
717 bind_timeout_handler, c);
722 composite_error(c, c->status);
727 recv side of async dcerpc bind request
729 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
731 NTSTATUS result = composite_wait(ctx);
737 perform a bind using the given syntax
739 the auth_info structure is updated with the reply authentication info
742 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
744 const struct dcerpc_syntax_id *syntax,
745 const struct dcerpc_syntax_id *transfer_syntax)
747 struct composite_context *creq;
748 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
749 return dcerpc_bind_recv(creq);
753 perform a continued bind (and auth3)
755 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
758 struct ncacn_packet pkt;
762 init_ncacn_hdr(c, &pkt);
764 pkt.ptype = DCERPC_PKT_AUTH3;
765 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
766 pkt.call_id = next_call_id(c);
768 pkt.u.auth3._pad = 0;
769 pkt.u.auth3.auth_info = data_blob(NULL, 0);
771 /* construct the NDR form of the packet */
772 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
773 if (!NT_STATUS_IS_OK(status)) {
777 /* send it on its way */
778 status = c->transport.send_request(c, &blob, False);
779 if (!NT_STATUS_IS_OK(status)) {
788 return the rpc syntax and transfer syntax given the pipe uuid and version
790 NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
791 struct dcerpc_syntax_id *syntax,
792 struct dcerpc_syntax_id *transfer_syntax)
794 syntax->uuid = table->uuid;
795 syntax->if_version = table->if_version;
797 *transfer_syntax = ndr_transfer_syntax;
802 /* perform a dcerpc bind, using the uuid as the key */
803 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
805 const struct dcerpc_interface_table *table)
807 struct dcerpc_syntax_id syntax;
808 struct dcerpc_syntax_id transfer_syntax;
811 status = dcerpc_init_syntaxes(table,
812 &syntax, &transfer_syntax);
813 if (!NT_STATUS_IS_OK(status)) {
814 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
818 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
823 process a fragment received from the transport layer during a
826 This function frees the data
828 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
829 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
831 struct rpc_request *req;
833 NTSTATUS status = NT_STATUS_OK;
836 if this is an authenticated connection then parse and check
837 the auth info. We have to do this before finding the
838 matching packet, as the request structure might have been
839 removed due to a timeout, but if it has been we still need
840 to run the auth routines so that we don't get the sign/seal
841 info out of step with the server
843 if (c->security_state.auth_info && c->security_state.generic_state &&
844 pkt->ptype == DCERPC_PKT_RESPONSE) {
845 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
848 /* find the matching request */
849 for (req=c->pending;req;req=req->next) {
850 if (pkt->call_id == req->call_id) break;
854 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
855 data_blob_free(raw_packet);
859 talloc_steal(req, raw_packet->data);
861 if (pkt->ptype == DCERPC_PKT_FAULT) {
862 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
863 req->fault_code = pkt->u.fault.status;
864 req->status = NT_STATUS_NET_WRITE_FAULT;
868 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
869 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
871 req->fault_code = DCERPC_FAULT_OTHER;
872 req->status = NT_STATUS_NET_WRITE_FAULT;
876 /* now check the status from the auth routines, and if it failed then fail
877 this request accordingly */
878 if (!NT_STATUS_IS_OK(status)) {
879 req->status = status;
883 length = pkt->u.response.stub_and_verifier.length;
886 req->payload.data = talloc_realloc(req,
889 req->payload.length + length);
890 if (!req->payload.data) {
891 req->status = NT_STATUS_NO_MEMORY;
894 memcpy(req->payload.data+req->payload.length,
895 pkt->u.response.stub_and_verifier.data, length);
896 req->payload.length += length;
899 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
900 c->transport.send_read(c);
904 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
905 req->flags |= DCERPC_PULL_BIGENDIAN;
907 req->flags &= ~DCERPC_PULL_BIGENDIAN;
912 /* we've got the full payload */
913 req->state = RPC_REQUEST_DONE;
914 DLIST_REMOVE(c->pending, req);
916 if (c->request_queue != NULL) {
917 /* We have to look at shipping further requests before calling
918 * the async function, that one might close the pipe */
919 dcerpc_ship_next_request(c);
922 if (req->async.callback) {
923 req->async.callback(req);
928 handle timeouts of individual dcerpc requests
930 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
931 struct timeval t, void *private)
933 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
935 if (req->state != RPC_REQUEST_PENDING) {
939 req->status = NT_STATUS_IO_TIMEOUT;
940 req->state = RPC_REQUEST_DONE;
941 DLIST_REMOVE(req->p->conn->pending, req);
942 if (req->async.callback) {
943 req->async.callback(req);
949 make sure requests are cleaned up
951 static int dcerpc_req_destructor(void *ptr)
953 struct rpc_request *req = ptr;
954 DLIST_REMOVE(req->p->conn->pending, req);
959 perform the send side of a async dcerpc request
961 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
962 const struct GUID *object,
965 DATA_BLOB *stub_data)
967 struct rpc_request *req;
969 p->conn->transport.recv_data = dcerpc_recv_data;
971 req = talloc(p, struct rpc_request);
977 req->call_id = next_call_id(p->conn);
978 req->status = NT_STATUS_OK;
979 req->state = RPC_REQUEST_PENDING;
980 req->payload = data_blob(NULL, 0);
983 req->async_call = async;
984 req->async.callback = NULL;
986 if (object != NULL) {
987 req->object = talloc_memdup(req, object, sizeof(*object));
988 if (req->object == NULL) {
997 req->request_data.length = stub_data->length;
998 req->request_data.data = talloc_reference(req, stub_data->data);
999 if (req->request_data.data == NULL) {
1003 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1005 dcerpc_ship_next_request(p->conn);
1007 if (p->request_timeout) {
1008 event_add_timed(dcerpc_event_context(p), req,
1009 timeval_current_ofs(p->request_timeout, 0),
1010 dcerpc_timeout_handler, req);
1013 talloc_set_destructor(req, dcerpc_req_destructor);
1018 Send a request using the transport
1021 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1023 struct rpc_request *req;
1024 struct dcerpc_pipe *p;
1025 DATA_BLOB *stub_data;
1026 struct ncacn_packet pkt;
1028 uint32_t remaining, chunk_size;
1029 BOOL first_packet = True;
1031 req = c->request_queue;
1037 stub_data = &req->request_data;
1039 if (!req->async_call && (c->pending != NULL)) {
1043 DLIST_REMOVE(c->request_queue, req);
1044 DLIST_ADD(c->pending, req);
1046 init_ncacn_hdr(p->conn, &pkt);
1048 remaining = stub_data->length;
1050 /* we can write a full max_recv_frag size, minus the dcerpc
1051 request header size */
1052 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1054 pkt.ptype = DCERPC_PKT_REQUEST;
1055 pkt.call_id = req->call_id;
1056 pkt.auth_length = 0;
1058 pkt.u.request.alloc_hint = remaining;
1059 pkt.u.request.context_id = p->context_id;
1060 pkt.u.request.opnum = req->opnum;
1063 pkt.u.request.object.object = *req->object;
1064 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1065 chunk_size -= ndr_size_GUID(req->object,0);
1068 /* we send a series of pdus without waiting for a reply */
1069 while (remaining > 0 || first_packet) {
1070 uint32_t chunk = MIN(chunk_size, remaining);
1071 BOOL last_frag = False;
1073 first_packet = False;
1074 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1076 if (remaining == stub_data->length) {
1077 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1079 if (chunk == remaining) {
1080 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1084 pkt.u.request.stub_and_verifier.data = stub_data->data +
1085 (stub_data->length - remaining);
1086 pkt.u.request.stub_and_verifier.length = chunk;
1088 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1089 if (!NT_STATUS_IS_OK(req->status)) {
1090 req->state = RPC_REQUEST_DONE;
1091 DLIST_REMOVE(p->conn->pending, req);
1095 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1096 if (!NT_STATUS_IS_OK(req->status)) {
1097 req->state = RPC_REQUEST_DONE;
1098 DLIST_REMOVE(p->conn->pending, req);
1107 return the event context for a dcerpc pipe
1108 used by callers who wish to operate asynchronously
1110 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1112 return p->conn->event_ctx;
1118 perform the receive side of a async dcerpc request
1120 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1121 TALLOC_CTX *mem_ctx,
1122 DATA_BLOB *stub_data)
1126 while (req->state == RPC_REQUEST_PENDING) {
1127 struct event_context *ctx = dcerpc_event_context(req->p);
1128 if (event_loop_once(ctx) != 0) {
1129 return NT_STATUS_CONNECTION_DISCONNECTED;
1132 *stub_data = req->payload;
1133 status = req->status;
1134 if (stub_data->data) {
1135 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1137 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1138 req->p->last_fault_code = req->fault_code;
1145 perform a full request/response pair on a dcerpc pipe
1147 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1148 struct GUID *object,
1151 TALLOC_CTX *mem_ctx,
1152 DATA_BLOB *stub_data_in,
1153 DATA_BLOB *stub_data_out)
1155 struct rpc_request *req;
1157 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1159 return NT_STATUS_NO_MEMORY;
1162 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1167 this is a paranoid NDR validator. For every packet we push onto the wire
1168 we pull it back again, then push it again. Then we compare the raw NDR data
1169 for that to the NDR we initially generated. If they don't match then we know
1170 we must have a bug in either the pull or push side of our code
1172 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1173 TALLOC_CTX *mem_ctx,
1176 ndr_push_flags_fn_t ndr_push,
1177 ndr_pull_flags_fn_t ndr_pull)
1180 struct ndr_pull *pull;
1181 struct ndr_push *push;
1185 st = talloc_size(mem_ctx, struct_size);
1187 return NT_STATUS_NO_MEMORY;
1190 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1192 return NT_STATUS_NO_MEMORY;
1194 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1196 status = ndr_pull(pull, NDR_IN, st);
1197 if (!NT_STATUS_IS_OK(status)) {
1198 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1199 "failed input validation pull - %s",
1203 push = ndr_push_init_ctx(mem_ctx);
1205 return NT_STATUS_NO_MEMORY;
1208 status = ndr_push(push, NDR_IN, st);
1209 if (!NT_STATUS_IS_OK(status)) {
1210 return ndr_push_error(push, NDR_ERR_VALIDATE,
1211 "failed input validation push - %s",
1215 blob2 = ndr_push_blob(push);
1217 if (!data_blob_equal(&blob, &blob2)) {
1218 DEBUG(3,("original:\n"));
1219 dump_data(3, blob.data, blob.length);
1220 DEBUG(3,("secondary:\n"));
1221 dump_data(3, blob2.data, blob2.length);
1222 return ndr_push_error(push, NDR_ERR_VALIDATE,
1223 "failed input validation data - %s",
1227 return NT_STATUS_OK;
1231 this is a paranoid NDR input validator. For every packet we pull
1232 from the wire we push it back again then pull and push it
1233 again. Then we compare the raw NDR data for that to the NDR we
1234 initially generated. If they don't match then we know we must have a
1235 bug in either the pull or push side of our code
1237 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1238 TALLOC_CTX *mem_ctx,
1241 ndr_push_flags_fn_t ndr_push,
1242 ndr_pull_flags_fn_t ndr_pull)
1245 struct ndr_pull *pull;
1246 struct ndr_push *push;
1248 DATA_BLOB blob, blob2;
1250 st = talloc_size(mem_ctx, struct_size);
1252 return NT_STATUS_NO_MEMORY;
1254 memcpy(st, struct_ptr, struct_size);
1256 push = ndr_push_init_ctx(mem_ctx);
1258 return NT_STATUS_NO_MEMORY;
1261 status = ndr_push(push, NDR_OUT, struct_ptr);
1262 if (!NT_STATUS_IS_OK(status)) {
1263 return ndr_push_error(push, NDR_ERR_VALIDATE,
1264 "failed output validation push - %s",
1268 blob = ndr_push_blob(push);
1270 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1272 return NT_STATUS_NO_MEMORY;
1275 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1276 status = ndr_pull(pull, NDR_OUT, st);
1277 if (!NT_STATUS_IS_OK(status)) {
1278 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1279 "failed output validation pull - %s",
1283 push = ndr_push_init_ctx(mem_ctx);
1285 return NT_STATUS_NO_MEMORY;
1288 status = ndr_push(push, NDR_OUT, st);
1289 if (!NT_STATUS_IS_OK(status)) {
1290 return ndr_push_error(push, NDR_ERR_VALIDATE,
1291 "failed output validation push2 - %s",
1295 blob2 = ndr_push_blob(push);
1297 if (!data_blob_equal(&blob, &blob2)) {
1298 DEBUG(3,("original:\n"));
1299 dump_data(3, blob.data, blob.length);
1300 DEBUG(3,("secondary:\n"));
1301 dump_data(3, blob2.data, blob2.length);
1302 return ndr_push_error(push, NDR_ERR_VALIDATE,
1303 "failed output validation data - %s",
1307 return NT_STATUS_OK;
1312 send a rpc request given a dcerpc_call structure
1314 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1315 const struct GUID *object,
1316 const struct dcerpc_interface_table *table,
1318 TALLOC_CTX *mem_ctx,
1321 const struct dcerpc_interface_call *call;
1322 struct ndr_push *push;
1325 struct rpc_request *req;
1327 call = &table->calls[opnum];
1329 /* setup for a ndr_push_* call */
1330 push = ndr_push_init_ctx(mem_ctx);
1335 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1336 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1339 /* push the structure into a blob */
1340 status = call->ndr_push(push, NDR_IN, r);
1341 if (!NT_STATUS_IS_OK(status)) {
1342 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1343 nt_errstr(status)));
1348 /* retrieve the blob */
1349 request = ndr_push_blob(push);
1351 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1352 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1353 call->ndr_push, call->ndr_pull);
1354 if (!NT_STATUS_IS_OK(status)) {
1355 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1356 nt_errstr(status)));
1362 DEBUG(10,("rpc request data:\n"));
1363 dump_data(10, request.data, request.length);
1365 /* make the actual dcerpc request */
1366 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1370 req->ndr.table = table;
1371 req->ndr.opnum = opnum;
1372 req->ndr.struct_ptr = r;
1373 req->ndr.mem_ctx = mem_ctx;
1382 receive the answer from a dcerpc_ndr_request_send()
1384 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1386 struct dcerpc_pipe *p = req->p;
1389 struct ndr_pull *pull;
1391 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1392 void *r = req->ndr.struct_ptr;
1393 uint32_t opnum = req->ndr.opnum;
1394 const struct dcerpc_interface_table *table = req->ndr.table;
1395 const struct dcerpc_interface_call *call = &table->calls[opnum];
1397 /* make sure the recv code doesn't free the request, as we
1398 need to grab the flags element before it is freed */
1399 talloc_increase_ref_count(req);
1401 status = dcerpc_request_recv(req, mem_ctx, &response);
1402 if (!NT_STATUS_IS_OK(status)) {
1408 /* prepare for ndr_pull_* */
1409 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1412 return NT_STATUS_NO_MEMORY;
1416 pull->data = talloc_steal(pull, pull->data);
1420 if (flags & DCERPC_PULL_BIGENDIAN) {
1421 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1424 DEBUG(10,("rpc reply data:\n"));
1425 dump_data(10, pull->data, pull->data_size);
1427 /* pull the structure from the blob */
1428 status = call->ndr_pull(pull, NDR_OUT, r);
1429 if (!NT_STATUS_IS_OK(status)) {
1430 dcerpc_log_packet(table, opnum, NDR_OUT,
1435 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1436 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1437 call->ndr_push, call->ndr_pull);
1438 if (!NT_STATUS_IS_OK(status)) {
1439 dcerpc_log_packet(table, opnum, NDR_OUT,
1445 if (pull->offset != pull->data_size) {
1446 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1447 pull->data_size - pull->offset));
1448 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1449 but it turns out that early versions of NT
1450 (specifically NT3.1) add junk onto the end of rpc
1451 packets, so if we want to interoperate at all with
1452 those versions then we need to ignore this error */
1455 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1457 return NT_STATUS_OK;
1462 a useful helper function for synchronous rpc requests
1464 this can be used when you have ndr push/pull functions in the
1467 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1468 const struct GUID *object,
1469 const struct dcerpc_interface_table *table,
1471 TALLOC_CTX *mem_ctx,
1474 struct rpc_request *req;
1476 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1478 return NT_STATUS_NO_MEMORY;
1481 return dcerpc_ndr_request_recv(req);
1486 a useful function for retrieving the server name we connected to
1488 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1490 if (!p->conn->transport.peer_name) {
1493 return p->conn->transport.peer_name(p->conn);
1498 get the dcerpc auth_level for a open connection
1500 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1504 if (c->flags & DCERPC_SEAL) {
1505 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1506 } else if (c->flags & DCERPC_SIGN) {
1507 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1508 } else if (c->flags & DCERPC_CONNECT) {
1509 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1511 auth_level = DCERPC_AUTH_LEVEL_NONE;
1517 Receive an alter reply from the transport
1519 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
1521 struct composite_context *c;
1522 struct dcerpc_pipe *pipe;
1524 c = talloc_get_type(conn->alter_private, struct composite_context);
1525 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1527 /* mark the connection as not waiting for a alter context reply */
1528 conn->alter_private = NULL;
1530 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1531 pkt->u.alter_resp.num_results == 1 &&
1532 pkt->u.alter_resp.ctx_list[0].result != 0) {
1533 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1534 pkt->u.alter_resp.ctx_list[0].reason));
1535 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1539 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1540 pkt->u.alter_resp.num_results == 0 ||
1541 pkt->u.alter_resp.ctx_list[0].result != 0) {
1542 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1546 /* the alter_resp might contain a reply set of credentials */
1547 if (pipe->conn->security_state.auth_info &&
1548 pkt->u.alter_resp.auth_info.length) {
1549 c->status = ndr_pull_struct_blob(
1550 &pkt->u.alter_resp.auth_info, pipe,
1551 pipe->conn->security_state.auth_info,
1552 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1553 if (!composite_is_ok(c)) return;
1560 send a dcerpc alter_context request
1562 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1563 TALLOC_CTX *mem_ctx,
1564 const struct dcerpc_syntax_id *syntax,
1565 const struct dcerpc_syntax_id *transfer_syntax)
1567 struct composite_context *c;
1568 struct ncacn_packet pkt;
1571 c = talloc_zero(mem_ctx, struct composite_context);
1572 if (c == NULL) return NULL;
1574 c->state = COMPOSITE_STATE_IN_PROGRESS;
1575 c->private_data = p;
1576 c->event_ctx = p->conn->event_ctx;
1578 p->syntax = *syntax;
1579 p->transfer_syntax = *transfer_syntax;
1581 init_ncacn_hdr(p->conn, &pkt);
1583 pkt.ptype = DCERPC_PKT_ALTER;
1584 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1585 pkt.call_id = p->conn->call_id;
1586 pkt.auth_length = 0;
1588 pkt.u.alter.max_xmit_frag = 5840;
1589 pkt.u.alter.max_recv_frag = 5840;
1590 pkt.u.alter.assoc_group_id = 0;
1591 pkt.u.alter.num_contexts = 1;
1592 pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1593 struct dcerpc_ctx_list, 1);
1594 if (pkt.u.alter.ctx_list == NULL) {
1595 c->status = NT_STATUS_NO_MEMORY;
1598 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1599 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1600 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1601 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1602 pkt.u.alter.auth_info = data_blob(NULL, 0);
1604 /* construct the NDR form of the packet */
1605 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1606 p->conn->security_state.auth_info);
1607 if (!NT_STATUS_IS_OK(c->status)) {
1611 p->conn->transport.recv_data = dcerpc_recv_data;
1612 p->conn->alter_private = c;
1614 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1615 if (!NT_STATUS_IS_OK(c->status)) {
1619 event_add_timed(c->event_ctx, c,
1620 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1621 bind_timeout_handler, c);
1626 composite_error(c, c->status);
1630 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1632 NTSTATUS result = composite_wait(ctx);
1638 send a dcerpc alter_context request
1640 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1641 TALLOC_CTX *mem_ctx,
1642 const struct dcerpc_syntax_id *syntax,
1643 const struct dcerpc_syntax_id *transfer_syntax)
1645 struct composite_context *creq;
1646 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1647 return dcerpc_alter_context_recv(creq);