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 struct dcerpc_interface_list *dcerpc_pipes = NULL;
38 register a dcerpc client interface
40 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
42 struct dcerpc_interface_list *l;
44 for (l = dcerpc_pipes; l; l = l->next) {
45 if (GUID_equal(&interface->uuid, &l->table->uuid)) {
46 DEBUG(0, ("Attempt to register interface %s which has the "
47 "same UUID as already registered interface %s\n",
48 interface->name, l->table->name));
49 return NT_STATUS_OBJECT_NAME_COLLISION;
53 l = talloc(talloc_autofree_context(), struct dcerpc_interface_list);
56 DLIST_ADD(dcerpc_pipes, l);
61 /* destroy a dcerpc connection */
62 static int dcerpc_connection_destructor(void *ptr)
64 struct dcerpc_connection *c = ptr;
65 if (c->transport.shutdown_pipe) {
66 c->transport.shutdown_pipe(c);
72 /* initialise a dcerpc connection.
73 the event context is optional
75 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
76 struct event_context *ev)
78 struct dcerpc_connection *c;
80 c = talloc_zero(mem_ctx, struct dcerpc_connection);
86 ev = event_context_init(c);
95 c->security_state.auth_info = NULL;
96 c->security_state.session_key = dcerpc_generic_session_key;
97 c->security_state.generic_state = NULL;
98 c->binding_string = NULL;
100 c->srv_max_xmit_frag = 0;
101 c->srv_max_recv_frag = 0;
104 talloc_set_destructor(c, dcerpc_connection_destructor);
109 /* initialise a dcerpc pipe. */
110 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
112 struct dcerpc_pipe *p;
114 p = talloc(mem_ctx, struct dcerpc_pipe);
119 p->conn = dcerpc_connection_init(p, ev);
120 if (p->conn == NULL) {
125 p->last_fault_code = 0;
127 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
129 ZERO_STRUCT(p->syntax);
130 ZERO_STRUCT(p->transfer_syntax);
137 choose the next call id to use
139 static uint32_t next_call_id(struct dcerpc_connection *c)
142 if (c->call_id == 0) {
148 /* we need to be able to get/set the fragment length without doing a full
150 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
152 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
153 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
155 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
159 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
161 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
162 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
164 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
168 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
170 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
171 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
173 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
179 setup for a ndr pull, also setting up any flags from the binding string
181 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
182 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
184 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
186 if (ndr == NULL) return ndr;
188 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
189 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
192 if (c->flags & DCERPC_NDR_REF_ALLOC) {
193 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
200 parse a data blob into a ncacn_packet structure. This handles both
201 input and output packets
203 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
204 struct ncacn_packet *pkt)
206 struct ndr_pull *ndr;
208 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
210 return NT_STATUS_NO_MEMORY;
213 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
214 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
217 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
221 generate a CONNECT level verifier
223 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
225 *blob = data_blob_talloc(mem_ctx, NULL, 16);
226 if (blob->data == NULL) {
227 return NT_STATUS_NO_MEMORY;
229 SIVAL(blob->data, 0, 1);
230 memset(blob->data+4, 0, 12);
235 check a CONNECT level verifier
237 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
239 if (blob->length != 16 ||
240 IVAL(blob->data, 0) != 1) {
241 return NT_STATUS_ACCESS_DENIED;
247 parse the authentication information on a dcerpc response packet
249 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
250 DATA_BLOB *raw_packet,
251 struct ncacn_packet *pkt)
253 struct ndr_pull *ndr;
255 struct dcerpc_auth auth;
258 if (pkt->auth_length == 0 &&
259 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
263 auth_blob.length = 8 + pkt->auth_length;
265 /* check for a valid length */
266 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
267 return NT_STATUS_INFO_LENGTH_MISMATCH;
271 pkt->u.response.stub_and_verifier.data +
272 pkt->u.response.stub_and_verifier.length - auth_blob.length;
273 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
275 /* pull the auth structure */
276 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
278 return NT_STATUS_NO_MEMORY;
281 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
282 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
285 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
286 if (!NT_STATUS_IS_OK(status)) {
291 /* check signature or unseal the packet */
292 switch (c->security_state.auth_info->auth_level) {
293 case DCERPC_AUTH_LEVEL_PRIVACY:
294 status = gensec_unseal_packet(c->security_state.generic_state,
296 raw_packet->data + DCERPC_REQUEST_LENGTH,
297 pkt->u.response.stub_and_verifier.length,
299 raw_packet->length - auth.credentials.length,
301 memcpy(pkt->u.response.stub_and_verifier.data,
302 raw_packet->data + DCERPC_REQUEST_LENGTH,
303 pkt->u.response.stub_and_verifier.length);
306 case DCERPC_AUTH_LEVEL_INTEGRITY:
307 status = gensec_check_packet(c->security_state.generic_state,
309 pkt->u.response.stub_and_verifier.data,
310 pkt->u.response.stub_and_verifier.length,
312 raw_packet->length - auth.credentials.length,
316 case DCERPC_AUTH_LEVEL_CONNECT:
317 status = dcerpc_check_connect_verifier(&auth.credentials);
320 case DCERPC_AUTH_LEVEL_NONE:
324 status = NT_STATUS_INVALID_LEVEL;
328 /* remove the indicated amount of paddiing */
329 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
330 return NT_STATUS_INFO_LENGTH_MISMATCH;
332 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
339 push a dcerpc request packet into a blob, possibly signing it.
341 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
342 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
343 struct ncacn_packet *pkt)
346 struct ndr_push *ndr;
348 size_t payload_length;
350 /* non-signed packets are simpler */
351 if (!c->security_state.auth_info ||
352 !c->security_state.generic_state) {
353 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
356 ndr = ndr_push_init_ctx(mem_ctx);
358 return NT_STATUS_NO_MEMORY;
361 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
362 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
365 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
366 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
369 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
370 if (!NT_STATUS_IS_OK(status)) {
374 /* pad to 16 byte multiple in the payload portion of the
375 packet. This matches what w2k3 does */
376 c->security_state.auth_info->auth_pad_length =
377 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
378 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
380 payload_length = pkt->u.request.stub_and_verifier.length +
381 c->security_state.auth_info->auth_pad_length;
383 /* sign or seal the packet */
384 switch (c->security_state.auth_info->auth_level) {
385 case DCERPC_AUTH_LEVEL_PRIVACY:
386 case DCERPC_AUTH_LEVEL_INTEGRITY:
387 c->security_state.auth_info->credentials
388 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
390 data_blob_clear(&c->security_state.auth_info->credentials);
393 case DCERPC_AUTH_LEVEL_CONNECT:
394 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
397 case DCERPC_AUTH_LEVEL_NONE:
398 c->security_state.auth_info->credentials = data_blob(NULL, 0);
402 status = NT_STATUS_INVALID_LEVEL;
406 if (!NT_STATUS_IS_OK(status)) {
410 /* add the auth verifier */
411 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
412 if (!NT_STATUS_IS_OK(status)) {
416 /* extract the whole packet as a blob */
417 *blob = ndr_push_blob(ndr);
419 /* fill in the fragment length and auth_length, we can't fill
420 in these earlier as we don't know the signature length (it
421 could be variable length) */
422 dcerpc_set_frag_length(blob, blob->length);
423 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
425 /* sign or seal the packet */
426 switch (c->security_state.auth_info->auth_level) {
427 case DCERPC_AUTH_LEVEL_PRIVACY:
428 status = gensec_seal_packet(c->security_state.generic_state,
430 blob->data + DCERPC_REQUEST_LENGTH,
434 c->security_state.auth_info->credentials.length,
436 if (!NT_STATUS_IS_OK(status)) {
439 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
442 case DCERPC_AUTH_LEVEL_INTEGRITY:
443 status = gensec_sign_packet(c->security_state.generic_state,
445 blob->data + DCERPC_REQUEST_LENGTH,
449 c->security_state.auth_info->credentials.length,
451 if (!NT_STATUS_IS_OK(status)) {
454 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
457 case DCERPC_AUTH_LEVEL_CONNECT:
460 case DCERPC_AUTH_LEVEL_NONE:
461 c->security_state.auth_info->credentials = data_blob(NULL, 0);
465 status = NT_STATUS_INVALID_LEVEL;
469 data_blob_free(&c->security_state.auth_info->credentials);
476 fill in the fixed values in a dcerpc header
478 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
481 pkt->rpc_vers_minor = 0;
482 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
485 pkt->drep[0] = DCERPC_DREP_LE;
493 map a bind nak reason to a NTSTATUS
495 static NTSTATUS dcerpc_map_reason(uint16_t reason)
498 case DCERPC_BIND_REASON_ASYNTAX:
499 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
501 return NT_STATUS_UNSUCCESSFUL;
505 mark the dcerpc connection dead. All outstanding requests get an error
507 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
509 /* all pending requests get the error */
510 while (conn->pending) {
511 struct rpc_request *req = conn->pending;
512 req->state = RPC_REQUEST_DONE;
513 req->status = status;
514 DLIST_REMOVE(conn->pending, req);
515 if (req->async.callback) {
516 req->async.callback(req);
520 if (conn->bind_private) {
521 /* a bind was in flight - fail it */
522 struct composite_context *c = talloc_get_type(conn->bind_private, struct composite_context);
523 composite_error(c, status);
526 if (conn->alter_private) {
527 /* a alter context was in flight - fail it */
528 struct composite_context *c = talloc_get_type(conn->alter_private, struct composite_context);
529 composite_error(c, status);
534 forward declarations of the recv_data handlers for the 3 types of packets we need
537 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
538 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
539 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
540 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
543 receive a dcerpc reply from the transport. Here we work out what
544 type of reply it is (normal request, bind or alter context) and
545 dispatch to the appropriate handler
547 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
549 struct ncacn_packet pkt;
551 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
552 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
555 /* the transport may be telling us of a severe error, such as
557 if (!NT_STATUS_IS_OK(status)) {
558 data_blob_free(blob);
559 dcerpc_connection_dead(conn, status);
563 /* parse the basic packet to work out what type of response this is */
564 status = ncacn_pull(conn, blob, blob->data, &pkt);
565 if (!NT_STATUS_IS_OK(status)) {
566 data_blob_free(blob);
567 dcerpc_connection_dead(conn, status);
571 case DCERPC_PKT_BIND_NAK:
572 case DCERPC_PKT_BIND_ACK:
573 if (conn->bind_private) {
574 talloc_steal(conn->bind_private, blob->data);
575 dcerpc_bind_recv_data(conn, &pkt);
579 case DCERPC_PKT_ALTER_RESP:
580 if (conn->alter_private) {
581 talloc_steal(conn->alter_private, blob->data);
582 dcerpc_alter_recv_data(conn, &pkt);
587 /* assume its an ordinary request */
588 dcerpc_request_recv_data(conn, blob, &pkt);
595 Receive a bind reply from the transport
597 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
599 struct composite_context *c;
600 struct dcerpc_pipe *pipe;
602 c = talloc_get_type(conn->bind_private, struct composite_context);
603 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
605 /* mark the connection as not waiting for a bind reply */
606 conn->bind_private = NULL;
608 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
609 DEBUG(2,("dcerpc: bind_nak reason %d\n",
610 pkt->u.bind_nak.reject_reason));
611 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
616 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
617 (pkt->u.bind_ack.num_results == 0) ||
618 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
619 composite_error(c, NT_STATUS_UNSUCCESSFUL);
623 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
624 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
626 /* the bind_ack might contain a reply set of credentials */
627 if (conn->security_state.auth_info &&
628 pkt->u.bind_ack.auth_info.length) {
629 c->status = ndr_pull_struct_blob(
630 &pkt->u.bind_ack.auth_info, conn,
631 conn->security_state.auth_info,
632 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
633 if (!composite_is_ok(c)) return;
640 handle timeouts of dcerpc bind and alter context requests
642 static void bind_timeout_handler(struct event_context *ev,
643 struct timed_event *te,
644 struct timeval t, void *private)
646 struct composite_context *ctx =
647 talloc_get_type(private, struct composite_context);
648 struct dcerpc_pipe *pipe = talloc_get_type(ctx->private_data, struct dcerpc_pipe);
650 SMB_ASSERT(pipe->conn->bind_private != NULL);
651 pipe->conn->bind_private = NULL;
652 composite_error(ctx, NT_STATUS_IO_TIMEOUT);
656 send a async dcerpc bind request
658 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
660 const struct dcerpc_syntax_id *syntax,
661 const struct dcerpc_syntax_id *transfer_syntax)
663 struct composite_context *c;
664 struct ncacn_packet pkt;
667 c = talloc_zero(mem_ctx, struct composite_context);
668 if (c == NULL) return NULL;
670 c->state = COMPOSITE_STATE_IN_PROGRESS;
672 c->event_ctx = p->conn->event_ctx;
675 p->transfer_syntax = *transfer_syntax;
677 init_ncacn_hdr(p->conn, &pkt);
679 pkt.ptype = DCERPC_PKT_BIND;
680 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
681 pkt.call_id = p->conn->call_id;
684 pkt.u.bind.max_xmit_frag = 5840;
685 pkt.u.bind.max_recv_frag = 5840;
686 pkt.u.bind.assoc_group_id = 0;
687 pkt.u.bind.num_contexts = 1;
688 pkt.u.bind.ctx_list =
689 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
690 if (pkt.u.bind.ctx_list == NULL) {
691 c->status = NT_STATUS_NO_MEMORY;
694 pkt.u.bind.ctx_list[0].context_id = p->context_id;
695 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
696 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
697 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
698 pkt.u.bind.auth_info = data_blob(NULL, 0);
700 /* construct the NDR form of the packet */
701 c->status = ncacn_push_auth(&blob, c, &pkt,
702 p->conn->security_state.auth_info);
703 if (!NT_STATUS_IS_OK(c->status)) {
707 p->conn->transport.recv_data = dcerpc_recv_data;
708 p->conn->bind_private = c;
710 c->status = p->conn->transport.send_request(p->conn, &blob,
712 if (!NT_STATUS_IS_OK(c->status)) {
716 event_add_timed(c->event_ctx, c,
717 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
718 bind_timeout_handler, c);
723 composite_error(c, c->status);
728 recv side of async dcerpc bind request
730 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
732 NTSTATUS result = composite_wait(ctx);
738 perform a bind using the given syntax
740 the auth_info structure is updated with the reply authentication info
743 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
745 const struct dcerpc_syntax_id *syntax,
746 const struct dcerpc_syntax_id *transfer_syntax)
748 struct composite_context *creq;
749 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
750 return dcerpc_bind_recv(creq);
754 perform a continued bind (and auth3)
756 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
759 struct ncacn_packet pkt;
763 init_ncacn_hdr(c, &pkt);
765 pkt.ptype = DCERPC_PKT_AUTH3;
766 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
767 pkt.call_id = next_call_id(c);
769 pkt.u.auth3._pad = 0;
770 pkt.u.auth3.auth_info = data_blob(NULL, 0);
772 /* construct the NDR form of the packet */
773 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
774 if (!NT_STATUS_IS_OK(status)) {
778 /* send it on its way */
779 status = c->transport.send_request(c, &blob, False);
780 if (!NT_STATUS_IS_OK(status)) {
789 return the rpc syntax and transfer syntax given the pipe uuid and version
791 NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
792 struct dcerpc_syntax_id *syntax,
793 struct dcerpc_syntax_id *transfer_syntax)
795 syntax->uuid = table->uuid;
796 syntax->if_version = table->if_version;
798 *transfer_syntax = ndr_transfer_syntax;
803 /* perform a dcerpc bind, using the uuid as the key */
804 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
806 const struct dcerpc_interface_table *table)
808 struct dcerpc_syntax_id syntax;
809 struct dcerpc_syntax_id transfer_syntax;
812 status = dcerpc_init_syntaxes(table,
813 &syntax, &transfer_syntax);
814 if (!NT_STATUS_IS_OK(status)) {
815 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
819 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
824 process a fragment received from the transport layer during a
827 This function frees the data
829 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
830 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
832 struct rpc_request *req;
834 NTSTATUS status = NT_STATUS_OK;
837 if this is an authenticated connection then parse and check
838 the auth info. We have to do this before finding the
839 matching packet, as the request structure might have been
840 removed due to a timeout, but if it has been we still need
841 to run the auth routines so that we don't get the sign/seal
842 info out of step with the server
844 if (c->security_state.auth_info && c->security_state.generic_state &&
845 pkt->ptype == DCERPC_PKT_RESPONSE) {
846 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
849 /* find the matching request */
850 for (req=c->pending;req;req=req->next) {
851 if (pkt->call_id == req->call_id) break;
855 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
856 data_blob_free(raw_packet);
860 talloc_steal(req, raw_packet->data);
862 if (pkt->ptype == DCERPC_PKT_FAULT) {
863 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
864 req->fault_code = pkt->u.fault.status;
865 req->status = NT_STATUS_NET_WRITE_FAULT;
869 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
870 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
872 req->fault_code = DCERPC_FAULT_OTHER;
873 req->status = NT_STATUS_NET_WRITE_FAULT;
877 /* now check the status from the auth routines, and if it failed then fail
878 this request accordingly */
879 if (!NT_STATUS_IS_OK(status)) {
880 req->status = status;
884 length = pkt->u.response.stub_and_verifier.length;
887 req->payload.data = talloc_realloc(req,
890 req->payload.length + length);
891 if (!req->payload.data) {
892 req->status = NT_STATUS_NO_MEMORY;
895 memcpy(req->payload.data+req->payload.length,
896 pkt->u.response.stub_and_verifier.data, length);
897 req->payload.length += length;
900 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
901 c->transport.send_read(c);
905 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
906 req->flags |= DCERPC_PULL_BIGENDIAN;
908 req->flags &= ~DCERPC_PULL_BIGENDIAN;
913 /* we've got the full payload */
914 req->state = RPC_REQUEST_DONE;
915 DLIST_REMOVE(c->pending, req);
917 if (c->request_queue != NULL) {
918 /* We have to look at shipping further requests before calling
919 * the async function, that one might close the pipe */
920 dcerpc_ship_next_request(c);
923 if (req->async.callback) {
924 req->async.callback(req);
929 handle timeouts of individual dcerpc requests
931 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
932 struct timeval t, void *private)
934 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
936 if (req->state != RPC_REQUEST_PENDING) {
940 req->status = NT_STATUS_IO_TIMEOUT;
941 req->state = RPC_REQUEST_DONE;
942 DLIST_REMOVE(req->p->conn->pending, req);
943 if (req->async.callback) {
944 req->async.callback(req);
950 make sure requests are cleaned up
952 static int dcerpc_req_destructor(void *ptr)
954 struct rpc_request *req = ptr;
955 DLIST_REMOVE(req->p->conn->pending, req);
960 perform the send side of a async dcerpc request
962 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
963 const struct GUID *object,
966 DATA_BLOB *stub_data)
968 struct rpc_request *req;
970 p->conn->transport.recv_data = dcerpc_recv_data;
972 req = talloc(p, struct rpc_request);
978 req->call_id = next_call_id(p->conn);
979 req->status = NT_STATUS_OK;
980 req->state = RPC_REQUEST_PENDING;
981 req->payload = data_blob(NULL, 0);
984 req->async_call = async;
985 req->async.callback = NULL;
987 if (object != NULL) {
988 req->object = talloc_memdup(req, object, sizeof(*object));
989 if (req->object == NULL) {
998 req->request_data.length = stub_data->length;
999 req->request_data.data = talloc_reference(req, stub_data->data);
1000 if (req->request_data.data == NULL) {
1004 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1006 dcerpc_ship_next_request(p->conn);
1008 if (p->request_timeout) {
1009 event_add_timed(dcerpc_event_context(p), req,
1010 timeval_current_ofs(p->request_timeout, 0),
1011 dcerpc_timeout_handler, req);
1014 talloc_set_destructor(req, dcerpc_req_destructor);
1019 Send a request using the transport
1022 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1024 struct rpc_request *req;
1025 struct dcerpc_pipe *p;
1026 DATA_BLOB *stub_data;
1027 struct ncacn_packet pkt;
1029 uint32_t remaining, chunk_size;
1030 BOOL first_packet = True;
1032 req = c->request_queue;
1038 stub_data = &req->request_data;
1040 if (!req->async_call && (c->pending != NULL)) {
1044 DLIST_REMOVE(c->request_queue, req);
1045 DLIST_ADD(c->pending, req);
1047 init_ncacn_hdr(p->conn, &pkt);
1049 remaining = stub_data->length;
1051 /* we can write a full max_recv_frag size, minus the dcerpc
1052 request header size */
1053 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1055 pkt.ptype = DCERPC_PKT_REQUEST;
1056 pkt.call_id = req->call_id;
1057 pkt.auth_length = 0;
1059 pkt.u.request.alloc_hint = remaining;
1060 pkt.u.request.context_id = p->context_id;
1061 pkt.u.request.opnum = req->opnum;
1064 pkt.u.request.object.object = *req->object;
1065 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1066 chunk_size -= ndr_size_GUID(req->object,0);
1069 /* we send a series of pdus without waiting for a reply */
1070 while (remaining > 0 || first_packet) {
1071 uint32_t chunk = MIN(chunk_size, remaining);
1072 BOOL last_frag = False;
1074 first_packet = False;
1075 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1077 if (remaining == stub_data->length) {
1078 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1080 if (chunk == remaining) {
1081 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1085 pkt.u.request.stub_and_verifier.data = stub_data->data +
1086 (stub_data->length - remaining);
1087 pkt.u.request.stub_and_verifier.length = chunk;
1089 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1090 if (!NT_STATUS_IS_OK(req->status)) {
1091 req->state = RPC_REQUEST_DONE;
1092 DLIST_REMOVE(p->conn->pending, req);
1096 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1097 if (!NT_STATUS_IS_OK(req->status)) {
1098 req->state = RPC_REQUEST_DONE;
1099 DLIST_REMOVE(p->conn->pending, req);
1108 return the event context for a dcerpc pipe
1109 used by callers who wish to operate asynchronously
1111 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1113 return p->conn->event_ctx;
1119 perform the receive side of a async dcerpc request
1121 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1122 TALLOC_CTX *mem_ctx,
1123 DATA_BLOB *stub_data)
1127 while (req->state == RPC_REQUEST_PENDING) {
1128 struct event_context *ctx = dcerpc_event_context(req->p);
1129 if (event_loop_once(ctx) != 0) {
1130 return NT_STATUS_CONNECTION_DISCONNECTED;
1133 *stub_data = req->payload;
1134 status = req->status;
1135 if (stub_data->data) {
1136 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1138 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1139 req->p->last_fault_code = req->fault_code;
1146 perform a full request/response pair on a dcerpc pipe
1148 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1149 struct GUID *object,
1152 TALLOC_CTX *mem_ctx,
1153 DATA_BLOB *stub_data_in,
1154 DATA_BLOB *stub_data_out)
1156 struct rpc_request *req;
1158 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1160 return NT_STATUS_NO_MEMORY;
1163 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1168 this is a paranoid NDR validator. For every packet we push onto the wire
1169 we pull it back again, then push it again. Then we compare the raw NDR data
1170 for that to the NDR we initially generated. If they don't match then we know
1171 we must have a bug in either the pull or push side of our code
1173 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1174 TALLOC_CTX *mem_ctx,
1177 ndr_push_flags_fn_t ndr_push,
1178 ndr_pull_flags_fn_t ndr_pull)
1181 struct ndr_pull *pull;
1182 struct ndr_push *push;
1186 st = talloc_size(mem_ctx, struct_size);
1188 return NT_STATUS_NO_MEMORY;
1191 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1193 return NT_STATUS_NO_MEMORY;
1195 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1197 status = ndr_pull(pull, NDR_IN, st);
1198 if (!NT_STATUS_IS_OK(status)) {
1199 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1200 "failed input validation pull - %s",
1204 push = ndr_push_init_ctx(mem_ctx);
1206 return NT_STATUS_NO_MEMORY;
1209 status = ndr_push(push, NDR_IN, st);
1210 if (!NT_STATUS_IS_OK(status)) {
1211 return ndr_push_error(push, NDR_ERR_VALIDATE,
1212 "failed input validation push - %s",
1216 blob2 = ndr_push_blob(push);
1218 if (!data_blob_equal(&blob, &blob2)) {
1219 DEBUG(3,("original:\n"));
1220 dump_data(3, blob.data, blob.length);
1221 DEBUG(3,("secondary:\n"));
1222 dump_data(3, blob2.data, blob2.length);
1223 return ndr_push_error(push, NDR_ERR_VALIDATE,
1224 "failed input validation data - %s",
1228 return NT_STATUS_OK;
1232 this is a paranoid NDR input validator. For every packet we pull
1233 from the wire we push it back again then pull and push it
1234 again. Then we compare the raw NDR data for that to the NDR we
1235 initially generated. If they don't match then we know we must have a
1236 bug in either the pull or push side of our code
1238 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1239 TALLOC_CTX *mem_ctx,
1242 ndr_push_flags_fn_t ndr_push,
1243 ndr_pull_flags_fn_t ndr_pull)
1246 struct ndr_pull *pull;
1247 struct ndr_push *push;
1249 DATA_BLOB blob, blob2;
1251 st = talloc_size(mem_ctx, struct_size);
1253 return NT_STATUS_NO_MEMORY;
1255 memcpy(st, struct_ptr, struct_size);
1257 push = ndr_push_init_ctx(mem_ctx);
1259 return NT_STATUS_NO_MEMORY;
1262 status = ndr_push(push, NDR_OUT, struct_ptr);
1263 if (!NT_STATUS_IS_OK(status)) {
1264 return ndr_push_error(push, NDR_ERR_VALIDATE,
1265 "failed output validation push - %s",
1269 blob = ndr_push_blob(push);
1271 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1273 return NT_STATUS_NO_MEMORY;
1276 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1277 status = ndr_pull(pull, NDR_OUT, st);
1278 if (!NT_STATUS_IS_OK(status)) {
1279 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1280 "failed output validation pull - %s",
1284 push = ndr_push_init_ctx(mem_ctx);
1286 return NT_STATUS_NO_MEMORY;
1289 status = ndr_push(push, NDR_OUT, st);
1290 if (!NT_STATUS_IS_OK(status)) {
1291 return ndr_push_error(push, NDR_ERR_VALIDATE,
1292 "failed output validation push2 - %s",
1296 blob2 = ndr_push_blob(push);
1298 if (!data_blob_equal(&blob, &blob2)) {
1299 DEBUG(3,("original:\n"));
1300 dump_data(3, blob.data, blob.length);
1301 DEBUG(3,("secondary:\n"));
1302 dump_data(3, blob2.data, blob2.length);
1303 return ndr_push_error(push, NDR_ERR_VALIDATE,
1304 "failed output validation data - %s",
1308 return NT_STATUS_OK;
1313 send a rpc request given a dcerpc_call structure
1315 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1316 const struct GUID *object,
1317 const struct dcerpc_interface_table *table,
1319 TALLOC_CTX *mem_ctx,
1322 const struct dcerpc_interface_call *call;
1323 struct ndr_push *push;
1326 struct rpc_request *req;
1328 call = &table->calls[opnum];
1330 /* setup for a ndr_push_* call */
1331 push = ndr_push_init_ctx(mem_ctx);
1336 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1337 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1340 /* push the structure into a blob */
1341 status = call->ndr_push(push, NDR_IN, r);
1342 if (!NT_STATUS_IS_OK(status)) {
1343 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1344 nt_errstr(status)));
1349 /* retrieve the blob */
1350 request = ndr_push_blob(push);
1352 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1353 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1354 call->ndr_push, call->ndr_pull);
1355 if (!NT_STATUS_IS_OK(status)) {
1356 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1357 nt_errstr(status)));
1363 DEBUG(10,("rpc request data:\n"));
1364 dump_data(10, request.data, request.length);
1366 /* make the actual dcerpc request */
1367 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1371 req->ndr.table = table;
1372 req->ndr.opnum = opnum;
1373 req->ndr.struct_ptr = r;
1374 req->ndr.mem_ctx = mem_ctx;
1383 receive the answer from a dcerpc_ndr_request_send()
1385 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1387 struct dcerpc_pipe *p = req->p;
1390 struct ndr_pull *pull;
1392 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1393 void *r = req->ndr.struct_ptr;
1394 uint32_t opnum = req->ndr.opnum;
1395 const struct dcerpc_interface_table *table = req->ndr.table;
1396 const struct dcerpc_interface_call *call = &table->calls[opnum];
1398 /* make sure the recv code doesn't free the request, as we
1399 need to grab the flags element before it is freed */
1400 talloc_increase_ref_count(req);
1402 status = dcerpc_request_recv(req, mem_ctx, &response);
1403 if (!NT_STATUS_IS_OK(status)) {
1409 /* prepare for ndr_pull_* */
1410 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1413 return NT_STATUS_NO_MEMORY;
1417 pull->data = talloc_steal(pull, pull->data);
1421 if (flags & DCERPC_PULL_BIGENDIAN) {
1422 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1425 DEBUG(10,("rpc reply data:\n"));
1426 dump_data(10, pull->data, pull->data_size);
1428 /* pull the structure from the blob */
1429 status = call->ndr_pull(pull, NDR_OUT, r);
1430 if (!NT_STATUS_IS_OK(status)) {
1431 dcerpc_log_packet(table, opnum, NDR_OUT,
1436 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1437 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1438 call->ndr_push, call->ndr_pull);
1439 if (!NT_STATUS_IS_OK(status)) {
1440 dcerpc_log_packet(table, opnum, NDR_OUT,
1446 if (pull->offset != pull->data_size) {
1447 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1448 pull->data_size - pull->offset));
1449 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1450 but it turns out that early versions of NT
1451 (specifically NT3.1) add junk onto the end of rpc
1452 packets, so if we want to interoperate at all with
1453 those versions then we need to ignore this error */
1456 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1458 return NT_STATUS_OK;
1463 a useful helper function for synchronous rpc requests
1465 this can be used when you have ndr push/pull functions in the
1468 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1469 const struct GUID *object,
1470 const struct dcerpc_interface_table *table,
1472 TALLOC_CTX *mem_ctx,
1475 struct rpc_request *req;
1477 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1479 return NT_STATUS_NO_MEMORY;
1482 return dcerpc_ndr_request_recv(req);
1487 a useful function for retrieving the server name we connected to
1489 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1491 if (!p->conn->transport.peer_name) {
1494 return p->conn->transport.peer_name(p->conn);
1499 get the dcerpc auth_level for a open connection
1501 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1505 if (c->flags & DCERPC_SEAL) {
1506 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1507 } else if (c->flags & DCERPC_SIGN) {
1508 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1509 } else if (c->flags & DCERPC_CONNECT) {
1510 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1512 auth_level = DCERPC_AUTH_LEVEL_NONE;
1518 Receive an alter reply from the transport
1520 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
1522 struct composite_context *c;
1523 struct dcerpc_pipe *pipe;
1525 c = talloc_get_type(conn->alter_private, struct composite_context);
1526 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1528 /* mark the connection as not waiting for a alter context reply */
1529 conn->alter_private = NULL;
1531 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1532 pkt->u.alter_resp.num_results == 1 &&
1533 pkt->u.alter_resp.ctx_list[0].result != 0) {
1534 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1535 pkt->u.alter_resp.ctx_list[0].reason));
1536 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1540 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1541 pkt->u.alter_resp.num_results == 0 ||
1542 pkt->u.alter_resp.ctx_list[0].result != 0) {
1543 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1547 /* the alter_resp might contain a reply set of credentials */
1548 if (pipe->conn->security_state.auth_info &&
1549 pkt->u.alter_resp.auth_info.length) {
1550 c->status = ndr_pull_struct_blob(
1551 &pkt->u.alter_resp.auth_info, pipe,
1552 pipe->conn->security_state.auth_info,
1553 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1554 if (!composite_is_ok(c)) return;
1561 send a dcerpc alter_context request
1563 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1564 TALLOC_CTX *mem_ctx,
1565 const struct dcerpc_syntax_id *syntax,
1566 const struct dcerpc_syntax_id *transfer_syntax)
1568 struct composite_context *c;
1569 struct ncacn_packet pkt;
1572 c = talloc_zero(mem_ctx, struct composite_context);
1573 if (c == NULL) return NULL;
1575 c->state = COMPOSITE_STATE_IN_PROGRESS;
1576 c->private_data = p;
1577 c->event_ctx = p->conn->event_ctx;
1579 p->syntax = *syntax;
1580 p->transfer_syntax = *transfer_syntax;
1582 init_ncacn_hdr(p->conn, &pkt);
1584 pkt.ptype = DCERPC_PKT_ALTER;
1585 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1586 pkt.call_id = p->conn->call_id;
1587 pkt.auth_length = 0;
1589 pkt.u.alter.max_xmit_frag = 5840;
1590 pkt.u.alter.max_recv_frag = 5840;
1591 pkt.u.alter.assoc_group_id = 0;
1592 pkt.u.alter.num_contexts = 1;
1593 pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1594 struct dcerpc_ctx_list, 1);
1595 if (pkt.u.alter.ctx_list == NULL) {
1596 c->status = NT_STATUS_NO_MEMORY;
1599 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1600 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1601 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1602 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1603 pkt.u.alter.auth_info = data_blob(NULL, 0);
1605 /* construct the NDR form of the packet */
1606 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1607 p->conn->security_state.auth_info);
1608 if (!NT_STATUS_IS_OK(c->status)) {
1612 p->conn->transport.recv_data = dcerpc_recv_data;
1613 p->conn->alter_private = c;
1615 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1616 if (!NT_STATUS_IS_OK(c->status)) {
1620 event_add_timed(c->event_ctx, c,
1621 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1622 bind_timeout_handler, c);
1627 composite_error(c, c->status);
1631 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1633 NTSTATUS result = composite_wait(ctx);
1639 send a dcerpc alter_context request
1641 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1642 TALLOC_CTX *mem_ctx,
1643 const struct dcerpc_syntax_id *syntax,
1644 const struct dcerpc_syntax_id *transfer_syntax)
1646 struct composite_context *creq;
1647 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1648 return dcerpc_alter_context_recv(creq);