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,
59 struct smb_iconv_convenience *ic)
61 struct dcerpc_connection *c;
63 c = talloc_zero(mem_ctx, struct dcerpc_connection);
68 c->iconv_convenience = talloc_reference(c, ic);
72 if (c->event_ctx == NULL) {
78 c->security_state.auth_info = NULL;
79 c->security_state.session_key = dcerpc_generic_session_key;
80 c->security_state.generic_state = NULL;
81 c->binding_string = NULL;
83 c->srv_max_xmit_frag = 0;
84 c->srv_max_recv_frag = 0;
87 talloc_set_destructor(c, dcerpc_connection_destructor);
92 /* initialise a dcerpc pipe. */
93 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
94 struct smb_iconv_convenience *ic)
96 struct dcerpc_pipe *p;
98 p = talloc(mem_ctx, struct dcerpc_pipe);
103 p->conn = dcerpc_connection_init(p, ev, ic);
104 if (p->conn == NULL) {
109 p->last_fault_code = 0;
111 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
114 ZERO_STRUCT(p->syntax);
115 ZERO_STRUCT(p->transfer_syntax);
118 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
126 choose the next call id to use
128 static uint32_t next_call_id(struct dcerpc_connection *c)
131 if (c->call_id == 0) {
137 /* we need to be able to get/set the fragment length without doing a full
139 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
141 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
142 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
144 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
148 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
150 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
151 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
153 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
157 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
159 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
160 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
162 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
168 setup for a ndr pull, also setting up any flags from the binding string
170 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
171 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
173 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
175 if (ndr == NULL) return ndr;
177 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
178 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
181 if (c->flags & DCERPC_NDR_REF_ALLOC) {
182 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
185 if (c->flags & DCERPC_NDR64) {
186 ndr->flags |= LIBNDR_FLAG_NDR64;
193 parse a data blob into a ncacn_packet structure. This handles both
194 input and output packets
196 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
197 struct ncacn_packet *pkt)
199 struct ndr_pull *ndr;
200 enum ndr_err_code ndr_err;
202 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
204 return NT_STATUS_NO_MEMORY;
207 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
208 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
211 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
212 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
213 return ndr_map_error2ntstatus(ndr_err);
220 parse the authentication information on a dcerpc response packet
222 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
223 DATA_BLOB *raw_packet,
224 struct ncacn_packet *pkt)
227 struct dcerpc_auth auth;
228 uint32_t auth_length;
230 if (!c->security_state.auth_info ||
231 !c->security_state.generic_state) {
235 switch (c->security_state.auth_info->auth_level) {
236 case DCERPC_AUTH_LEVEL_PRIVACY:
237 case DCERPC_AUTH_LEVEL_INTEGRITY:
240 case DCERPC_AUTH_LEVEL_CONNECT:
241 if (pkt->auth_length != 0) {
245 case DCERPC_AUTH_LEVEL_NONE:
246 if (pkt->auth_length != 0) {
247 return NT_STATUS_INVALID_NETWORK_RESPONSE;
252 return NT_STATUS_INVALID_LEVEL;
255 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
256 &pkt->u.response.stub_and_verifier,
257 &auth, &auth_length, false);
258 NT_STATUS_NOT_OK_RETURN(status);
260 pkt->u.response.stub_and_verifier.length -= auth_length;
262 /* check signature or unseal the packet */
263 switch (c->security_state.auth_info->auth_level) {
264 case DCERPC_AUTH_LEVEL_PRIVACY:
265 status = gensec_unseal_packet(c->security_state.generic_state,
267 raw_packet->data + DCERPC_REQUEST_LENGTH,
268 pkt->u.response.stub_and_verifier.length,
270 raw_packet->length - auth.credentials.length,
272 memcpy(pkt->u.response.stub_and_verifier.data,
273 raw_packet->data + DCERPC_REQUEST_LENGTH,
274 pkt->u.response.stub_and_verifier.length);
277 case DCERPC_AUTH_LEVEL_INTEGRITY:
278 status = gensec_check_packet(c->security_state.generic_state,
280 pkt->u.response.stub_and_verifier.data,
281 pkt->u.response.stub_and_verifier.length,
283 raw_packet->length - auth.credentials.length,
287 case DCERPC_AUTH_LEVEL_CONNECT:
288 /* for now we ignore possible signatures here */
289 status = NT_STATUS_OK;
293 status = NT_STATUS_INVALID_LEVEL;
297 /* remove the indicated amount of padding */
298 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
299 return NT_STATUS_INFO_LENGTH_MISMATCH;
301 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
308 push a dcerpc request packet into a blob, possibly signing it.
310 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
311 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
313 struct ncacn_packet *pkt)
316 struct ndr_push *ndr;
318 size_t payload_length;
319 enum ndr_err_code ndr_err;
320 size_t hdr_size = DCERPC_REQUEST_LENGTH;
322 /* non-signed packets are simpler */
324 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
327 switch (c->security_state.auth_info->auth_level) {
328 case DCERPC_AUTH_LEVEL_PRIVACY:
329 case DCERPC_AUTH_LEVEL_INTEGRITY:
332 case DCERPC_AUTH_LEVEL_CONNECT:
333 /* TODO: let the gensec mech decide if it wants to generate a signature */
334 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
336 case DCERPC_AUTH_LEVEL_NONE:
337 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
340 return NT_STATUS_INVALID_LEVEL;
343 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
345 return NT_STATUS_NO_MEMORY;
348 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
349 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
352 if (c->flags & DCERPC_NDR64) {
353 ndr->flags |= LIBNDR_FLAG_NDR64;
356 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
357 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
361 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
362 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
363 return ndr_map_error2ntstatus(ndr_err);
366 /* pad to 16 byte multiple in the payload portion of the
367 packet. This matches what w2k3 does. Note that we can't use
368 ndr_push_align() as that is relative to the start of the
369 whole packet, whereas w2k8 wants it relative to the start
371 c->security_state.auth_info->auth_pad_length =
372 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
373 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
374 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
375 return ndr_map_error2ntstatus(ndr_err);
378 payload_length = pkt->u.request.stub_and_verifier.length +
379 c->security_state.auth_info->auth_pad_length;
381 /* we start without signature, it will appended later */
382 c->security_state.auth_info->credentials = data_blob(NULL,0);
384 /* add the auth verifier */
385 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
386 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
387 return ndr_map_error2ntstatus(ndr_err);
390 /* extract the whole packet as a blob */
391 *blob = ndr_push_blob(ndr);
394 * Setup the frag and auth length in the packet buffer.
395 * This is needed if the GENSEC mech does AEAD signing
396 * of the packet headers. The signature itself will be
399 dcerpc_set_frag_length(blob, blob->length + sig_size);
400 dcerpc_set_auth_length(blob, sig_size);
402 /* sign or seal the packet */
403 switch (c->security_state.auth_info->auth_level) {
404 case DCERPC_AUTH_LEVEL_PRIVACY:
405 status = gensec_seal_packet(c->security_state.generic_state,
407 blob->data + hdr_size,
412 if (!NT_STATUS_IS_OK(status)) {
417 case DCERPC_AUTH_LEVEL_INTEGRITY:
418 status = gensec_sign_packet(c->security_state.generic_state,
420 blob->data + hdr_size,
425 if (!NT_STATUS_IS_OK(status)) {
431 status = NT_STATUS_INVALID_LEVEL;
435 if (creds2.length != sig_size) {
436 /* this means the sig_size estimate for the signature
437 was incorrect. We have to correct the packet
438 sizes. That means we could go over the max fragment
440 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
441 (unsigned) creds2.length,
443 (unsigned) c->security_state.auth_info->auth_pad_length,
444 (unsigned) pkt->u.request.stub_and_verifier.length));
445 dcerpc_set_frag_length(blob, blob->length + creds2.length);
446 dcerpc_set_auth_length(blob, creds2.length);
449 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
450 return NT_STATUS_NO_MEMORY;
458 fill in the fixed values in a dcerpc header
460 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
463 pkt->rpc_vers_minor = 0;
464 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
467 pkt->drep[0] = DCERPC_DREP_LE;
475 map a bind nak reason to a NTSTATUS
477 static NTSTATUS dcerpc_map_reason(uint16_t reason)
480 case DCERPC_BIND_REASON_ASYNTAX:
481 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
482 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
483 return NT_STATUS_INVALID_PARAMETER;
485 return NT_STATUS_UNSUCCESSFUL;
489 a bind or alter context has failed
491 static void dcerpc_composite_fail(struct rpc_request *req)
493 struct composite_context *c = talloc_get_type(req->async.private_data,
494 struct composite_context);
495 composite_error(c, req->status);
499 remove requests from the pending or queued queues
501 static int dcerpc_req_dequeue(struct rpc_request *req)
503 switch (req->state) {
504 case RPC_REQUEST_QUEUED:
505 DLIST_REMOVE(req->p->conn->request_queue, req);
507 case RPC_REQUEST_PENDING:
508 DLIST_REMOVE(req->p->conn->pending, req);
510 case RPC_REQUEST_DONE:
518 mark the dcerpc connection dead. All outstanding requests get an error
520 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
522 if (conn->dead) return;
526 if (conn->transport.shutdown_pipe) {
527 conn->transport.shutdown_pipe(conn, status);
530 /* all pending requests get the error */
531 while (conn->pending) {
532 struct rpc_request *req = conn->pending;
533 dcerpc_req_dequeue(req);
534 req->state = RPC_REQUEST_DONE;
535 req->status = status;
536 if (req->async.callback) {
537 req->async.callback(req);
541 talloc_set_destructor(conn, NULL);
542 if (conn->free_skipped) {
548 forward declarations of the recv_data handlers for the types of
549 packets we need to handle
551 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
552 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
555 receive a dcerpc reply from the transport. Here we work out what
556 type of reply it is (normal request, bind or alter context) and
557 dispatch to the appropriate handler
559 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
561 struct ncacn_packet pkt;
563 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
564 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
567 /* the transport may be telling us of a severe error, such as
569 if (!NT_STATUS_IS_OK(status)) {
570 data_blob_free(blob);
571 dcerpc_connection_dead(conn, status);
575 /* parse the basic packet to work out what type of response this is */
576 status = ncacn_pull(conn, blob, blob->data, &pkt);
577 if (!NT_STATUS_IS_OK(status)) {
578 data_blob_free(blob);
579 dcerpc_connection_dead(conn, status);
582 dcerpc_request_recv_data(conn, blob, &pkt);
586 Receive a bind reply from the transport
588 static void dcerpc_bind_recv_handler(struct rpc_request *req,
589 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
591 struct composite_context *c;
592 struct dcerpc_connection *conn;
594 c = talloc_get_type(req->async.private_data, struct composite_context);
596 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
597 DEBUG(2,("dcerpc: bind_nak reason %d\n",
598 pkt->u.bind_nak.reject_reason));
599 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
604 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
605 (pkt->u.bind_ack.num_results == 0) ||
606 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
607 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
613 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
614 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
616 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
617 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
618 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
621 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
622 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
623 conn->flags |= DCERPC_HEADER_SIGNING;
626 /* the bind_ack might contain a reply set of credentials */
627 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
629 uint32_t auth_length;
630 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
631 conn->security_state.auth_info, &auth_length, true);
632 if (!NT_STATUS_IS_OK(status)) {
633 composite_error(c, status);
638 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
644 handle timeouts of individual dcerpc requests
646 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
647 struct timeval t, void *private_data)
649 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
651 if (req->ignore_timeout) {
652 dcerpc_req_dequeue(req);
653 req->state = RPC_REQUEST_DONE;
654 req->status = NT_STATUS_IO_TIMEOUT;
655 if (req->async.callback) {
656 req->async.callback(req);
661 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
665 send a async dcerpc bind request
667 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
669 const struct ndr_syntax_id *syntax,
670 const struct ndr_syntax_id *transfer_syntax)
672 struct composite_context *c;
673 struct ncacn_packet pkt;
675 struct rpc_request *req;
677 c = composite_create(mem_ctx,p->conn->event_ctx);
678 if (c == NULL) return NULL;
683 p->transfer_syntax = *transfer_syntax;
685 init_ncacn_hdr(p->conn, &pkt);
687 pkt.ptype = DCERPC_PKT_BIND;
688 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
689 pkt.call_id = p->conn->call_id;
692 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
693 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
696 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
697 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
700 pkt.u.bind.max_xmit_frag = 5840;
701 pkt.u.bind.max_recv_frag = 5840;
702 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
703 pkt.u.bind.num_contexts = 1;
704 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
705 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
706 pkt.u.bind.ctx_list[0].context_id = p->context_id;
707 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
708 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
709 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
710 pkt.u.bind.auth_info = data_blob(NULL, 0);
712 /* construct the NDR form of the packet */
713 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
714 p->conn->security_state.auth_info);
715 if (!composite_is_ok(c)) return c;
717 p->conn->transport.recv_data = dcerpc_recv_data;
720 * we allocate a dcerpc_request so we can be in the same
721 * request queue as normal requests
723 req = talloc_zero(c, struct rpc_request);
724 if (composite_nomem(req, c)) return c;
726 req->state = RPC_REQUEST_PENDING;
727 req->call_id = pkt.call_id;
728 req->async.private_data = c;
729 req->async.callback = dcerpc_composite_fail;
731 req->recv_handler = dcerpc_bind_recv_handler;
732 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
733 talloc_set_destructor(req, dcerpc_req_dequeue);
735 c->status = p->conn->transport.send_request(p->conn, &blob,
737 if (!composite_is_ok(c)) return c;
739 event_add_timed(c->event_ctx, req,
740 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
741 dcerpc_timeout_handler, req);
747 recv side of async dcerpc bind request
749 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
751 NTSTATUS result = composite_wait(ctx);
757 perform a continued bind (and auth3)
759 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
762 struct ncacn_packet pkt;
766 init_ncacn_hdr(p->conn, &pkt);
768 pkt.ptype = DCERPC_PKT_AUTH3;
769 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
770 pkt.call_id = next_call_id(p->conn);
772 pkt.u.auth3.auth_info = data_blob(NULL, 0);
774 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
775 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
778 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
779 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
782 /* construct the NDR form of the packet */
783 status = ncacn_push_auth(&blob, mem_ctx,
784 p->conn->iconv_convenience,
786 p->conn->security_state.auth_info);
787 if (!NT_STATUS_IS_OK(status)) {
791 /* send it on its way */
792 status = p->conn->transport.send_request(p->conn, &blob, false);
793 if (!NT_STATUS_IS_OK(status)) {
802 process a fragment received from the transport layer during a
805 This function frees the data
807 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
808 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
810 struct rpc_request *req;
812 NTSTATUS status = NT_STATUS_OK;
815 if this is an authenticated connection then parse and check
816 the auth info. We have to do this before finding the
817 matching packet, as the request structure might have been
818 removed due to a timeout, but if it has been we still need
819 to run the auth routines so that we don't get the sign/seal
820 info out of step with the server
822 if (c->security_state.auth_info && c->security_state.generic_state &&
823 pkt->ptype == DCERPC_PKT_RESPONSE) {
824 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
827 /* find the matching request */
828 for (req=c->pending;req;req=req->next) {
829 if (pkt->call_id == req->call_id) break;
833 /* useful for testing certain vendors RPC servers */
834 if (req == NULL && c->pending && pkt->call_id == 0) {
835 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
841 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
842 data_blob_free(raw_packet);
846 talloc_steal(req, raw_packet->data);
848 if (req->recv_handler != NULL) {
849 dcerpc_req_dequeue(req);
850 req->state = RPC_REQUEST_DONE;
851 req->recv_handler(req, raw_packet, pkt);
855 if (pkt->ptype == DCERPC_PKT_FAULT) {
856 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
857 req->fault_code = pkt->u.fault.status;
858 req->status = NT_STATUS_NET_WRITE_FAULT;
862 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
863 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
865 req->fault_code = DCERPC_FAULT_OTHER;
866 req->status = NT_STATUS_NET_WRITE_FAULT;
870 /* now check the status from the auth routines, and if it failed then fail
871 this request accordingly */
872 if (!NT_STATUS_IS_OK(status)) {
873 req->status = status;
877 length = pkt->u.response.stub_and_verifier.length;
880 req->payload.data = talloc_realloc(req,
883 req->payload.length + length);
884 if (!req->payload.data) {
885 req->status = NT_STATUS_NO_MEMORY;
888 memcpy(req->payload.data+req->payload.length,
889 pkt->u.response.stub_and_verifier.data, length);
890 req->payload.length += length;
893 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
894 c->transport.send_read(c);
898 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
899 req->flags |= DCERPC_PULL_BIGENDIAN;
901 req->flags &= ~DCERPC_PULL_BIGENDIAN;
906 /* we've got the full payload */
907 req->state = RPC_REQUEST_DONE;
908 DLIST_REMOVE(c->pending, req);
910 if (c->request_queue != NULL) {
911 /* We have to look at shipping further requests before calling
912 * the async function, that one might close the pipe */
913 dcerpc_ship_next_request(c);
916 if (req->async.callback) {
917 req->async.callback(req);
922 perform the send side of a async dcerpc request
924 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
925 const struct GUID *object,
928 DATA_BLOB *stub_data)
930 struct rpc_request *req;
932 p->conn->transport.recv_data = dcerpc_recv_data;
934 req = talloc(p, struct rpc_request);
940 req->call_id = next_call_id(p->conn);
941 req->status = NT_STATUS_OK;
942 req->state = RPC_REQUEST_QUEUED;
943 req->payload = data_blob(NULL, 0);
946 req->async_call = async;
947 req->ignore_timeout = false;
948 req->async.callback = NULL;
949 req->async.private_data = NULL;
950 req->recv_handler = NULL;
952 if (object != NULL) {
953 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
954 if (req->object == NULL) {
963 req->request_data.length = stub_data->length;
964 req->request_data.data = talloc_reference(req, stub_data->data);
965 if (req->request_data.length && req->request_data.data == NULL) {
969 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
970 talloc_set_destructor(req, dcerpc_req_dequeue);
972 dcerpc_ship_next_request(p->conn);
974 if (p->request_timeout) {
975 event_add_timed(dcerpc_event_context(p), req,
976 timeval_current_ofs(p->request_timeout, 0),
977 dcerpc_timeout_handler, req);
984 Send a request using the transport
987 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
989 struct rpc_request *req;
990 struct dcerpc_pipe *p;
991 DATA_BLOB *stub_data;
992 struct ncacn_packet pkt;
994 uint32_t remaining, chunk_size;
995 bool first_packet = true;
998 req = c->request_queue;
1004 stub_data = &req->request_data;
1006 if (!req->async_call && (c->pending != NULL)) {
1010 DLIST_REMOVE(c->request_queue, req);
1011 DLIST_ADD(c->pending, req);
1012 req->state = RPC_REQUEST_PENDING;
1014 init_ncacn_hdr(p->conn, &pkt);
1016 remaining = stub_data->length;
1018 /* we can write a full max_recv_frag size, minus the dcerpc
1019 request header size */
1020 chunk_size = p->conn->srv_max_recv_frag;
1021 chunk_size -= DCERPC_REQUEST_LENGTH;
1022 if (c->security_state.auth_info &&
1023 c->security_state.generic_state) {
1024 sig_size = gensec_sig_size(c->security_state.generic_state,
1025 p->conn->srv_max_recv_frag);
1027 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1028 chunk_size -= sig_size;
1031 chunk_size -= (chunk_size % 16);
1033 pkt.ptype = DCERPC_PKT_REQUEST;
1034 pkt.call_id = req->call_id;
1035 pkt.auth_length = 0;
1037 pkt.u.request.alloc_hint = remaining;
1038 pkt.u.request.context_id = p->context_id;
1039 pkt.u.request.opnum = req->opnum;
1042 pkt.u.request.object.object = *req->object;
1043 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1044 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1047 /* we send a series of pdus without waiting for a reply */
1048 while (remaining > 0 || first_packet) {
1049 uint32_t chunk = MIN(chunk_size, remaining);
1050 bool last_frag = false;
1051 bool do_trans = false;
1053 first_packet = false;
1054 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1056 if (remaining == stub_data->length) {
1057 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1059 if (chunk == remaining) {
1060 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1064 pkt.u.request.stub_and_verifier.data = stub_data->data +
1065 (stub_data->length - remaining);
1066 pkt.u.request.stub_and_verifier.length = chunk;
1068 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1069 if (!NT_STATUS_IS_OK(req->status)) {
1070 req->state = RPC_REQUEST_DONE;
1071 DLIST_REMOVE(p->conn->pending, req);
1075 if (last_frag && !req->async_call) {
1079 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1080 if (!NT_STATUS_IS_OK(req->status)) {
1081 req->state = RPC_REQUEST_DONE;
1082 DLIST_REMOVE(p->conn->pending, req);
1086 if (last_frag && !do_trans) {
1087 req->status = p->conn->transport.send_read(p->conn);
1088 if (!NT_STATUS_IS_OK(req->status)) {
1089 req->state = RPC_REQUEST_DONE;
1090 DLIST_REMOVE(p->conn->pending, req);
1100 return the event context for a dcerpc pipe
1101 used by callers who wish to operate asynchronously
1103 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1105 return p->conn->event_ctx;
1111 perform the receive side of a async dcerpc request
1113 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1114 TALLOC_CTX *mem_ctx,
1115 DATA_BLOB *stub_data)
1119 while (req->state != RPC_REQUEST_DONE) {
1120 struct tevent_context *ctx = dcerpc_event_context(req->p);
1121 if (event_loop_once(ctx) != 0) {
1122 return NT_STATUS_CONNECTION_DISCONNECTED;
1125 *stub_data = req->payload;
1126 status = req->status;
1127 if (stub_data->data) {
1128 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1130 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1131 req->p->last_fault_code = req->fault_code;
1133 talloc_unlink(talloc_parent(req), req);
1138 perform a full request/response pair on a dcerpc pipe
1140 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1141 struct GUID *object,
1143 TALLOC_CTX *mem_ctx,
1144 DATA_BLOB *stub_data_in,
1145 DATA_BLOB *stub_data_out)
1147 struct rpc_request *req;
1149 req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1151 return NT_STATUS_NO_MEMORY;
1154 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1159 this is a paranoid NDR validator. For every packet we push onto the wire
1160 we pull it back again, then push it again. Then we compare the raw NDR data
1161 for that to the NDR we initially generated. If they don't match then we know
1162 we must have a bug in either the pull or push side of our code
1164 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1165 TALLOC_CTX *mem_ctx,
1168 ndr_push_flags_fn_t ndr_push,
1169 ndr_pull_flags_fn_t ndr_pull)
1172 struct ndr_pull *pull;
1173 struct ndr_push *push;
1175 enum ndr_err_code ndr_err;
1177 st = talloc_size(mem_ctx, struct_size);
1179 return NT_STATUS_NO_MEMORY;
1182 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1184 return NT_STATUS_NO_MEMORY;
1186 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1188 ndr_err = ndr_pull(pull, NDR_IN, st);
1189 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1190 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1191 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1192 "failed input validation pull - %s",
1194 return ndr_map_error2ntstatus(ndr_err);
1197 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1199 return NT_STATUS_NO_MEMORY;
1202 ndr_err = ndr_push(push, NDR_IN, st);
1203 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1204 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1205 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1206 "failed input validation push - %s",
1208 return ndr_map_error2ntstatus(ndr_err);
1211 blob2 = ndr_push_blob(push);
1213 if (data_blob_cmp(&blob, &blob2) != 0) {
1214 DEBUG(3,("original:\n"));
1215 dump_data(3, blob.data, blob.length);
1216 DEBUG(3,("secondary:\n"));
1217 dump_data(3, blob2.data, blob2.length);
1218 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1219 "failed input validation blobs doesn't match");
1220 return ndr_map_error2ntstatus(ndr_err);
1223 return NT_STATUS_OK;
1227 this is a paranoid NDR input validator. For every packet we pull
1228 from the wire we push it back again then pull and push it
1229 again. Then we compare the raw NDR data for that to the NDR we
1230 initially generated. If they don't match then we know we must have a
1231 bug in either the pull or push side of our code
1233 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1234 struct ndr_pull *pull_in,
1237 ndr_push_flags_fn_t ndr_push,
1238 ndr_pull_flags_fn_t ndr_pull,
1239 ndr_print_function_t ndr_print)
1242 struct ndr_pull *pull;
1243 struct ndr_push *push;
1244 DATA_BLOB blob, blob2;
1245 TALLOC_CTX *mem_ctx = pull_in;
1247 enum ndr_err_code ndr_err;
1249 st = talloc_size(mem_ctx, struct_size);
1251 return NT_STATUS_NO_MEMORY;
1253 memcpy(st, struct_ptr, struct_size);
1255 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1257 return NT_STATUS_NO_MEMORY;
1260 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1261 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1262 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1263 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1264 "failed output validation push - %s",
1266 return ndr_map_error2ntstatus(ndr_err);
1269 blob = ndr_push_blob(push);
1271 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1273 return NT_STATUS_NO_MEMORY;
1276 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1277 ndr_err = ndr_pull(pull, NDR_OUT, st);
1278 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1279 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1280 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1281 "failed output validation pull - %s",
1283 return ndr_map_error2ntstatus(ndr_err);
1286 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1288 return NT_STATUS_NO_MEMORY;
1291 ndr_err = ndr_push(push, NDR_OUT, st);
1292 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1293 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1294 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1295 "failed output validation push2 - %s",
1297 return ndr_map_error2ntstatus(ndr_err);
1300 blob2 = ndr_push_blob(push);
1302 if (data_blob_cmp(&blob, &blob2) != 0) {
1303 DEBUG(3,("original:\n"));
1304 dump_data(3, blob.data, blob.length);
1305 DEBUG(3,("secondary:\n"));
1306 dump_data(3, blob2.data, blob2.length);
1307 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1308 "failed output validation blobs doesn't match");
1309 return ndr_map_error2ntstatus(ndr_err);
1312 /* this checks the printed forms of the two structures, which effectively
1313 tests all of the value() attributes */
1314 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1315 NDR_OUT, struct_ptr);
1316 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1318 if (strcmp(s1, s2) != 0) {
1320 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1322 /* this is sometimes useful */
1323 printf("VALIDATE ERROR\n");
1324 file_save("wire.dat", s1, strlen(s1));
1325 file_save("gen.dat", s2, strlen(s2));
1326 system("diff -u wire.dat gen.dat");
1328 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1329 "failed output validation strings doesn't match");
1330 return ndr_map_error2ntstatus(ndr_err);
1333 return NT_STATUS_OK;
1338 send a rpc request given a dcerpc_call structure
1340 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1341 const struct GUID *object,
1342 const struct ndr_interface_table *table,
1345 TALLOC_CTX *mem_ctx,
1348 const struct ndr_interface_call *call;
1349 struct ndr_push *push;
1352 struct rpc_request *req;
1353 enum ndr_err_code ndr_err;
1355 call = &table->calls[opnum];
1357 /* setup for a ndr_push_* call */
1358 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1363 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1364 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1367 if (p->conn->flags & DCERPC_NDR64) {
1368 push->flags |= LIBNDR_FLAG_NDR64;
1371 /* push the structure into a blob */
1372 ndr_err = call->ndr_push(push, NDR_IN, r);
1373 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1374 status = ndr_map_error2ntstatus(ndr_err);
1375 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1376 nt_errstr(status)));
1381 /* retrieve the blob */
1382 request = ndr_push_blob(push);
1384 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1385 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1386 call->ndr_push, call->ndr_pull);
1387 if (!NT_STATUS_IS_OK(status)) {
1388 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1389 nt_errstr(status)));
1395 DEBUG(10,("rpc request data:\n"));
1396 dump_data(10, request.data, request.length);
1398 /* make the actual dcerpc request */
1399 req = dcerpc_request_send(p, object, opnum, async, &request);
1402 req->ndr.table = table;
1403 req->ndr.opnum = opnum;
1404 req->ndr.struct_ptr = r;
1405 req->ndr.mem_ctx = mem_ctx;
1414 receive the answer from a dcerpc_ndr_request_send()
1416 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1418 struct dcerpc_pipe *p = req->p;
1421 struct ndr_pull *pull;
1423 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1424 void *r = req->ndr.struct_ptr;
1425 uint32_t opnum = req->ndr.opnum;
1426 const struct ndr_interface_table *table = req->ndr.table;
1427 const struct ndr_interface_call *call = &table->calls[opnum];
1428 enum ndr_err_code ndr_err;
1430 /* make sure the recv code doesn't free the request, as we
1431 need to grab the flags element before it is freed */
1432 if (talloc_reference(p, req) == NULL) {
1433 return NT_STATUS_NO_MEMORY;
1436 status = dcerpc_request_recv(req, mem_ctx, &response);
1437 if (!NT_STATUS_IS_OK(status)) {
1438 talloc_unlink(p, req);
1444 /* prepare for ndr_pull_* */
1445 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1447 talloc_unlink(p, req);
1448 return NT_STATUS_NO_MEMORY;
1452 pull->data = talloc_steal(pull, pull->data);
1454 talloc_unlink(p, req);
1456 if (flags & DCERPC_PULL_BIGENDIAN) {
1457 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1460 DEBUG(10,("rpc reply data:\n"));
1461 dump_data(10, pull->data, pull->data_size);
1463 /* pull the structure from the blob */
1464 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1465 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1466 status = ndr_map_error2ntstatus(ndr_err);
1467 dcerpc_log_packet(p->conn->packet_log_dir,
1468 table, opnum, NDR_OUT,
1473 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1474 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1475 call->ndr_push, call->ndr_pull,
1477 if (!NT_STATUS_IS_OK(status)) {
1478 dcerpc_log_packet(p->conn->packet_log_dir,
1479 table, opnum, NDR_OUT,
1485 if (pull->offset != pull->data_size) {
1486 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1487 pull->data_size - pull->offset));
1488 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1489 but it turns out that early versions of NT
1490 (specifically NT3.1) add junk onto the end of rpc
1491 packets, so if we want to interoperate at all with
1492 those versions then we need to ignore this error */
1495 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1497 return NT_STATUS_OK;
1502 a useful helper function for synchronous rpc requests
1504 this can be used when you have ndr push/pull functions in the
1507 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1508 const struct GUID *object,
1509 const struct ndr_interface_table *table,
1511 TALLOC_CTX *mem_ctx,
1514 struct rpc_request *req;
1516 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1518 return NT_STATUS_NO_MEMORY;
1521 return dcerpc_ndr_request_recv(req);
1526 a useful function for retrieving the server name we connected to
1528 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1530 if (!p->conn->transport.target_hostname) {
1531 if (!p->conn->transport.peer_name) {
1534 return p->conn->transport.peer_name(p->conn);
1536 return p->conn->transport.target_hostname(p->conn);
1541 get the dcerpc auth_level for a open connection
1543 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1547 if (c->flags & DCERPC_SEAL) {
1548 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1549 } else if (c->flags & DCERPC_SIGN) {
1550 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1551 } else if (c->flags & DCERPC_CONNECT) {
1552 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1554 auth_level = DCERPC_AUTH_LEVEL_NONE;
1560 Receive an alter reply from the transport
1562 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1563 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1565 struct composite_context *c;
1566 struct dcerpc_pipe *recv_pipe;
1568 c = talloc_get_type(req->async.private_data, struct composite_context);
1569 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1571 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1572 pkt->u.alter_resp.num_results == 1 &&
1573 pkt->u.alter_resp.ctx_list[0].result != 0) {
1574 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1575 pkt->u.alter_resp.ctx_list[0].reason));
1576 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1580 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1581 pkt->u.alter_resp.num_results == 0 ||
1582 pkt->u.alter_resp.ctx_list[0].result != 0) {
1583 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1587 /* the alter_resp might contain a reply set of credentials */
1588 if (recv_pipe->conn->security_state.auth_info &&
1589 pkt->u.alter_resp.auth_info.length) {
1590 struct dcerpc_connection *conn = recv_pipe->conn;
1592 uint32_t auth_length;
1593 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1594 conn->security_state.auth_info, &auth_length, true);
1595 if (!NT_STATUS_IS_OK(status)) {
1596 composite_error(c, status);
1605 send a dcerpc alter_context request
1607 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1608 TALLOC_CTX *mem_ctx,
1609 const struct ndr_syntax_id *syntax,
1610 const struct ndr_syntax_id *transfer_syntax)
1612 struct composite_context *c;
1613 struct ncacn_packet pkt;
1615 struct rpc_request *req;
1617 c = composite_create(mem_ctx, p->conn->event_ctx);
1618 if (c == NULL) return NULL;
1620 c->private_data = p;
1622 p->syntax = *syntax;
1623 p->transfer_syntax = *transfer_syntax;
1625 init_ncacn_hdr(p->conn, &pkt);
1627 pkt.ptype = DCERPC_PKT_ALTER;
1628 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1629 pkt.call_id = p->conn->call_id;
1630 pkt.auth_length = 0;
1632 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1633 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1636 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1637 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1640 pkt.u.alter.max_xmit_frag = 5840;
1641 pkt.u.alter.max_recv_frag = 5840;
1642 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1643 pkt.u.alter.num_contexts = 1;
1644 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1645 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1646 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1647 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1648 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1649 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1650 pkt.u.alter.auth_info = data_blob(NULL, 0);
1652 /* construct the NDR form of the packet */
1653 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1654 p->conn->security_state.auth_info);
1655 if (!composite_is_ok(c)) return c;
1657 p->conn->transport.recv_data = dcerpc_recv_data;
1660 * we allocate a dcerpc_request so we can be in the same
1661 * request queue as normal requests
1663 req = talloc_zero(c, struct rpc_request);
1664 if (composite_nomem(req, c)) return c;
1666 req->state = RPC_REQUEST_PENDING;
1667 req->call_id = pkt.call_id;
1668 req->async.private_data = c;
1669 req->async.callback = dcerpc_composite_fail;
1671 req->recv_handler = dcerpc_alter_recv_handler;
1672 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1673 talloc_set_destructor(req, dcerpc_req_dequeue);
1675 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1676 if (!composite_is_ok(c)) return c;
1678 event_add_timed(c->event_ctx, req,
1679 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1680 dcerpc_timeout_handler, req);
1685 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1687 NTSTATUS result = composite_wait(ctx);
1693 send a dcerpc alter_context request
1695 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1696 TALLOC_CTX *mem_ctx,
1697 const struct ndr_syntax_id *syntax,
1698 const struct ndr_syntax_id *transfer_syntax)
1700 struct composite_context *creq;
1701 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1702 return dcerpc_alter_context_recv(creq);