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)
226 struct ndr_pull *ndr;
228 struct dcerpc_auth auth;
230 enum ndr_err_code ndr_err;
232 if (!c->security_state.auth_info ||
233 !c->security_state.generic_state) {
237 switch (c->security_state.auth_info->auth_level) {
238 case DCERPC_AUTH_LEVEL_PRIVACY:
239 case DCERPC_AUTH_LEVEL_INTEGRITY:
242 case DCERPC_AUTH_LEVEL_CONNECT:
243 if (pkt->auth_length != 0) {
247 case DCERPC_AUTH_LEVEL_NONE:
248 if (pkt->auth_length != 0) {
249 return NT_STATUS_INVALID_NETWORK_RESPONSE;
254 return NT_STATUS_INVALID_LEVEL;
257 auth_blob.length = 8 + pkt->auth_length;
259 /* check for a valid length */
260 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
261 return NT_STATUS_INFO_LENGTH_MISMATCH;
265 pkt->u.response.stub_and_verifier.data +
266 pkt->u.response.stub_and_verifier.length - auth_blob.length;
267 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
269 /* pull the auth structure */
270 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
272 return NT_STATUS_NO_MEMORY;
275 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
276 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
279 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
280 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
281 return ndr_map_error2ntstatus(ndr_err);
283 status = NT_STATUS_OK;
285 /* check signature or unseal the packet */
286 switch (c->security_state.auth_info->auth_level) {
287 case DCERPC_AUTH_LEVEL_PRIVACY:
288 status = gensec_unseal_packet(c->security_state.generic_state,
290 raw_packet->data + DCERPC_REQUEST_LENGTH,
291 pkt->u.response.stub_and_verifier.length,
293 raw_packet->length - auth.credentials.length,
295 memcpy(pkt->u.response.stub_and_verifier.data,
296 raw_packet->data + DCERPC_REQUEST_LENGTH,
297 pkt->u.response.stub_and_verifier.length);
300 case DCERPC_AUTH_LEVEL_INTEGRITY:
301 status = gensec_check_packet(c->security_state.generic_state,
303 pkt->u.response.stub_and_verifier.data,
304 pkt->u.response.stub_and_verifier.length,
306 raw_packet->length - auth.credentials.length,
310 case DCERPC_AUTH_LEVEL_CONNECT:
311 /* for now we ignore possible signatures here */
312 status = NT_STATUS_OK;
316 status = NT_STATUS_INVALID_LEVEL;
320 /* remove the indicated amount of paddiing */
321 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
322 return NT_STATUS_INFO_LENGTH_MISMATCH;
324 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
331 push a dcerpc request packet into a blob, possibly signing it.
333 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
334 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
336 struct ncacn_packet *pkt)
339 struct ndr_push *ndr;
341 size_t payload_length;
342 enum ndr_err_code ndr_err;
343 size_t hdr_size = DCERPC_REQUEST_LENGTH;
345 /* non-signed packets are simpler */
347 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
350 switch (c->security_state.auth_info->auth_level) {
351 case DCERPC_AUTH_LEVEL_PRIVACY:
352 case DCERPC_AUTH_LEVEL_INTEGRITY:
355 case DCERPC_AUTH_LEVEL_CONNECT:
356 /* TODO: let the gensec mech decide if it wants to generate a signature */
357 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
359 case DCERPC_AUTH_LEVEL_NONE:
360 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
363 return NT_STATUS_INVALID_LEVEL;
366 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
368 return NT_STATUS_NO_MEMORY;
371 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
372 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
375 if (c->flags & DCERPC_NDR64) {
376 ndr->flags |= LIBNDR_FLAG_NDR64;
379 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
380 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
384 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
385 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
386 return ndr_map_error2ntstatus(ndr_err);
388 status = NT_STATUS_OK;
390 /* pad to 16 byte multiple in the payload portion of the
391 packet. This matches what w2k3 does */
392 c->security_state.auth_info->auth_pad_length =
393 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
394 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
395 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
396 return ndr_map_error2ntstatus(ndr_err);
398 status = NT_STATUS_OK;
400 payload_length = pkt->u.request.stub_and_verifier.length +
401 c->security_state.auth_info->auth_pad_length;
403 /* we start without signature, it will appended later */
404 c->security_state.auth_info->credentials = data_blob(NULL,0);
406 /* add the auth verifier */
407 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
408 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
409 return ndr_map_error2ntstatus(ndr_err);
411 status = NT_STATUS_OK;
413 /* extract the whole packet as a blob */
414 *blob = ndr_push_blob(ndr);
417 * Setup the frag and auth length in the packet buffer.
418 * This is needed if the GENSEC mech does AEAD signing
419 * of the packet headers. The signature itself will be
422 dcerpc_set_frag_length(blob, blob->length + sig_size);
423 dcerpc_set_auth_length(blob, sig_size);
425 /* sign or seal the packet */
426 switch (c->security_state.auth_info->auth_level) {
427 case DCERPC_AUTH_LEVEL_PRIVACY:
428 status = gensec_seal_packet(c->security_state.generic_state,
430 blob->data + hdr_size,
435 if (!NT_STATUS_IS_OK(status)) {
440 case DCERPC_AUTH_LEVEL_INTEGRITY:
441 status = gensec_sign_packet(c->security_state.generic_state,
443 blob->data + hdr_size,
448 if (!NT_STATUS_IS_OK(status)) {
454 status = NT_STATUS_INVALID_LEVEL;
458 if (creds2.length != sig_size) {
459 DEBUG(0,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
460 (unsigned) creds2.length,
462 (unsigned) c->security_state.auth_info->auth_pad_length,
463 (unsigned) pkt->u.request.stub_and_verifier.length));
464 return NT_STATUS_INTERNAL_ERROR;
467 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
468 return NT_STATUS_NO_MEMORY;
476 fill in the fixed values in a dcerpc header
478 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
481 pkt->rpc_vers_minor = 0;
482 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
485 pkt->drep[0] = DCERPC_DREP_LE;
493 map a bind nak reason to a NTSTATUS
495 static NTSTATUS dcerpc_map_reason(uint16_t reason)
498 case DCERPC_BIND_REASON_ASYNTAX:
499 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
500 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
501 return NT_STATUS_INVALID_PARAMETER;
503 return NT_STATUS_UNSUCCESSFUL;
507 a bind or alter context has failed
509 static void dcerpc_composite_fail(struct rpc_request *req)
511 struct composite_context *c = talloc_get_type(req->async.private_data,
512 struct composite_context);
513 composite_error(c, req->status);
517 remove requests from the pending or queued queues
519 static int dcerpc_req_dequeue(struct rpc_request *req)
521 switch (req->state) {
522 case RPC_REQUEST_QUEUED:
523 DLIST_REMOVE(req->p->conn->request_queue, req);
525 case RPC_REQUEST_PENDING:
526 DLIST_REMOVE(req->p->conn->pending, req);
528 case RPC_REQUEST_DONE:
536 mark the dcerpc connection dead. All outstanding requests get an error
538 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
540 if (conn->dead) return;
544 if (conn->transport.shutdown_pipe) {
545 conn->transport.shutdown_pipe(conn, status);
548 /* all pending requests get the error */
549 while (conn->pending) {
550 struct rpc_request *req = conn->pending;
551 dcerpc_req_dequeue(req);
552 req->state = RPC_REQUEST_DONE;
553 req->status = status;
554 if (req->async.callback) {
555 req->async.callback(req);
559 talloc_set_destructor(conn, NULL);
560 if (conn->free_skipped) {
566 forward declarations of the recv_data handlers for the types of
567 packets we need to handle
569 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
570 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
573 receive a dcerpc reply from the transport. Here we work out what
574 type of reply it is (normal request, bind or alter context) and
575 dispatch to the appropriate handler
577 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
579 struct ncacn_packet pkt;
581 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
582 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
585 /* the transport may be telling us of a severe error, such as
587 if (!NT_STATUS_IS_OK(status)) {
588 data_blob_free(blob);
589 dcerpc_connection_dead(conn, status);
593 /* parse the basic packet to work out what type of response this is */
594 status = ncacn_pull(conn, blob, blob->data, &pkt);
595 if (!NT_STATUS_IS_OK(status)) {
596 data_blob_free(blob);
597 dcerpc_connection_dead(conn, status);
600 dcerpc_request_recv_data(conn, blob, &pkt);
605 Receive a bind reply from the transport
607 static void dcerpc_bind_recv_handler(struct rpc_request *req,
608 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
610 struct composite_context *c;
611 struct dcerpc_connection *conn;
613 c = talloc_get_type(req->async.private_data, struct composite_context);
615 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
616 DEBUG(2,("dcerpc: bind_nak reason %d\n",
617 pkt->u.bind_nak.reject_reason));
618 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
623 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
624 (pkt->u.bind_ack.num_results == 0) ||
625 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
626 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
632 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
633 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
635 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
636 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
637 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
640 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
641 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
642 conn->flags |= DCERPC_HEADER_SIGNING;
645 /* the bind_ack might contain a reply set of credentials */
646 if (conn->security_state.auth_info &&
647 pkt->u.bind_ack.auth_info.length) {
648 enum ndr_err_code ndr_err;
649 ndr_err = ndr_pull_struct_blob(
650 &pkt->u.bind_ack.auth_info, conn,
652 conn->security_state.auth_info,
653 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
654 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
655 c->status = ndr_map_error2ntstatus(ndr_err);
656 if (!composite_is_ok(c)) return;
660 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
666 handle timeouts of individual dcerpc requests
668 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
669 struct timeval t, void *private_data)
671 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
673 if (req->ignore_timeout) {
674 dcerpc_req_dequeue(req);
675 req->state = RPC_REQUEST_DONE;
676 req->status = NT_STATUS_IO_TIMEOUT;
677 if (req->async.callback) {
678 req->async.callback(req);
683 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
687 send a async dcerpc bind request
689 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
691 const struct ndr_syntax_id *syntax,
692 const struct ndr_syntax_id *transfer_syntax)
694 struct composite_context *c;
695 struct ncacn_packet pkt;
697 struct rpc_request *req;
699 c = composite_create(mem_ctx,p->conn->event_ctx);
700 if (c == NULL) return NULL;
705 p->transfer_syntax = *transfer_syntax;
707 init_ncacn_hdr(p->conn, &pkt);
709 pkt.ptype = DCERPC_PKT_BIND;
710 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
711 pkt.call_id = p->conn->call_id;
714 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
715 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
718 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
719 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
722 pkt.u.bind.max_xmit_frag = 5840;
723 pkt.u.bind.max_recv_frag = 5840;
724 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
725 pkt.u.bind.num_contexts = 1;
726 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
727 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
728 pkt.u.bind.ctx_list[0].context_id = p->context_id;
729 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
730 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
731 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
732 pkt.u.bind.auth_info = data_blob(NULL, 0);
734 /* construct the NDR form of the packet */
735 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
736 p->conn->security_state.auth_info);
737 if (!composite_is_ok(c)) return c;
739 p->conn->transport.recv_data = dcerpc_recv_data;
742 * we allocate a dcerpc_request so we can be in the same
743 * request queue as normal requests
745 req = talloc_zero(c, struct rpc_request);
746 if (composite_nomem(req, c)) return c;
748 req->state = RPC_REQUEST_PENDING;
749 req->call_id = pkt.call_id;
750 req->async.private_data = c;
751 req->async.callback = dcerpc_composite_fail;
753 req->recv_handler = dcerpc_bind_recv_handler;
754 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
755 talloc_set_destructor(req, dcerpc_req_dequeue);
757 c->status = p->conn->transport.send_request(p->conn, &blob,
759 if (!composite_is_ok(c)) return c;
761 event_add_timed(c->event_ctx, req,
762 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
763 dcerpc_timeout_handler, req);
769 recv side of async dcerpc bind request
771 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
773 NTSTATUS result = composite_wait(ctx);
779 perform a continued bind (and auth3)
781 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
784 struct ncacn_packet pkt;
788 init_ncacn_hdr(p->conn, &pkt);
790 pkt.ptype = DCERPC_PKT_AUTH3;
791 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
792 pkt.call_id = next_call_id(p->conn);
794 pkt.u.auth3._pad = 0;
795 pkt.u.auth3.auth_info = data_blob(NULL, 0);
797 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
798 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
801 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
802 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
805 /* construct the NDR form of the packet */
806 status = ncacn_push_auth(&blob, mem_ctx,
807 p->conn->iconv_convenience,
809 p->conn->security_state.auth_info);
810 if (!NT_STATUS_IS_OK(status)) {
814 /* send it on its way */
815 status = p->conn->transport.send_request(p->conn, &blob, false);
816 if (!NT_STATUS_IS_OK(status)) {
825 process a fragment received from the transport layer during a
828 This function frees the data
830 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
831 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
833 struct rpc_request *req;
835 NTSTATUS status = NT_STATUS_OK;
838 if this is an authenticated connection then parse and check
839 the auth info. We have to do this before finding the
840 matching packet, as the request structure might have been
841 removed due to a timeout, but if it has been we still need
842 to run the auth routines so that we don't get the sign/seal
843 info out of step with the server
845 if (c->security_state.auth_info && c->security_state.generic_state &&
846 pkt->ptype == DCERPC_PKT_RESPONSE) {
847 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
850 /* find the matching request */
851 for (req=c->pending;req;req=req->next) {
852 if (pkt->call_id == req->call_id) break;
856 /* useful for testing certain vendors RPC servers */
857 if (req == NULL && c->pending && pkt->call_id == 0) {
858 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
864 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
865 data_blob_free(raw_packet);
869 talloc_steal(req, raw_packet->data);
871 if (req->recv_handler != NULL) {
872 dcerpc_req_dequeue(req);
873 req->state = RPC_REQUEST_DONE;
874 req->recv_handler(req, raw_packet, pkt);
878 if (pkt->ptype == DCERPC_PKT_FAULT) {
879 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
880 req->fault_code = pkt->u.fault.status;
881 req->status = NT_STATUS_NET_WRITE_FAULT;
885 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
886 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
888 req->fault_code = DCERPC_FAULT_OTHER;
889 req->status = NT_STATUS_NET_WRITE_FAULT;
893 /* now check the status from the auth routines, and if it failed then fail
894 this request accordingly */
895 if (!NT_STATUS_IS_OK(status)) {
896 req->status = status;
900 length = pkt->u.response.stub_and_verifier.length;
903 req->payload.data = talloc_realloc(req,
906 req->payload.length + length);
907 if (!req->payload.data) {
908 req->status = NT_STATUS_NO_MEMORY;
911 memcpy(req->payload.data+req->payload.length,
912 pkt->u.response.stub_and_verifier.data, length);
913 req->payload.length += length;
916 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
917 c->transport.send_read(c);
921 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
922 req->flags |= DCERPC_PULL_BIGENDIAN;
924 req->flags &= ~DCERPC_PULL_BIGENDIAN;
929 /* we've got the full payload */
930 req->state = RPC_REQUEST_DONE;
931 DLIST_REMOVE(c->pending, req);
933 if (c->request_queue != NULL) {
934 /* We have to look at shipping further requests before calling
935 * the async function, that one might close the pipe */
936 dcerpc_ship_next_request(c);
939 if (req->async.callback) {
940 req->async.callback(req);
945 perform the send side of a async dcerpc request
947 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
948 const struct GUID *object,
951 DATA_BLOB *stub_data)
953 struct rpc_request *req;
955 p->conn->transport.recv_data = dcerpc_recv_data;
957 req = talloc(p, struct rpc_request);
963 req->call_id = next_call_id(p->conn);
964 req->status = NT_STATUS_OK;
965 req->state = RPC_REQUEST_QUEUED;
966 req->payload = data_blob(NULL, 0);
969 req->async_call = async;
970 req->ignore_timeout = false;
971 req->async.callback = NULL;
972 req->async.private_data = NULL;
973 req->recv_handler = NULL;
975 if (object != NULL) {
976 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
977 if (req->object == NULL) {
986 req->request_data.length = stub_data->length;
987 req->request_data.data = talloc_reference(req, stub_data->data);
988 if (req->request_data.length && req->request_data.data == NULL) {
992 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
993 talloc_set_destructor(req, dcerpc_req_dequeue);
995 dcerpc_ship_next_request(p->conn);
997 if (p->request_timeout) {
998 event_add_timed(dcerpc_event_context(p), req,
999 timeval_current_ofs(p->request_timeout, 0),
1000 dcerpc_timeout_handler, req);
1007 Send a request using the transport
1010 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1012 struct rpc_request *req;
1013 struct dcerpc_pipe *p;
1014 DATA_BLOB *stub_data;
1015 struct ncacn_packet pkt;
1017 uint32_t remaining, chunk_size;
1018 bool first_packet = true;
1019 size_t sig_size = 0;
1021 req = c->request_queue;
1027 stub_data = &req->request_data;
1029 if (!req->async_call && (c->pending != NULL)) {
1033 DLIST_REMOVE(c->request_queue, req);
1034 DLIST_ADD(c->pending, req);
1035 req->state = RPC_REQUEST_PENDING;
1037 init_ncacn_hdr(p->conn, &pkt);
1039 remaining = stub_data->length;
1041 /* we can write a full max_recv_frag size, minus the dcerpc
1042 request header size */
1043 chunk_size = p->conn->srv_max_recv_frag;
1044 chunk_size -= DCERPC_REQUEST_LENGTH;
1045 if (c->security_state.auth_info &&
1046 c->security_state.generic_state) {
1047 sig_size = gensec_sig_size(c->security_state.generic_state,
1048 p->conn->srv_max_recv_frag);
1050 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1051 chunk_size -= sig_size;
1054 chunk_size -= (chunk_size % 16);
1056 pkt.ptype = DCERPC_PKT_REQUEST;
1057 pkt.call_id = req->call_id;
1058 pkt.auth_length = 0;
1060 pkt.u.request.alloc_hint = remaining;
1061 pkt.u.request.context_id = p->context_id;
1062 pkt.u.request.opnum = req->opnum;
1065 pkt.u.request.object.object = *req->object;
1066 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1067 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1070 /* we send a series of pdus without waiting for a reply */
1071 while (remaining > 0 || first_packet) {
1072 uint32_t chunk = MIN(chunk_size, remaining);
1073 bool last_frag = false;
1074 bool do_trans = false;
1076 first_packet = false;
1077 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1079 if (remaining == stub_data->length) {
1080 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1082 if (chunk == remaining) {
1083 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1087 pkt.u.request.stub_and_verifier.data = stub_data->data +
1088 (stub_data->length - remaining);
1089 pkt.u.request.stub_and_verifier.length = chunk;
1091 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1092 if (!NT_STATUS_IS_OK(req->status)) {
1093 req->state = RPC_REQUEST_DONE;
1094 DLIST_REMOVE(p->conn->pending, req);
1098 if (last_frag && !req->async_call) {
1102 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1103 if (!NT_STATUS_IS_OK(req->status)) {
1104 req->state = RPC_REQUEST_DONE;
1105 DLIST_REMOVE(p->conn->pending, req);
1109 if (last_frag && !do_trans) {
1110 req->status = p->conn->transport.send_read(p->conn);
1111 if (!NT_STATUS_IS_OK(req->status)) {
1112 req->state = RPC_REQUEST_DONE;
1113 DLIST_REMOVE(p->conn->pending, req);
1123 return the event context for a dcerpc pipe
1124 used by callers who wish to operate asynchronously
1126 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1128 return p->conn->event_ctx;
1134 perform the receive side of a async dcerpc request
1136 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1137 TALLOC_CTX *mem_ctx,
1138 DATA_BLOB *stub_data)
1142 while (req->state != RPC_REQUEST_DONE) {
1143 struct tevent_context *ctx = dcerpc_event_context(req->p);
1144 if (event_loop_once(ctx) != 0) {
1145 return NT_STATUS_CONNECTION_DISCONNECTED;
1148 *stub_data = req->payload;
1149 status = req->status;
1150 if (stub_data->data) {
1151 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1153 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1154 req->p->last_fault_code = req->fault_code;
1156 talloc_unlink(talloc_parent(req), req);
1161 perform a full request/response pair on a dcerpc pipe
1163 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1164 struct GUID *object,
1166 TALLOC_CTX *mem_ctx,
1167 DATA_BLOB *stub_data_in,
1168 DATA_BLOB *stub_data_out)
1170 struct rpc_request *req;
1172 req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1174 return NT_STATUS_NO_MEMORY;
1177 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1182 this is a paranoid NDR validator. For every packet we push onto the wire
1183 we pull it back again, then push it again. Then we compare the raw NDR data
1184 for that to the NDR we initially generated. If they don't match then we know
1185 we must have a bug in either the pull or push side of our code
1187 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1188 TALLOC_CTX *mem_ctx,
1191 ndr_push_flags_fn_t ndr_push,
1192 ndr_pull_flags_fn_t ndr_pull)
1195 struct ndr_pull *pull;
1196 struct ndr_push *push;
1198 enum ndr_err_code ndr_err;
1200 st = talloc_size(mem_ctx, struct_size);
1202 return NT_STATUS_NO_MEMORY;
1205 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1207 return NT_STATUS_NO_MEMORY;
1209 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1211 ndr_err = ndr_pull(pull, NDR_IN, st);
1212 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1213 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1214 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1215 "failed input validation pull - %s",
1217 return ndr_map_error2ntstatus(ndr_err);
1220 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1222 return NT_STATUS_NO_MEMORY;
1225 ndr_err = ndr_push(push, NDR_IN, st);
1226 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1227 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1228 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1229 "failed input validation push - %s",
1231 return ndr_map_error2ntstatus(ndr_err);
1234 blob2 = ndr_push_blob(push);
1236 if (data_blob_cmp(&blob, &blob2) != 0) {
1237 DEBUG(3,("original:\n"));
1238 dump_data(3, blob.data, blob.length);
1239 DEBUG(3,("secondary:\n"));
1240 dump_data(3, blob2.data, blob2.length);
1241 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1242 "failed input validation blobs doesn't match");
1243 return ndr_map_error2ntstatus(ndr_err);
1246 return NT_STATUS_OK;
1250 this is a paranoid NDR input validator. For every packet we pull
1251 from the wire we push it back again then pull and push it
1252 again. Then we compare the raw NDR data for that to the NDR we
1253 initially generated. If they don't match then we know we must have a
1254 bug in either the pull or push side of our code
1256 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1257 struct ndr_pull *pull_in,
1260 ndr_push_flags_fn_t ndr_push,
1261 ndr_pull_flags_fn_t ndr_pull,
1262 ndr_print_function_t ndr_print)
1265 struct ndr_pull *pull;
1266 struct ndr_push *push;
1267 DATA_BLOB blob, blob2;
1268 TALLOC_CTX *mem_ctx = pull_in;
1270 enum ndr_err_code ndr_err;
1272 st = talloc_size(mem_ctx, struct_size);
1274 return NT_STATUS_NO_MEMORY;
1276 memcpy(st, struct_ptr, struct_size);
1278 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1280 return NT_STATUS_NO_MEMORY;
1283 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1285 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1286 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1287 "failed output validation push - %s",
1289 return ndr_map_error2ntstatus(ndr_err);
1292 blob = ndr_push_blob(push);
1294 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1296 return NT_STATUS_NO_MEMORY;
1299 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1300 ndr_err = ndr_pull(pull, NDR_OUT, st);
1301 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1302 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1303 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1304 "failed output validation pull - %s",
1306 return ndr_map_error2ntstatus(ndr_err);
1309 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1311 return NT_STATUS_NO_MEMORY;
1314 ndr_err = ndr_push(push, NDR_OUT, st);
1315 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1316 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1317 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1318 "failed output validation push2 - %s",
1320 return ndr_map_error2ntstatus(ndr_err);
1323 blob2 = ndr_push_blob(push);
1325 if (data_blob_cmp(&blob, &blob2) != 0) {
1326 DEBUG(3,("original:\n"));
1327 dump_data(3, blob.data, blob.length);
1328 DEBUG(3,("secondary:\n"));
1329 dump_data(3, blob2.data, blob2.length);
1330 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1331 "failed output validation blobs doesn't match");
1332 return ndr_map_error2ntstatus(ndr_err);
1335 /* this checks the printed forms of the two structures, which effectively
1336 tests all of the value() attributes */
1337 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1338 NDR_OUT, struct_ptr);
1339 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1341 if (strcmp(s1, s2) != 0) {
1343 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1345 /* this is sometimes useful */
1346 printf("VALIDATE ERROR\n");
1347 file_save("wire.dat", s1, strlen(s1));
1348 file_save("gen.dat", s2, strlen(s2));
1349 system("diff -u wire.dat gen.dat");
1351 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1352 "failed output validation strings doesn't match");
1353 return ndr_map_error2ntstatus(ndr_err);
1356 return NT_STATUS_OK;
1361 send a rpc request given a dcerpc_call structure
1363 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1364 const struct GUID *object,
1365 const struct ndr_interface_table *table,
1368 TALLOC_CTX *mem_ctx,
1371 const struct ndr_interface_call *call;
1372 struct ndr_push *push;
1375 struct rpc_request *req;
1376 enum ndr_err_code ndr_err;
1378 call = &table->calls[opnum];
1380 /* setup for a ndr_push_* call */
1381 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1386 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1387 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1390 if (p->conn->flags & DCERPC_NDR64) {
1391 push->flags |= LIBNDR_FLAG_NDR64;
1394 /* push the structure into a blob */
1395 ndr_err = call->ndr_push(push, NDR_IN, r);
1396 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1397 status = ndr_map_error2ntstatus(ndr_err);
1398 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1399 nt_errstr(status)));
1404 /* retrieve the blob */
1405 request = ndr_push_blob(push);
1407 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1408 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1409 call->ndr_push, call->ndr_pull);
1410 if (!NT_STATUS_IS_OK(status)) {
1411 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1412 nt_errstr(status)));
1418 DEBUG(10,("rpc request data:\n"));
1419 dump_data(10, request.data, request.length);
1421 /* make the actual dcerpc request */
1422 req = dcerpc_request_send(p, object, opnum, async, &request);
1425 req->ndr.table = table;
1426 req->ndr.opnum = opnum;
1427 req->ndr.struct_ptr = r;
1428 req->ndr.mem_ctx = mem_ctx;
1437 receive the answer from a dcerpc_ndr_request_send()
1439 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1441 struct dcerpc_pipe *p = req->p;
1444 struct ndr_pull *pull;
1446 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1447 void *r = req->ndr.struct_ptr;
1448 uint32_t opnum = req->ndr.opnum;
1449 const struct ndr_interface_table *table = req->ndr.table;
1450 const struct ndr_interface_call *call = &table->calls[opnum];
1451 enum ndr_err_code ndr_err;
1453 /* make sure the recv code doesn't free the request, as we
1454 need to grab the flags element before it is freed */
1455 if (talloc_reference(p, req) == NULL) {
1456 return NT_STATUS_NO_MEMORY;
1459 status = dcerpc_request_recv(req, mem_ctx, &response);
1460 if (!NT_STATUS_IS_OK(status)) {
1461 talloc_unlink(p, req);
1467 /* prepare for ndr_pull_* */
1468 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1470 talloc_unlink(p, req);
1471 return NT_STATUS_NO_MEMORY;
1475 pull->data = talloc_steal(pull, pull->data);
1477 talloc_unlink(p, req);
1479 if (flags & DCERPC_PULL_BIGENDIAN) {
1480 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1483 DEBUG(10,("rpc reply data:\n"));
1484 dump_data(10, pull->data, pull->data_size);
1486 /* pull the structure from the blob */
1487 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1488 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1489 status = ndr_map_error2ntstatus(ndr_err);
1490 dcerpc_log_packet(p->conn->packet_log_dir,
1491 table, opnum, NDR_OUT,
1496 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1497 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1498 call->ndr_push, call->ndr_pull,
1500 if (!NT_STATUS_IS_OK(status)) {
1501 dcerpc_log_packet(p->conn->packet_log_dir,
1502 table, opnum, NDR_OUT,
1508 if (pull->offset != pull->data_size) {
1509 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1510 pull->data_size - pull->offset));
1511 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1512 but it turns out that early versions of NT
1513 (specifically NT3.1) add junk onto the end of rpc
1514 packets, so if we want to interoperate at all with
1515 those versions then we need to ignore this error */
1518 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1520 return NT_STATUS_OK;
1525 a useful helper function for synchronous rpc requests
1527 this can be used when you have ndr push/pull functions in the
1530 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1531 const struct GUID *object,
1532 const struct ndr_interface_table *table,
1534 TALLOC_CTX *mem_ctx,
1537 struct rpc_request *req;
1539 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1541 return NT_STATUS_NO_MEMORY;
1544 return dcerpc_ndr_request_recv(req);
1549 a useful function for retrieving the server name we connected to
1551 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1553 if (!p->conn->transport.target_hostname) {
1554 if (!p->conn->transport.peer_name) {
1557 return p->conn->transport.peer_name(p->conn);
1559 return p->conn->transport.target_hostname(p->conn);
1564 get the dcerpc auth_level for a open connection
1566 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1570 if (c->flags & DCERPC_SEAL) {
1571 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1572 } else if (c->flags & DCERPC_SIGN) {
1573 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1574 } else if (c->flags & DCERPC_CONNECT) {
1575 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1577 auth_level = DCERPC_AUTH_LEVEL_NONE;
1583 Receive an alter reply from the transport
1585 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1586 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1588 struct composite_context *c;
1589 struct dcerpc_pipe *recv_pipe;
1591 c = talloc_get_type(req->async.private_data, struct composite_context);
1592 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1594 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1595 pkt->u.alter_resp.num_results == 1 &&
1596 pkt->u.alter_resp.ctx_list[0].result != 0) {
1597 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1598 pkt->u.alter_resp.ctx_list[0].reason));
1599 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1603 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1604 pkt->u.alter_resp.num_results == 0 ||
1605 pkt->u.alter_resp.ctx_list[0].result != 0) {
1606 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1610 /* the alter_resp might contain a reply set of credentials */
1611 if (recv_pipe->conn->security_state.auth_info &&
1612 pkt->u.alter_resp.auth_info.length) {
1613 enum ndr_err_code ndr_err;
1614 ndr_err = ndr_pull_struct_blob(
1615 &pkt->u.alter_resp.auth_info, recv_pipe,
1617 recv_pipe->conn->security_state.auth_info,
1618 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1619 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1620 c->status = ndr_map_error2ntstatus(ndr_err);
1621 if (!composite_is_ok(c)) return;
1629 send a dcerpc alter_context request
1631 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1632 TALLOC_CTX *mem_ctx,
1633 const struct ndr_syntax_id *syntax,
1634 const struct ndr_syntax_id *transfer_syntax)
1636 struct composite_context *c;
1637 struct ncacn_packet pkt;
1639 struct rpc_request *req;
1641 c = composite_create(mem_ctx, p->conn->event_ctx);
1642 if (c == NULL) return NULL;
1644 c->private_data = p;
1646 p->syntax = *syntax;
1647 p->transfer_syntax = *transfer_syntax;
1649 init_ncacn_hdr(p->conn, &pkt);
1651 pkt.ptype = DCERPC_PKT_ALTER;
1652 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1653 pkt.call_id = p->conn->call_id;
1654 pkt.auth_length = 0;
1656 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1657 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1660 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1661 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1664 pkt.u.alter.max_xmit_frag = 5840;
1665 pkt.u.alter.max_recv_frag = 5840;
1666 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1667 pkt.u.alter.num_contexts = 1;
1668 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1669 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1670 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1671 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1672 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1673 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1674 pkt.u.alter.auth_info = data_blob(NULL, 0);
1676 /* construct the NDR form of the packet */
1677 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1678 p->conn->security_state.auth_info);
1679 if (!composite_is_ok(c)) return c;
1681 p->conn->transport.recv_data = dcerpc_recv_data;
1684 * we allocate a dcerpc_request so we can be in the same
1685 * request queue as normal requests
1687 req = talloc_zero(c, struct rpc_request);
1688 if (composite_nomem(req, c)) return c;
1690 req->state = RPC_REQUEST_PENDING;
1691 req->call_id = pkt.call_id;
1692 req->async.private_data = c;
1693 req->async.callback = dcerpc_composite_fail;
1695 req->recv_handler = dcerpc_alter_recv_handler;
1696 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1697 talloc_set_destructor(req, dcerpc_req_dequeue);
1699 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1700 if (!composite_is_ok(c)) return c;
1702 event_add_timed(c->event_ctx, req,
1703 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1704 dcerpc_timeout_handler, req);
1709 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1711 NTSTATUS result = composite_wait(ctx);
1717 send a dcerpc alter_context request
1719 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1720 TALLOC_CTX *mem_ctx,
1721 const struct ndr_syntax_id *syntax,
1722 const struct ndr_syntax_id *transfer_syntax)
1724 struct composite_context *creq;
1725 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1726 return dcerpc_alter_context_recv(creq);