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 if (!data_blob_append(mem_ctx, blob,
433 creds2.data, creds2.length)) {
434 return NT_STATUS_NO_MEMORY;
436 dcerpc_set_auth_length(blob, creds2.length);
437 if (c->security_state.auth_info->credentials.length == 0) {
438 /* this is needed for krb5 only, to correct the total packet
440 dcerpc_set_frag_length(blob,
441 dcerpc_get_frag_length(blob)
446 case DCERPC_AUTH_LEVEL_INTEGRITY:
447 status = gensec_sign_packet(c->security_state.generic_state,
449 blob->data + DCERPC_REQUEST_LENGTH,
453 c->security_state.auth_info->credentials.length,
455 if (!NT_STATUS_IS_OK(status)) {
458 blob->length -= c->security_state.auth_info->credentials.length;
459 if (!data_blob_append(mem_ctx, blob,
460 creds2.data, creds2.length)) {
461 return NT_STATUS_NO_MEMORY;
463 dcerpc_set_auth_length(blob, creds2.length);
464 if (c->security_state.auth_info->credentials.length == 0) {
465 /* this is needed for krb5 only, to correct the total packet
467 dcerpc_set_frag_length(blob,
468 dcerpc_get_frag_length(blob)
473 case DCERPC_AUTH_LEVEL_CONNECT:
476 case DCERPC_AUTH_LEVEL_NONE:
477 c->security_state.auth_info->credentials = data_blob(NULL, 0);
481 status = NT_STATUS_INVALID_LEVEL;
485 data_blob_free(&c->security_state.auth_info->credentials);
492 fill in the fixed values in a dcerpc header
494 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
497 pkt->rpc_vers_minor = 0;
498 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
501 pkt->drep[0] = DCERPC_DREP_LE;
509 map a bind nak reason to a NTSTATUS
511 static NTSTATUS dcerpc_map_reason(uint16_t reason)
514 case DCERPC_BIND_REASON_ASYNTAX:
515 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
516 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
517 return NT_STATUS_INVALID_PARAMETER;
519 return NT_STATUS_UNSUCCESSFUL;
523 a bind or alter context has failed
525 static void dcerpc_composite_fail(struct rpc_request *req)
527 struct composite_context *c = talloc_get_type(req->async.private_data,
528 struct composite_context);
529 composite_error(c, req->status);
533 remove requests from the pending or queued queues
535 static int dcerpc_req_dequeue(struct rpc_request *req)
537 switch (req->state) {
538 case RPC_REQUEST_QUEUED:
539 DLIST_REMOVE(req->p->conn->request_queue, req);
541 case RPC_REQUEST_PENDING:
542 DLIST_REMOVE(req->p->conn->pending, req);
544 case RPC_REQUEST_DONE:
552 mark the dcerpc connection dead. All outstanding requests get an error
554 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
556 if (conn->dead) return;
560 if (conn->transport.shutdown_pipe) {
561 conn->transport.shutdown_pipe(conn, status);
564 /* all pending requests get the error */
565 while (conn->pending) {
566 struct rpc_request *req = conn->pending;
567 dcerpc_req_dequeue(req);
568 req->state = RPC_REQUEST_DONE;
569 req->status = status;
570 if (req->async.callback) {
571 req->async.callback(req);
575 talloc_set_destructor(conn, NULL);
576 if (conn->free_skipped) {
582 forward declarations of the recv_data handlers for the types of
583 packets we need to handle
585 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
586 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
589 receive a dcerpc reply from the transport. Here we work out what
590 type of reply it is (normal request, bind or alter context) and
591 dispatch to the appropriate handler
593 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
595 struct ncacn_packet pkt;
597 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
598 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
601 /* the transport may be telling us of a severe error, such as
603 if (!NT_STATUS_IS_OK(status)) {
604 data_blob_free(blob);
605 dcerpc_connection_dead(conn, status);
609 /* parse the basic packet to work out what type of response this is */
610 status = ncacn_pull(conn, blob, blob->data, &pkt);
611 if (!NT_STATUS_IS_OK(status)) {
612 data_blob_free(blob);
613 dcerpc_connection_dead(conn, status);
616 dcerpc_request_recv_data(conn, blob, &pkt);
621 Receive a bind reply from the transport
623 static void dcerpc_bind_recv_handler(struct rpc_request *req,
624 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
626 struct composite_context *c;
627 struct dcerpc_connection *conn;
629 c = talloc_get_type(req->async.private_data, struct composite_context);
631 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
632 DEBUG(2,("dcerpc: bind_nak reason %d\n",
633 pkt->u.bind_nak.reject_reason));
634 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
639 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
640 (pkt->u.bind_ack.num_results == 0) ||
641 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
642 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
648 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
649 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
651 /* the bind_ack might contain a reply set of credentials */
652 if (conn->security_state.auth_info &&
653 pkt->u.bind_ack.auth_info.length) {
654 c->status = ndr_pull_struct_blob(
655 &pkt->u.bind_ack.auth_info, conn,
656 conn->security_state.auth_info,
657 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
658 if (!composite_is_ok(c)) return;
661 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
667 handle timeouts of individual dcerpc requests
669 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
670 struct timeval t, void *private)
672 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
674 if (req->ignore_timeout) {
675 dcerpc_req_dequeue(req);
676 req->state = RPC_REQUEST_DONE;
677 req->status = NT_STATUS_IO_TIMEOUT;
678 if (req->async.callback) {
679 req->async.callback(req);
684 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
688 send a async dcerpc bind request
690 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
692 const struct ndr_syntax_id *syntax,
693 const struct ndr_syntax_id *transfer_syntax)
695 struct composite_context *c;
696 struct ncacn_packet pkt;
698 struct rpc_request *req;
700 c = composite_create(mem_ctx,p->conn->event_ctx);
701 if (c == NULL) return NULL;
706 p->transfer_syntax = *transfer_syntax;
708 init_ncacn_hdr(p->conn, &pkt);
710 pkt.ptype = DCERPC_PKT_BIND;
711 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
712 pkt.call_id = p->conn->call_id;
715 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
716 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
719 pkt.u.bind.max_xmit_frag = 5840;
720 pkt.u.bind.max_recv_frag = 5840;
721 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
722 pkt.u.bind.num_contexts = 1;
723 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
724 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
725 pkt.u.bind.ctx_list[0].context_id = p->context_id;
726 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
727 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
728 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
729 pkt.u.bind.auth_info = data_blob(NULL, 0);
731 /* construct the NDR form of the packet */
732 c->status = ncacn_push_auth(&blob, c, &pkt,
733 p->conn->security_state.auth_info);
734 if (!composite_is_ok(c)) return c;
736 p->conn->transport.recv_data = dcerpc_recv_data;
739 * we allocate a dcerpc_request so we can be in the same
740 * request queue as normal requests
742 req = talloc_zero(c, struct rpc_request);
743 if (composite_nomem(req, c)) return c;
745 req->state = RPC_REQUEST_PENDING;
746 req->call_id = pkt.call_id;
747 req->async.private_data = c;
748 req->async.callback = dcerpc_composite_fail;
750 req->recv_handler = dcerpc_bind_recv_handler;
751 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
752 talloc_set_destructor(req, dcerpc_req_dequeue);
754 c->status = p->conn->transport.send_request(p->conn, &blob,
756 if (!composite_is_ok(c)) return c;
758 event_add_timed(c->event_ctx, req,
759 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
760 dcerpc_timeout_handler, req);
766 recv side of async dcerpc bind request
768 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
770 NTSTATUS result = composite_wait(ctx);
776 perform a continued bind (and auth3)
778 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
781 struct ncacn_packet pkt;
785 init_ncacn_hdr(c, &pkt);
787 pkt.ptype = DCERPC_PKT_AUTH3;
788 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
789 pkt.call_id = next_call_id(c);
791 pkt.u.auth3._pad = 0;
792 pkt.u.auth3.auth_info = data_blob(NULL, 0);
794 /* construct the NDR form of the packet */
795 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
796 if (!NT_STATUS_IS_OK(status)) {
800 /* send it on its way */
801 status = c->transport.send_request(c, &blob, False);
802 if (!NT_STATUS_IS_OK(status)) {
811 process a fragment received from the transport layer during a
814 This function frees the data
816 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
817 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
819 struct rpc_request *req;
821 NTSTATUS status = NT_STATUS_OK;
824 if this is an authenticated connection then parse and check
825 the auth info. We have to do this before finding the
826 matching packet, as the request structure might have been
827 removed due to a timeout, but if it has been we still need
828 to run the auth routines so that we don't get the sign/seal
829 info out of step with the server
831 if (c->security_state.auth_info && c->security_state.generic_state &&
832 pkt->ptype == DCERPC_PKT_RESPONSE) {
833 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
836 /* find the matching request */
837 for (req=c->pending;req;req=req->next) {
838 if (pkt->call_id == req->call_id) break;
842 /* useful for testing certain vendors RPC servers */
843 if (req == NULL && c->pending && pkt->call_id == 0) {
844 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
850 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
851 data_blob_free(raw_packet);
855 talloc_steal(req, raw_packet->data);
857 if (req->recv_handler != NULL) {
858 dcerpc_req_dequeue(req);
859 req->state = RPC_REQUEST_DONE;
860 req->recv_handler(req, raw_packet, pkt);
864 if (pkt->ptype == DCERPC_PKT_FAULT) {
865 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
866 req->fault_code = pkt->u.fault.status;
867 req->status = NT_STATUS_NET_WRITE_FAULT;
871 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
872 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
874 req->fault_code = DCERPC_FAULT_OTHER;
875 req->status = NT_STATUS_NET_WRITE_FAULT;
879 /* now check the status from the auth routines, and if it failed then fail
880 this request accordingly */
881 if (!NT_STATUS_IS_OK(status)) {
882 req->status = status;
886 length = pkt->u.response.stub_and_verifier.length;
889 req->payload.data = talloc_realloc(req,
892 req->payload.length + length);
893 if (!req->payload.data) {
894 req->status = NT_STATUS_NO_MEMORY;
897 memcpy(req->payload.data+req->payload.length,
898 pkt->u.response.stub_and_verifier.data, length);
899 req->payload.length += length;
902 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
903 c->transport.send_read(c);
907 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
908 req->flags |= DCERPC_PULL_BIGENDIAN;
910 req->flags &= ~DCERPC_PULL_BIGENDIAN;
915 /* we've got the full payload */
916 req->state = RPC_REQUEST_DONE;
917 DLIST_REMOVE(c->pending, req);
919 if (c->request_queue != NULL) {
920 /* We have to look at shipping further requests before calling
921 * the async function, that one might close the pipe */
922 dcerpc_ship_next_request(c);
925 if (req->async.callback) {
926 req->async.callback(req);
931 perform the send side of a async dcerpc request
933 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
934 const struct GUID *object,
937 DATA_BLOB *stub_data)
939 struct rpc_request *req;
941 p->conn->transport.recv_data = dcerpc_recv_data;
943 req = talloc(p, struct rpc_request);
949 req->call_id = next_call_id(p->conn);
950 req->status = NT_STATUS_OK;
951 req->state = RPC_REQUEST_QUEUED;
952 req->payload = data_blob(NULL, 0);
955 req->async_call = async;
956 req->ignore_timeout = False;
957 req->async.callback = NULL;
958 req->async.private_data = NULL;
959 req->recv_handler = NULL;
961 if (object != NULL) {
962 req->object = (struct GUID *)talloc_memdup(req, (void *)object, sizeof(*object));
963 if (req->object == NULL) {
972 req->request_data.length = stub_data->length;
973 req->request_data.data = talloc_reference(req, stub_data->data);
974 if (req->request_data.length && req->request_data.data == NULL) {
978 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
979 talloc_set_destructor(req, dcerpc_req_dequeue);
981 dcerpc_ship_next_request(p->conn);
983 if (p->request_timeout) {
984 event_add_timed(dcerpc_event_context(p), req,
985 timeval_current_ofs(p->request_timeout, 0),
986 dcerpc_timeout_handler, req);
993 Send a request using the transport
996 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
998 struct rpc_request *req;
999 struct dcerpc_pipe *p;
1000 DATA_BLOB *stub_data;
1001 struct ncacn_packet pkt;
1003 uint32_t remaining, chunk_size;
1004 BOOL first_packet = True;
1006 req = c->request_queue;
1012 stub_data = &req->request_data;
1014 if (!req->async_call && (c->pending != NULL)) {
1018 DLIST_REMOVE(c->request_queue, req);
1019 DLIST_ADD(c->pending, req);
1020 req->state = RPC_REQUEST_PENDING;
1022 init_ncacn_hdr(p->conn, &pkt);
1024 remaining = stub_data->length;
1026 /* we can write a full max_recv_frag size, minus the dcerpc
1027 request header size */
1028 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1030 pkt.ptype = DCERPC_PKT_REQUEST;
1031 pkt.call_id = req->call_id;
1032 pkt.auth_length = 0;
1034 pkt.u.request.alloc_hint = remaining;
1035 pkt.u.request.context_id = p->context_id;
1036 pkt.u.request.opnum = req->opnum;
1039 pkt.u.request.object.object = *req->object;
1040 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1041 chunk_size -= ndr_size_GUID(req->object,0);
1044 /* we send a series of pdus without waiting for a reply */
1045 while (remaining > 0 || first_packet) {
1046 uint32_t chunk = MIN(chunk_size, remaining);
1047 BOOL last_frag = False;
1049 first_packet = False;
1050 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1052 if (remaining == stub_data->length) {
1053 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1055 if (chunk == remaining) {
1056 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1060 pkt.u.request.stub_and_verifier.data = stub_data->data +
1061 (stub_data->length - remaining);
1062 pkt.u.request.stub_and_verifier.length = chunk;
1064 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1065 if (!NT_STATUS_IS_OK(req->status)) {
1066 req->state = RPC_REQUEST_DONE;
1067 DLIST_REMOVE(p->conn->pending, req);
1071 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1072 if (!NT_STATUS_IS_OK(req->status)) {
1073 req->state = RPC_REQUEST_DONE;
1074 DLIST_REMOVE(p->conn->pending, req);
1083 return the event context for a dcerpc pipe
1084 used by callers who wish to operate asynchronously
1086 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1088 return p->conn->event_ctx;
1094 perform the receive side of a async dcerpc request
1096 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1097 TALLOC_CTX *mem_ctx,
1098 DATA_BLOB *stub_data)
1102 while (req->state != RPC_REQUEST_DONE) {
1103 struct event_context *ctx = dcerpc_event_context(req->p);
1104 if (event_loop_once(ctx) != 0) {
1105 return NT_STATUS_CONNECTION_DISCONNECTED;
1108 *stub_data = req->payload;
1109 status = req->status;
1110 if (stub_data->data) {
1111 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1113 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1114 req->p->last_fault_code = req->fault_code;
1121 perform a full request/response pair on a dcerpc pipe
1123 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1124 struct GUID *object,
1127 TALLOC_CTX *mem_ctx,
1128 DATA_BLOB *stub_data_in,
1129 DATA_BLOB *stub_data_out)
1131 struct rpc_request *req;
1133 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1135 return NT_STATUS_NO_MEMORY;
1138 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1143 this is a paranoid NDR validator. For every packet we push onto the wire
1144 we pull it back again, then push it again. Then we compare the raw NDR data
1145 for that to the NDR we initially generated. If they don't match then we know
1146 we must have a bug in either the pull or push side of our code
1148 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1149 TALLOC_CTX *mem_ctx,
1152 ndr_push_flags_fn_t ndr_push,
1153 ndr_pull_flags_fn_t ndr_pull)
1156 struct ndr_pull *pull;
1157 struct ndr_push *push;
1161 st = talloc_size(mem_ctx, struct_size);
1163 return NT_STATUS_NO_MEMORY;
1166 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1168 return NT_STATUS_NO_MEMORY;
1170 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1172 status = ndr_pull(pull, NDR_IN, st);
1173 if (!NT_STATUS_IS_OK(status)) {
1174 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1175 "failed input validation pull - %s",
1179 push = ndr_push_init_ctx(mem_ctx);
1181 return NT_STATUS_NO_MEMORY;
1184 status = ndr_push(push, NDR_IN, st);
1185 if (!NT_STATUS_IS_OK(status)) {
1186 return ndr_push_error(push, NDR_ERR_VALIDATE,
1187 "failed input validation push - %s",
1191 blob2 = ndr_push_blob(push);
1193 if (data_blob_cmp(&blob, &blob2) != 0) {
1194 DEBUG(3,("original:\n"));
1195 dump_data(3, blob.data, blob.length);
1196 DEBUG(3,("secondary:\n"));
1197 dump_data(3, blob2.data, blob2.length);
1198 return ndr_push_error(push, NDR_ERR_VALIDATE,
1199 "failed input validation data - %s",
1203 return NT_STATUS_OK;
1207 this is a paranoid NDR input validator. For every packet we pull
1208 from the wire we push it back again then pull and push it
1209 again. Then we compare the raw NDR data for that to the NDR we
1210 initially generated. If they don't match then we know we must have a
1211 bug in either the pull or push side of our code
1213 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1214 struct ndr_pull *pull_in,
1217 ndr_push_flags_fn_t ndr_push,
1218 ndr_pull_flags_fn_t ndr_pull,
1219 ndr_print_function_t ndr_print)
1222 struct ndr_pull *pull;
1223 struct ndr_push *push;
1225 DATA_BLOB blob, blob2;
1226 TALLOC_CTX *mem_ctx = pull_in;
1229 st = talloc_size(mem_ctx, struct_size);
1231 return NT_STATUS_NO_MEMORY;
1233 memcpy(st, struct_ptr, struct_size);
1235 push = ndr_push_init_ctx(mem_ctx);
1237 return NT_STATUS_NO_MEMORY;
1240 status = ndr_push(push, NDR_OUT, struct_ptr);
1241 if (!NT_STATUS_IS_OK(status)) {
1242 return ndr_push_error(push, NDR_ERR_VALIDATE,
1243 "failed output validation push - %s",
1247 blob = ndr_push_blob(push);
1249 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1251 return NT_STATUS_NO_MEMORY;
1254 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1255 status = ndr_pull(pull, NDR_OUT, st);
1256 if (!NT_STATUS_IS_OK(status)) {
1257 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1258 "failed output validation pull - %s",
1262 push = ndr_push_init_ctx(mem_ctx);
1264 return NT_STATUS_NO_MEMORY;
1267 status = ndr_push(push, NDR_OUT, st);
1268 if (!NT_STATUS_IS_OK(status)) {
1269 return ndr_push_error(push, NDR_ERR_VALIDATE,
1270 "failed output validation push2 - %s",
1274 blob2 = ndr_push_blob(push);
1276 if (data_blob_cmp(&blob, &blob2) != 0) {
1277 DEBUG(3,("original:\n"));
1278 dump_data(3, blob.data, blob.length);
1279 DEBUG(3,("secondary:\n"));
1280 dump_data(3, blob2.data, blob2.length);
1281 return ndr_push_error(push, NDR_ERR_VALIDATE,
1282 "failed output validation data - %s",
1286 /* this checks the printed forms of the two structures, which effectively
1287 tests all of the value() attributes */
1288 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1289 NDR_OUT, struct_ptr);
1290 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1292 if (strcmp(s1, s2) != 0) {
1294 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1296 /* this is sometimes useful */
1297 printf("VALIDATE ERROR\n");
1298 file_save("wire.dat", s1, strlen(s1));
1299 file_save("gen.dat", s2, strlen(s2));
1300 system("diff -u wire.dat gen.dat");
1304 return NT_STATUS_OK;
1309 send a rpc request given a dcerpc_call structure
1311 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1312 const struct GUID *object,
1313 const struct ndr_interface_table *table,
1315 TALLOC_CTX *mem_ctx,
1318 const struct ndr_interface_call *call;
1319 struct ndr_push *push;
1322 struct rpc_request *req;
1324 call = &table->calls[opnum];
1326 /* setup for a ndr_push_* call */
1327 push = ndr_push_init_ctx(mem_ctx);
1332 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1333 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1336 /* push the structure into a blob */
1337 status = call->ndr_push(push, NDR_IN, r);
1338 if (!NT_STATUS_IS_OK(status)) {
1339 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1340 nt_errstr(status)));
1345 /* retrieve the blob */
1346 request = ndr_push_blob(push);
1348 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1349 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1350 call->ndr_push, call->ndr_pull);
1351 if (!NT_STATUS_IS_OK(status)) {
1352 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1353 nt_errstr(status)));
1359 DEBUG(10,("rpc request data:\n"));
1360 dump_data(10, request.data, request.length);
1362 /* make the actual dcerpc request */
1363 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1367 req->ndr.table = table;
1368 req->ndr.opnum = opnum;
1369 req->ndr.struct_ptr = r;
1370 req->ndr.mem_ctx = mem_ctx;
1379 receive the answer from a dcerpc_ndr_request_send()
1381 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1383 struct dcerpc_pipe *p = req->p;
1386 struct ndr_pull *pull;
1388 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1389 void *r = req->ndr.struct_ptr;
1390 uint32_t opnum = req->ndr.opnum;
1391 const struct ndr_interface_table *table = req->ndr.table;
1392 const struct ndr_interface_call *call = &table->calls[opnum];
1394 /* make sure the recv code doesn't free the request, as we
1395 need to grab the flags element before it is freed */
1396 if (talloc_reference(p, req) == NULL) {
1397 return NT_STATUS_NO_MEMORY;
1400 status = dcerpc_request_recv(req, mem_ctx, &response);
1401 if (!NT_STATUS_IS_OK(status)) {
1402 talloc_unlink(p, req);
1408 /* prepare for ndr_pull_* */
1409 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1411 talloc_unlink(p, req);
1412 return NT_STATUS_NO_MEMORY;
1416 pull->data = talloc_steal(pull, pull->data);
1418 talloc_unlink(p, req);
1420 if (flags & DCERPC_PULL_BIGENDIAN) {
1421 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1424 DEBUG(10,("rpc reply data:\n"));
1425 dump_data(10, pull->data, pull->data_size);
1427 /* pull the structure from the blob */
1428 status = call->ndr_pull(pull, NDR_OUT, r);
1429 if (!NT_STATUS_IS_OK(status)) {
1430 dcerpc_log_packet(table, opnum, NDR_OUT,
1435 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1436 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1437 call->ndr_push, call->ndr_pull,
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 ndr_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_handler(struct rpc_request *req,
1521 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1523 struct composite_context *c;
1524 struct dcerpc_pipe *recv_pipe;
1526 c = talloc_get_type(req->async.private_data, struct composite_context);
1527 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1529 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1530 pkt->u.alter_resp.num_results == 1 &&
1531 pkt->u.alter_resp.ctx_list[0].result != 0) {
1532 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1533 pkt->u.alter_resp.ctx_list[0].reason));
1534 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1538 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1539 pkt->u.alter_resp.num_results == 0 ||
1540 pkt->u.alter_resp.ctx_list[0].result != 0) {
1541 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1545 /* the alter_resp might contain a reply set of credentials */
1546 if (recv_pipe->conn->security_state.auth_info &&
1547 pkt->u.alter_resp.auth_info.length) {
1548 c->status = ndr_pull_struct_blob(
1549 &pkt->u.alter_resp.auth_info, recv_pipe,
1550 recv_pipe->conn->security_state.auth_info,
1551 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1552 if (!composite_is_ok(c)) return;
1559 send a dcerpc alter_context request
1561 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1562 TALLOC_CTX *mem_ctx,
1563 const struct ndr_syntax_id *syntax,
1564 const struct ndr_syntax_id *transfer_syntax)
1566 struct composite_context *c;
1567 struct ncacn_packet pkt;
1569 struct rpc_request *req;
1571 c = composite_create(mem_ctx, p->conn->event_ctx);
1572 if (c == NULL) return NULL;
1574 c->private_data = p;
1576 p->syntax = *syntax;
1577 p->transfer_syntax = *transfer_syntax;
1579 init_ncacn_hdr(p->conn, &pkt);
1581 pkt.ptype = DCERPC_PKT_ALTER;
1582 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1583 pkt.call_id = p->conn->call_id;
1584 pkt.auth_length = 0;
1586 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1587 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1590 pkt.u.alter.max_xmit_frag = 5840;
1591 pkt.u.alter.max_recv_frag = 5840;
1592 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1593 pkt.u.alter.num_contexts = 1;
1594 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1595 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1596 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1597 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1598 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1599 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1600 pkt.u.alter.auth_info = data_blob(NULL, 0);
1602 /* construct the NDR form of the packet */
1603 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1604 p->conn->security_state.auth_info);
1605 if (!composite_is_ok(c)) return c;
1607 p->conn->transport.recv_data = dcerpc_recv_data;
1610 * we allocate a dcerpc_request so we can be in the same
1611 * request queue as normal requests
1613 req = talloc_zero(c, struct rpc_request);
1614 if (composite_nomem(req, c)) return c;
1616 req->state = RPC_REQUEST_PENDING;
1617 req->call_id = pkt.call_id;
1618 req->async.private_data = c;
1619 req->async.callback = dcerpc_composite_fail;
1621 req->recv_handler = dcerpc_alter_recv_handler;
1622 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1623 talloc_set_destructor(req, dcerpc_req_dequeue);
1625 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1626 if (!composite_is_ok(c)) return c;
1628 event_add_timed(c->event_ctx, req,
1629 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1630 dcerpc_timeout_handler, req);
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 ndr_syntax_id *syntax,
1648 const struct ndr_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);