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;
323 /* non-signed packets are simpler */
325 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
328 switch (c->security_state.auth_info->auth_level) {
329 case DCERPC_AUTH_LEVEL_PRIVACY:
330 case DCERPC_AUTH_LEVEL_INTEGRITY:
333 case DCERPC_AUTH_LEVEL_CONNECT:
334 /* TODO: let the gensec mech decide if it wants to generate a signature */
335 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
337 case DCERPC_AUTH_LEVEL_NONE:
338 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
341 return NT_STATUS_INVALID_LEVEL;
344 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
346 return NT_STATUS_NO_MEMORY;
349 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
350 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
353 if (c->flags & DCERPC_NDR64) {
354 ndr->flags |= LIBNDR_FLAG_NDR64;
357 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
358 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
362 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
363 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
364 return ndr_map_error2ntstatus(ndr_err);
367 /* pad to 16 byte multiple in the payload portion of the
368 packet. This matches what w2k3 does */
369 offset = ndr->offset;
370 ndr_err = ndr_push_align(ndr, 16);
371 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
372 return ndr_map_error2ntstatus(ndr_err);
374 c->security_state.auth_info->auth_pad_length = ndr->offset - offset;
376 payload_length = pkt->u.request.stub_and_verifier.length +
377 c->security_state.auth_info->auth_pad_length;
379 /* we start without signature, it will appended later */
380 c->security_state.auth_info->credentials = data_blob(NULL,0);
382 /* add the auth verifier */
383 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
384 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
385 return ndr_map_error2ntstatus(ndr_err);
388 /* extract the whole packet as a blob */
389 *blob = ndr_push_blob(ndr);
392 * Setup the frag and auth length in the packet buffer.
393 * This is needed if the GENSEC mech does AEAD signing
394 * of the packet headers. The signature itself will be
397 dcerpc_set_frag_length(blob, blob->length + sig_size);
398 dcerpc_set_auth_length(blob, sig_size);
400 /* sign or seal the packet */
401 switch (c->security_state.auth_info->auth_level) {
402 case DCERPC_AUTH_LEVEL_PRIVACY:
403 status = gensec_seal_packet(c->security_state.generic_state,
405 blob->data + hdr_size,
410 if (!NT_STATUS_IS_OK(status)) {
415 case DCERPC_AUTH_LEVEL_INTEGRITY:
416 status = gensec_sign_packet(c->security_state.generic_state,
418 blob->data + hdr_size,
423 if (!NT_STATUS_IS_OK(status)) {
429 status = NT_STATUS_INVALID_LEVEL;
433 if (creds2.length != sig_size) {
434 /* this means the sig_size estimate for the signature
435 was incorrect. We have to correct the packet
436 sizes. That means we could go over the max fragment
438 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
439 (unsigned) creds2.length,
441 (unsigned) c->security_state.auth_info->auth_pad_length,
442 (unsigned) pkt->u.request.stub_and_verifier.length));
443 dcerpc_set_frag_length(blob, blob->length + creds2.length);
444 dcerpc_set_auth_length(blob, creds2.length);
447 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
448 return NT_STATUS_NO_MEMORY;
456 fill in the fixed values in a dcerpc header
458 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
461 pkt->rpc_vers_minor = 0;
462 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
465 pkt->drep[0] = DCERPC_DREP_LE;
473 map a bind nak reason to a NTSTATUS
475 static NTSTATUS dcerpc_map_reason(uint16_t reason)
478 case DCERPC_BIND_REASON_ASYNTAX:
479 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
480 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
481 return NT_STATUS_INVALID_PARAMETER;
483 return NT_STATUS_UNSUCCESSFUL;
487 a bind or alter context has failed
489 static void dcerpc_composite_fail(struct rpc_request *req)
491 struct composite_context *c = talloc_get_type(req->async.private_data,
492 struct composite_context);
493 composite_error(c, req->status);
497 remove requests from the pending or queued queues
499 static int dcerpc_req_dequeue(struct rpc_request *req)
501 switch (req->state) {
502 case RPC_REQUEST_QUEUED:
503 DLIST_REMOVE(req->p->conn->request_queue, req);
505 case RPC_REQUEST_PENDING:
506 DLIST_REMOVE(req->p->conn->pending, req);
508 case RPC_REQUEST_DONE:
516 mark the dcerpc connection dead. All outstanding requests get an error
518 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
520 if (conn->dead) return;
524 if (conn->transport.shutdown_pipe) {
525 conn->transport.shutdown_pipe(conn, status);
528 /* all pending requests get the error */
529 while (conn->pending) {
530 struct rpc_request *req = conn->pending;
531 dcerpc_req_dequeue(req);
532 req->state = RPC_REQUEST_DONE;
533 req->status = status;
534 if (req->async.callback) {
535 req->async.callback(req);
539 talloc_set_destructor(conn, NULL);
540 if (conn->free_skipped) {
546 forward declarations of the recv_data handlers for the types of
547 packets we need to handle
549 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
550 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
553 receive a dcerpc reply from the transport. Here we work out what
554 type of reply it is (normal request, bind or alter context) and
555 dispatch to the appropriate handler
557 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
559 struct ncacn_packet pkt;
561 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
562 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
565 /* the transport may be telling us of a severe error, such as
567 if (!NT_STATUS_IS_OK(status)) {
568 data_blob_free(blob);
569 dcerpc_connection_dead(conn, status);
573 /* parse the basic packet to work out what type of response this is */
574 status = ncacn_pull(conn, blob, blob->data, &pkt);
575 if (!NT_STATUS_IS_OK(status)) {
576 data_blob_free(blob);
577 dcerpc_connection_dead(conn, status);
580 dcerpc_request_recv_data(conn, blob, &pkt);
584 Receive a bind reply from the transport
586 static void dcerpc_bind_recv_handler(struct rpc_request *req,
587 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
589 struct composite_context *c;
590 struct dcerpc_connection *conn;
592 c = talloc_get_type(req->async.private_data, struct composite_context);
594 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
595 DEBUG(2,("dcerpc: bind_nak reason %d\n",
596 pkt->u.bind_nak.reject_reason));
597 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
602 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
603 (pkt->u.bind_ack.num_results == 0) ||
604 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
605 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
611 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
612 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
614 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
615 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
616 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
619 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
620 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
621 conn->flags |= DCERPC_HEADER_SIGNING;
624 /* the bind_ack might contain a reply set of credentials */
625 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
627 uint32_t auth_length;
628 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
629 conn->security_state.auth_info, &auth_length, true);
630 if (!NT_STATUS_IS_OK(status)) {
631 composite_error(c, status);
636 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
642 handle timeouts of individual dcerpc requests
644 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
645 struct timeval t, void *private_data)
647 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
649 if (req->ignore_timeout) {
650 dcerpc_req_dequeue(req);
651 req->state = RPC_REQUEST_DONE;
652 req->status = NT_STATUS_IO_TIMEOUT;
653 if (req->async.callback) {
654 req->async.callback(req);
659 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
663 send a async dcerpc bind request
665 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
667 const struct ndr_syntax_id *syntax,
668 const struct ndr_syntax_id *transfer_syntax)
670 struct composite_context *c;
671 struct ncacn_packet pkt;
673 struct rpc_request *req;
675 c = composite_create(mem_ctx,p->conn->event_ctx);
676 if (c == NULL) return NULL;
681 p->transfer_syntax = *transfer_syntax;
683 init_ncacn_hdr(p->conn, &pkt);
685 pkt.ptype = DCERPC_PKT_BIND;
686 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
687 pkt.call_id = p->conn->call_id;
690 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
691 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
694 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
695 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
698 pkt.u.bind.max_xmit_frag = 5840;
699 pkt.u.bind.max_recv_frag = 5840;
700 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
701 pkt.u.bind.num_contexts = 1;
702 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
703 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
704 pkt.u.bind.ctx_list[0].context_id = p->context_id;
705 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
706 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
707 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
708 pkt.u.bind.auth_info = data_blob(NULL, 0);
710 /* construct the NDR form of the packet */
711 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
712 p->conn->security_state.auth_info);
713 if (!composite_is_ok(c)) return c;
715 p->conn->transport.recv_data = dcerpc_recv_data;
718 * we allocate a dcerpc_request so we can be in the same
719 * request queue as normal requests
721 req = talloc_zero(c, struct rpc_request);
722 if (composite_nomem(req, c)) return c;
724 req->state = RPC_REQUEST_PENDING;
725 req->call_id = pkt.call_id;
726 req->async.private_data = c;
727 req->async.callback = dcerpc_composite_fail;
729 req->recv_handler = dcerpc_bind_recv_handler;
730 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
731 talloc_set_destructor(req, dcerpc_req_dequeue);
733 c->status = p->conn->transport.send_request(p->conn, &blob,
735 if (!composite_is_ok(c)) return c;
737 event_add_timed(c->event_ctx, req,
738 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
739 dcerpc_timeout_handler, req);
745 recv side of async dcerpc bind request
747 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
749 NTSTATUS result = composite_wait(ctx);
755 perform a continued bind (and auth3)
757 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
760 struct ncacn_packet pkt;
764 init_ncacn_hdr(p->conn, &pkt);
766 pkt.ptype = DCERPC_PKT_AUTH3;
767 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
768 pkt.call_id = next_call_id(p->conn);
770 pkt.u.auth3.auth_info = data_blob(NULL, 0);
772 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
773 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
776 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
777 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
780 /* construct the NDR form of the packet */
781 status = ncacn_push_auth(&blob, mem_ctx,
782 p->conn->iconv_convenience,
784 p->conn->security_state.auth_info);
785 if (!NT_STATUS_IS_OK(status)) {
789 /* send it on its way */
790 status = p->conn->transport.send_request(p->conn, &blob, false);
791 if (!NT_STATUS_IS_OK(status)) {
800 process a fragment received from the transport layer during a
803 This function frees the data
805 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
806 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
808 struct rpc_request *req;
810 NTSTATUS status = NT_STATUS_OK;
813 if this is an authenticated connection then parse and check
814 the auth info. We have to do this before finding the
815 matching packet, as the request structure might have been
816 removed due to a timeout, but if it has been we still need
817 to run the auth routines so that we don't get the sign/seal
818 info out of step with the server
820 if (c->security_state.auth_info && c->security_state.generic_state &&
821 pkt->ptype == DCERPC_PKT_RESPONSE) {
822 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
825 /* find the matching request */
826 for (req=c->pending;req;req=req->next) {
827 if (pkt->call_id == req->call_id) break;
831 /* useful for testing certain vendors RPC servers */
832 if (req == NULL && c->pending && pkt->call_id == 0) {
833 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
839 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
840 data_blob_free(raw_packet);
844 talloc_steal(req, raw_packet->data);
846 if (req->recv_handler != NULL) {
847 dcerpc_req_dequeue(req);
848 req->state = RPC_REQUEST_DONE;
849 req->recv_handler(req, raw_packet, pkt);
853 if (pkt->ptype == DCERPC_PKT_FAULT) {
854 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
855 req->fault_code = pkt->u.fault.status;
856 req->status = NT_STATUS_NET_WRITE_FAULT;
860 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
861 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
863 req->fault_code = DCERPC_FAULT_OTHER;
864 req->status = NT_STATUS_NET_WRITE_FAULT;
868 /* now check the status from the auth routines, and if it failed then fail
869 this request accordingly */
870 if (!NT_STATUS_IS_OK(status)) {
871 req->status = status;
875 length = pkt->u.response.stub_and_verifier.length;
878 req->payload.data = talloc_realloc(req,
881 req->payload.length + length);
882 if (!req->payload.data) {
883 req->status = NT_STATUS_NO_MEMORY;
886 memcpy(req->payload.data+req->payload.length,
887 pkt->u.response.stub_and_verifier.data, length);
888 req->payload.length += length;
891 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
892 c->transport.send_read(c);
896 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
897 req->flags |= DCERPC_PULL_BIGENDIAN;
899 req->flags &= ~DCERPC_PULL_BIGENDIAN;
904 /* we've got the full payload */
905 req->state = RPC_REQUEST_DONE;
906 DLIST_REMOVE(c->pending, req);
908 if (c->request_queue != NULL) {
909 /* We have to look at shipping further requests before calling
910 * the async function, that one might close the pipe */
911 dcerpc_ship_next_request(c);
914 if (req->async.callback) {
915 req->async.callback(req);
920 perform the send side of a async dcerpc request
922 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
923 const struct GUID *object,
926 DATA_BLOB *stub_data)
928 struct rpc_request *req;
930 p->conn->transport.recv_data = dcerpc_recv_data;
932 req = talloc(p, struct rpc_request);
938 req->call_id = next_call_id(p->conn);
939 req->status = NT_STATUS_OK;
940 req->state = RPC_REQUEST_QUEUED;
941 req->payload = data_blob(NULL, 0);
944 req->async_call = async;
945 req->ignore_timeout = false;
946 req->async.callback = NULL;
947 req->async.private_data = NULL;
948 req->recv_handler = NULL;
950 if (object != NULL) {
951 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
952 if (req->object == NULL) {
961 req->request_data.length = stub_data->length;
962 req->request_data.data = talloc_reference(req, stub_data->data);
963 if (req->request_data.length && req->request_data.data == NULL) {
967 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
968 talloc_set_destructor(req, dcerpc_req_dequeue);
970 dcerpc_ship_next_request(p->conn);
972 if (p->request_timeout) {
973 event_add_timed(dcerpc_event_context(p), req,
974 timeval_current_ofs(p->request_timeout, 0),
975 dcerpc_timeout_handler, req);
982 Send a request using the transport
985 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
987 struct rpc_request *req;
988 struct dcerpc_pipe *p;
989 DATA_BLOB *stub_data;
990 struct ncacn_packet pkt;
992 uint32_t remaining, chunk_size;
993 bool first_packet = true;
996 req = c->request_queue;
1002 stub_data = &req->request_data;
1004 if (!req->async_call && (c->pending != NULL)) {
1008 DLIST_REMOVE(c->request_queue, req);
1009 DLIST_ADD(c->pending, req);
1010 req->state = RPC_REQUEST_PENDING;
1012 init_ncacn_hdr(p->conn, &pkt);
1014 remaining = stub_data->length;
1016 /* we can write a full max_recv_frag size, minus the dcerpc
1017 request header size */
1018 chunk_size = p->conn->srv_max_recv_frag;
1019 chunk_size -= DCERPC_REQUEST_LENGTH;
1020 if (c->security_state.auth_info &&
1021 c->security_state.generic_state) {
1022 sig_size = gensec_sig_size(c->security_state.generic_state,
1023 p->conn->srv_max_recv_frag);
1025 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1026 chunk_size -= sig_size;
1029 chunk_size -= (chunk_size % 16);
1031 pkt.ptype = DCERPC_PKT_REQUEST;
1032 pkt.call_id = req->call_id;
1033 pkt.auth_length = 0;
1035 pkt.u.request.alloc_hint = remaining;
1036 pkt.u.request.context_id = p->context_id;
1037 pkt.u.request.opnum = req->opnum;
1040 pkt.u.request.object.object = *req->object;
1041 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1042 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1045 /* we send a series of pdus without waiting for a reply */
1046 while (remaining > 0 || first_packet) {
1047 uint32_t chunk = MIN(chunk_size, remaining);
1048 bool last_frag = false;
1049 bool do_trans = false;
1051 first_packet = false;
1052 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1054 if (remaining == stub_data->length) {
1055 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1057 if (chunk == remaining) {
1058 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1062 pkt.u.request.stub_and_verifier.data = stub_data->data +
1063 (stub_data->length - remaining);
1064 pkt.u.request.stub_and_verifier.length = chunk;
1066 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1067 if (!NT_STATUS_IS_OK(req->status)) {
1068 req->state = RPC_REQUEST_DONE;
1069 DLIST_REMOVE(p->conn->pending, req);
1073 if (last_frag && !req->async_call) {
1077 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1078 if (!NT_STATUS_IS_OK(req->status)) {
1079 req->state = RPC_REQUEST_DONE;
1080 DLIST_REMOVE(p->conn->pending, req);
1084 if (last_frag && !do_trans) {
1085 req->status = p->conn->transport.send_read(p->conn);
1086 if (!NT_STATUS_IS_OK(req->status)) {
1087 req->state = RPC_REQUEST_DONE;
1088 DLIST_REMOVE(p->conn->pending, req);
1098 return the event context for a dcerpc pipe
1099 used by callers who wish to operate asynchronously
1101 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1103 return p->conn->event_ctx;
1109 perform the receive side of a async dcerpc request
1111 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1112 TALLOC_CTX *mem_ctx,
1113 DATA_BLOB *stub_data)
1117 while (req->state != RPC_REQUEST_DONE) {
1118 struct tevent_context *ctx = dcerpc_event_context(req->p);
1119 if (event_loop_once(ctx) != 0) {
1120 return NT_STATUS_CONNECTION_DISCONNECTED;
1123 *stub_data = req->payload;
1124 status = req->status;
1125 if (stub_data->data) {
1126 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1128 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1129 req->p->last_fault_code = req->fault_code;
1131 talloc_unlink(talloc_parent(req), req);
1136 perform a full request/response pair on a dcerpc pipe
1138 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1139 struct GUID *object,
1141 TALLOC_CTX *mem_ctx,
1142 DATA_BLOB *stub_data_in,
1143 DATA_BLOB *stub_data_out)
1145 struct rpc_request *req;
1147 req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1149 return NT_STATUS_NO_MEMORY;
1152 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1157 this is a paranoid NDR validator. For every packet we push onto the wire
1158 we pull it back again, then push it again. Then we compare the raw NDR data
1159 for that to the NDR we initially generated. If they don't match then we know
1160 we must have a bug in either the pull or push side of our code
1162 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1163 TALLOC_CTX *mem_ctx,
1166 ndr_push_flags_fn_t ndr_push,
1167 ndr_pull_flags_fn_t ndr_pull)
1170 struct ndr_pull *pull;
1171 struct ndr_push *push;
1173 enum ndr_err_code ndr_err;
1175 st = talloc_size(mem_ctx, struct_size);
1177 return NT_STATUS_NO_MEMORY;
1180 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1182 return NT_STATUS_NO_MEMORY;
1184 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1186 ndr_err = ndr_pull(pull, NDR_IN, st);
1187 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1188 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1189 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1190 "failed input validation pull - %s",
1192 return ndr_map_error2ntstatus(ndr_err);
1195 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1197 return NT_STATUS_NO_MEMORY;
1200 ndr_err = ndr_push(push, NDR_IN, st);
1201 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1202 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1203 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1204 "failed input validation push - %s",
1206 return ndr_map_error2ntstatus(ndr_err);
1209 blob2 = ndr_push_blob(push);
1211 if (data_blob_cmp(&blob, &blob2) != 0) {
1212 DEBUG(3,("original:\n"));
1213 dump_data(3, blob.data, blob.length);
1214 DEBUG(3,("secondary:\n"));
1215 dump_data(3, blob2.data, blob2.length);
1216 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1217 "failed input validation blobs doesn't match");
1218 return ndr_map_error2ntstatus(ndr_err);
1221 return NT_STATUS_OK;
1225 this is a paranoid NDR input validator. For every packet we pull
1226 from the wire we push it back again then pull and push it
1227 again. Then we compare the raw NDR data for that to the NDR we
1228 initially generated. If they don't match then we know we must have a
1229 bug in either the pull or push side of our code
1231 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1232 struct ndr_pull *pull_in,
1235 ndr_push_flags_fn_t ndr_push,
1236 ndr_pull_flags_fn_t ndr_pull,
1237 ndr_print_function_t ndr_print)
1240 struct ndr_pull *pull;
1241 struct ndr_push *push;
1242 DATA_BLOB blob, blob2;
1243 TALLOC_CTX *mem_ctx = pull_in;
1245 enum ndr_err_code ndr_err;
1247 st = talloc_size(mem_ctx, struct_size);
1249 return NT_STATUS_NO_MEMORY;
1251 memcpy(st, struct_ptr, struct_size);
1253 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1255 return NT_STATUS_NO_MEMORY;
1258 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1259 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1260 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1261 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1262 "failed output validation push - %s",
1264 return ndr_map_error2ntstatus(ndr_err);
1267 blob = ndr_push_blob(push);
1269 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1271 return NT_STATUS_NO_MEMORY;
1274 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1275 ndr_err = ndr_pull(pull, NDR_OUT, st);
1276 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1277 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1278 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1279 "failed output validation pull - %s",
1281 return ndr_map_error2ntstatus(ndr_err);
1284 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1286 return NT_STATUS_NO_MEMORY;
1289 ndr_err = ndr_push(push, NDR_OUT, st);
1290 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1291 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1292 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1293 "failed output validation push2 - %s",
1295 return ndr_map_error2ntstatus(ndr_err);
1298 blob2 = ndr_push_blob(push);
1300 if (data_blob_cmp(&blob, &blob2) != 0) {
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 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1306 "failed output validation blobs doesn't match");
1307 return ndr_map_error2ntstatus(ndr_err);
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) {
1318 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1320 /* this is sometimes useful */
1321 printf("VALIDATE ERROR\n");
1322 file_save("wire.dat", s1, strlen(s1));
1323 file_save("gen.dat", s2, strlen(s2));
1324 system("diff -u wire.dat gen.dat");
1326 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1327 "failed output validation strings doesn't match");
1328 return ndr_map_error2ntstatus(ndr_err);
1331 return NT_STATUS_OK;
1336 send a rpc request given a dcerpc_call structure
1338 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1339 const struct GUID *object,
1340 const struct ndr_interface_table *table,
1343 TALLOC_CTX *mem_ctx,
1346 const struct ndr_interface_call *call;
1347 struct ndr_push *push;
1350 struct rpc_request *req;
1351 enum ndr_err_code ndr_err;
1353 call = &table->calls[opnum];
1355 /* setup for a ndr_push_* call */
1356 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1361 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1362 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1365 if (p->conn->flags & DCERPC_NDR64) {
1366 push->flags |= LIBNDR_FLAG_NDR64;
1369 /* push the structure into a blob */
1370 ndr_err = call->ndr_push(push, NDR_IN, r);
1371 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1372 status = ndr_map_error2ntstatus(ndr_err);
1373 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1374 nt_errstr(status)));
1379 /* retrieve the blob */
1380 request = ndr_push_blob(push);
1382 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1383 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1384 call->ndr_push, call->ndr_pull);
1385 if (!NT_STATUS_IS_OK(status)) {
1386 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1387 nt_errstr(status)));
1393 DEBUG(10,("rpc request data:\n"));
1394 dump_data(10, request.data, request.length);
1396 /* make the actual dcerpc request */
1397 req = dcerpc_request_send(p, object, opnum, async, &request);
1400 req->ndr.table = table;
1401 req->ndr.opnum = opnum;
1402 req->ndr.struct_ptr = r;
1403 req->ndr.mem_ctx = mem_ctx;
1412 receive the answer from a dcerpc_ndr_request_send()
1414 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1416 struct dcerpc_pipe *p = req->p;
1419 struct ndr_pull *pull;
1421 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1422 void *r = req->ndr.struct_ptr;
1423 uint32_t opnum = req->ndr.opnum;
1424 const struct ndr_interface_table *table = req->ndr.table;
1425 const struct ndr_interface_call *call = &table->calls[opnum];
1426 enum ndr_err_code ndr_err;
1428 /* make sure the recv code doesn't free the request, as we
1429 need to grab the flags element before it is freed */
1430 if (talloc_reference(p, req) == NULL) {
1431 return NT_STATUS_NO_MEMORY;
1434 status = dcerpc_request_recv(req, mem_ctx, &response);
1435 if (!NT_STATUS_IS_OK(status)) {
1436 talloc_unlink(p, req);
1442 /* prepare for ndr_pull_* */
1443 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1445 talloc_unlink(p, req);
1446 return NT_STATUS_NO_MEMORY;
1450 pull->data = talloc_steal(pull, pull->data);
1452 talloc_unlink(p, req);
1454 if (flags & DCERPC_PULL_BIGENDIAN) {
1455 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1458 DEBUG(10,("rpc reply data:\n"));
1459 dump_data(10, pull->data, pull->data_size);
1461 /* pull the structure from the blob */
1462 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1463 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1464 status = ndr_map_error2ntstatus(ndr_err);
1465 dcerpc_log_packet(p->conn->packet_log_dir,
1466 table, opnum, NDR_OUT,
1471 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1472 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1473 call->ndr_push, call->ndr_pull,
1475 if (!NT_STATUS_IS_OK(status)) {
1476 dcerpc_log_packet(p->conn->packet_log_dir,
1477 table, opnum, NDR_OUT,
1483 if (pull->offset != pull->data_size) {
1484 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1485 pull->data_size - pull->offset));
1486 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1487 but it turns out that early versions of NT
1488 (specifically NT3.1) add junk onto the end of rpc
1489 packets, so if we want to interoperate at all with
1490 those versions then we need to ignore this error */
1493 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1495 return NT_STATUS_OK;
1500 a useful helper function for synchronous rpc requests
1502 this can be used when you have ndr push/pull functions in the
1505 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1506 const struct GUID *object,
1507 const struct ndr_interface_table *table,
1509 TALLOC_CTX *mem_ctx,
1512 struct rpc_request *req;
1514 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1516 return NT_STATUS_NO_MEMORY;
1519 return dcerpc_ndr_request_recv(req);
1524 a useful function for retrieving the server name we connected to
1526 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1528 if (!p->conn->transport.target_hostname) {
1529 if (!p->conn->transport.peer_name) {
1532 return p->conn->transport.peer_name(p->conn);
1534 return p->conn->transport.target_hostname(p->conn);
1539 get the dcerpc auth_level for a open connection
1541 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1545 if (c->flags & DCERPC_SEAL) {
1546 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1547 } else if (c->flags & DCERPC_SIGN) {
1548 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1549 } else if (c->flags & DCERPC_CONNECT) {
1550 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1552 auth_level = DCERPC_AUTH_LEVEL_NONE;
1558 Receive an alter reply from the transport
1560 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1561 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1563 struct composite_context *c;
1564 struct dcerpc_pipe *recv_pipe;
1566 c = talloc_get_type(req->async.private_data, struct composite_context);
1567 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1569 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1570 pkt->u.alter_resp.num_results == 1 &&
1571 pkt->u.alter_resp.ctx_list[0].result != 0) {
1572 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1573 pkt->u.alter_resp.ctx_list[0].reason));
1574 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1578 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1579 pkt->u.alter_resp.num_results == 0 ||
1580 pkt->u.alter_resp.ctx_list[0].result != 0) {
1581 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1585 /* the alter_resp might contain a reply set of credentials */
1586 if (recv_pipe->conn->security_state.auth_info &&
1587 pkt->u.alter_resp.auth_info.length) {
1588 struct dcerpc_connection *conn = recv_pipe->conn;
1590 uint32_t auth_length;
1591 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1592 conn->security_state.auth_info, &auth_length, true);
1593 if (!NT_STATUS_IS_OK(status)) {
1594 composite_error(c, status);
1603 send a dcerpc alter_context request
1605 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1606 TALLOC_CTX *mem_ctx,
1607 const struct ndr_syntax_id *syntax,
1608 const struct ndr_syntax_id *transfer_syntax)
1610 struct composite_context *c;
1611 struct ncacn_packet pkt;
1613 struct rpc_request *req;
1615 c = composite_create(mem_ctx, p->conn->event_ctx);
1616 if (c == NULL) return NULL;
1618 c->private_data = p;
1620 p->syntax = *syntax;
1621 p->transfer_syntax = *transfer_syntax;
1623 init_ncacn_hdr(p->conn, &pkt);
1625 pkt.ptype = DCERPC_PKT_ALTER;
1626 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1627 pkt.call_id = p->conn->call_id;
1628 pkt.auth_length = 0;
1630 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1631 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1634 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1635 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1638 pkt.u.alter.max_xmit_frag = 5840;
1639 pkt.u.alter.max_recv_frag = 5840;
1640 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1641 pkt.u.alter.num_contexts = 1;
1642 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1643 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1644 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1645 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1646 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1647 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1648 pkt.u.alter.auth_info = data_blob(NULL, 0);
1650 /* construct the NDR form of the packet */
1651 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1652 p->conn->security_state.auth_info);
1653 if (!composite_is_ok(c)) return c;
1655 p->conn->transport.recv_data = dcerpc_recv_data;
1658 * we allocate a dcerpc_request so we can be in the same
1659 * request queue as normal requests
1661 req = talloc_zero(c, struct rpc_request);
1662 if (composite_nomem(req, c)) return c;
1664 req->state = RPC_REQUEST_PENDING;
1665 req->call_id = pkt.call_id;
1666 req->async.private_data = c;
1667 req->async.callback = dcerpc_composite_fail;
1669 req->recv_handler = dcerpc_alter_recv_handler;
1670 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1671 talloc_set_destructor(req, dcerpc_req_dequeue);
1673 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1674 if (!composite_is_ok(c)) return c;
1676 event_add_timed(c->event_ctx, req,
1677 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1678 dcerpc_timeout_handler, req);
1683 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1685 NTSTATUS result = composite_wait(ctx);
1691 send a dcerpc alter_context request
1693 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1694 TALLOC_CTX *mem_ctx,
1695 const struct ndr_syntax_id *syntax,
1696 const struct ndr_syntax_id *transfer_syntax)
1698 struct composite_context *creq;
1699 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1700 return dcerpc_alter_context_recv(creq);