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/rpc/dcerpc.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
33 NTSTATUS dcerpc_init(void)
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(void *ptr)
45 struct dcerpc_connection *c = ptr;
46 if (c->transport.shutdown_pipe) {
47 c->transport.shutdown_pipe(c);
53 /* initialise a dcerpc connection.
54 the event context is optional
56 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
57 struct event_context *ev)
59 struct dcerpc_connection *c;
61 c = talloc_zero(mem_ctx, struct dcerpc_connection);
67 ev = event_context_init(c);
76 if (!talloc_reference(c, ev)) {
81 c->security_state.auth_info = NULL;
82 c->security_state.session_key = dcerpc_generic_session_key;
83 c->security_state.generic_state = NULL;
84 c->binding_string = NULL;
86 c->srv_max_xmit_frag = 0;
87 c->srv_max_recv_frag = 0;
90 talloc_set_destructor(c, dcerpc_connection_destructor);
95 /* initialise a dcerpc pipe. */
96 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
98 struct dcerpc_pipe *p;
100 p = talloc(mem_ctx, struct dcerpc_pipe);
105 p->conn = dcerpc_connection_init(p, ev);
106 if (p->conn == NULL) {
111 p->last_fault_code = 0;
113 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
115 ZERO_STRUCT(p->syntax);
116 ZERO_STRUCT(p->transfer_syntax);
123 choose the next call id to use
125 static uint32_t next_call_id(struct dcerpc_connection *c)
128 if (c->call_id == 0) {
134 /* we need to be able to get/set the fragment length without doing a full
136 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
138 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
139 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
141 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
145 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
147 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
148 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
150 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
154 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
156 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
157 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
159 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
165 setup for a ndr pull, also setting up any flags from the binding string
167 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
168 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
170 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
172 if (ndr == NULL) return ndr;
174 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
175 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
178 if (c->flags & DCERPC_NDR_REF_ALLOC) {
179 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
186 parse a data blob into a ncacn_packet structure. This handles both
187 input and output packets
189 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
190 struct ncacn_packet *pkt)
192 struct ndr_pull *ndr;
194 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
196 return NT_STATUS_NO_MEMORY;
199 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
200 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
203 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
207 generate a CONNECT level verifier
209 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
211 *blob = data_blob_talloc(mem_ctx, NULL, 16);
212 if (blob->data == NULL) {
213 return NT_STATUS_NO_MEMORY;
215 SIVAL(blob->data, 0, 1);
216 memset(blob->data+4, 0, 12);
221 check a CONNECT level verifier
223 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
225 if (blob->length != 16 ||
226 IVAL(blob->data, 0) != 1) {
227 return NT_STATUS_ACCESS_DENIED;
233 parse the authentication information on a dcerpc response packet
235 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
236 DATA_BLOB *raw_packet,
237 struct ncacn_packet *pkt)
239 struct ndr_pull *ndr;
241 struct dcerpc_auth auth;
244 if (pkt->auth_length == 0 &&
245 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
249 auth_blob.length = 8 + pkt->auth_length;
251 /* check for a valid length */
252 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
253 return NT_STATUS_INFO_LENGTH_MISMATCH;
257 pkt->u.response.stub_and_verifier.data +
258 pkt->u.response.stub_and_verifier.length - auth_blob.length;
259 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
261 /* pull the auth structure */
262 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
264 return NT_STATUS_NO_MEMORY;
267 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
268 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
271 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
272 if (!NT_STATUS_IS_OK(status)) {
277 /* check signature or unseal the packet */
278 switch (c->security_state.auth_info->auth_level) {
279 case DCERPC_AUTH_LEVEL_PRIVACY:
280 status = gensec_unseal_packet(c->security_state.generic_state,
282 raw_packet->data + DCERPC_REQUEST_LENGTH,
283 pkt->u.response.stub_and_verifier.length,
285 raw_packet->length - auth.credentials.length,
287 memcpy(pkt->u.response.stub_and_verifier.data,
288 raw_packet->data + DCERPC_REQUEST_LENGTH,
289 pkt->u.response.stub_and_verifier.length);
292 case DCERPC_AUTH_LEVEL_INTEGRITY:
293 status = gensec_check_packet(c->security_state.generic_state,
295 pkt->u.response.stub_and_verifier.data,
296 pkt->u.response.stub_and_verifier.length,
298 raw_packet->length - auth.credentials.length,
302 case DCERPC_AUTH_LEVEL_CONNECT:
303 status = dcerpc_check_connect_verifier(&auth.credentials);
306 case DCERPC_AUTH_LEVEL_NONE:
310 status = NT_STATUS_INVALID_LEVEL;
314 /* remove the indicated amount of paddiing */
315 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
316 return NT_STATUS_INFO_LENGTH_MISMATCH;
318 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
325 push a dcerpc request packet into a blob, possibly signing it.
327 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
328 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
329 struct ncacn_packet *pkt)
332 struct ndr_push *ndr;
334 size_t payload_length;
336 /* non-signed packets are simpler */
337 if (!c->security_state.auth_info ||
338 !c->security_state.generic_state) {
339 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
342 ndr = ndr_push_init_ctx(mem_ctx);
344 return NT_STATUS_NO_MEMORY;
347 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
348 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
351 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
352 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
355 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
356 if (!NT_STATUS_IS_OK(status)) {
360 /* pad to 16 byte multiple in the payload portion of the
361 packet. This matches what w2k3 does */
362 c->security_state.auth_info->auth_pad_length =
363 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
364 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
366 payload_length = pkt->u.request.stub_and_verifier.length +
367 c->security_state.auth_info->auth_pad_length;
369 /* sign or seal the packet */
370 switch (c->security_state.auth_info->auth_level) {
371 case DCERPC_AUTH_LEVEL_PRIVACY:
372 case DCERPC_AUTH_LEVEL_INTEGRITY:
373 c->security_state.auth_info->credentials
374 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
376 data_blob_clear(&c->security_state.auth_info->credentials);
379 case DCERPC_AUTH_LEVEL_CONNECT:
380 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
383 case DCERPC_AUTH_LEVEL_NONE:
384 c->security_state.auth_info->credentials = data_blob(NULL, 0);
388 status = NT_STATUS_INVALID_LEVEL;
392 if (!NT_STATUS_IS_OK(status)) {
396 /* add the auth verifier */
397 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
398 if (!NT_STATUS_IS_OK(status)) {
402 /* extract the whole packet as a blob */
403 *blob = ndr_push_blob(ndr);
405 /* fill in the fragment length and auth_length, we can't fill
406 in these earlier as we don't know the signature length (it
407 could be variable length) */
408 dcerpc_set_frag_length(blob, blob->length);
409 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
411 /* sign or seal the packet */
412 switch (c->security_state.auth_info->auth_level) {
413 case DCERPC_AUTH_LEVEL_PRIVACY:
414 status = gensec_seal_packet(c->security_state.generic_state,
416 blob->data + DCERPC_REQUEST_LENGTH,
420 c->security_state.auth_info->credentials.length,
422 if (!NT_STATUS_IS_OK(status)) {
425 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
428 case DCERPC_AUTH_LEVEL_INTEGRITY:
429 status = gensec_sign_packet(c->security_state.generic_state,
431 blob->data + DCERPC_REQUEST_LENGTH,
435 c->security_state.auth_info->credentials.length,
437 if (!NT_STATUS_IS_OK(status)) {
440 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
443 case DCERPC_AUTH_LEVEL_CONNECT:
446 case DCERPC_AUTH_LEVEL_NONE:
447 c->security_state.auth_info->credentials = data_blob(NULL, 0);
451 status = NT_STATUS_INVALID_LEVEL;
455 data_blob_free(&c->security_state.auth_info->credentials);
462 fill in the fixed values in a dcerpc header
464 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
467 pkt->rpc_vers_minor = 0;
468 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
471 pkt->drep[0] = DCERPC_DREP_LE;
479 map a bind nak reason to a NTSTATUS
481 static NTSTATUS dcerpc_map_reason(uint16_t reason)
484 case DCERPC_BIND_REASON_ASYNTAX:
485 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
486 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
487 return NT_STATUS_INVALID_PARAMETER;
489 return NT_STATUS_UNSUCCESSFUL;
493 map a fault reason to a NTSTATUS
495 static NTSTATUS dcerpc_map_fault(uint32_t status)
498 case DCERPC_FAULT_OP_RNG_ERROR:
499 return NT_STATUS_ILLEGAL_FUNCTION;
500 case DCERPC_FAULT_ACCESS_DENIED:
501 return NT_STATUS_ACCESS_DENIED;
503 return NT_STATUS_NET_WRITE_FAULT;
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 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
554 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
557 /* the transport may be telling us of a severe error, such as
559 if (!NT_STATUS_IS_OK(status)) {
560 data_blob_free(blob);
561 dcerpc_connection_dead(conn, status);
565 /* parse the basic packet to work out what type of response this is */
566 status = ncacn_pull(conn, blob, blob->data, &pkt);
567 if (!NT_STATUS_IS_OK(status)) {
568 data_blob_free(blob);
569 dcerpc_connection_dead(conn, status);
572 if (conn->bind_private) {
573 talloc_steal(conn->bind_private, blob->data);
574 dcerpc_bind_recv_data(conn, &pkt);
577 if (conn->alter_private) {
578 talloc_steal(conn->alter_private, blob->data);
579 dcerpc_alter_recv_data(conn, &pkt);
583 /* assume its an ordinary request */
584 dcerpc_request_recv_data(conn, blob, &pkt);
589 Receive a bind reply from the transport
591 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
593 struct composite_context *c;
595 c = talloc_get_type(conn->bind_private, struct composite_context);
597 /* mark the connection as not waiting for a bind reply */
598 conn->bind_private = NULL;
600 if (pkt->ptype == DCERPC_PKT_FAULT) {
601 DEBUG(2,("dcerpc: bind faulted: reason %s\n",
602 dcerpc_errstr(c, pkt->u.fault.status)));
603 composite_error(c, dcerpc_map_fault(pkt->u.fault.status));
607 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
608 DEBUG(2,("dcerpc: bind_nak reason %d\n",
609 pkt->u.bind_nak.reject_reason));
610 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
615 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
616 (pkt->u.bind_ack.num_results == 0) ||
617 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
618 composite_error(c, NT_STATUS_UNSUCCESSFUL);
622 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
623 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
625 /* the bind_ack might contain a reply set of credentials */
626 if (conn->security_state.auth_info &&
627 pkt->u.bind_ack.auth_info.length) {
628 c->status = ndr_pull_struct_blob(
629 &pkt->u.bind_ack.auth_info, conn,
630 conn->security_state.auth_info,
631 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
632 if (!composite_is_ok(c)) return;
639 handle timeouts of dcerpc bind and alter context requests
641 static void bind_timeout_handler(struct event_context *ev,
642 struct timed_event *te,
643 struct timeval t, void *private)
645 struct composite_context *ctx =
646 talloc_get_type(private, struct composite_context);
647 struct dcerpc_pipe *timeout_pipe = talloc_get_type(ctx->private_data, struct dcerpc_pipe);
649 SMB_ASSERT(timeout_pipe->conn->bind_private != NULL);
650 timeout_pipe->conn->bind_private = NULL;
651 composite_error(ctx, NT_STATUS_IO_TIMEOUT);
655 send a async dcerpc bind request
657 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
659 const struct dcerpc_syntax_id *syntax,
660 const struct dcerpc_syntax_id *transfer_syntax)
662 struct composite_context *c;
663 struct ncacn_packet pkt;
666 c = talloc_zero(mem_ctx, struct composite_context);
667 if (c == NULL) return NULL;
669 c->state = COMPOSITE_STATE_IN_PROGRESS;
671 c->event_ctx = p->conn->event_ctx;
674 p->transfer_syntax = *transfer_syntax;
676 init_ncacn_hdr(p->conn, &pkt);
678 pkt.ptype = DCERPC_PKT_BIND;
679 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
680 pkt.call_id = p->conn->call_id;
683 pkt.u.bind.max_xmit_frag = 5840;
684 pkt.u.bind.max_recv_frag = 5840;
685 pkt.u.bind.assoc_group_id = 0;
686 pkt.u.bind.num_contexts = 1;
687 pkt.u.bind.ctx_list =
688 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
689 if (pkt.u.bind.ctx_list == NULL) {
690 c->status = NT_STATUS_NO_MEMORY;
693 pkt.u.bind.ctx_list[0].context_id = p->context_id;
694 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
695 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
696 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
697 pkt.u.bind.auth_info = data_blob(NULL, 0);
699 /* construct the NDR form of the packet */
700 c->status = ncacn_push_auth(&blob, c, &pkt,
701 p->conn->security_state.auth_info);
702 if (!NT_STATUS_IS_OK(c->status)) {
706 p->conn->transport.recv_data = dcerpc_recv_data;
707 p->conn->bind_private = c;
709 c->status = p->conn->transport.send_request(p->conn, &blob,
711 if (!NT_STATUS_IS_OK(c->status)) {
715 event_add_timed(c->event_ctx, c,
716 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
717 bind_timeout_handler, c);
722 composite_error(c, c->status);
727 recv side of async dcerpc bind request
729 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
731 NTSTATUS result = composite_wait(ctx);
737 perform a bind using the given syntax
739 the auth_info structure is updated with the reply authentication info
742 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
744 const struct dcerpc_syntax_id *syntax,
745 const struct dcerpc_syntax_id *transfer_syntax)
747 struct composite_context *creq;
748 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
749 return dcerpc_bind_recv(creq);
753 perform a continued bind (and auth3)
755 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
758 struct ncacn_packet pkt;
762 init_ncacn_hdr(c, &pkt);
764 pkt.ptype = DCERPC_PKT_AUTH3;
765 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
766 pkt.call_id = next_call_id(c);
768 pkt.u.auth3._pad = 0;
769 pkt.u.auth3.auth_info = data_blob(NULL, 0);
771 /* construct the NDR form of the packet */
772 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
773 if (!NT_STATUS_IS_OK(status)) {
777 /* send it on its way */
778 status = c->transport.send_request(c, &blob, False);
779 if (!NT_STATUS_IS_OK(status)) {
788 return the rpc syntax and transfer syntax given the pipe uuid and version
790 NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
791 struct dcerpc_syntax_id *syntax,
792 struct dcerpc_syntax_id *transfer_syntax)
794 syntax->uuid = table->syntax_id.uuid;
795 syntax->if_version = table->syntax_id.if_version;
797 *transfer_syntax = ndr_transfer_syntax;
802 /* perform a dcerpc bind, using the uuid as the key */
803 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
805 const struct dcerpc_interface_table *table)
807 struct dcerpc_syntax_id syntax;
808 struct dcerpc_syntax_id transfer_syntax;
811 status = dcerpc_init_syntaxes(table,
812 &syntax, &transfer_syntax);
813 if (!NT_STATUS_IS_OK(status)) {
814 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
818 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
823 process a fragment received from the transport layer during a
826 This function frees the data
828 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
829 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
831 struct rpc_request *req;
833 NTSTATUS status = NT_STATUS_OK;
836 if this is an authenticated connection then parse and check
837 the auth info. We have to do this before finding the
838 matching packet, as the request structure might have been
839 removed due to a timeout, but if it has been we still need
840 to run the auth routines so that we don't get the sign/seal
841 info out of step with the server
843 if (c->security_state.auth_info && c->security_state.generic_state &&
844 pkt->ptype == DCERPC_PKT_RESPONSE) {
845 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
848 /* find the matching request */
849 for (req=c->pending;req;req=req->next) {
850 if (pkt->call_id == req->call_id) break;
854 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
855 data_blob_free(raw_packet);
859 talloc_steal(req, raw_packet->data);
861 if (pkt->ptype == DCERPC_PKT_FAULT) {
862 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
863 req->fault_code = pkt->u.fault.status;
864 req->status = NT_STATUS_NET_WRITE_FAULT;
868 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
869 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
871 req->fault_code = DCERPC_FAULT_OTHER;
872 req->status = NT_STATUS_NET_WRITE_FAULT;
876 /* now check the status from the auth routines, and if it failed then fail
877 this request accordingly */
878 if (!NT_STATUS_IS_OK(status)) {
879 req->status = status;
883 length = pkt->u.response.stub_and_verifier.length;
886 req->payload.data = talloc_realloc(req,
889 req->payload.length + length);
890 if (!req->payload.data) {
891 req->status = NT_STATUS_NO_MEMORY;
894 memcpy(req->payload.data+req->payload.length,
895 pkt->u.response.stub_and_verifier.data, length);
896 req->payload.length += length;
899 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
900 c->transport.send_read(c);
904 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
905 req->flags |= DCERPC_PULL_BIGENDIAN;
907 req->flags &= ~DCERPC_PULL_BIGENDIAN;
912 /* we've got the full payload */
913 req->state = RPC_REQUEST_DONE;
914 DLIST_REMOVE(c->pending, req);
916 if (c->request_queue != NULL) {
917 /* We have to look at shipping further requests before calling
918 * the async function, that one might close the pipe */
919 dcerpc_ship_next_request(c);
922 if (req->async.callback) {
923 req->async.callback(req);
928 handle timeouts of individual dcerpc requests
930 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
931 struct timeval t, void *private)
933 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
935 if (req->state != RPC_REQUEST_PENDING) {
939 req->status = NT_STATUS_IO_TIMEOUT;
940 req->state = RPC_REQUEST_DONE;
941 DLIST_REMOVE(req->p->conn->pending, req);
942 if (req->async.callback) {
943 req->async.callback(req);
949 make sure requests are cleaned up
951 static int dcerpc_req_destructor(void *ptr)
953 struct rpc_request *req = ptr;
954 DLIST_REMOVE(req->p->conn->pending, req);
959 perform the send side of a async dcerpc request
961 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
962 const struct GUID *object,
965 DATA_BLOB *stub_data)
967 struct rpc_request *req;
969 p->conn->transport.recv_data = dcerpc_recv_data;
971 req = talloc(p, struct rpc_request);
977 req->call_id = next_call_id(p->conn);
978 req->status = NT_STATUS_OK;
979 req->state = RPC_REQUEST_PENDING;
980 req->payload = data_blob(NULL, 0);
983 req->async_call = async;
984 req->async.callback = NULL;
986 if (object != NULL) {
987 req->object = talloc_memdup(req, object, sizeof(*object));
988 if (req->object == NULL) {
997 req->request_data.length = stub_data->length;
998 req->request_data.data = talloc_reference(req, stub_data->data);
999 if (req->request_data.data == NULL) {
1003 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1005 dcerpc_ship_next_request(p->conn);
1007 if (p->request_timeout) {
1008 event_add_timed(dcerpc_event_context(p), req,
1009 timeval_current_ofs(p->request_timeout, 0),
1010 dcerpc_timeout_handler, req);
1013 talloc_set_destructor(req, dcerpc_req_destructor);
1018 Send a request using the transport
1021 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1023 struct rpc_request *req;
1024 struct dcerpc_pipe *p;
1025 DATA_BLOB *stub_data;
1026 struct ncacn_packet pkt;
1028 uint32_t remaining, chunk_size;
1029 BOOL first_packet = True;
1031 req = c->request_queue;
1037 stub_data = &req->request_data;
1039 if (!req->async_call && (c->pending != NULL)) {
1043 DLIST_REMOVE(c->request_queue, req);
1044 DLIST_ADD(c->pending, req);
1046 init_ncacn_hdr(p->conn, &pkt);
1048 remaining = stub_data->length;
1050 /* we can write a full max_recv_frag size, minus the dcerpc
1051 request header size */
1052 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1054 pkt.ptype = DCERPC_PKT_REQUEST;
1055 pkt.call_id = req->call_id;
1056 pkt.auth_length = 0;
1058 pkt.u.request.alloc_hint = remaining;
1059 pkt.u.request.context_id = p->context_id;
1060 pkt.u.request.opnum = req->opnum;
1063 pkt.u.request.object.object = *req->object;
1064 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1065 chunk_size -= ndr_size_GUID(req->object,0);
1068 /* we send a series of pdus without waiting for a reply */
1069 while (remaining > 0 || first_packet) {
1070 uint32_t chunk = MIN(chunk_size, remaining);
1071 BOOL last_frag = False;
1073 first_packet = False;
1074 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1076 if (remaining == stub_data->length) {
1077 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1079 if (chunk == remaining) {
1080 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1084 pkt.u.request.stub_and_verifier.data = stub_data->data +
1085 (stub_data->length - remaining);
1086 pkt.u.request.stub_and_verifier.length = chunk;
1088 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1089 if (!NT_STATUS_IS_OK(req->status)) {
1090 req->state = RPC_REQUEST_DONE;
1091 DLIST_REMOVE(p->conn->pending, req);
1095 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1096 if (!NT_STATUS_IS_OK(req->status)) {
1097 req->state = RPC_REQUEST_DONE;
1098 DLIST_REMOVE(p->conn->pending, req);
1107 return the event context for a dcerpc pipe
1108 used by callers who wish to operate asynchronously
1110 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1112 return p->conn->event_ctx;
1118 perform the receive side of a async dcerpc request
1120 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1121 TALLOC_CTX *mem_ctx,
1122 DATA_BLOB *stub_data)
1126 while (req->state == RPC_REQUEST_PENDING) {
1127 struct event_context *ctx = dcerpc_event_context(req->p);
1128 if (event_loop_once(ctx) != 0) {
1129 return NT_STATUS_CONNECTION_DISCONNECTED;
1132 *stub_data = req->payload;
1133 status = req->status;
1134 if (stub_data->data) {
1135 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1137 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1138 req->p->last_fault_code = req->fault_code;
1145 perform a full request/response pair on a dcerpc pipe
1147 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1148 struct GUID *object,
1151 TALLOC_CTX *mem_ctx,
1152 DATA_BLOB *stub_data_in,
1153 DATA_BLOB *stub_data_out)
1155 struct rpc_request *req;
1157 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1159 return NT_STATUS_NO_MEMORY;
1162 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1167 this is a paranoid NDR validator. For every packet we push onto the wire
1168 we pull it back again, then push it again. Then we compare the raw NDR data
1169 for that to the NDR we initially generated. If they don't match then we know
1170 we must have a bug in either the pull or push side of our code
1172 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1173 TALLOC_CTX *mem_ctx,
1176 ndr_push_flags_fn_t ndr_push,
1177 ndr_pull_flags_fn_t ndr_pull)
1180 struct ndr_pull *pull;
1181 struct ndr_push *push;
1185 st = talloc_size(mem_ctx, struct_size);
1187 return NT_STATUS_NO_MEMORY;
1190 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1192 return NT_STATUS_NO_MEMORY;
1194 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1196 status = ndr_pull(pull, NDR_IN, st);
1197 if (!NT_STATUS_IS_OK(status)) {
1198 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1199 "failed input validation pull - %s",
1203 push = ndr_push_init_ctx(mem_ctx);
1205 return NT_STATUS_NO_MEMORY;
1208 status = ndr_push(push, NDR_IN, st);
1209 if (!NT_STATUS_IS_OK(status)) {
1210 return ndr_push_error(push, NDR_ERR_VALIDATE,
1211 "failed input validation push - %s",
1215 blob2 = ndr_push_blob(push);
1217 if (!data_blob_equal(&blob, &blob2)) {
1218 DEBUG(3,("original:\n"));
1219 dump_data(3, blob.data, blob.length);
1220 DEBUG(3,("secondary:\n"));
1221 dump_data(3, blob2.data, blob2.length);
1222 return ndr_push_error(push, NDR_ERR_VALIDATE,
1223 "failed input validation data - %s",
1227 return NT_STATUS_OK;
1231 this is a paranoid NDR input validator. For every packet we pull
1232 from the wire we push it back again then pull and push it
1233 again. Then we compare the raw NDR data for that to the NDR we
1234 initially generated. If they don't match then we know we must have a
1235 bug in either the pull or push side of our code
1237 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1238 struct ndr_pull *pull_in,
1241 ndr_push_flags_fn_t ndr_push,
1242 ndr_pull_flags_fn_t ndr_pull,
1243 ndr_print_function_t ndr_print)
1246 struct ndr_pull *pull;
1247 struct ndr_push *push;
1249 DATA_BLOB blob, blob2;
1250 TALLOC_CTX *mem_ctx = pull_in;
1253 st = talloc_size(mem_ctx, struct_size);
1255 return NT_STATUS_NO_MEMORY;
1257 memcpy(st, struct_ptr, struct_size);
1259 push = ndr_push_init_ctx(mem_ctx);
1261 return NT_STATUS_NO_MEMORY;
1264 status = ndr_push(push, NDR_OUT, struct_ptr);
1265 if (!NT_STATUS_IS_OK(status)) {
1266 return ndr_push_error(push, NDR_ERR_VALIDATE,
1267 "failed output validation push - %s",
1271 blob = ndr_push_blob(push);
1273 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1275 return NT_STATUS_NO_MEMORY;
1278 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1279 status = ndr_pull(pull, NDR_OUT, st);
1280 if (!NT_STATUS_IS_OK(status)) {
1281 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1282 "failed output validation pull - %s",
1286 push = ndr_push_init_ctx(mem_ctx);
1288 return NT_STATUS_NO_MEMORY;
1291 status = ndr_push(push, NDR_OUT, st);
1292 if (!NT_STATUS_IS_OK(status)) {
1293 return ndr_push_error(push, NDR_ERR_VALIDATE,
1294 "failed output validation push2 - %s",
1298 blob2 = ndr_push_blob(push);
1300 if (!data_blob_equal(&blob, &blob2)) {
1301 DEBUG(3,("original:\n"));
1302 dump_data(3, blob.data, blob.length);
1303 DEBUG(3,("secondary:\n"));
1304 dump_data(3, blob2.data, blob2.length);
1305 return ndr_push_error(push, NDR_ERR_VALIDATE,
1306 "failed output validation data - %s",
1310 /* this checks the printed forms of the two structures, which effectively
1311 tests all of the value() attributes */
1312 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1313 NDR_OUT, struct_ptr);
1314 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1316 if (strcmp(s1, s2) != 0) {
1317 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1320 return NT_STATUS_OK;
1325 send a rpc request given a dcerpc_call structure
1327 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1328 const struct GUID *object,
1329 const struct dcerpc_interface_table *table,
1331 TALLOC_CTX *mem_ctx,
1334 const struct dcerpc_interface_call *call;
1335 struct ndr_push *push;
1338 struct rpc_request *req;
1340 call = &table->calls[opnum];
1342 /* setup for a ndr_push_* call */
1343 push = ndr_push_init_ctx(mem_ctx);
1348 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1349 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1352 /* push the structure into a blob */
1353 status = call->ndr_push(push, NDR_IN, r);
1354 if (!NT_STATUS_IS_OK(status)) {
1355 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1356 nt_errstr(status)));
1361 /* retrieve the blob */
1362 request = ndr_push_blob(push);
1364 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1365 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1366 call->ndr_push, call->ndr_pull);
1367 if (!NT_STATUS_IS_OK(status)) {
1368 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1369 nt_errstr(status)));
1375 DEBUG(10,("rpc request data:\n"));
1376 dump_data(10, request.data, request.length);
1378 /* make the actual dcerpc request */
1379 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1383 req->ndr.table = table;
1384 req->ndr.opnum = opnum;
1385 req->ndr.struct_ptr = r;
1386 req->ndr.mem_ctx = mem_ctx;
1395 receive the answer from a dcerpc_ndr_request_send()
1397 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1399 struct dcerpc_pipe *p = req->p;
1402 struct ndr_pull *pull;
1404 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1405 void *r = req->ndr.struct_ptr;
1406 uint32_t opnum = req->ndr.opnum;
1407 const struct dcerpc_interface_table *table = req->ndr.table;
1408 const struct dcerpc_interface_call *call = &table->calls[opnum];
1410 /* make sure the recv code doesn't free the request, as we
1411 need to grab the flags element before it is freed */
1412 talloc_increase_ref_count(req);
1414 status = dcerpc_request_recv(req, mem_ctx, &response);
1415 if (!NT_STATUS_IS_OK(status)) {
1421 /* prepare for ndr_pull_* */
1422 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1425 return NT_STATUS_NO_MEMORY;
1429 pull->data = talloc_steal(pull, pull->data);
1433 if (flags & DCERPC_PULL_BIGENDIAN) {
1434 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1437 DEBUG(10,("rpc reply data:\n"));
1438 dump_data(10, pull->data, pull->data_size);
1440 /* pull the structure from the blob */
1441 status = call->ndr_pull(pull, NDR_OUT, r);
1442 if (!NT_STATUS_IS_OK(status)) {
1443 dcerpc_log_packet(table, opnum, NDR_OUT,
1448 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1449 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1450 call->ndr_push, call->ndr_pull,
1452 if (!NT_STATUS_IS_OK(status)) {
1453 dcerpc_log_packet(table, opnum, NDR_OUT,
1459 if (pull->offset != pull->data_size) {
1460 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1461 pull->data_size - pull->offset));
1462 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1463 but it turns out that early versions of NT
1464 (specifically NT3.1) add junk onto the end of rpc
1465 packets, so if we want to interoperate at all with
1466 those versions then we need to ignore this error */
1469 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1471 return NT_STATUS_OK;
1476 a useful helper function for synchronous rpc requests
1478 this can be used when you have ndr push/pull functions in the
1481 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1482 const struct GUID *object,
1483 const struct dcerpc_interface_table *table,
1485 TALLOC_CTX *mem_ctx,
1488 struct rpc_request *req;
1490 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1492 return NT_STATUS_NO_MEMORY;
1495 return dcerpc_ndr_request_recv(req);
1500 a useful function for retrieving the server name we connected to
1502 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1504 if (!p->conn->transport.peer_name) {
1507 return p->conn->transport.peer_name(p->conn);
1512 get the dcerpc auth_level for a open connection
1514 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1518 if (c->flags & DCERPC_SEAL) {
1519 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1520 } else if (c->flags & DCERPC_SIGN) {
1521 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1522 } else if (c->flags & DCERPC_CONNECT) {
1523 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1525 auth_level = DCERPC_AUTH_LEVEL_NONE;
1531 Receive an alter reply from the transport
1533 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
1535 struct composite_context *c;
1536 struct dcerpc_pipe *recv_pipe;
1538 c = talloc_get_type(conn->alter_private, struct composite_context);
1539 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1541 /* mark the connection as not waiting for a alter context reply */
1542 conn->alter_private = NULL;
1544 if (pkt->ptype == DCERPC_PKT_FAULT) {
1545 DEBUG(2,("dcerpc: alter context faulted: reason %s\n",
1546 dcerpc_errstr(c, pkt->u.fault.status)));
1547 composite_error(c, dcerpc_map_fault(pkt->u.fault.status));
1551 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1552 pkt->u.alter_resp.num_results == 1 &&
1553 pkt->u.alter_resp.ctx_list[0].result != 0) {
1554 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1555 pkt->u.alter_resp.ctx_list[0].reason));
1556 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1560 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1561 pkt->u.alter_resp.num_results == 0 ||
1562 pkt->u.alter_resp.ctx_list[0].result != 0) {
1563 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1567 /* the alter_resp might contain a reply set of credentials */
1568 if (recv_pipe->conn->security_state.auth_info &&
1569 pkt->u.alter_resp.auth_info.length) {
1570 c->status = ndr_pull_struct_blob(
1571 &pkt->u.alter_resp.auth_info, recv_pipe,
1572 recv_pipe->conn->security_state.auth_info,
1573 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1574 if (!composite_is_ok(c)) return;
1581 send a dcerpc alter_context request
1583 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1584 TALLOC_CTX *mem_ctx,
1585 const struct dcerpc_syntax_id *syntax,
1586 const struct dcerpc_syntax_id *transfer_syntax)
1588 struct composite_context *c;
1589 struct ncacn_packet pkt;
1592 c = talloc_zero(mem_ctx, struct composite_context);
1593 if (c == NULL) return NULL;
1595 c->state = COMPOSITE_STATE_IN_PROGRESS;
1596 c->private_data = p;
1597 c->event_ctx = p->conn->event_ctx;
1599 p->syntax = *syntax;
1600 p->transfer_syntax = *transfer_syntax;
1602 init_ncacn_hdr(p->conn, &pkt);
1604 pkt.ptype = DCERPC_PKT_ALTER;
1605 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1606 pkt.call_id = p->conn->call_id;
1607 pkt.auth_length = 0;
1609 pkt.u.alter.max_xmit_frag = 5840;
1610 pkt.u.alter.max_recv_frag = 5840;
1611 pkt.u.alter.assoc_group_id = 0;
1612 pkt.u.alter.num_contexts = 1;
1613 pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1614 struct dcerpc_ctx_list, 1);
1615 if (pkt.u.alter.ctx_list == NULL) {
1616 c->status = NT_STATUS_NO_MEMORY;
1619 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1620 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1621 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1622 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1623 pkt.u.alter.auth_info = data_blob(NULL, 0);
1625 /* construct the NDR form of the packet */
1626 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1627 p->conn->security_state.auth_info);
1628 if (!NT_STATUS_IS_OK(c->status)) {
1632 p->conn->transport.recv_data = dcerpc_recv_data;
1633 p->conn->alter_private = c;
1635 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1636 if (!NT_STATUS_IS_OK(c->status)) {
1640 event_add_timed(c->event_ctx, c,
1641 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1642 bind_timeout_handler, c);
1647 composite_error(c, c->status);
1651 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1653 NTSTATUS result = composite_wait(ctx);
1659 send a dcerpc alter_context request
1661 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1662 TALLOC_CTX *mem_ctx,
1663 const struct dcerpc_syntax_id *syntax,
1664 const struct dcerpc_syntax_id *transfer_syntax)
1666 struct composite_context *creq;
1667 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1668 return dcerpc_alter_context_recv(creq);