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(void)
36 gensec_init(global_loadparm);
41 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
42 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
44 /* destroy a dcerpc connection */
45 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
48 conn->free_skipped = true;
51 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
56 /* initialise a dcerpc connection.
57 the event context is optional
59 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
60 struct event_context *ev,
61 struct smb_iconv_convenience *ic)
63 struct dcerpc_connection *c;
65 c = talloc_zero(mem_ctx, struct dcerpc_connection);
70 c->iconv_convenience = talloc_reference(c, ic);
72 c->event_ctx = talloc_reference(c, ev);
74 if (c->event_ctx == NULL) {
80 c->security_state.auth_info = NULL;
81 c->security_state.session_key = dcerpc_generic_session_key;
82 c->security_state.generic_state = NULL;
83 c->binding_string = NULL;
85 c->srv_max_xmit_frag = 0;
86 c->srv_max_recv_frag = 0;
89 talloc_set_destructor(c, dcerpc_connection_destructor);
94 /* initialise a dcerpc pipe. */
95 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev,
96 struct smb_iconv_convenience *ic)
98 struct dcerpc_pipe *p;
100 p = talloc(mem_ctx, struct dcerpc_pipe);
105 p->conn = dcerpc_connection_init(p, ev, ic);
106 if (p->conn == NULL) {
111 p->last_fault_code = 0;
113 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
116 ZERO_STRUCT(p->syntax);
117 ZERO_STRUCT(p->transfer_syntax);
124 choose the next call id to use
126 static uint32_t next_call_id(struct dcerpc_connection *c)
129 if (c->call_id == 0) {
135 /* we need to be able to get/set the fragment length without doing a full
137 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
139 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
140 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
142 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
146 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
148 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
149 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
151 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
155 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
157 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
158 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
160 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
166 setup for a ndr pull, also setting up any flags from the binding string
168 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
169 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
171 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
173 if (ndr == NULL) return ndr;
175 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
176 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
179 if (c->flags & DCERPC_NDR_REF_ALLOC) {
180 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
187 parse a data blob into a ncacn_packet structure. This handles both
188 input and output packets
190 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
191 struct ncacn_packet *pkt)
193 struct ndr_pull *ndr;
194 enum ndr_err_code ndr_err;
196 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
198 return NT_STATUS_NO_MEMORY;
201 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
202 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
205 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
206 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
207 return ndr_map_error2ntstatus(ndr_err);
214 parse the authentication information on a dcerpc response packet
216 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
217 DATA_BLOB *raw_packet,
218 struct ncacn_packet *pkt)
220 struct ndr_pull *ndr;
222 struct dcerpc_auth auth;
224 enum ndr_err_code ndr_err;
226 if (!c->security_state.auth_info ||
227 !c->security_state.generic_state) {
231 switch (c->security_state.auth_info->auth_level) {
232 case DCERPC_AUTH_LEVEL_PRIVACY:
233 case DCERPC_AUTH_LEVEL_INTEGRITY:
236 case DCERPC_AUTH_LEVEL_CONNECT:
237 if (pkt->auth_length != 0) {
241 case DCERPC_AUTH_LEVEL_NONE:
242 if (pkt->auth_length != 0) {
243 return NT_STATUS_INVALID_NETWORK_RESPONSE;
248 return NT_STATUS_INVALID_LEVEL;
251 auth_blob.length = 8 + pkt->auth_length;
253 /* check for a valid length */
254 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
255 return NT_STATUS_INFO_LENGTH_MISMATCH;
259 pkt->u.response.stub_and_verifier.data +
260 pkt->u.response.stub_and_verifier.length - auth_blob.length;
261 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
263 /* pull the auth structure */
264 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
266 return NT_STATUS_NO_MEMORY;
269 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
270 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
273 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
274 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
275 return ndr_map_error2ntstatus(ndr_err);
277 status = NT_STATUS_OK;
279 /* check signature or unseal the packet */
280 switch (c->security_state.auth_info->auth_level) {
281 case DCERPC_AUTH_LEVEL_PRIVACY:
282 status = gensec_unseal_packet(c->security_state.generic_state,
284 raw_packet->data + DCERPC_REQUEST_LENGTH,
285 pkt->u.response.stub_and_verifier.length,
287 raw_packet->length - auth.credentials.length,
289 memcpy(pkt->u.response.stub_and_verifier.data,
290 raw_packet->data + DCERPC_REQUEST_LENGTH,
291 pkt->u.response.stub_and_verifier.length);
294 case DCERPC_AUTH_LEVEL_INTEGRITY:
295 status = gensec_check_packet(c->security_state.generic_state,
297 pkt->u.response.stub_and_verifier.data,
298 pkt->u.response.stub_and_verifier.length,
300 raw_packet->length - auth.credentials.length,
304 case DCERPC_AUTH_LEVEL_CONNECT:
305 /* for now we ignore possible signatures here */
306 status = NT_STATUS_OK;
310 status = NT_STATUS_INVALID_LEVEL;
314 /* remove the indicated amount of paddiing */
315 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
316 return NT_STATUS_INFO_LENGTH_MISMATCH;
318 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
325 push a dcerpc request packet into a blob, possibly signing it.
327 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
328 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
330 struct ncacn_packet *pkt)
333 struct ndr_push *ndr;
335 size_t payload_length;
336 enum ndr_err_code ndr_err;
337 size_t hdr_size = DCERPC_REQUEST_LENGTH;
339 /* non-signed packets are simpler */
341 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
344 switch (c->security_state.auth_info->auth_level) {
345 case DCERPC_AUTH_LEVEL_PRIVACY:
346 case DCERPC_AUTH_LEVEL_INTEGRITY:
349 case DCERPC_AUTH_LEVEL_CONNECT:
350 /* TODO: let the gensec mech decide if it wants to generate a signature */
351 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
353 case DCERPC_AUTH_LEVEL_NONE:
354 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
357 return NT_STATUS_INVALID_LEVEL;
360 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
362 return NT_STATUS_NO_MEMORY;
365 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
366 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
369 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
370 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
374 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
375 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
376 return ndr_map_error2ntstatus(ndr_err);
378 status = NT_STATUS_OK;
380 /* pad to 16 byte multiple in the payload portion of the
381 packet. This matches what w2k3 does */
382 c->security_state.auth_info->auth_pad_length =
383 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
384 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
385 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
386 return ndr_map_error2ntstatus(ndr_err);
388 status = NT_STATUS_OK;
390 payload_length = pkt->u.request.stub_and_verifier.length +
391 c->security_state.auth_info->auth_pad_length;
393 /* we start without signature, it will appended later */
394 c->security_state.auth_info->credentials = data_blob(NULL,0);
396 /* add the auth verifier */
397 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
398 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
399 return ndr_map_error2ntstatus(ndr_err);
401 status = NT_STATUS_OK;
403 /* extract the whole packet as a blob */
404 *blob = ndr_push_blob(ndr);
407 * Setup the frag and auth length in the packet buffer.
408 * This is needed if the GENSEC mech does AEAD signing
409 * of the packet headers. The signature itself will be
412 dcerpc_set_frag_length(blob, blob->length + sig_size);
413 dcerpc_set_auth_length(blob, sig_size);
415 /* sign or seal the packet */
416 switch (c->security_state.auth_info->auth_level) {
417 case DCERPC_AUTH_LEVEL_PRIVACY:
418 status = gensec_seal_packet(c->security_state.generic_state,
420 blob->data + hdr_size,
425 if (!NT_STATUS_IS_OK(status)) {
430 case DCERPC_AUTH_LEVEL_INTEGRITY:
431 status = gensec_sign_packet(c->security_state.generic_state,
433 blob->data + hdr_size,
438 if (!NT_STATUS_IS_OK(status)) {
444 status = NT_STATUS_INVALID_LEVEL;
448 if (creds2.length != sig_size) {
449 DEBUG(0,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
450 creds2.length, (uint32_t)sig_size,
451 c->security_state.auth_info->auth_pad_length,
452 pkt->u.request.stub_and_verifier.length));
453 return NT_STATUS_INTERNAL_ERROR;
456 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
457 return NT_STATUS_NO_MEMORY;
465 fill in the fixed values in a dcerpc header
467 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
470 pkt->rpc_vers_minor = 0;
471 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
474 pkt->drep[0] = DCERPC_DREP_LE;
482 map a bind nak reason to a NTSTATUS
484 static NTSTATUS dcerpc_map_reason(uint16_t reason)
487 case DCERPC_BIND_REASON_ASYNTAX:
488 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
489 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
490 return NT_STATUS_INVALID_PARAMETER;
492 return NT_STATUS_UNSUCCESSFUL;
496 a bind or alter context has failed
498 static void dcerpc_composite_fail(struct rpc_request *req)
500 struct composite_context *c = talloc_get_type(req->async.private_data,
501 struct composite_context);
502 composite_error(c, req->status);
506 remove requests from the pending or queued queues
508 static int dcerpc_req_dequeue(struct rpc_request *req)
510 switch (req->state) {
511 case RPC_REQUEST_QUEUED:
512 DLIST_REMOVE(req->p->conn->request_queue, req);
514 case RPC_REQUEST_PENDING:
515 DLIST_REMOVE(req->p->conn->pending, req);
517 case RPC_REQUEST_DONE:
525 mark the dcerpc connection dead. All outstanding requests get an error
527 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
529 if (conn->dead) return;
533 if (conn->transport.shutdown_pipe) {
534 conn->transport.shutdown_pipe(conn, status);
537 /* all pending requests get the error */
538 while (conn->pending) {
539 struct rpc_request *req = conn->pending;
540 dcerpc_req_dequeue(req);
541 req->state = RPC_REQUEST_DONE;
542 req->status = status;
543 if (req->async.callback) {
544 req->async.callback(req);
548 talloc_set_destructor(conn, NULL);
549 if (conn->free_skipped) {
555 forward declarations of the recv_data handlers for the types of
556 packets we need to handle
558 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
559 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
562 receive a dcerpc reply from the transport. Here we work out what
563 type of reply it is (normal request, bind or alter context) and
564 dispatch to the appropriate handler
566 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
568 struct ncacn_packet pkt;
570 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
571 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
574 /* the transport may be telling us of a severe error, such as
576 if (!NT_STATUS_IS_OK(status)) {
577 data_blob_free(blob);
578 dcerpc_connection_dead(conn, status);
582 /* parse the basic packet to work out what type of response this is */
583 status = ncacn_pull(conn, blob, blob->data, &pkt);
584 if (!NT_STATUS_IS_OK(status)) {
585 data_blob_free(blob);
586 dcerpc_connection_dead(conn, status);
589 dcerpc_request_recv_data(conn, blob, &pkt);
594 Receive a bind reply from the transport
596 static void dcerpc_bind_recv_handler(struct rpc_request *req,
597 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
599 struct composite_context *c;
600 struct dcerpc_connection *conn;
602 c = talloc_get_type(req->async.private_data, struct composite_context);
604 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
605 DEBUG(2,("dcerpc: bind_nak reason %d\n",
606 pkt->u.bind_nak.reject_reason));
607 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
612 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
613 (pkt->u.bind_ack.num_results == 0) ||
614 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
615 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
621 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
622 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
624 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
625 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
626 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
629 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
630 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
631 conn->flags |= DCERPC_HEADER_SIGNING;
634 /* the bind_ack might contain a reply set of credentials */
635 if (conn->security_state.auth_info &&
636 pkt->u.bind_ack.auth_info.length) {
637 enum ndr_err_code ndr_err;
638 ndr_err = ndr_pull_struct_blob(
639 &pkt->u.bind_ack.auth_info, conn,
641 conn->security_state.auth_info,
642 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
643 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
644 c->status = ndr_map_error2ntstatus(ndr_err);
645 if (!composite_is_ok(c)) return;
649 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
655 handle timeouts of individual dcerpc requests
657 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
658 struct timeval t, void *private)
660 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
662 if (req->ignore_timeout) {
663 dcerpc_req_dequeue(req);
664 req->state = RPC_REQUEST_DONE;
665 req->status = NT_STATUS_IO_TIMEOUT;
666 if (req->async.callback) {
667 req->async.callback(req);
672 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
676 send a async dcerpc bind request
678 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
680 const struct ndr_syntax_id *syntax,
681 const struct ndr_syntax_id *transfer_syntax)
683 struct composite_context *c;
684 struct ncacn_packet pkt;
686 struct rpc_request *req;
688 c = composite_create(mem_ctx,p->conn->event_ctx);
689 if (c == NULL) return NULL;
694 p->transfer_syntax = *transfer_syntax;
696 init_ncacn_hdr(p->conn, &pkt);
698 pkt.ptype = DCERPC_PKT_BIND;
699 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
700 pkt.call_id = p->conn->call_id;
703 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
704 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
707 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
708 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
711 pkt.u.bind.max_xmit_frag = 5840;
712 pkt.u.bind.max_recv_frag = 5840;
713 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
714 pkt.u.bind.num_contexts = 1;
715 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
716 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
717 pkt.u.bind.ctx_list[0].context_id = p->context_id;
718 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
719 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
720 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
721 pkt.u.bind.auth_info = data_blob(NULL, 0);
723 /* construct the NDR form of the packet */
724 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
725 p->conn->security_state.auth_info);
726 if (!composite_is_ok(c)) return c;
728 p->conn->transport.recv_data = dcerpc_recv_data;
731 * we allocate a dcerpc_request so we can be in the same
732 * request queue as normal requests
734 req = talloc_zero(c, struct rpc_request);
735 if (composite_nomem(req, c)) return c;
737 req->state = RPC_REQUEST_PENDING;
738 req->call_id = pkt.call_id;
739 req->async.private_data = c;
740 req->async.callback = dcerpc_composite_fail;
742 req->recv_handler = dcerpc_bind_recv_handler;
743 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
744 talloc_set_destructor(req, dcerpc_req_dequeue);
746 c->status = p->conn->transport.send_request(p->conn, &blob,
748 if (!composite_is_ok(c)) return c;
750 event_add_timed(c->event_ctx, req,
751 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
752 dcerpc_timeout_handler, req);
758 recv side of async dcerpc bind request
760 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
762 NTSTATUS result = composite_wait(ctx);
768 perform a continued bind (and auth3)
770 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
773 struct ncacn_packet pkt;
777 init_ncacn_hdr(p->conn, &pkt);
779 pkt.ptype = DCERPC_PKT_AUTH3;
780 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
781 pkt.call_id = next_call_id(p->conn);
783 pkt.u.auth3._pad = 0;
784 pkt.u.auth3.auth_info = data_blob(NULL, 0);
786 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
787 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
790 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
791 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
794 /* construct the NDR form of the packet */
795 status = ncacn_push_auth(&blob, mem_ctx,
796 p->conn->iconv_convenience,
798 p->conn->security_state.auth_info);
799 if (!NT_STATUS_IS_OK(status)) {
803 /* send it on its way */
804 status = p->conn->transport.send_request(p->conn, &blob, false);
805 if (!NT_STATUS_IS_OK(status)) {
814 process a fragment received from the transport layer during a
817 This function frees the data
819 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
820 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
822 struct rpc_request *req;
824 NTSTATUS status = NT_STATUS_OK;
827 if this is an authenticated connection then parse and check
828 the auth info. We have to do this before finding the
829 matching packet, as the request structure might have been
830 removed due to a timeout, but if it has been we still need
831 to run the auth routines so that we don't get the sign/seal
832 info out of step with the server
834 if (c->security_state.auth_info && c->security_state.generic_state &&
835 pkt->ptype == DCERPC_PKT_RESPONSE) {
836 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
839 /* find the matching request */
840 for (req=c->pending;req;req=req->next) {
841 if (pkt->call_id == req->call_id) break;
845 /* useful for testing certain vendors RPC servers */
846 if (req == NULL && c->pending && pkt->call_id == 0) {
847 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
853 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
854 data_blob_free(raw_packet);
858 talloc_steal(req, raw_packet->data);
860 if (req->recv_handler != NULL) {
861 dcerpc_req_dequeue(req);
862 req->state = RPC_REQUEST_DONE;
863 req->recv_handler(req, raw_packet, pkt);
867 if (pkt->ptype == DCERPC_PKT_FAULT) {
868 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
869 req->fault_code = pkt->u.fault.status;
870 req->status = NT_STATUS_NET_WRITE_FAULT;
874 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
875 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
877 req->fault_code = DCERPC_FAULT_OTHER;
878 req->status = NT_STATUS_NET_WRITE_FAULT;
882 /* now check the status from the auth routines, and if it failed then fail
883 this request accordingly */
884 if (!NT_STATUS_IS_OK(status)) {
885 req->status = status;
889 length = pkt->u.response.stub_and_verifier.length;
892 req->payload.data = talloc_realloc(req,
895 req->payload.length + length);
896 if (!req->payload.data) {
897 req->status = NT_STATUS_NO_MEMORY;
900 memcpy(req->payload.data+req->payload.length,
901 pkt->u.response.stub_and_verifier.data, length);
902 req->payload.length += length;
905 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
906 c->transport.send_read(c);
910 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
911 req->flags |= DCERPC_PULL_BIGENDIAN;
913 req->flags &= ~DCERPC_PULL_BIGENDIAN;
918 /* we've got the full payload */
919 req->state = RPC_REQUEST_DONE;
920 DLIST_REMOVE(c->pending, req);
922 if (c->request_queue != NULL) {
923 /* We have to look at shipping further requests before calling
924 * the async function, that one might close the pipe */
925 dcerpc_ship_next_request(c);
928 if (req->async.callback) {
929 req->async.callback(req);
934 perform the send side of a async dcerpc request
936 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
937 const struct GUID *object,
940 DATA_BLOB *stub_data)
942 struct rpc_request *req;
944 p->conn->transport.recv_data = dcerpc_recv_data;
946 req = talloc(p, struct rpc_request);
952 req->call_id = next_call_id(p->conn);
953 req->status = NT_STATUS_OK;
954 req->state = RPC_REQUEST_QUEUED;
955 req->payload = data_blob(NULL, 0);
958 req->async_call = async;
959 req->ignore_timeout = false;
960 req->async.callback = NULL;
961 req->async.private_data = NULL;
962 req->recv_handler = NULL;
964 if (object != NULL) {
965 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
966 if (req->object == NULL) {
975 req->request_data.length = stub_data->length;
976 req->request_data.data = talloc_reference(req, stub_data->data);
977 if (req->request_data.length && req->request_data.data == NULL) {
981 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
982 talloc_set_destructor(req, dcerpc_req_dequeue);
984 dcerpc_ship_next_request(p->conn);
986 if (p->request_timeout) {
987 event_add_timed(dcerpc_event_context(p), req,
988 timeval_current_ofs(p->request_timeout, 0),
989 dcerpc_timeout_handler, req);
996 Send a request using the transport
999 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1001 struct rpc_request *req;
1002 struct dcerpc_pipe *p;
1003 DATA_BLOB *stub_data;
1004 struct ncacn_packet pkt;
1006 uint32_t remaining, chunk_size;
1007 bool first_packet = true;
1008 size_t sig_size = 0;
1010 req = c->request_queue;
1016 stub_data = &req->request_data;
1018 if (!req->async_call && (c->pending != NULL)) {
1022 DLIST_REMOVE(c->request_queue, req);
1023 DLIST_ADD(c->pending, req);
1024 req->state = RPC_REQUEST_PENDING;
1026 init_ncacn_hdr(p->conn, &pkt);
1028 remaining = stub_data->length;
1030 /* we can write a full max_recv_frag size, minus the dcerpc
1031 request header size */
1032 chunk_size = p->conn->srv_max_recv_frag;
1033 chunk_size -= DCERPC_REQUEST_LENGTH;
1034 if (c->security_state.auth_info &&
1035 c->security_state.generic_state) {
1036 sig_size = gensec_sig_size(c->security_state.generic_state,
1037 p->conn->srv_max_recv_frag);
1039 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1040 chunk_size -= sig_size;
1043 chunk_size -= (chunk_size % 16);
1045 pkt.ptype = DCERPC_PKT_REQUEST;
1046 pkt.call_id = req->call_id;
1047 pkt.auth_length = 0;
1049 pkt.u.request.alloc_hint = remaining;
1050 pkt.u.request.context_id = p->context_id;
1051 pkt.u.request.opnum = req->opnum;
1054 pkt.u.request.object.object = *req->object;
1055 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1056 chunk_size -= ndr_size_GUID(req->object,0);
1059 /* we send a series of pdus without waiting for a reply */
1060 while (remaining > 0 || first_packet) {
1061 uint32_t chunk = MIN(chunk_size, remaining);
1062 bool last_frag = false;
1064 first_packet = false;
1065 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1067 if (remaining == stub_data->length) {
1068 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1070 if (chunk == remaining) {
1071 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1075 pkt.u.request.stub_and_verifier.data = stub_data->data +
1076 (stub_data->length - remaining);
1077 pkt.u.request.stub_and_verifier.length = chunk;
1079 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1080 if (!NT_STATUS_IS_OK(req->status)) {
1081 req->state = RPC_REQUEST_DONE;
1082 DLIST_REMOVE(p->conn->pending, req);
1086 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1087 if (!NT_STATUS_IS_OK(req->status)) {
1088 req->state = RPC_REQUEST_DONE;
1089 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 event_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 event_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;
1136 perform a full request/response pair on a dcerpc pipe
1138 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1139 struct GUID *object,
1142 TALLOC_CTX *mem_ctx,
1143 DATA_BLOB *stub_data_in,
1144 DATA_BLOB *stub_data_out)
1146 struct rpc_request *req;
1148 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1150 return NT_STATUS_NO_MEMORY;
1153 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1158 this is a paranoid NDR validator. For every packet we push onto the wire
1159 we pull it back again, then push it again. Then we compare the raw NDR data
1160 for that to the NDR we initially generated. If they don't match then we know
1161 we must have a bug in either the pull or push side of our code
1163 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1164 TALLOC_CTX *mem_ctx,
1167 ndr_push_flags_fn_t ndr_push,
1168 ndr_pull_flags_fn_t ndr_pull)
1171 struct ndr_pull *pull;
1172 struct ndr_push *push;
1174 enum ndr_err_code ndr_err;
1176 st = talloc_size(mem_ctx, struct_size);
1178 return NT_STATUS_NO_MEMORY;
1181 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1183 return NT_STATUS_NO_MEMORY;
1185 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1187 ndr_err = ndr_pull(pull, NDR_IN, st);
1188 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1189 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1190 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1191 "failed input validation pull - %s",
1193 return ndr_map_error2ntstatus(ndr_err);
1196 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1198 return NT_STATUS_NO_MEMORY;
1201 ndr_err = ndr_push(push, NDR_IN, st);
1202 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1203 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1204 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1205 "failed input validation push - %s",
1207 return ndr_map_error2ntstatus(ndr_err);
1210 blob2 = ndr_push_blob(push);
1212 if (data_blob_cmp(&blob, &blob2) != 0) {
1213 DEBUG(3,("original:\n"));
1214 dump_data(3, blob.data, blob.length);
1215 DEBUG(3,("secondary:\n"));
1216 dump_data(3, blob2.data, blob2.length);
1217 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1218 "failed input validation blobs doesn't match");
1219 return ndr_map_error2ntstatus(ndr_err);
1222 return NT_STATUS_OK;
1226 this is a paranoid NDR input validator. For every packet we pull
1227 from the wire we push it back again then pull and push it
1228 again. Then we compare the raw NDR data for that to the NDR we
1229 initially generated. If they don't match then we know we must have a
1230 bug in either the pull or push side of our code
1232 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1233 struct ndr_pull *pull_in,
1236 ndr_push_flags_fn_t ndr_push,
1237 ndr_pull_flags_fn_t ndr_pull,
1238 ndr_print_function_t ndr_print)
1241 struct ndr_pull *pull;
1242 struct ndr_push *push;
1243 DATA_BLOB blob, blob2;
1244 TALLOC_CTX *mem_ctx = pull_in;
1246 enum ndr_err_code ndr_err;
1248 st = talloc_size(mem_ctx, struct_size);
1250 return NT_STATUS_NO_MEMORY;
1252 memcpy(st, struct_ptr, struct_size);
1254 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1256 return NT_STATUS_NO_MEMORY;
1259 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1260 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1261 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1262 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1263 "failed output validation push - %s",
1265 return ndr_map_error2ntstatus(ndr_err);
1268 blob = ndr_push_blob(push);
1270 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1272 return NT_STATUS_NO_MEMORY;
1275 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1276 ndr_err = ndr_pull(pull, NDR_OUT, st);
1277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1278 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1279 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1280 "failed output validation pull - %s",
1282 return ndr_map_error2ntstatus(ndr_err);
1285 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1287 return NT_STATUS_NO_MEMORY;
1290 ndr_err = ndr_push(push, NDR_OUT, st);
1291 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1292 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1293 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1294 "failed output validation push2 - %s",
1296 return ndr_map_error2ntstatus(ndr_err);
1299 blob2 = ndr_push_blob(push);
1301 if (data_blob_cmp(&blob, &blob2) != 0) {
1302 DEBUG(3,("original:\n"));
1303 dump_data(3, blob.data, blob.length);
1304 DEBUG(3,("secondary:\n"));
1305 dump_data(3, blob2.data, blob2.length);
1306 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1307 "failed output validation blobs doesn't match");
1308 return ndr_map_error2ntstatus(ndr_err);
1311 /* this checks the printed forms of the two structures, which effectively
1312 tests all of the value() attributes */
1313 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1314 NDR_OUT, struct_ptr);
1315 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1317 if (strcmp(s1, s2) != 0) {
1319 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1321 /* this is sometimes useful */
1322 printf("VALIDATE ERROR\n");
1323 file_save("wire.dat", s1, strlen(s1));
1324 file_save("gen.dat", s2, strlen(s2));
1325 system("diff -u wire.dat gen.dat");
1327 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1328 "failed output validation strings doesn't match");
1329 return ndr_map_error2ntstatus(ndr_err);
1332 return NT_STATUS_OK;
1337 send a rpc request given a dcerpc_call structure
1339 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1340 const struct GUID *object,
1341 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 /* push the structure into a blob */
1366 ndr_err = call->ndr_push(push, NDR_IN, r);
1367 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1368 status = ndr_map_error2ntstatus(ndr_err);
1369 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1370 nt_errstr(status)));
1375 /* retrieve the blob */
1376 request = ndr_push_blob(push);
1378 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1379 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1380 call->ndr_push, call->ndr_pull);
1381 if (!NT_STATUS_IS_OK(status)) {
1382 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1383 nt_errstr(status)));
1389 DEBUG(10,("rpc request data:\n"));
1390 dump_data(10, request.data, request.length);
1392 /* make the actual dcerpc request */
1393 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1397 req->ndr.table = table;
1398 req->ndr.opnum = opnum;
1399 req->ndr.struct_ptr = r;
1400 req->ndr.mem_ctx = mem_ctx;
1409 receive the answer from a dcerpc_ndr_request_send()
1411 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1413 struct dcerpc_pipe *p = req->p;
1416 struct ndr_pull *pull;
1418 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1419 void *r = req->ndr.struct_ptr;
1420 uint32_t opnum = req->ndr.opnum;
1421 const struct ndr_interface_table *table = req->ndr.table;
1422 const struct ndr_interface_call *call = &table->calls[opnum];
1423 enum ndr_err_code ndr_err;
1425 /* make sure the recv code doesn't free the request, as we
1426 need to grab the flags element before it is freed */
1427 if (talloc_reference(p, req) == NULL) {
1428 return NT_STATUS_NO_MEMORY;
1431 status = dcerpc_request_recv(req, mem_ctx, &response);
1432 if (!NT_STATUS_IS_OK(status)) {
1433 talloc_unlink(p, req);
1439 /* prepare for ndr_pull_* */
1440 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1442 talloc_unlink(p, req);
1443 return NT_STATUS_NO_MEMORY;
1447 pull->data = talloc_steal(pull, pull->data);
1449 talloc_unlink(p, req);
1451 if (flags & DCERPC_PULL_BIGENDIAN) {
1452 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1455 DEBUG(10,("rpc reply data:\n"));
1456 dump_data(10, pull->data, pull->data_size);
1458 /* pull the structure from the blob */
1459 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1460 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1461 status = ndr_map_error2ntstatus(ndr_err);
1462 dcerpc_log_packet(table, opnum, NDR_OUT,
1467 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1468 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1469 call->ndr_push, call->ndr_pull,
1471 if (!NT_STATUS_IS_OK(status)) {
1472 dcerpc_log_packet(table, opnum, NDR_OUT,
1478 if (pull->offset != pull->data_size) {
1479 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1480 pull->data_size - pull->offset));
1481 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1482 but it turns out that early versions of NT
1483 (specifically NT3.1) add junk onto the end of rpc
1484 packets, so if we want to interoperate at all with
1485 those versions then we need to ignore this error */
1488 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1490 return NT_STATUS_OK;
1495 a useful helper function for synchronous rpc requests
1497 this can be used when you have ndr push/pull functions in the
1500 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1501 const struct GUID *object,
1502 const struct ndr_interface_table *table,
1504 TALLOC_CTX *mem_ctx,
1507 struct rpc_request *req;
1509 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1511 return NT_STATUS_NO_MEMORY;
1514 return dcerpc_ndr_request_recv(req);
1519 a useful function for retrieving the server name we connected to
1521 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1523 if (!p->conn->transport.target_hostname) {
1524 if (!p->conn->transport.peer_name) {
1527 return p->conn->transport.peer_name(p->conn);
1529 return p->conn->transport.target_hostname(p->conn);
1534 get the dcerpc auth_level for a open connection
1536 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1540 if (c->flags & DCERPC_SEAL) {
1541 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1542 } else if (c->flags & DCERPC_SIGN) {
1543 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1544 } else if (c->flags & DCERPC_CONNECT) {
1545 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1547 auth_level = DCERPC_AUTH_LEVEL_NONE;
1553 Receive an alter reply from the transport
1555 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1556 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1558 struct composite_context *c;
1559 struct dcerpc_pipe *recv_pipe;
1561 c = talloc_get_type(req->async.private_data, struct composite_context);
1562 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1564 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1565 pkt->u.alter_resp.num_results == 1 &&
1566 pkt->u.alter_resp.ctx_list[0].result != 0) {
1567 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1568 pkt->u.alter_resp.ctx_list[0].reason));
1569 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1573 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1574 pkt->u.alter_resp.num_results == 0 ||
1575 pkt->u.alter_resp.ctx_list[0].result != 0) {
1576 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1580 /* the alter_resp might contain a reply set of credentials */
1581 if (recv_pipe->conn->security_state.auth_info &&
1582 pkt->u.alter_resp.auth_info.length) {
1583 enum ndr_err_code ndr_err;
1584 ndr_err = ndr_pull_struct_blob(
1585 &pkt->u.alter_resp.auth_info, recv_pipe,
1587 recv_pipe->conn->security_state.auth_info,
1588 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1589 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1590 c->status = ndr_map_error2ntstatus(ndr_err);
1591 if (!composite_is_ok(c)) return;
1599 send a dcerpc alter_context request
1601 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1602 TALLOC_CTX *mem_ctx,
1603 const struct ndr_syntax_id *syntax,
1604 const struct ndr_syntax_id *transfer_syntax)
1606 struct composite_context *c;
1607 struct ncacn_packet pkt;
1609 struct rpc_request *req;
1611 c = composite_create(mem_ctx, p->conn->event_ctx);
1612 if (c == NULL) return NULL;
1614 c->private_data = p;
1616 p->syntax = *syntax;
1617 p->transfer_syntax = *transfer_syntax;
1619 init_ncacn_hdr(p->conn, &pkt);
1621 pkt.ptype = DCERPC_PKT_ALTER;
1622 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1623 pkt.call_id = p->conn->call_id;
1624 pkt.auth_length = 0;
1626 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1627 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1630 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1631 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1634 pkt.u.alter.max_xmit_frag = 5840;
1635 pkt.u.alter.max_recv_frag = 5840;
1636 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1637 pkt.u.alter.num_contexts = 1;
1638 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1639 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1640 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1641 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1642 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1643 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1644 pkt.u.alter.auth_info = data_blob(NULL, 0);
1646 /* construct the NDR form of the packet */
1647 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1648 p->conn->security_state.auth_info);
1649 if (!composite_is_ok(c)) return c;
1651 p->conn->transport.recv_data = dcerpc_recv_data;
1654 * we allocate a dcerpc_request so we can be in the same
1655 * request queue as normal requests
1657 req = talloc_zero(c, struct rpc_request);
1658 if (composite_nomem(req, c)) return c;
1660 req->state = RPC_REQUEST_PENDING;
1661 req->call_id = pkt.call_id;
1662 req->async.private_data = c;
1663 req->async.callback = dcerpc_composite_fail;
1665 req->recv_handler = dcerpc_alter_recv_handler;
1666 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1667 talloc_set_destructor(req, dcerpc_req_dequeue);
1669 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1670 if (!composite_is_ok(c)) return c;
1672 event_add_timed(c->event_ctx, req,
1673 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1674 dcerpc_timeout_handler, req);
1679 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1681 NTSTATUS result = composite_wait(ctx);
1687 send a dcerpc alter_context request
1689 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1690 TALLOC_CTX *mem_ctx,
1691 const struct ndr_syntax_id *syntax,
1692 const struct ndr_syntax_id *transfer_syntax)
1694 struct composite_context *creq;
1695 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1696 return dcerpc_alter_context_recv(creq);