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 static 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 = talloc(talloc_autofree_context(),
42 struct dcerpc_interface_list);
44 if (idl_iface_by_name (interface->name) != NULL) {
45 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
46 return NT_STATUS_OBJECT_NAME_COLLISION;
50 DLIST_ADD(dcerpc_pipes, l);
56 return the list of registered dcerpc_pipes
58 const struct dcerpc_interface_list *librpc_dcerpc_pipes(void)
63 /* destroy a dcerpc connection */
64 static int dcerpc_connection_destructor(void *ptr)
66 struct dcerpc_connection *c = ptr;
67 if (c->transport.shutdown_pipe) {
68 c->transport.shutdown_pipe(c);
74 /* initialise a dcerpc connection.
75 the event context is optional
77 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
78 struct event_context *ev)
80 struct dcerpc_connection *c;
82 c = talloc_zero(mem_ctx, struct dcerpc_connection);
88 ev = event_context_init(c);
97 c->security_state.auth_info = NULL;
98 c->security_state.session_key = dcerpc_generic_session_key;
99 c->security_state.generic_state = NULL;
100 c->binding_string = NULL;
102 c->srv_max_xmit_frag = 0;
103 c->srv_max_recv_frag = 0;
106 talloc_set_destructor(c, dcerpc_connection_destructor);
111 /* initialise a dcerpc pipe. */
112 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
114 struct dcerpc_pipe *p;
116 p = talloc(mem_ctx, struct dcerpc_pipe);
121 p->conn = dcerpc_connection_init(p, ev);
122 if (p->conn == NULL) {
127 p->last_fault_code = 0;
129 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
131 ZERO_STRUCT(p->syntax);
132 ZERO_STRUCT(p->transfer_syntax);
139 choose the next call id to use
141 static uint32_t next_call_id(struct dcerpc_connection *c)
144 if (c->call_id == 0) {
150 /* we need to be able to get/set the fragment length without doing a full
152 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
154 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
155 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
157 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
161 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
163 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
164 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
166 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
170 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
172 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
173 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
175 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
181 setup for a ndr pull, also setting up any flags from the binding string
183 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
184 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
186 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
188 if (ndr == NULL) return ndr;
190 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
191 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
194 if (c->flags & DCERPC_NDR_REF_ALLOC) {
195 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
202 parse a data blob into a ncacn_packet structure. This handles both
203 input and output packets
205 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
206 struct ncacn_packet *pkt)
208 struct ndr_pull *ndr;
210 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
212 return NT_STATUS_NO_MEMORY;
215 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
216 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
219 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
223 generate a CONNECT level verifier
225 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
227 *blob = data_blob_talloc(mem_ctx, NULL, 16);
228 if (blob->data == NULL) {
229 return NT_STATUS_NO_MEMORY;
231 SIVAL(blob->data, 0, 1);
232 memset(blob->data+4, 0, 12);
237 check a CONNECT level verifier
239 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
241 if (blob->length != 16 ||
242 IVAL(blob->data, 0) != 1) {
243 return NT_STATUS_ACCESS_DENIED;
249 parse the authentication information on a dcerpc response packet
251 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
252 DATA_BLOB *raw_packet,
253 struct ncacn_packet *pkt)
255 struct ndr_pull *ndr;
257 struct dcerpc_auth auth;
260 if (pkt->auth_length == 0 &&
261 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
265 auth_blob.length = 8 + pkt->auth_length;
267 /* check for a valid length */
268 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
269 return NT_STATUS_INFO_LENGTH_MISMATCH;
273 pkt->u.response.stub_and_verifier.data +
274 pkt->u.response.stub_and_verifier.length - auth_blob.length;
275 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
277 /* pull the auth structure */
278 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
280 return NT_STATUS_NO_MEMORY;
283 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
284 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
287 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
288 if (!NT_STATUS_IS_OK(status)) {
293 /* check signature or unseal the packet */
294 switch (c->security_state.auth_info->auth_level) {
295 case DCERPC_AUTH_LEVEL_PRIVACY:
296 status = gensec_unseal_packet(c->security_state.generic_state,
298 raw_packet->data + DCERPC_REQUEST_LENGTH,
299 pkt->u.response.stub_and_verifier.length,
301 raw_packet->length - auth.credentials.length,
303 memcpy(pkt->u.response.stub_and_verifier.data,
304 raw_packet->data + DCERPC_REQUEST_LENGTH,
305 pkt->u.response.stub_and_verifier.length);
308 case DCERPC_AUTH_LEVEL_INTEGRITY:
309 status = gensec_check_packet(c->security_state.generic_state,
311 pkt->u.response.stub_and_verifier.data,
312 pkt->u.response.stub_and_verifier.length,
314 raw_packet->length - auth.credentials.length,
318 case DCERPC_AUTH_LEVEL_CONNECT:
319 status = dcerpc_check_connect_verifier(&auth.credentials);
322 case DCERPC_AUTH_LEVEL_NONE:
326 status = NT_STATUS_INVALID_LEVEL;
330 /* remove the indicated amount of paddiing */
331 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
332 return NT_STATUS_INFO_LENGTH_MISMATCH;
334 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
341 push a dcerpc request packet into a blob, possibly signing it.
343 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
344 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
345 struct ncacn_packet *pkt)
348 struct ndr_push *ndr;
350 size_t payload_length;
352 /* non-signed packets are simpler */
353 if (!c->security_state.auth_info ||
354 !c->security_state.generic_state) {
355 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
358 ndr = ndr_push_init_ctx(mem_ctx);
360 return NT_STATUS_NO_MEMORY;
363 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
364 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
367 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
368 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
371 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
372 if (!NT_STATUS_IS_OK(status)) {
376 /* pad to 16 byte multiple in the payload portion of the
377 packet. This matches what w2k3 does */
378 c->security_state.auth_info->auth_pad_length =
379 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
380 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
382 payload_length = pkt->u.request.stub_and_verifier.length +
383 c->security_state.auth_info->auth_pad_length;
385 /* sign or seal the packet */
386 switch (c->security_state.auth_info->auth_level) {
387 case DCERPC_AUTH_LEVEL_PRIVACY:
388 case DCERPC_AUTH_LEVEL_INTEGRITY:
389 c->security_state.auth_info->credentials
390 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
392 data_blob_clear(&c->security_state.auth_info->credentials);
395 case DCERPC_AUTH_LEVEL_CONNECT:
396 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
399 case DCERPC_AUTH_LEVEL_NONE:
400 c->security_state.auth_info->credentials = data_blob(NULL, 0);
404 status = NT_STATUS_INVALID_LEVEL;
408 if (!NT_STATUS_IS_OK(status)) {
412 /* add the auth verifier */
413 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
414 if (!NT_STATUS_IS_OK(status)) {
418 /* extract the whole packet as a blob */
419 *blob = ndr_push_blob(ndr);
421 /* fill in the fragment length and auth_length, we can't fill
422 in these earlier as we don't know the signature length (it
423 could be variable length) */
424 dcerpc_set_frag_length(blob, blob->length);
425 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
427 /* sign or seal the packet */
428 switch (c->security_state.auth_info->auth_level) {
429 case DCERPC_AUTH_LEVEL_PRIVACY:
430 status = gensec_seal_packet(c->security_state.generic_state,
432 blob->data + DCERPC_REQUEST_LENGTH,
436 c->security_state.auth_info->credentials.length,
438 if (!NT_STATUS_IS_OK(status)) {
441 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
444 case DCERPC_AUTH_LEVEL_INTEGRITY:
445 status = gensec_sign_packet(c->security_state.generic_state,
447 blob->data + DCERPC_REQUEST_LENGTH,
451 c->security_state.auth_info->credentials.length,
453 if (!NT_STATUS_IS_OK(status)) {
456 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
459 case DCERPC_AUTH_LEVEL_CONNECT:
462 case DCERPC_AUTH_LEVEL_NONE:
463 c->security_state.auth_info->credentials = data_blob(NULL, 0);
467 status = NT_STATUS_INVALID_LEVEL;
471 data_blob_free(&c->security_state.auth_info->credentials);
478 fill in the fixed values in a dcerpc header
480 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
483 pkt->rpc_vers_minor = 0;
484 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
487 pkt->drep[0] = DCERPC_DREP_LE;
495 map a bind nak reason to a NTSTATUS
497 static NTSTATUS dcerpc_map_reason(uint16_t reason)
500 case DCERPC_BIND_REASON_ASYNTAX:
501 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
503 return NT_STATUS_UNSUCCESSFUL;
507 mark the dcerpc connection dead. All outstanding requests get an error
509 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
511 /* all pending requests get the error */
512 while (conn->pending) {
513 struct rpc_request *req = conn->pending;
514 req->state = RPC_REQUEST_DONE;
515 req->status = status;
516 DLIST_REMOVE(conn->pending, req);
517 if (req->async.callback) {
518 req->async.callback(req);
522 if (conn->bind_private) {
523 /* a bind was in flight - fail it */
524 struct composite_context *c = talloc_get_type(conn->bind_private, struct composite_context);
525 composite_error(c, status);
528 if (conn->alter_private) {
529 /* a alter context was in flight - fail it */
530 struct composite_context *c = talloc_get_type(conn->alter_private, struct composite_context);
531 composite_error(c, status);
536 forward declarations of the recv_data handlers for the 3 types of packets we need
539 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
540 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
541 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
542 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
545 receive a dcerpc reply from the transport. Here we work out what
546 type of reply it is (normal request, bind or alter context) and
547 dispatch to the appropriate handler
549 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
551 struct ncacn_packet pkt;
553 /* the transport may be telling us of a severe error, such as
555 if (!NT_STATUS_IS_OK(status)) {
556 data_blob_free(blob);
557 dcerpc_connection_dead(conn, status);
560 /* parse the basic packet to work out what type of response this is */
561 status = ncacn_pull(conn, blob, blob->data, &pkt);
562 if (!NT_STATUS_IS_OK(status)) {
563 data_blob_free(blob);
564 dcerpc_connection_dead(conn, status);
568 case DCERPC_PKT_BIND_NAK:
569 case DCERPC_PKT_BIND_ACK:
570 if (conn->bind_private) {
571 talloc_steal(conn->bind_private, blob->data);
572 dcerpc_bind_recv_data(conn, &pkt);
576 case DCERPC_PKT_ALTER_RESP:
577 if (conn->alter_private) {
578 talloc_steal(conn->alter_private, blob->data);
579 dcerpc_alter_recv_data(conn, &pkt);
584 /* assume its an ordinary request */
585 dcerpc_request_recv_data(conn, blob, &pkt);
592 Receive a bind reply from the transport
594 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
596 struct composite_context *c;
597 struct dcerpc_pipe *pipe;
599 c = talloc_get_type(conn->bind_private, struct composite_context);
600 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
602 /* mark the connection as not waiting for a bind reply */
603 conn->bind_private = NULL;
605 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
606 DEBUG(2,("dcerpc: bind_nak reason %d\n",
607 pkt->u.bind_nak.reject_reason));
608 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
613 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
614 (pkt->u.bind_ack.num_results == 0) ||
615 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
616 composite_error(c, NT_STATUS_UNSUCCESSFUL);
620 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
621 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
623 /* the bind_ack might contain a reply set of credentials */
624 if (conn->security_state.auth_info &&
625 pkt->u.bind_ack.auth_info.length) {
626 c->status = ndr_pull_struct_blob(
627 &pkt->u.bind_ack.auth_info, conn,
628 conn->security_state.auth_info,
629 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
630 if (!composite_is_ok(c)) return;
637 handle timeouts of dcerpc bind and alter context requests
639 static void bind_timeout_handler(struct event_context *ev,
640 struct timed_event *te,
641 struct timeval t, void *private)
643 struct composite_context *ctx =
644 talloc_get_type(private, struct composite_context);
645 struct dcerpc_pipe *pipe = talloc_get_type(ctx->private_data, struct dcerpc_pipe);
647 SMB_ASSERT(pipe->conn->bind_private != NULL);
648 pipe->conn->bind_private = NULL;
649 composite_error(ctx, NT_STATUS_IO_TIMEOUT);
653 send a async dcerpc bind request
655 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
657 const struct dcerpc_syntax_id *syntax,
658 const struct dcerpc_syntax_id *transfer_syntax)
660 struct composite_context *c;
661 struct ncacn_packet pkt;
664 c = talloc_zero(mem_ctx, struct composite_context);
665 if (c == NULL) return NULL;
667 c->state = COMPOSITE_STATE_IN_PROGRESS;
669 c->event_ctx = p->conn->event_ctx;
672 p->transfer_syntax = *transfer_syntax;
674 init_ncacn_hdr(p->conn, &pkt);
676 pkt.ptype = DCERPC_PKT_BIND;
677 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
678 pkt.call_id = p->conn->call_id;
681 pkt.u.bind.max_xmit_frag = 5840;
682 pkt.u.bind.max_recv_frag = 5840;
683 pkt.u.bind.assoc_group_id = 0;
684 pkt.u.bind.num_contexts = 1;
685 pkt.u.bind.ctx_list =
686 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
687 if (pkt.u.bind.ctx_list == NULL) {
688 c->status = NT_STATUS_NO_MEMORY;
691 pkt.u.bind.ctx_list[0].context_id = p->context_id;
692 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
693 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
694 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
695 pkt.u.bind.auth_info = data_blob(NULL, 0);
697 /* construct the NDR form of the packet */
698 c->status = ncacn_push_auth(&blob, c, &pkt,
699 p->conn->security_state.auth_info);
700 if (!NT_STATUS_IS_OK(c->status)) {
704 p->conn->transport.recv_data = dcerpc_recv_data;
705 p->conn->bind_private = c;
707 c->status = p->conn->transport.send_request(p->conn, &blob,
709 if (!NT_STATUS_IS_OK(c->status)) {
713 event_add_timed(c->event_ctx, c,
714 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
715 bind_timeout_handler, c);
720 composite_trigger_error(c);
725 recv side of async dcerpc bind request
727 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
729 NTSTATUS result = composite_wait(ctx);
735 perform a bind using the given syntax
737 the auth_info structure is updated with the reply authentication info
740 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
742 const struct dcerpc_syntax_id *syntax,
743 const struct dcerpc_syntax_id *transfer_syntax)
745 struct composite_context *creq;
746 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
747 return dcerpc_bind_recv(creq);
751 perform a continued bind (and auth3)
753 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
756 struct ncacn_packet pkt;
760 init_ncacn_hdr(c, &pkt);
762 pkt.ptype = DCERPC_PKT_AUTH3;
763 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
764 pkt.call_id = next_call_id(c);
766 pkt.u.auth3._pad = 0;
767 pkt.u.auth3.auth_info = data_blob(NULL, 0);
769 /* construct the NDR form of the packet */
770 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
771 if (!NT_STATUS_IS_OK(status)) {
775 /* send it on its way */
776 status = c->transport.send_request(c, &blob, False);
777 if (!NT_STATUS_IS_OK(status)) {
786 return the rpc syntax and transfer syntax given the pipe uuid and version
788 NTSTATUS dcerpc_init_syntaxes(const char *uuid, uint_t version,
789 struct dcerpc_syntax_id *syntax,
790 struct dcerpc_syntax_id *transfer_syntax)
794 status = GUID_from_string(uuid, &syntax->uuid);
795 if (!NT_STATUS_IS_OK(status)) return status;
797 syntax->if_version = version;
799 status = GUID_from_string(NDR_GUID, &transfer_syntax->uuid);
800 if (!NT_STATUS_IS_OK(status)) return status;
802 transfer_syntax->if_version = NDR_GUID_VERSION;
807 /* perform a dcerpc bind, using the uuid as the key */
808 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
810 const char *uuid, uint_t version)
812 struct dcerpc_syntax_id syntax;
813 struct dcerpc_syntax_id transfer_syntax;
816 status = dcerpc_init_syntaxes(uuid, version,
817 &syntax, &transfer_syntax);
818 if (!NT_STATUS_IS_OK(status)) {
819 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
823 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
828 process a fragment received from the transport layer during a
831 This function frees the data
833 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
834 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
836 struct rpc_request *req;
838 NTSTATUS status = NT_STATUS_OK;
841 if this is an authenticated connection then parse and check
842 the auth info. We have to do this before finding the
843 matching packet, as the request structure might have been
844 removed due to a timeout, but if it has been we still need
845 to run the auth routines so that we don't get the sign/seal
846 info out of step with the server
848 if (c->security_state.auth_info && c->security_state.generic_state &&
849 pkt->ptype == DCERPC_PKT_RESPONSE) {
850 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
853 /* find the matching request */
854 for (req=c->pending;req;req=req->next) {
855 if (pkt->call_id == req->call_id) break;
859 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
860 data_blob_free(raw_packet);
864 talloc_steal(req, raw_packet->data);
866 if (pkt->ptype == DCERPC_PKT_FAULT) {
867 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
868 req->fault_code = pkt->u.fault.status;
869 req->status = NT_STATUS_NET_WRITE_FAULT;
873 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
874 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
876 req->fault_code = DCERPC_FAULT_OTHER;
877 req->status = NT_STATUS_NET_WRITE_FAULT;
881 /* now check the status from the auth routines, and if it failed then fail
882 this request accordingly */
883 if (!NT_STATUS_IS_OK(status)) {
884 req->status = status;
888 length = pkt->u.response.stub_and_verifier.length;
891 req->payload.data = talloc_realloc(req,
894 req->payload.length + length);
895 if (!req->payload.data) {
896 req->status = NT_STATUS_NO_MEMORY;
899 memcpy(req->payload.data+req->payload.length,
900 pkt->u.response.stub_and_verifier.data, length);
901 req->payload.length += length;
904 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
905 c->transport.send_read(c);
909 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
910 req->flags |= DCERPC_PULL_BIGENDIAN;
912 req->flags &= ~DCERPC_PULL_BIGENDIAN;
917 /* we've got the full payload */
918 req->state = RPC_REQUEST_DONE;
919 DLIST_REMOVE(c->pending, req);
921 if (c->request_queue != NULL) {
922 /* We have to look at shipping further requests before calling
923 * the async function, that one might close the pipe */
924 dcerpc_ship_next_request(c);
927 if (req->async.callback) {
928 req->async.callback(req);
933 handle timeouts of individual dcerpc requests
935 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
936 struct timeval t, void *private)
938 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
940 if (req->state != RPC_REQUEST_PENDING) {
944 req->status = NT_STATUS_IO_TIMEOUT;
945 req->state = RPC_REQUEST_DONE;
946 DLIST_REMOVE(req->p->conn->pending, req);
947 if (req->async.callback) {
948 req->async.callback(req);
954 make sure requests are cleaned up
956 static int dcerpc_req_destructor(void *ptr)
958 struct rpc_request *req = ptr;
959 DLIST_REMOVE(req->p->conn->pending, req);
964 perform the send side of a async dcerpc request
966 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
967 const struct GUID *object,
970 DATA_BLOB *stub_data)
972 struct rpc_request *req;
974 p->conn->transport.recv_data = dcerpc_recv_data;
976 req = talloc(p, struct rpc_request);
982 req->call_id = next_call_id(p->conn);
983 req->status = NT_STATUS_OK;
984 req->state = RPC_REQUEST_PENDING;
985 req->payload = data_blob(NULL, 0);
988 req->async_call = async;
989 req->async.callback = NULL;
991 if (object != NULL) {
992 req->object = talloc_memdup(req, object, sizeof(*object));
993 if (req->object == NULL) {
1002 req->request_data.length = stub_data->length;
1003 req->request_data.data = talloc_reference(req, stub_data->data);
1004 if (req->request_data.data == NULL) {
1008 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1010 dcerpc_ship_next_request(p->conn);
1012 if (p->request_timeout) {
1013 event_add_timed(dcerpc_event_context(p), req,
1014 timeval_current_ofs(p->request_timeout, 0),
1015 dcerpc_timeout_handler, req);
1018 talloc_set_destructor(req, dcerpc_req_destructor);
1023 Send a request using the transport
1026 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1028 struct rpc_request *req;
1029 struct dcerpc_pipe *p;
1030 DATA_BLOB *stub_data;
1031 struct ncacn_packet pkt;
1033 uint32_t remaining, chunk_size;
1034 BOOL first_packet = True;
1036 req = c->request_queue;
1042 stub_data = &req->request_data;
1044 if (!req->async_call && (c->pending != NULL)) {
1048 DLIST_REMOVE(c->request_queue, req);
1049 DLIST_ADD(c->pending, req);
1051 init_ncacn_hdr(p->conn, &pkt);
1053 remaining = stub_data->length;
1055 /* we can write a full max_recv_frag size, minus the dcerpc
1056 request header size */
1057 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1059 pkt.ptype = DCERPC_PKT_REQUEST;
1060 pkt.call_id = req->call_id;
1061 pkt.auth_length = 0;
1063 pkt.u.request.alloc_hint = remaining;
1064 pkt.u.request.context_id = p->context_id;
1065 pkt.u.request.opnum = req->opnum;
1068 pkt.u.request.object.object = *req->object;
1069 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1070 chunk_size -= ndr_size_GUID(req->object,0);
1073 /* we send a series of pdus without waiting for a reply */
1074 while (remaining > 0 || first_packet) {
1075 uint32_t chunk = MIN(chunk_size, remaining);
1076 BOOL last_frag = False;
1078 first_packet = False;
1079 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1081 if (remaining == stub_data->length) {
1082 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1084 if (chunk == remaining) {
1085 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1089 pkt.u.request.stub_and_verifier.data = stub_data->data +
1090 (stub_data->length - remaining);
1091 pkt.u.request.stub_and_verifier.length = chunk;
1093 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1094 if (!NT_STATUS_IS_OK(req->status)) {
1095 req->state = RPC_REQUEST_DONE;
1096 DLIST_REMOVE(p->conn->pending, req);
1100 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1101 if (!NT_STATUS_IS_OK(req->status)) {
1102 req->state = RPC_REQUEST_DONE;
1103 DLIST_REMOVE(p->conn->pending, req);
1112 return the event context for a dcerpc pipe
1113 used by callers who wish to operate asynchronously
1115 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1117 return p->conn->event_ctx;
1123 perform the receive side of a async dcerpc request
1125 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1126 TALLOC_CTX *mem_ctx,
1127 DATA_BLOB *stub_data)
1131 while (req->state == RPC_REQUEST_PENDING) {
1132 struct event_context *ctx = dcerpc_event_context(req->p);
1133 if (event_loop_once(ctx) != 0) {
1134 return NT_STATUS_CONNECTION_DISCONNECTED;
1137 *stub_data = req->payload;
1138 status = req->status;
1139 if (stub_data->data) {
1140 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1142 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1143 req->p->last_fault_code = req->fault_code;
1150 perform a full request/response pair on a dcerpc pipe
1152 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1153 struct GUID *object,
1156 TALLOC_CTX *mem_ctx,
1157 DATA_BLOB *stub_data_in,
1158 DATA_BLOB *stub_data_out)
1160 struct rpc_request *req;
1162 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1164 return NT_STATUS_NO_MEMORY;
1167 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1172 this is a paranoid NDR validator. For every packet we push onto the wire
1173 we pull it back again, then push it again. Then we compare the raw NDR data
1174 for that to the NDR we initially generated. If they don't match then we know
1175 we must have a bug in either the pull or push side of our code
1177 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1178 TALLOC_CTX *mem_ctx,
1181 ndr_push_flags_fn_t ndr_push,
1182 ndr_pull_flags_fn_t ndr_pull)
1185 struct ndr_pull *pull;
1186 struct ndr_push *push;
1190 st = talloc_size(mem_ctx, struct_size);
1192 return NT_STATUS_NO_MEMORY;
1195 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1197 return NT_STATUS_NO_MEMORY;
1199 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1201 status = ndr_pull(pull, NDR_IN, st);
1202 if (!NT_STATUS_IS_OK(status)) {
1203 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1204 "failed input validation pull - %s",
1208 push = ndr_push_init_ctx(mem_ctx);
1210 return NT_STATUS_NO_MEMORY;
1213 status = ndr_push(push, NDR_IN, st);
1214 if (!NT_STATUS_IS_OK(status)) {
1215 return ndr_push_error(push, NDR_ERR_VALIDATE,
1216 "failed input validation push - %s",
1220 blob2 = ndr_push_blob(push);
1222 if (!data_blob_equal(&blob, &blob2)) {
1223 DEBUG(3,("original:\n"));
1224 dump_data(3, blob.data, blob.length);
1225 DEBUG(3,("secondary:\n"));
1226 dump_data(3, blob2.data, blob2.length);
1227 return ndr_push_error(push, NDR_ERR_VALIDATE,
1228 "failed input validation data - %s",
1232 return NT_STATUS_OK;
1236 this is a paranoid NDR input validator. For every packet we pull
1237 from the wire we push it back again then pull and push it
1238 again. Then we compare the raw NDR data for that to the NDR we
1239 initially generated. If they don't match then we know we must have a
1240 bug in either the pull or push side of our code
1242 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1243 TALLOC_CTX *mem_ctx,
1246 ndr_push_flags_fn_t ndr_push,
1247 ndr_pull_flags_fn_t ndr_pull)
1250 struct ndr_pull *pull;
1251 struct ndr_push *push;
1253 DATA_BLOB blob, blob2;
1255 st = talloc_size(mem_ctx, struct_size);
1257 return NT_STATUS_NO_MEMORY;
1259 memcpy(st, struct_ptr, struct_size);
1261 push = ndr_push_init_ctx(mem_ctx);
1263 return NT_STATUS_NO_MEMORY;
1266 status = ndr_push(push, NDR_OUT, struct_ptr);
1267 if (!NT_STATUS_IS_OK(status)) {
1268 return ndr_push_error(push, NDR_ERR_VALIDATE,
1269 "failed output validation push - %s",
1273 blob = ndr_push_blob(push);
1275 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1277 return NT_STATUS_NO_MEMORY;
1280 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1281 status = ndr_pull(pull, NDR_OUT, st);
1282 if (!NT_STATUS_IS_OK(status)) {
1283 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1284 "failed output validation pull - %s",
1288 push = ndr_push_init_ctx(mem_ctx);
1290 return NT_STATUS_NO_MEMORY;
1293 status = ndr_push(push, NDR_OUT, st);
1294 if (!NT_STATUS_IS_OK(status)) {
1295 return ndr_push_error(push, NDR_ERR_VALIDATE,
1296 "failed output validation push2 - %s",
1300 blob2 = ndr_push_blob(push);
1302 if (!data_blob_equal(&blob, &blob2)) {
1303 DEBUG(3,("original:\n"));
1304 dump_data(3, blob.data, blob.length);
1305 DEBUG(3,("secondary:\n"));
1306 dump_data(3, blob2.data, blob2.length);
1307 return ndr_push_error(push, NDR_ERR_VALIDATE,
1308 "failed output validation data - %s",
1312 return NT_STATUS_OK;
1317 send a rpc request given a dcerpc_call structure
1319 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1320 const struct GUID *object,
1321 const struct dcerpc_interface_table *table,
1323 TALLOC_CTX *mem_ctx,
1326 const struct dcerpc_interface_call *call;
1327 struct ndr_push *push;
1330 struct rpc_request *req;
1332 call = &table->calls[opnum];
1334 /* setup for a ndr_push_* call */
1335 push = ndr_push_init_ctx(mem_ctx);
1340 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1341 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1344 /* push the structure into a blob */
1345 status = call->ndr_push(push, NDR_IN, r);
1346 if (!NT_STATUS_IS_OK(status)) {
1347 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1348 nt_errstr(status)));
1353 /* retrieve the blob */
1354 request = ndr_push_blob(push);
1356 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1357 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1358 call->ndr_push, call->ndr_pull);
1359 if (!NT_STATUS_IS_OK(status)) {
1360 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1361 nt_errstr(status)));
1367 DEBUG(10,("rpc request data:\n"));
1368 dump_data(10, request.data, request.length);
1370 /* make the actual dcerpc request */
1371 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1375 req->ndr.table = table;
1376 req->ndr.opnum = opnum;
1377 req->ndr.struct_ptr = r;
1378 req->ndr.mem_ctx = mem_ctx;
1387 receive the answer from a dcerpc_ndr_request_send()
1389 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1391 struct dcerpc_pipe *p = req->p;
1394 struct ndr_pull *pull;
1396 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1397 void *r = req->ndr.struct_ptr;
1398 uint32_t opnum = req->ndr.opnum;
1399 const struct dcerpc_interface_table *table = req->ndr.table;
1400 const struct dcerpc_interface_call *call = &table->calls[opnum];
1402 /* make sure the recv code doesn't free the request, as we
1403 need to grab the flags element before it is freed */
1404 talloc_increase_ref_count(req);
1406 status = dcerpc_request_recv(req, mem_ctx, &response);
1407 if (!NT_STATUS_IS_OK(status)) {
1413 /* prepare for ndr_pull_* */
1414 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1417 return NT_STATUS_NO_MEMORY;
1421 pull->data = talloc_steal(pull, pull->data);
1425 if (flags & DCERPC_PULL_BIGENDIAN) {
1426 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1429 DEBUG(10,("rpc reply data:\n"));
1430 dump_data(10, pull->data, pull->data_size);
1432 /* pull the structure from the blob */
1433 status = call->ndr_pull(pull, NDR_OUT, r);
1434 if (!NT_STATUS_IS_OK(status)) {
1435 dcerpc_log_packet(table, opnum, NDR_OUT,
1440 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1441 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1442 call->ndr_push, call->ndr_pull);
1443 if (!NT_STATUS_IS_OK(status)) {
1444 dcerpc_log_packet(table, opnum, NDR_OUT,
1450 if (pull->offset != pull->data_size) {
1451 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1452 pull->data_size - pull->offset));
1453 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1454 but it turns out that early versions of NT
1455 (specifically NT3.1) add junk onto the end of rpc
1456 packets, so if we want to interoperate at all with
1457 those versions then we need to ignore this error */
1460 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1462 return NT_STATUS_OK;
1467 a useful helper function for synchronous rpc requests
1469 this can be used when you have ndr push/pull functions in the
1472 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1473 const struct GUID *object,
1474 const struct dcerpc_interface_table *table,
1476 TALLOC_CTX *mem_ctx,
1479 struct rpc_request *req;
1481 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1483 return NT_STATUS_NO_MEMORY;
1486 return dcerpc_ndr_request_recv(req);
1491 a useful function for retrieving the server name we connected to
1493 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1495 if (!p->conn->transport.peer_name) {
1498 return p->conn->transport.peer_name(p->conn);
1503 get the dcerpc auth_level for a open connection
1505 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1509 if (c->flags & DCERPC_SEAL) {
1510 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1511 } else if (c->flags & DCERPC_SIGN) {
1512 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1513 } else if (c->flags & DCERPC_CONNECT) {
1514 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1516 auth_level = DCERPC_AUTH_LEVEL_NONE;
1522 Receive an alter reply from the transport
1524 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
1526 struct composite_context *c;
1527 struct dcerpc_pipe *pipe;
1529 c = talloc_get_type(conn->alter_private, struct composite_context);
1530 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1532 /* mark the connection as not waiting for a alter context reply */
1533 conn->alter_private = NULL;
1535 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1536 pkt->u.alter_resp.num_results == 1 &&
1537 pkt->u.alter_resp.ctx_list[0].result != 0) {
1538 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1539 pkt->u.alter_resp.ctx_list[0].reason));
1540 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1544 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1545 pkt->u.alter_resp.num_results == 0 ||
1546 pkt->u.alter_resp.ctx_list[0].result != 0) {
1547 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1551 /* the alter_resp might contain a reply set of credentials */
1552 if (pipe->conn->security_state.auth_info &&
1553 pkt->u.alter_resp.auth_info.length) {
1554 c->status = ndr_pull_struct_blob(
1555 &pkt->u.alter_resp.auth_info, c,
1556 pipe->conn->security_state.auth_info,
1557 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1558 if (!composite_is_ok(c)) return;
1565 send a dcerpc alter_context request
1567 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1568 TALLOC_CTX *mem_ctx,
1569 const struct dcerpc_syntax_id *syntax,
1570 const struct dcerpc_syntax_id *transfer_syntax)
1572 struct composite_context *c;
1573 struct ncacn_packet pkt;
1576 c = talloc_zero(mem_ctx, struct composite_context);
1577 if (c == NULL) return NULL;
1579 c->state = COMPOSITE_STATE_IN_PROGRESS;
1580 c->private_data = p;
1581 c->event_ctx = p->conn->event_ctx;
1583 p->syntax = *syntax;
1584 p->transfer_syntax = *transfer_syntax;
1586 init_ncacn_hdr(p->conn, &pkt);
1588 pkt.ptype = DCERPC_PKT_ALTER;
1589 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1590 pkt.call_id = p->conn->call_id;
1591 pkt.auth_length = 0;
1593 pkt.u.alter.max_xmit_frag = 5840;
1594 pkt.u.alter.max_recv_frag = 5840;
1595 pkt.u.alter.assoc_group_id = 0;
1596 pkt.u.alter.num_contexts = 1;
1597 pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1598 struct dcerpc_ctx_list, 1);
1599 if (pkt.u.alter.ctx_list == NULL) {
1600 c->status = NT_STATUS_NO_MEMORY;
1603 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1604 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1605 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1606 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1607 pkt.u.alter.auth_info = data_blob(NULL, 0);
1609 /* construct the NDR form of the packet */
1610 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1611 p->conn->security_state.auth_info);
1612 if (!NT_STATUS_IS_OK(c->status)) {
1616 p->conn->transport.recv_data = dcerpc_recv_data;
1617 p->conn->alter_private = c;
1619 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1620 if (!NT_STATUS_IS_OK(c->status)) {
1624 event_add_timed(c->event_ctx, c,
1625 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1626 bind_timeout_handler, c);
1631 composite_trigger_error(c);
1635 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1637 NTSTATUS result = composite_wait(ctx);
1643 send a dcerpc alter_context request
1645 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1646 TALLOC_CTX *mem_ctx,
1647 const struct dcerpc_syntax_id *syntax,
1648 const struct dcerpc_syntax_id *transfer_syntax)
1650 struct composite_context *creq;
1651 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1652 return dcerpc_alter_context_recv(creq);