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 3 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, see <http://www.gnu.org/licenses/>.
24 #include "lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "libcli/composite/composite.h"
30 #include "auth/gensec/gensec.h"
32 NTSTATUS dcerpc_init(void)
39 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
46 conn->free_skipped = True;
49 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
54 /* initialise a dcerpc connection.
55 the event context is optional
57 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
58 struct event_context *ev)
60 struct dcerpc_connection *c;
62 c = talloc_zero(mem_ctx, struct dcerpc_connection);
68 ev = event_context_init(c);
77 if (!talloc_reference(c, ev)) {
82 c->security_state.auth_info = NULL;
83 c->security_state.session_key = dcerpc_generic_session_key;
84 c->security_state.generic_state = NULL;
85 c->binding_string = NULL;
87 c->srv_max_xmit_frag = 0;
88 c->srv_max_recv_frag = 0;
91 talloc_set_destructor(c, dcerpc_connection_destructor);
96 /* initialise a dcerpc pipe. */
97 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
99 struct dcerpc_pipe *p;
101 p = talloc(mem_ctx, struct dcerpc_pipe);
106 p->conn = dcerpc_connection_init(p, ev);
107 if (p->conn == NULL) {
112 p->last_fault_code = 0;
114 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
117 ZERO_STRUCT(p->syntax);
118 ZERO_STRUCT(p->transfer_syntax);
125 choose the next call id to use
127 static uint32_t next_call_id(struct dcerpc_connection *c)
130 if (c->call_id == 0) {
136 /* we need to be able to get/set the fragment length without doing a full
138 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
140 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
141 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
143 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
147 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
149 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
150 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
152 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
156 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
158 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
159 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
161 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
167 setup for a ndr pull, also setting up any flags from the binding string
169 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
170 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
172 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
174 if (ndr == NULL) return ndr;
176 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
177 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
180 if (c->flags & DCERPC_NDR_REF_ALLOC) {
181 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
188 parse a data blob into a ncacn_packet structure. This handles both
189 input and output packets
191 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
192 struct ncacn_packet *pkt)
194 struct ndr_pull *ndr;
196 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
198 return NT_STATUS_NO_MEMORY;
201 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
202 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
205 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
209 generate a CONNECT level verifier
211 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
213 *blob = data_blob_talloc(mem_ctx, NULL, 16);
214 if (blob->data == NULL) {
215 return NT_STATUS_NO_MEMORY;
217 SIVAL(blob->data, 0, 1);
218 memset(blob->data+4, 0, 12);
223 check a CONNECT level verifier
225 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
227 if (blob->length != 16 ||
228 IVAL(blob->data, 0) != 1) {
229 return NT_STATUS_ACCESS_DENIED;
235 parse the authentication information on a dcerpc response packet
237 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
238 DATA_BLOB *raw_packet,
239 struct ncacn_packet *pkt)
241 struct ndr_pull *ndr;
243 struct dcerpc_auth auth;
246 if (pkt->auth_length == 0 &&
247 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
251 auth_blob.length = 8 + pkt->auth_length;
253 /* check for a valid length */
254 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
255 return NT_STATUS_INFO_LENGTH_MISMATCH;
259 pkt->u.response.stub_and_verifier.data +
260 pkt->u.response.stub_and_verifier.length - auth_blob.length;
261 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
263 /* pull the auth structure */
264 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
266 return NT_STATUS_NO_MEMORY;
269 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
270 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
273 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
274 if (!NT_STATUS_IS_OK(status)) {
278 /* check signature or unseal the packet */
279 switch (c->security_state.auth_info->auth_level) {
280 case DCERPC_AUTH_LEVEL_PRIVACY:
281 status = gensec_unseal_packet(c->security_state.generic_state,
283 raw_packet->data + DCERPC_REQUEST_LENGTH,
284 pkt->u.response.stub_and_verifier.length,
286 raw_packet->length - auth.credentials.length,
288 memcpy(pkt->u.response.stub_and_verifier.data,
289 raw_packet->data + DCERPC_REQUEST_LENGTH,
290 pkt->u.response.stub_and_verifier.length);
293 case DCERPC_AUTH_LEVEL_INTEGRITY:
294 status = gensec_check_packet(c->security_state.generic_state,
296 pkt->u.response.stub_and_verifier.data,
297 pkt->u.response.stub_and_verifier.length,
299 raw_packet->length - auth.credentials.length,
303 case DCERPC_AUTH_LEVEL_CONNECT:
304 status = dcerpc_check_connect_verifier(&auth.credentials);
307 case DCERPC_AUTH_LEVEL_NONE:
311 status = NT_STATUS_INVALID_LEVEL;
315 /* remove the indicated amount of paddiing */
316 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
317 return NT_STATUS_INFO_LENGTH_MISMATCH;
319 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
326 push a dcerpc request packet into a blob, possibly signing it.
328 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
329 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
330 struct ncacn_packet *pkt)
333 struct ndr_push *ndr;
335 size_t payload_length;
337 /* non-signed packets are simpler */
338 if (!c->security_state.auth_info ||
339 !c->security_state.generic_state) {
340 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
343 ndr = ndr_push_init_ctx(mem_ctx);
345 return NT_STATUS_NO_MEMORY;
348 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
349 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
352 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
353 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
356 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
357 if (!NT_STATUS_IS_OK(status)) {
361 /* pad to 16 byte multiple in the payload portion of the
362 packet. This matches what w2k3 does */
363 c->security_state.auth_info->auth_pad_length =
364 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
365 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
367 payload_length = pkt->u.request.stub_and_verifier.length +
368 c->security_state.auth_info->auth_pad_length;
370 /* sign or seal the packet */
371 switch (c->security_state.auth_info->auth_level) {
372 case DCERPC_AUTH_LEVEL_PRIVACY:
373 case DCERPC_AUTH_LEVEL_INTEGRITY:
374 /* We hope this length is accruate. If must be if the
375 * GENSEC mech does AEAD signing of the packet
377 c->security_state.auth_info->credentials
378 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
380 data_blob_clear(&c->security_state.auth_info->credentials);
383 case DCERPC_AUTH_LEVEL_CONNECT:
384 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
387 case DCERPC_AUTH_LEVEL_NONE:
388 c->security_state.auth_info->credentials = data_blob(NULL, 0);
392 status = NT_STATUS_INVALID_LEVEL;
396 if (!NT_STATUS_IS_OK(status)) {
400 /* add the auth verifier */
401 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
402 if (!NT_STATUS_IS_OK(status)) {
406 /* extract the whole packet as a blob */
407 *blob = ndr_push_blob(ndr);
409 /* fill in the fragment length and auth_length, we can't fill
410 in these earlier as we don't know the signature length (it
411 could be variable length) */
412 dcerpc_set_frag_length(blob, blob->length);
413 /* We hope this value is accruate. If must be if the GENSEC
414 * mech does AEAD signing of the packet headers */
415 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
417 /* sign or seal the packet */
418 switch (c->security_state.auth_info->auth_level) {
419 case DCERPC_AUTH_LEVEL_PRIVACY:
420 status = gensec_seal_packet(c->security_state.generic_state,
422 blob->data + DCERPC_REQUEST_LENGTH,
426 c->security_state.auth_info->credentials.length,
428 if (!NT_STATUS_IS_OK(status)) {
431 blob->length -= c->security_state.auth_info->credentials.length;
432 status = data_blob_append(mem_ctx, blob,
433 creds2.data, creds2.length);
434 if (!NT_STATUS_IS_OK(status)) {
437 dcerpc_set_auth_length(blob, creds2.length);
438 if (c->security_state.auth_info->credentials.length == 0) {
439 /* this is needed for krb5 only, to correct the total packet
441 dcerpc_set_frag_length(blob,
442 dcerpc_get_frag_length(blob)
447 case DCERPC_AUTH_LEVEL_INTEGRITY:
448 status = gensec_sign_packet(c->security_state.generic_state,
450 blob->data + DCERPC_REQUEST_LENGTH,
454 c->security_state.auth_info->credentials.length,
456 if (!NT_STATUS_IS_OK(status)) {
459 blob->length -= c->security_state.auth_info->credentials.length;
460 status = data_blob_append(mem_ctx, blob,
461 creds2.data, creds2.length);
462 if (!NT_STATUS_IS_OK(status)) {
465 dcerpc_set_auth_length(blob, creds2.length);
466 if (c->security_state.auth_info->credentials.length == 0) {
467 /* this is needed for krb5 only, to correct the total packet
469 dcerpc_set_frag_length(blob,
470 dcerpc_get_frag_length(blob)
475 case DCERPC_AUTH_LEVEL_CONNECT:
478 case DCERPC_AUTH_LEVEL_NONE:
479 c->security_state.auth_info->credentials = data_blob(NULL, 0);
483 status = NT_STATUS_INVALID_LEVEL;
487 data_blob_free(&c->security_state.auth_info->credentials);
494 fill in the fixed values in a dcerpc header
496 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
499 pkt->rpc_vers_minor = 0;
500 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
503 pkt->drep[0] = DCERPC_DREP_LE;
511 map a bind nak reason to a NTSTATUS
513 static NTSTATUS dcerpc_map_reason(uint16_t reason)
516 case DCERPC_BIND_REASON_ASYNTAX:
517 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
518 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
519 return NT_STATUS_INVALID_PARAMETER;
521 return NT_STATUS_UNSUCCESSFUL;
525 a bind or alter context has failed
527 static void dcerpc_composite_fail(struct rpc_request *req)
529 struct composite_context *c = talloc_get_type(req->async.private_data,
530 struct composite_context);
531 composite_error(c, req->status);
535 remove requests from the pending or queued queues
537 static int dcerpc_req_dequeue(struct rpc_request *req)
539 switch (req->state) {
540 case RPC_REQUEST_QUEUED:
541 DLIST_REMOVE(req->p->conn->request_queue, req);
543 case RPC_REQUEST_PENDING:
544 DLIST_REMOVE(req->p->conn->pending, req);
546 case RPC_REQUEST_DONE:
554 mark the dcerpc connection dead. All outstanding requests get an error
556 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
558 if (conn->dead) return;
562 if (conn->transport.shutdown_pipe) {
563 conn->transport.shutdown_pipe(conn, status);
566 /* all pending requests get the error */
567 while (conn->pending) {
568 struct rpc_request *req = conn->pending;
569 dcerpc_req_dequeue(req);
570 req->state = RPC_REQUEST_DONE;
571 req->status = status;
572 if (req->async.callback) {
573 req->async.callback(req);
577 talloc_set_destructor(conn, NULL);
578 if (conn->free_skipped) {
584 forward declarations of the recv_data handlers for the types of
585 packets we need to handle
587 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
588 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
591 receive a dcerpc reply from the transport. Here we work out what
592 type of reply it is (normal request, bind or alter context) and
593 dispatch to the appropriate handler
595 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
597 struct ncacn_packet pkt;
599 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
600 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
603 /* the transport may be telling us of a severe error, such as
605 if (!NT_STATUS_IS_OK(status)) {
606 data_blob_free(blob);
607 dcerpc_connection_dead(conn, status);
611 /* parse the basic packet to work out what type of response this is */
612 status = ncacn_pull(conn, blob, blob->data, &pkt);
613 if (!NT_STATUS_IS_OK(status)) {
614 data_blob_free(blob);
615 dcerpc_connection_dead(conn, status);
618 dcerpc_request_recv_data(conn, blob, &pkt);
623 Receive a bind reply from the transport
625 static void dcerpc_bind_recv_handler(struct rpc_request *req,
626 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
628 struct composite_context *c;
629 struct dcerpc_connection *conn;
631 c = talloc_get_type(req->async.private_data, struct composite_context);
633 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
634 DEBUG(2,("dcerpc: bind_nak reason %d\n",
635 pkt->u.bind_nak.reject_reason));
636 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
641 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
642 (pkt->u.bind_ack.num_results == 0) ||
643 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
644 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
650 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
651 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
653 /* the bind_ack might contain a reply set of credentials */
654 if (conn->security_state.auth_info &&
655 pkt->u.bind_ack.auth_info.length) {
656 c->status = ndr_pull_struct_blob(
657 &pkt->u.bind_ack.auth_info, conn,
658 conn->security_state.auth_info,
659 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
660 if (!composite_is_ok(c)) return;
663 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
669 handle timeouts of individual dcerpc requests
671 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
672 struct timeval t, void *private)
674 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
676 if (req->ignore_timeout) {
677 dcerpc_req_dequeue(req);
678 req->state = RPC_REQUEST_DONE;
679 req->status = NT_STATUS_IO_TIMEOUT;
680 if (req->async.callback) {
681 req->async.callback(req);
686 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
690 send a async dcerpc bind request
692 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
694 const struct dcerpc_syntax_id *syntax,
695 const struct dcerpc_syntax_id *transfer_syntax)
697 struct composite_context *c;
698 struct ncacn_packet pkt;
700 struct rpc_request *req;
702 c = composite_create(mem_ctx,p->conn->event_ctx);
703 if (c == NULL) return NULL;
708 p->transfer_syntax = *transfer_syntax;
710 init_ncacn_hdr(p->conn, &pkt);
712 pkt.ptype = DCERPC_PKT_BIND;
713 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
714 pkt.call_id = p->conn->call_id;
717 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
718 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
721 pkt.u.bind.max_xmit_frag = 5840;
722 pkt.u.bind.max_recv_frag = 5840;
723 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
724 pkt.u.bind.num_contexts = 1;
725 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
726 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
727 pkt.u.bind.ctx_list[0].context_id = p->context_id;
728 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
729 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
730 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
731 pkt.u.bind.auth_info = data_blob(NULL, 0);
733 /* construct the NDR form of the packet */
734 c->status = ncacn_push_auth(&blob, c, &pkt,
735 p->conn->security_state.auth_info);
736 if (!composite_is_ok(c)) return c;
738 p->conn->transport.recv_data = dcerpc_recv_data;
741 * we allocate a dcerpc_request so we can be in the same
742 * request queue as normal requests
744 req = talloc_zero(c, struct rpc_request);
745 if (composite_nomem(req, c)) return c;
747 req->state = RPC_REQUEST_PENDING;
748 req->call_id = pkt.call_id;
749 req->async.private_data = c;
750 req->async.callback = dcerpc_composite_fail;
752 req->recv_handler = dcerpc_bind_recv_handler;
753 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
754 talloc_set_destructor(req, dcerpc_req_dequeue);
756 c->status = p->conn->transport.send_request(p->conn, &blob,
758 if (!composite_is_ok(c)) return c;
760 event_add_timed(c->event_ctx, req,
761 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
762 dcerpc_timeout_handler, req);
768 recv side of async dcerpc bind request
770 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
772 NTSTATUS result = composite_wait(ctx);
778 perform a continued bind (and auth3)
780 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
783 struct ncacn_packet pkt;
787 init_ncacn_hdr(c, &pkt);
789 pkt.ptype = DCERPC_PKT_AUTH3;
790 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
791 pkt.call_id = next_call_id(c);
793 pkt.u.auth3._pad = 0;
794 pkt.u.auth3.auth_info = data_blob(NULL, 0);
796 /* construct the NDR form of the packet */
797 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
798 if (!NT_STATUS_IS_OK(status)) {
802 /* send it on its way */
803 status = c->transport.send_request(c, &blob, False);
804 if (!NT_STATUS_IS_OK(status)) {
813 process a fragment received from the transport layer during a
816 This function frees the data
818 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
819 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
821 struct rpc_request *req;
823 NTSTATUS status = NT_STATUS_OK;
826 if this is an authenticated connection then parse and check
827 the auth info. We have to do this before finding the
828 matching packet, as the request structure might have been
829 removed due to a timeout, but if it has been we still need
830 to run the auth routines so that we don't get the sign/seal
831 info out of step with the server
833 if (c->security_state.auth_info && c->security_state.generic_state &&
834 pkt->ptype == DCERPC_PKT_RESPONSE) {
835 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
838 /* find the matching request */
839 for (req=c->pending;req;req=req->next) {
840 if (pkt->call_id == req->call_id) break;
844 /* useful for testing certain vendors RPC servers */
845 if (req == NULL && c->pending && pkt->call_id == 0) {
846 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
852 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
853 data_blob_free(raw_packet);
857 talloc_steal(req, raw_packet->data);
859 if (req->recv_handler != NULL) {
860 dcerpc_req_dequeue(req);
861 req->state = RPC_REQUEST_DONE;
862 req->recv_handler(req, raw_packet, pkt);
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 perform the send side of a async dcerpc request
935 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
936 const struct GUID *object,
939 DATA_BLOB *stub_data)
941 struct rpc_request *req;
943 p->conn->transport.recv_data = dcerpc_recv_data;
945 req = talloc(p, struct rpc_request);
951 req->call_id = next_call_id(p->conn);
952 req->status = NT_STATUS_OK;
953 req->state = RPC_REQUEST_QUEUED;
954 req->payload = data_blob(NULL, 0);
957 req->async_call = async;
958 req->ignore_timeout = False;
959 req->async.callback = NULL;
960 req->async.private_data = NULL;
961 req->recv_handler = NULL;
963 if (object != NULL) {
964 req->object = talloc_memdup(req, object, sizeof(*object));
965 if (req->object == NULL) {
974 req->request_data.length = stub_data->length;
975 req->request_data.data = talloc_reference(req, stub_data->data);
976 if (req->request_data.length && req->request_data.data == NULL) {
980 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
981 talloc_set_destructor(req, dcerpc_req_dequeue);
983 dcerpc_ship_next_request(p->conn);
985 if (p->request_timeout) {
986 event_add_timed(dcerpc_event_context(p), req,
987 timeval_current_ofs(p->request_timeout, 0),
988 dcerpc_timeout_handler, req);
995 Send a request using the transport
998 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1000 struct rpc_request *req;
1001 struct dcerpc_pipe *p;
1002 DATA_BLOB *stub_data;
1003 struct ncacn_packet pkt;
1005 uint32_t remaining, chunk_size;
1006 BOOL first_packet = True;
1008 req = c->request_queue;
1014 stub_data = &req->request_data;
1016 if (!req->async_call && (c->pending != NULL)) {
1020 DLIST_REMOVE(c->request_queue, req);
1021 DLIST_ADD(c->pending, req);
1022 req->state = RPC_REQUEST_PENDING;
1024 init_ncacn_hdr(p->conn, &pkt);
1026 remaining = stub_data->length;
1028 /* we can write a full max_recv_frag size, minus the dcerpc
1029 request header size */
1030 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1032 pkt.ptype = DCERPC_PKT_REQUEST;
1033 pkt.call_id = req->call_id;
1034 pkt.auth_length = 0;
1036 pkt.u.request.alloc_hint = remaining;
1037 pkt.u.request.context_id = p->context_id;
1038 pkt.u.request.opnum = req->opnum;
1041 pkt.u.request.object.object = *req->object;
1042 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1043 chunk_size -= ndr_size_GUID(req->object,0);
1046 /* we send a series of pdus without waiting for a reply */
1047 while (remaining > 0 || first_packet) {
1048 uint32_t chunk = MIN(chunk_size, remaining);
1049 BOOL last_frag = False;
1051 first_packet = False;
1052 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1054 if (remaining == stub_data->length) {
1055 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1057 if (chunk == remaining) {
1058 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1062 pkt.u.request.stub_and_verifier.data = stub_data->data +
1063 (stub_data->length - remaining);
1064 pkt.u.request.stub_and_verifier.length = chunk;
1066 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1067 if (!NT_STATUS_IS_OK(req->status)) {
1068 req->state = RPC_REQUEST_DONE;
1069 DLIST_REMOVE(p->conn->pending, req);
1073 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1074 if (!NT_STATUS_IS_OK(req->status)) {
1075 req->state = RPC_REQUEST_DONE;
1076 DLIST_REMOVE(p->conn->pending, req);
1085 return the event context for a dcerpc pipe
1086 used by callers who wish to operate asynchronously
1088 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1090 return p->conn->event_ctx;
1096 perform the receive side of a async dcerpc request
1098 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1099 TALLOC_CTX *mem_ctx,
1100 DATA_BLOB *stub_data)
1104 while (req->state != RPC_REQUEST_DONE) {
1105 struct event_context *ctx = dcerpc_event_context(req->p);
1106 if (event_loop_once(ctx) != 0) {
1107 return NT_STATUS_CONNECTION_DISCONNECTED;
1110 *stub_data = req->payload;
1111 status = req->status;
1112 if (stub_data->data) {
1113 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1115 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1116 req->p->last_fault_code = req->fault_code;
1123 perform a full request/response pair on a dcerpc pipe
1125 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1126 struct GUID *object,
1129 TALLOC_CTX *mem_ctx,
1130 DATA_BLOB *stub_data_in,
1131 DATA_BLOB *stub_data_out)
1133 struct rpc_request *req;
1135 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1137 return NT_STATUS_NO_MEMORY;
1140 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1145 this is a paranoid NDR validator. For every packet we push onto the wire
1146 we pull it back again, then push it again. Then we compare the raw NDR data
1147 for that to the NDR we initially generated. If they don't match then we know
1148 we must have a bug in either the pull or push side of our code
1150 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1151 TALLOC_CTX *mem_ctx,
1154 ndr_push_flags_fn_t ndr_push,
1155 ndr_pull_flags_fn_t ndr_pull)
1158 struct ndr_pull *pull;
1159 struct ndr_push *push;
1163 st = talloc_size(mem_ctx, struct_size);
1165 return NT_STATUS_NO_MEMORY;
1168 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1170 return NT_STATUS_NO_MEMORY;
1172 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1174 status = ndr_pull(pull, NDR_IN, st);
1175 if (!NT_STATUS_IS_OK(status)) {
1176 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1177 "failed input validation pull - %s",
1181 push = ndr_push_init_ctx(mem_ctx);
1183 return NT_STATUS_NO_MEMORY;
1186 status = ndr_push(push, NDR_IN, st);
1187 if (!NT_STATUS_IS_OK(status)) {
1188 return ndr_push_error(push, NDR_ERR_VALIDATE,
1189 "failed input validation push - %s",
1193 blob2 = ndr_push_blob(push);
1195 if (data_blob_cmp(&blob, &blob2) != 0) {
1196 DEBUG(3,("original:\n"));
1197 dump_data(3, blob.data, blob.length);
1198 DEBUG(3,("secondary:\n"));
1199 dump_data(3, blob2.data, blob2.length);
1200 return ndr_push_error(push, NDR_ERR_VALIDATE,
1201 "failed input validation data - %s",
1205 return NT_STATUS_OK;
1209 this is a paranoid NDR input validator. For every packet we pull
1210 from the wire we push it back again then pull and push it
1211 again. Then we compare the raw NDR data for that to the NDR we
1212 initially generated. If they don't match then we know we must have a
1213 bug in either the pull or push side of our code
1215 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1216 struct ndr_pull *pull_in,
1219 ndr_push_flags_fn_t ndr_push,
1220 ndr_pull_flags_fn_t ndr_pull,
1221 ndr_print_function_t ndr_print)
1224 struct ndr_pull *pull;
1225 struct ndr_push *push;
1227 DATA_BLOB blob, blob2;
1228 TALLOC_CTX *mem_ctx = pull_in;
1231 st = talloc_size(mem_ctx, struct_size);
1233 return NT_STATUS_NO_MEMORY;
1235 memcpy(st, struct_ptr, struct_size);
1237 push = ndr_push_init_ctx(mem_ctx);
1239 return NT_STATUS_NO_MEMORY;
1242 status = ndr_push(push, NDR_OUT, struct_ptr);
1243 if (!NT_STATUS_IS_OK(status)) {
1244 return ndr_push_error(push, NDR_ERR_VALIDATE,
1245 "failed output validation push - %s",
1249 blob = ndr_push_blob(push);
1251 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1253 return NT_STATUS_NO_MEMORY;
1256 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1257 status = ndr_pull(pull, NDR_OUT, st);
1258 if (!NT_STATUS_IS_OK(status)) {
1259 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1260 "failed output validation pull - %s",
1264 push = ndr_push_init_ctx(mem_ctx);
1266 return NT_STATUS_NO_MEMORY;
1269 status = ndr_push(push, NDR_OUT, st);
1270 if (!NT_STATUS_IS_OK(status)) {
1271 return ndr_push_error(push, NDR_ERR_VALIDATE,
1272 "failed output validation push2 - %s",
1276 blob2 = ndr_push_blob(push);
1278 if (data_blob_cmp(&blob, &blob2) != 0) {
1279 DEBUG(3,("original:\n"));
1280 dump_data(3, blob.data, blob.length);
1281 DEBUG(3,("secondary:\n"));
1282 dump_data(3, blob2.data, blob2.length);
1283 return ndr_push_error(push, NDR_ERR_VALIDATE,
1284 "failed output validation data - %s",
1288 /* this checks the printed forms of the two structures, which effectively
1289 tests all of the value() attributes */
1290 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1291 NDR_OUT, struct_ptr);
1292 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1294 if (strcmp(s1, s2) != 0) {
1296 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1298 /* this is sometimes useful */
1299 printf("VALIDATE ERROR\n");
1300 file_save("wire.dat", s1, strlen(s1));
1301 file_save("gen.dat", s2, strlen(s2));
1302 system("diff -u wire.dat gen.dat");
1306 return NT_STATUS_OK;
1311 send a rpc request given a dcerpc_call structure
1313 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1314 const struct GUID *object,
1315 const struct dcerpc_interface_table *table,
1317 TALLOC_CTX *mem_ctx,
1320 const struct dcerpc_interface_call *call;
1321 struct ndr_push *push;
1324 struct rpc_request *req;
1326 call = &table->calls[opnum];
1328 /* setup for a ndr_push_* call */
1329 push = ndr_push_init_ctx(mem_ctx);
1334 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1335 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1338 /* push the structure into a blob */
1339 status = call->ndr_push(push, NDR_IN, r);
1340 if (!NT_STATUS_IS_OK(status)) {
1341 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1342 nt_errstr(status)));
1347 /* retrieve the blob */
1348 request = ndr_push_blob(push);
1350 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1351 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1352 call->ndr_push, call->ndr_pull);
1353 if (!NT_STATUS_IS_OK(status)) {
1354 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1355 nt_errstr(status)));
1361 DEBUG(10,("rpc request data:\n"));
1362 dump_data(10, request.data, request.length);
1364 /* make the actual dcerpc request */
1365 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1369 req->ndr.table = table;
1370 req->ndr.opnum = opnum;
1371 req->ndr.struct_ptr = r;
1372 req->ndr.mem_ctx = mem_ctx;
1381 receive the answer from a dcerpc_ndr_request_send()
1383 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1385 struct dcerpc_pipe *p = req->p;
1388 struct ndr_pull *pull;
1390 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1391 void *r = req->ndr.struct_ptr;
1392 uint32_t opnum = req->ndr.opnum;
1393 const struct dcerpc_interface_table *table = req->ndr.table;
1394 const struct dcerpc_interface_call *call = &table->calls[opnum];
1396 /* make sure the recv code doesn't free the request, as we
1397 need to grab the flags element before it is freed */
1398 if (talloc_reference(p, req) == NULL) {
1399 return NT_STATUS_NO_MEMORY;
1402 status = dcerpc_request_recv(req, mem_ctx, &response);
1403 if (!NT_STATUS_IS_OK(status)) {
1404 talloc_unlink(p, req);
1410 /* prepare for ndr_pull_* */
1411 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1413 talloc_unlink(p, req);
1414 return NT_STATUS_NO_MEMORY;
1418 pull->data = talloc_steal(pull, pull->data);
1420 talloc_unlink(p, req);
1422 if (flags & DCERPC_PULL_BIGENDIAN) {
1423 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1426 DEBUG(10,("rpc reply data:\n"));
1427 dump_data(10, pull->data, pull->data_size);
1429 /* pull the structure from the blob */
1430 status = call->ndr_pull(pull, NDR_OUT, r);
1431 if (!NT_STATUS_IS_OK(status)) {
1432 dcerpc_log_packet(table, opnum, NDR_OUT,
1437 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1438 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1439 call->ndr_push, call->ndr_pull,
1441 if (!NT_STATUS_IS_OK(status)) {
1442 dcerpc_log_packet(table, opnum, NDR_OUT,
1448 if (pull->offset != pull->data_size) {
1449 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1450 pull->data_size - pull->offset));
1451 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1452 but it turns out that early versions of NT
1453 (specifically NT3.1) add junk onto the end of rpc
1454 packets, so if we want to interoperate at all with
1455 those versions then we need to ignore this error */
1458 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1460 return NT_STATUS_OK;
1465 a useful helper function for synchronous rpc requests
1467 this can be used when you have ndr push/pull functions in the
1470 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1471 const struct GUID *object,
1472 const struct dcerpc_interface_table *table,
1474 TALLOC_CTX *mem_ctx,
1477 struct rpc_request *req;
1479 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1481 return NT_STATUS_NO_MEMORY;
1484 return dcerpc_ndr_request_recv(req);
1489 a useful function for retrieving the server name we connected to
1491 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1493 if (!p->conn->transport.peer_name) {
1496 return p->conn->transport.peer_name(p->conn);
1501 get the dcerpc auth_level for a open connection
1503 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1507 if (c->flags & DCERPC_SEAL) {
1508 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1509 } else if (c->flags & DCERPC_SIGN) {
1510 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1511 } else if (c->flags & DCERPC_CONNECT) {
1512 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1514 auth_level = DCERPC_AUTH_LEVEL_NONE;
1520 Receive an alter reply from the transport
1522 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1523 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1525 struct composite_context *c;
1526 struct dcerpc_pipe *recv_pipe;
1528 c = talloc_get_type(req->async.private_data, struct composite_context);
1529 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
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_NET_WRITE_FAULT);
1547 /* the alter_resp might contain a reply set of credentials */
1548 if (recv_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, recv_pipe,
1552 recv_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;
1571 struct rpc_request *req;
1573 c = composite_create(mem_ctx, p->conn->event_ctx);
1574 if (c == NULL) return NULL;
1576 c->private_data = p;
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 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1589 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1592 pkt.u.alter.max_xmit_frag = 5840;
1593 pkt.u.alter.max_recv_frag = 5840;
1594 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1595 pkt.u.alter.num_contexts = 1;
1596 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1597 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
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 (!composite_is_ok(c)) return c;
1609 p->conn->transport.recv_data = dcerpc_recv_data;
1612 * we allocate a dcerpc_request so we can be in the same
1613 * request queue as normal requests
1615 req = talloc_zero(c, struct rpc_request);
1616 if (composite_nomem(req, c)) return c;
1618 req->state = RPC_REQUEST_PENDING;
1619 req->call_id = pkt.call_id;
1620 req->async.private_data = c;
1621 req->async.callback = dcerpc_composite_fail;
1623 req->recv_handler = dcerpc_alter_recv_handler;
1624 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1625 talloc_set_destructor(req, dcerpc_req_dequeue);
1627 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1628 if (!composite_is_ok(c)) return c;
1630 event_add_timed(c->event_ctx, req,
1631 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1632 dcerpc_timeout_handler, req);
1637 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1639 NTSTATUS result = composite_wait(ctx);
1645 send a dcerpc alter_context request
1647 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1648 TALLOC_CTX *mem_ctx,
1649 const struct dcerpc_syntax_id *syntax,
1650 const struct dcerpc_syntax_id *transfer_syntax)
1652 struct composite_context *creq;
1653 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1654 return dcerpc_alter_context_recv(creq);