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/rpc/dcerpc_proto.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"
32 #include "param/param.h"
34 _PUBLIC_ NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx)
36 return gensec_init(lp_ctx);
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 tevent_context *ev)
60 struct dcerpc_connection *c;
62 c = talloc_zero(mem_ctx, struct dcerpc_connection);
69 if (c->event_ctx == NULL) {
75 c->security_state.auth_info = NULL;
76 c->security_state.session_key = dcerpc_generic_session_key;
77 c->security_state.generic_state = NULL;
78 c->binding_string = NULL;
80 c->srv_max_xmit_frag = 0;
81 c->srv_max_recv_frag = 0;
84 talloc_set_destructor(c, dcerpc_connection_destructor);
89 /* initialise a dcerpc pipe. */
90 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
92 struct dcerpc_pipe *p;
94 p = talloc(mem_ctx, struct dcerpc_pipe);
99 p->conn = dcerpc_connection_init(p, ev);
100 if (p->conn == NULL) {
105 p->last_fault_code = 0;
107 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
110 ZERO_STRUCT(p->syntax);
111 ZERO_STRUCT(p->transfer_syntax);
114 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
117 p->binding_handle = talloc(p, struct dcerpc_binding_handle);
118 if (p->binding_handle == NULL) {
122 p->binding_handle->private_data = p;
129 choose the next call id to use
131 static uint32_t next_call_id(struct dcerpc_connection *c)
134 if (c->call_id == 0) {
141 setup for a ndr pull, also setting up any flags from the binding string
143 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
144 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
146 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
148 if (ndr == NULL) return ndr;
150 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
151 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
154 if (c->flags & DCERPC_NDR_REF_ALLOC) {
155 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
158 if (c->flags & DCERPC_NDR64) {
159 ndr->flags |= LIBNDR_FLAG_NDR64;
166 parse a data blob into a ncacn_packet structure. This handles both
167 input and output packets
169 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
170 struct ncacn_packet *pkt)
172 struct ndr_pull *ndr;
173 enum ndr_err_code ndr_err;
175 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
177 return NT_STATUS_NO_MEMORY;
180 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
181 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
184 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
185 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
186 return ndr_map_error2ntstatus(ndr_err);
193 parse the authentication information on a dcerpc response packet
195 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
196 DATA_BLOB *raw_packet,
197 struct ncacn_packet *pkt)
200 struct dcerpc_auth auth;
201 uint32_t auth_length;
203 if (!c->security_state.auth_info ||
204 !c->security_state.generic_state) {
208 switch (c->security_state.auth_info->auth_level) {
209 case DCERPC_AUTH_LEVEL_PRIVACY:
210 case DCERPC_AUTH_LEVEL_INTEGRITY:
213 case DCERPC_AUTH_LEVEL_CONNECT:
214 if (pkt->auth_length != 0) {
218 case DCERPC_AUTH_LEVEL_NONE:
219 if (pkt->auth_length != 0) {
220 return NT_STATUS_INVALID_NETWORK_RESPONSE;
225 return NT_STATUS_INVALID_LEVEL;
228 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
229 &pkt->u.response.stub_and_verifier,
230 &auth, &auth_length, false);
231 NT_STATUS_NOT_OK_RETURN(status);
233 pkt->u.response.stub_and_verifier.length -= auth_length;
235 /* check signature or unseal the packet */
236 switch (c->security_state.auth_info->auth_level) {
237 case DCERPC_AUTH_LEVEL_PRIVACY:
238 status = gensec_unseal_packet(c->security_state.generic_state,
240 raw_packet->data + DCERPC_REQUEST_LENGTH,
241 pkt->u.response.stub_and_verifier.length,
243 raw_packet->length - auth.credentials.length,
245 memcpy(pkt->u.response.stub_and_verifier.data,
246 raw_packet->data + DCERPC_REQUEST_LENGTH,
247 pkt->u.response.stub_and_verifier.length);
250 case DCERPC_AUTH_LEVEL_INTEGRITY:
251 status = gensec_check_packet(c->security_state.generic_state,
253 pkt->u.response.stub_and_verifier.data,
254 pkt->u.response.stub_and_verifier.length,
256 raw_packet->length - auth.credentials.length,
260 case DCERPC_AUTH_LEVEL_CONNECT:
261 /* for now we ignore possible signatures here */
262 status = NT_STATUS_OK;
266 status = NT_STATUS_INVALID_LEVEL;
270 /* remove the indicated amount of padding */
271 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
272 return NT_STATUS_INFO_LENGTH_MISMATCH;
274 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
281 push a dcerpc request packet into a blob, possibly signing it.
283 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
284 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
286 struct ncacn_packet *pkt)
289 struct ndr_push *ndr;
291 size_t payload_length;
292 enum ndr_err_code ndr_err;
293 size_t hdr_size = DCERPC_REQUEST_LENGTH;
295 /* non-signed packets are simpler */
297 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
300 switch (c->security_state.auth_info->auth_level) {
301 case DCERPC_AUTH_LEVEL_PRIVACY:
302 case DCERPC_AUTH_LEVEL_INTEGRITY:
305 case DCERPC_AUTH_LEVEL_CONNECT:
306 /* TODO: let the gensec mech decide if it wants to generate a signature */
307 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
309 case DCERPC_AUTH_LEVEL_NONE:
310 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
313 return NT_STATUS_INVALID_LEVEL;
316 ndr = ndr_push_init_ctx(mem_ctx);
318 return NT_STATUS_NO_MEMORY;
321 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
322 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
325 if (c->flags & DCERPC_NDR64) {
326 ndr->flags |= LIBNDR_FLAG_NDR64;
329 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
330 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
334 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
335 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
336 return ndr_map_error2ntstatus(ndr_err);
339 /* pad to 16 byte multiple in the payload portion of the
340 packet. This matches what w2k3 does. Note that we can't use
341 ndr_push_align() as that is relative to the start of the
342 whole packet, whereas w2k8 wants it relative to the start
344 c->security_state.auth_info->auth_pad_length =
345 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
346 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
347 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
348 return ndr_map_error2ntstatus(ndr_err);
351 payload_length = pkt->u.request.stub_and_verifier.length +
352 c->security_state.auth_info->auth_pad_length;
354 /* we start without signature, it will appended later */
355 c->security_state.auth_info->credentials = data_blob(NULL,0);
357 /* add the auth verifier */
358 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
359 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
360 return ndr_map_error2ntstatus(ndr_err);
363 /* extract the whole packet as a blob */
364 *blob = ndr_push_blob(ndr);
367 * Setup the frag and auth length in the packet buffer.
368 * This is needed if the GENSEC mech does AEAD signing
369 * of the packet headers. The signature itself will be
372 dcerpc_set_frag_length(blob, blob->length + sig_size);
373 dcerpc_set_auth_length(blob, sig_size);
375 /* sign or seal the packet */
376 switch (c->security_state.auth_info->auth_level) {
377 case DCERPC_AUTH_LEVEL_PRIVACY:
378 status = gensec_seal_packet(c->security_state.generic_state,
380 blob->data + hdr_size,
385 if (!NT_STATUS_IS_OK(status)) {
390 case DCERPC_AUTH_LEVEL_INTEGRITY:
391 status = gensec_sign_packet(c->security_state.generic_state,
393 blob->data + hdr_size,
398 if (!NT_STATUS_IS_OK(status)) {
404 status = NT_STATUS_INVALID_LEVEL;
408 if (creds2.length != sig_size) {
409 /* this means the sig_size estimate for the signature
410 was incorrect. We have to correct the packet
411 sizes. That means we could go over the max fragment
413 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
414 (unsigned) creds2.length,
416 (unsigned) c->security_state.auth_info->auth_pad_length,
417 (unsigned) pkt->u.request.stub_and_verifier.length));
418 dcerpc_set_frag_length(blob, blob->length + creds2.length);
419 dcerpc_set_auth_length(blob, creds2.length);
422 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
423 return NT_STATUS_NO_MEMORY;
431 fill in the fixed values in a dcerpc header
433 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
436 pkt->rpc_vers_minor = 0;
437 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
440 pkt->drep[0] = DCERPC_DREP_LE;
448 map a bind nak reason to a NTSTATUS
450 static NTSTATUS dcerpc_map_reason(uint16_t reason)
453 case DCERPC_BIND_REASON_ASYNTAX:
454 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
455 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
456 return NT_STATUS_INVALID_PARAMETER;
458 return NT_STATUS_UNSUCCESSFUL;
462 a bind or alter context has failed
464 static void dcerpc_composite_fail(struct rpc_request *req)
466 struct composite_context *c = talloc_get_type(req->async.private_data,
467 struct composite_context);
468 composite_error(c, req->status);
472 remove requests from the pending or queued queues
474 static int dcerpc_req_dequeue(struct rpc_request *req)
476 switch (req->state) {
477 case RPC_REQUEST_QUEUED:
478 DLIST_REMOVE(req->p->conn->request_queue, req);
480 case RPC_REQUEST_PENDING:
481 DLIST_REMOVE(req->p->conn->pending, req);
483 case RPC_REQUEST_DONE:
491 mark the dcerpc connection dead. All outstanding requests get an error
493 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
495 if (conn->dead) return;
499 if (conn->transport.shutdown_pipe) {
500 conn->transport.shutdown_pipe(conn, status);
503 /* all pending requests get the error */
504 while (conn->pending) {
505 struct rpc_request *req = conn->pending;
506 dcerpc_req_dequeue(req);
507 req->state = RPC_REQUEST_DONE;
508 req->status = status;
509 if (req->async.callback) {
510 req->async.callback(req);
514 talloc_set_destructor(conn, NULL);
515 if (conn->free_skipped) {
521 forward declarations of the recv_data handlers for the types of
522 packets we need to handle
524 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
525 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
528 receive a dcerpc reply from the transport. Here we work out what
529 type of reply it is (normal request, bind or alter context) and
530 dispatch to the appropriate handler
532 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
534 struct ncacn_packet pkt;
536 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
537 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
540 /* the transport may be telling us of a severe error, such as
542 if (!NT_STATUS_IS_OK(status)) {
543 data_blob_free(blob);
544 dcerpc_connection_dead(conn, status);
548 /* parse the basic packet to work out what type of response this is */
549 status = ncacn_pull(conn, blob, blob->data, &pkt);
550 if (!NT_STATUS_IS_OK(status)) {
551 data_blob_free(blob);
552 dcerpc_connection_dead(conn, status);
555 dcerpc_request_recv_data(conn, blob, &pkt);
559 Receive a bind reply from the transport
561 static void dcerpc_bind_recv_handler(struct rpc_request *req,
562 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
564 struct composite_context *c;
565 struct dcerpc_connection *conn;
567 c = talloc_get_type(req->async.private_data, struct composite_context);
569 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
570 DEBUG(2,("dcerpc: bind_nak reason %d\n",
571 pkt->u.bind_nak.reject_reason));
572 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
577 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
578 (pkt->u.bind_ack.num_results == 0) ||
579 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
580 req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
581 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
587 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
588 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
590 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
591 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
592 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
595 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
596 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
597 conn->flags |= DCERPC_HEADER_SIGNING;
600 /* the bind_ack might contain a reply set of credentials */
601 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
603 uint32_t auth_length;
604 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
605 conn->security_state.auth_info, &auth_length, true);
606 if (!NT_STATUS_IS_OK(status)) {
607 composite_error(c, status);
612 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
618 handle timeouts of individual dcerpc requests
620 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
621 struct timeval t, void *private_data)
623 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
625 if (req->ignore_timeout) {
626 dcerpc_req_dequeue(req);
627 req->state = RPC_REQUEST_DONE;
628 req->status = NT_STATUS_IO_TIMEOUT;
629 if (req->async.callback) {
630 req->async.callback(req);
635 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
639 send a async dcerpc bind request
641 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
643 const struct ndr_syntax_id *syntax,
644 const struct ndr_syntax_id *transfer_syntax)
646 struct composite_context *c;
647 struct ncacn_packet pkt;
649 struct rpc_request *req;
651 c = composite_create(mem_ctx,p->conn->event_ctx);
652 if (c == NULL) return NULL;
657 p->transfer_syntax = *transfer_syntax;
659 init_ncacn_hdr(p->conn, &pkt);
661 pkt.ptype = DCERPC_PKT_BIND;
662 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
663 pkt.call_id = p->conn->call_id;
666 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
667 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
670 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
671 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
674 pkt.u.bind.max_xmit_frag = 5840;
675 pkt.u.bind.max_recv_frag = 5840;
676 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
677 pkt.u.bind.num_contexts = 1;
678 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
679 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
680 pkt.u.bind.ctx_list[0].context_id = p->context_id;
681 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
682 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
683 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
684 pkt.u.bind.auth_info = data_blob(NULL, 0);
686 /* construct the NDR form of the packet */
687 c->status = ncacn_push_auth(&blob, c, &pkt,
688 p->conn->security_state.auth_info);
689 if (!composite_is_ok(c)) return c;
691 p->conn->transport.recv_data = dcerpc_recv_data;
694 * we allocate a dcerpc_request so we can be in the same
695 * request queue as normal requests
697 req = talloc_zero(c, struct rpc_request);
698 if (composite_nomem(req, c)) return c;
700 req->state = RPC_REQUEST_PENDING;
701 req->call_id = pkt.call_id;
702 req->async.private_data = c;
703 req->async.callback = dcerpc_composite_fail;
705 req->recv_handler = dcerpc_bind_recv_handler;
706 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
707 talloc_set_destructor(req, dcerpc_req_dequeue);
709 c->status = p->conn->transport.send_request(p->conn, &blob,
711 if (!composite_is_ok(c)) return c;
713 event_add_timed(c->event_ctx, req,
714 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
715 dcerpc_timeout_handler, req);
721 recv side of async dcerpc bind request
723 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
725 NTSTATUS result = composite_wait(ctx);
731 perform a continued bind (and auth3)
733 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
736 struct ncacn_packet pkt;
740 init_ncacn_hdr(p->conn, &pkt);
742 pkt.ptype = DCERPC_PKT_AUTH3;
743 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
744 pkt.call_id = next_call_id(p->conn);
746 pkt.u.auth3.auth_info = data_blob(NULL, 0);
748 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
749 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
752 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
753 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
756 /* construct the NDR form of the packet */
757 status = ncacn_push_auth(&blob, mem_ctx,
759 p->conn->security_state.auth_info);
760 if (!NT_STATUS_IS_OK(status)) {
764 /* send it on its way */
765 status = p->conn->transport.send_request(p->conn, &blob, false);
766 if (!NT_STATUS_IS_OK(status)) {
775 process a fragment received from the transport layer during a
778 This function frees the data
780 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
781 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
783 struct rpc_request *req;
785 NTSTATUS status = NT_STATUS_OK;
788 if this is an authenticated connection then parse and check
789 the auth info. We have to do this before finding the
790 matching packet, as the request structure might have been
791 removed due to a timeout, but if it has been we still need
792 to run the auth routines so that we don't get the sign/seal
793 info out of step with the server
795 if (c->security_state.auth_info && c->security_state.generic_state &&
796 pkt->ptype == DCERPC_PKT_RESPONSE) {
797 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
800 /* find the matching request */
801 for (req=c->pending;req;req=req->next) {
802 if (pkt->call_id == req->call_id) break;
806 /* useful for testing certain vendors RPC servers */
807 if (req == NULL && c->pending && pkt->call_id == 0) {
808 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
814 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
815 data_blob_free(raw_packet);
819 talloc_steal(req, raw_packet->data);
821 if (req->recv_handler != NULL) {
822 dcerpc_req_dequeue(req);
823 req->state = RPC_REQUEST_DONE;
824 req->recv_handler(req, raw_packet, pkt);
828 if (pkt->ptype == DCERPC_PKT_FAULT) {
829 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
830 req->fault_code = pkt->u.fault.status;
831 req->status = NT_STATUS_NET_WRITE_FAULT;
835 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
836 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
838 req->fault_code = DCERPC_FAULT_OTHER;
839 req->status = NT_STATUS_NET_WRITE_FAULT;
843 /* now check the status from the auth routines, and if it failed then fail
844 this request accordingly */
845 if (!NT_STATUS_IS_OK(status)) {
846 req->status = status;
850 length = pkt->u.response.stub_and_verifier.length;
853 req->payload.data = talloc_realloc(req,
856 req->payload.length + length);
857 if (!req->payload.data) {
858 req->status = NT_STATUS_NO_MEMORY;
861 memcpy(req->payload.data+req->payload.length,
862 pkt->u.response.stub_and_verifier.data, length);
863 req->payload.length += length;
866 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
867 c->transport.send_read(c);
871 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
872 req->flags |= DCERPC_PULL_BIGENDIAN;
874 req->flags &= ~DCERPC_PULL_BIGENDIAN;
879 /* we've got the full payload */
880 req->state = RPC_REQUEST_DONE;
881 DLIST_REMOVE(c->pending, req);
883 if (c->request_queue != NULL) {
884 /* We have to look at shipping further requests before calling
885 * the async function, that one might close the pipe */
886 dcerpc_ship_next_request(c);
889 if (req->async.callback) {
890 req->async.callback(req);
895 perform the send side of a async dcerpc request
897 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
898 const struct GUID *object,
900 DATA_BLOB *stub_data)
902 struct rpc_request *req;
904 p->conn->transport.recv_data = dcerpc_recv_data;
906 req = talloc(p, struct rpc_request);
912 req->call_id = next_call_id(p->conn);
913 req->status = NT_STATUS_OK;
914 req->state = RPC_REQUEST_QUEUED;
915 req->payload = data_blob(NULL, 0);
918 req->ignore_timeout = false;
919 req->async.callback = NULL;
920 req->async.private_data = NULL;
921 req->recv_handler = NULL;
923 if (object != NULL) {
924 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
925 if (req->object == NULL) {
934 req->request_data.length = stub_data->length;
935 req->request_data.data = talloc_reference(req, stub_data->data);
936 if (req->request_data.length && req->request_data.data == NULL) {
940 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
941 talloc_set_destructor(req, dcerpc_req_dequeue);
943 dcerpc_ship_next_request(p->conn);
945 if (p->request_timeout) {
946 event_add_timed(dcerpc_event_context(p), req,
947 timeval_current_ofs(p->request_timeout, 0),
948 dcerpc_timeout_handler, req);
955 Send a request using the transport
958 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
960 struct rpc_request *req;
961 struct dcerpc_pipe *p;
962 DATA_BLOB *stub_data;
963 struct ncacn_packet pkt;
965 uint32_t remaining, chunk_size;
966 bool first_packet = true;
968 bool need_async = false;
970 req = c->request_queue;
976 stub_data = &req->request_data;
982 DLIST_REMOVE(c->request_queue, req);
983 DLIST_ADD(c->pending, req);
984 req->state = RPC_REQUEST_PENDING;
986 init_ncacn_hdr(p->conn, &pkt);
988 remaining = stub_data->length;
990 /* we can write a full max_recv_frag size, minus the dcerpc
991 request header size */
992 chunk_size = p->conn->srv_max_recv_frag;
993 chunk_size -= DCERPC_REQUEST_LENGTH;
994 if (c->security_state.auth_info &&
995 c->security_state.generic_state) {
996 sig_size = gensec_sig_size(c->security_state.generic_state,
997 p->conn->srv_max_recv_frag);
999 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1000 chunk_size -= sig_size;
1003 chunk_size -= (chunk_size % 16);
1005 pkt.ptype = DCERPC_PKT_REQUEST;
1006 pkt.call_id = req->call_id;
1007 pkt.auth_length = 0;
1009 pkt.u.request.alloc_hint = remaining;
1010 pkt.u.request.context_id = p->context_id;
1011 pkt.u.request.opnum = req->opnum;
1014 pkt.u.request.object.object = *req->object;
1015 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1016 chunk_size -= ndr_size_GUID(req->object,0);
1019 /* we send a series of pdus without waiting for a reply */
1020 while (remaining > 0 || first_packet) {
1021 uint32_t chunk = MIN(chunk_size, remaining);
1022 bool last_frag = false;
1023 bool do_trans = false;
1025 first_packet = false;
1026 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1028 if (remaining == stub_data->length) {
1029 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1031 if (chunk == remaining) {
1032 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1036 pkt.u.request.stub_and_verifier.data = stub_data->data +
1037 (stub_data->length - remaining);
1038 pkt.u.request.stub_and_verifier.length = chunk;
1040 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1041 if (!NT_STATUS_IS_OK(req->status)) {
1042 req->state = RPC_REQUEST_DONE;
1043 DLIST_REMOVE(p->conn->pending, req);
1047 if (last_frag && !need_async) {
1051 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1052 if (!NT_STATUS_IS_OK(req->status)) {
1053 req->state = RPC_REQUEST_DONE;
1054 DLIST_REMOVE(p->conn->pending, req);
1058 if (last_frag && !do_trans) {
1059 req->status = p->conn->transport.send_read(p->conn);
1060 if (!NT_STATUS_IS_OK(req->status)) {
1061 req->state = RPC_REQUEST_DONE;
1062 DLIST_REMOVE(p->conn->pending, req);
1072 return the event context for a dcerpc pipe
1073 used by callers who wish to operate asynchronously
1075 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1077 return p->conn->event_ctx;
1083 perform the receive side of a async dcerpc request
1085 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1086 TALLOC_CTX *mem_ctx,
1087 DATA_BLOB *stub_data)
1091 while (req->state != RPC_REQUEST_DONE) {
1092 struct tevent_context *ctx = dcerpc_event_context(req->p);
1093 if (event_loop_once(ctx) != 0) {
1094 return NT_STATUS_CONNECTION_DISCONNECTED;
1097 *stub_data = req->payload;
1098 status = req->status;
1099 if (stub_data->data) {
1100 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1102 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1103 req->p->last_fault_code = req->fault_code;
1105 talloc_unlink(talloc_parent(req), req);
1110 perform a full request/response pair on a dcerpc pipe
1112 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1113 struct GUID *object,
1115 TALLOC_CTX *mem_ctx,
1116 DATA_BLOB *stub_data_in,
1117 DATA_BLOB *stub_data_out)
1119 struct rpc_request *req;
1121 req = dcerpc_request_send(p, object, opnum, stub_data_in);
1123 return NT_STATUS_NO_MEMORY;
1126 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1131 this is a paranoid NDR validator. For every packet we push onto the wire
1132 we pull it back again, then push it again. Then we compare the raw NDR data
1133 for that to the NDR we initially generated. If they don't match then we know
1134 we must have a bug in either the pull or push side of our code
1136 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1137 TALLOC_CTX *mem_ctx,
1140 ndr_push_flags_fn_t ndr_push,
1141 ndr_pull_flags_fn_t ndr_pull)
1144 struct ndr_pull *pull;
1145 struct ndr_push *push;
1147 enum ndr_err_code ndr_err;
1149 st = talloc_size(mem_ctx, struct_size);
1151 return NT_STATUS_NO_MEMORY;
1154 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1156 return NT_STATUS_NO_MEMORY;
1158 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1160 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1161 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1164 if (c->flags & DCERPC_NDR64) {
1165 pull->flags |= LIBNDR_FLAG_NDR64;
1168 ndr_err = ndr_pull(pull, NDR_IN, st);
1169 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1170 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1171 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1172 "failed input validation pull - %s",
1174 return ndr_map_error2ntstatus(ndr_err);
1177 push = ndr_push_init_ctx(mem_ctx);
1179 return NT_STATUS_NO_MEMORY;
1182 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1183 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1186 if (c->flags & DCERPC_NDR64) {
1187 push->flags |= LIBNDR_FLAG_NDR64;
1190 ndr_err = ndr_push(push, NDR_IN, st);
1191 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1192 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1193 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1194 "failed input validation push - %s",
1196 return ndr_map_error2ntstatus(ndr_err);
1199 blob2 = ndr_push_blob(push);
1201 if (data_blob_cmp(&blob, &blob2) != 0) {
1202 DEBUG(3,("original:\n"));
1203 dump_data(3, blob.data, blob.length);
1204 DEBUG(3,("secondary:\n"));
1205 dump_data(3, blob2.data, blob2.length);
1206 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1207 "failed input validation blobs doesn't match");
1208 return ndr_map_error2ntstatus(ndr_err);
1211 return NT_STATUS_OK;
1215 this is a paranoid NDR input validator. For every packet we pull
1216 from the wire we push it back again then pull and push it
1217 again. Then we compare the raw NDR data for that to the NDR we
1218 initially generated. If they don't match then we know we must have a
1219 bug in either the pull or push side of our code
1221 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1222 struct ndr_pull *pull_in,
1225 ndr_push_flags_fn_t ndr_push,
1226 ndr_pull_flags_fn_t ndr_pull,
1227 ndr_print_function_t ndr_print)
1230 struct ndr_pull *pull;
1231 struct ndr_push *push;
1232 DATA_BLOB blob, blob2;
1233 TALLOC_CTX *mem_ctx = pull_in;
1235 enum ndr_err_code ndr_err;
1237 st = talloc_size(mem_ctx, struct_size);
1239 return NT_STATUS_NO_MEMORY;
1241 memcpy(st, struct_ptr, struct_size);
1243 push = ndr_push_init_ctx(mem_ctx);
1245 return NT_STATUS_NO_MEMORY;
1248 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1249 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1250 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1251 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1252 "failed output validation push - %s",
1254 return ndr_map_error2ntstatus(ndr_err);
1257 blob = ndr_push_blob(push);
1259 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1261 return NT_STATUS_NO_MEMORY;
1264 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1265 ndr_err = ndr_pull(pull, NDR_OUT, st);
1266 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1267 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1268 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1269 "failed output validation pull - %s",
1271 return ndr_map_error2ntstatus(ndr_err);
1274 push = ndr_push_init_ctx(mem_ctx);
1276 return NT_STATUS_NO_MEMORY;
1279 ndr_err = ndr_push(push, NDR_OUT, st);
1280 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1281 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1282 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1283 "failed output validation push2 - %s",
1285 return ndr_map_error2ntstatus(ndr_err);
1288 blob2 = ndr_push_blob(push);
1290 if (data_blob_cmp(&blob, &blob2) != 0) {
1291 DEBUG(3,("original:\n"));
1292 dump_data(3, blob.data, blob.length);
1293 DEBUG(3,("secondary:\n"));
1294 dump_data(3, blob2.data, blob2.length);
1295 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1296 "failed output validation blobs doesn't match");
1297 return ndr_map_error2ntstatus(ndr_err);
1300 /* this checks the printed forms of the two structures, which effectively
1301 tests all of the value() attributes */
1302 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1303 NDR_OUT, struct_ptr);
1304 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1306 if (strcmp(s1, s2) != 0) {
1308 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1310 /* this is sometimes useful */
1311 printf("VALIDATE ERROR\n");
1312 file_save("wire.dat", s1, strlen(s1));
1313 file_save("gen.dat", s2, strlen(s2));
1314 system("diff -u wire.dat gen.dat");
1316 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1317 "failed output validation strings doesn't match");
1318 return ndr_map_error2ntstatus(ndr_err);
1321 return NT_STATUS_OK;
1326 send a rpc request given a dcerpc_call structure
1328 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1329 const struct GUID *object,
1330 const struct ndr_interface_table *table,
1333 TALLOC_CTX *mem_ctx,
1336 const struct ndr_interface_call *call;
1337 struct ndr_push *push;
1340 struct rpc_request *req;
1341 enum ndr_err_code ndr_err;
1343 call = &table->calls[opnum];
1345 /* setup for a ndr_push_* call */
1346 push = ndr_push_init_ctx(mem_ctx);
1351 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1352 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1355 if (p->conn->flags & DCERPC_NDR64) {
1356 push->flags |= LIBNDR_FLAG_NDR64;
1359 /* push the structure into a blob */
1360 ndr_err = call->ndr_push(push, NDR_IN, r);
1361 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1362 status = ndr_map_error2ntstatus(ndr_err);
1363 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1364 nt_errstr(status)));
1369 /* retrieve the blob */
1370 request = ndr_push_blob(push);
1372 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1373 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1374 call->ndr_push, call->ndr_pull);
1375 if (!NT_STATUS_IS_OK(status)) {
1376 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1377 nt_errstr(status)));
1383 DEBUG(10,("rpc request data:\n"));
1384 dump_data(10, request.data, request.length);
1386 /* make the actual dcerpc request */
1387 req = dcerpc_request_send(p, object, opnum, &request);
1390 req->ndr.table = table;
1391 req->ndr.opnum = opnum;
1392 req->ndr.struct_ptr = r;
1393 req->ndr.mem_ctx = mem_ctx;
1402 receive the answer from a dcerpc_ndr_request_send()
1404 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1406 struct dcerpc_pipe *p = req->p;
1409 struct ndr_pull *pull;
1411 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1412 void *r = req->ndr.struct_ptr;
1413 uint32_t opnum = req->ndr.opnum;
1414 const struct ndr_interface_table *table = req->ndr.table;
1415 const struct ndr_interface_call *call = &table->calls[opnum];
1416 enum ndr_err_code ndr_err;
1418 /* make sure the recv code doesn't free the request, as we
1419 need to grab the flags element before it is freed */
1420 if (talloc_reference(p, req) == NULL) {
1421 return NT_STATUS_NO_MEMORY;
1424 status = dcerpc_request_recv(req, mem_ctx, &response);
1425 if (!NT_STATUS_IS_OK(status)) {
1426 talloc_unlink(p, req);
1432 /* prepare for ndr_pull_* */
1433 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1435 talloc_unlink(p, req);
1436 return NT_STATUS_NO_MEMORY;
1440 pull->data = talloc_steal(pull, pull->data);
1442 talloc_unlink(p, req);
1444 if (flags & DCERPC_PULL_BIGENDIAN) {
1445 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1448 DEBUG(10,("rpc reply data:\n"));
1449 dump_data(10, pull->data, pull->data_size);
1451 /* pull the structure from the blob */
1452 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1453 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1454 status = ndr_map_error2ntstatus(ndr_err);
1455 dcerpc_log_packet(p->conn->packet_log_dir,
1456 table, opnum, NDR_OUT,
1461 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1462 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1463 call->ndr_push, call->ndr_pull,
1465 if (!NT_STATUS_IS_OK(status)) {
1466 dcerpc_log_packet(p->conn->packet_log_dir,
1467 table, opnum, NDR_OUT,
1473 if (pull->offset != pull->data_size) {
1474 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1475 pull->data_size - pull->offset));
1476 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1477 but it turns out that early versions of NT
1478 (specifically NT3.1) add junk onto the end of rpc
1479 packets, so if we want to interoperate at all with
1480 those versions then we need to ignore this error */
1483 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1485 return NT_STATUS_OK;
1490 a useful helper function for synchronous rpc requests
1492 this can be used when you have ndr push/pull functions in the
1495 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1496 const struct GUID *object,
1497 const struct ndr_interface_table *table,
1499 TALLOC_CTX *mem_ctx,
1502 struct rpc_request *req;
1504 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1506 return NT_STATUS_NO_MEMORY;
1509 return dcerpc_ndr_request_recv(req);
1514 a useful function for retrieving the server name we connected to
1516 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1518 if (!p->conn->transport.target_hostname) {
1519 if (!p->conn->transport.peer_name) {
1522 return p->conn->transport.peer_name(p->conn);
1524 return p->conn->transport.target_hostname(p->conn);
1529 get the dcerpc auth_level for a open connection
1531 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1535 if (c->flags & DCERPC_SEAL) {
1536 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1537 } else if (c->flags & DCERPC_SIGN) {
1538 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1539 } else if (c->flags & DCERPC_CONNECT) {
1540 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1542 auth_level = DCERPC_AUTH_LEVEL_NONE;
1548 Receive an alter reply from the transport
1550 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1551 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1553 struct composite_context *c;
1554 struct dcerpc_pipe *recv_pipe;
1556 c = talloc_get_type(req->async.private_data, struct composite_context);
1557 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1559 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1560 pkt->u.alter_resp.num_results == 1 &&
1561 pkt->u.alter_resp.ctx_list[0].result != 0) {
1562 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1563 pkt->u.alter_resp.ctx_list[0].reason));
1564 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1568 if (pkt->ptype == DCERPC_PKT_FAULT) {
1569 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1570 recv_pipe->last_fault_code = pkt->u.fault.status;
1571 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1575 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1576 pkt->u.alter_resp.num_results == 0 ||
1577 pkt->u.alter_resp.ctx_list[0].result != 0) {
1578 recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1579 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1583 /* the alter_resp might contain a reply set of credentials */
1584 if (recv_pipe->conn->security_state.auth_info &&
1585 pkt->u.alter_resp.auth_info.length) {
1586 struct dcerpc_connection *conn = recv_pipe->conn;
1588 uint32_t auth_length;
1589 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1590 conn->security_state.auth_info, &auth_length, true);
1591 if (!NT_STATUS_IS_OK(status)) {
1592 composite_error(c, status);
1601 send a dcerpc alter_context request
1603 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1604 TALLOC_CTX *mem_ctx,
1605 const struct ndr_syntax_id *syntax,
1606 const struct ndr_syntax_id *transfer_syntax)
1608 struct composite_context *c;
1609 struct ncacn_packet pkt;
1611 struct rpc_request *req;
1613 c = composite_create(mem_ctx, p->conn->event_ctx);
1614 if (c == NULL) return NULL;
1616 c->private_data = p;
1618 p->syntax = *syntax;
1619 p->transfer_syntax = *transfer_syntax;
1621 init_ncacn_hdr(p->conn, &pkt);
1623 pkt.ptype = DCERPC_PKT_ALTER;
1624 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1625 pkt.call_id = p->conn->call_id;
1626 pkt.auth_length = 0;
1628 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1629 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1632 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1633 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1636 pkt.u.alter.max_xmit_frag = 5840;
1637 pkt.u.alter.max_recv_frag = 5840;
1638 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1639 pkt.u.alter.num_contexts = 1;
1640 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1641 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1642 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1643 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1644 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1645 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1646 pkt.u.alter.auth_info = data_blob(NULL, 0);
1648 /* construct the NDR form of the packet */
1649 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1650 p->conn->security_state.auth_info);
1651 if (!composite_is_ok(c)) return c;
1653 p->conn->transport.recv_data = dcerpc_recv_data;
1656 * we allocate a dcerpc_request so we can be in the same
1657 * request queue as normal requests
1659 req = talloc_zero(c, struct rpc_request);
1660 if (composite_nomem(req, c)) return c;
1662 req->state = RPC_REQUEST_PENDING;
1663 req->call_id = pkt.call_id;
1664 req->async.private_data = c;
1665 req->async.callback = dcerpc_composite_fail;
1667 req->recv_handler = dcerpc_alter_recv_handler;
1668 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1669 talloc_set_destructor(req, dcerpc_req_dequeue);
1671 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1672 if (!composite_is_ok(c)) return c;
1674 event_add_timed(c->event_ctx, req,
1675 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1676 dcerpc_timeout_handler, req);
1681 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1683 NTSTATUS result = composite_wait(ctx);
1689 send a dcerpc alter_context request
1691 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1692 TALLOC_CTX *mem_ctx,
1693 const struct ndr_syntax_id *syntax,
1694 const struct ndr_syntax_id *transfer_syntax)
1696 struct composite_context *creq;
1697 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1698 return dcerpc_alter_context_recv(creq);