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);
71 ev = event_context_init(c);
78 c->iconv_convenience = talloc_reference(c, ic);
82 if (!talloc_reference(c, ev)) {
87 c->security_state.auth_info = NULL;
88 c->security_state.session_key = dcerpc_generic_session_key;
89 c->security_state.generic_state = NULL;
90 c->binding_string = NULL;
92 c->srv_max_xmit_frag = 0;
93 c->srv_max_recv_frag = 0;
96 talloc_set_destructor(c, dcerpc_connection_destructor);
101 /* initialise a dcerpc pipe. */
102 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev,
103 struct smb_iconv_convenience *ic)
105 struct dcerpc_pipe *p;
107 p = talloc(mem_ctx, struct dcerpc_pipe);
112 p->conn = dcerpc_connection_init(p, ev, ic);
113 if (p->conn == NULL) {
118 p->last_fault_code = 0;
120 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
123 ZERO_STRUCT(p->syntax);
124 ZERO_STRUCT(p->transfer_syntax);
131 choose the next call id to use
133 static uint32_t next_call_id(struct dcerpc_connection *c)
136 if (c->call_id == 0) {
142 /* we need to be able to get/set the fragment length without doing a full
144 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
146 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
147 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
149 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
153 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
155 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
156 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
158 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
162 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
164 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
165 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
167 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
173 setup for a ndr pull, also setting up any flags from the binding string
175 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
176 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
178 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
180 if (ndr == NULL) return ndr;
182 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
183 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
186 if (c->flags & DCERPC_NDR_REF_ALLOC) {
187 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
194 parse a data blob into a ncacn_packet structure. This handles both
195 input and output packets
197 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
198 struct ncacn_packet *pkt)
200 struct ndr_pull *ndr;
201 enum ndr_err_code ndr_err;
203 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
205 return NT_STATUS_NO_MEMORY;
208 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
209 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
212 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
213 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
214 return ndr_map_error2ntstatus(ndr_err);
221 generate a CONNECT level verifier
223 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
225 *blob = data_blob_talloc(mem_ctx, NULL, 16);
226 if (blob->data == NULL) {
227 return NT_STATUS_NO_MEMORY;
229 SIVAL(blob->data, 0, 1);
230 memset(blob->data+4, 0, 12);
235 check a CONNECT level verifier
237 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
239 if (blob->length != 16 ||
240 IVAL(blob->data, 0) != 1) {
241 return NT_STATUS_ACCESS_DENIED;
247 parse the authentication information on a dcerpc response packet
249 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
250 DATA_BLOB *raw_packet,
251 struct ncacn_packet *pkt)
253 struct ndr_pull *ndr;
255 struct dcerpc_auth auth;
257 enum ndr_err_code ndr_err;
259 if (pkt->auth_length == 0 &&
260 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
264 auth_blob.length = 8 + pkt->auth_length;
266 /* check for a valid length */
267 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
268 return NT_STATUS_INFO_LENGTH_MISMATCH;
272 pkt->u.response.stub_and_verifier.data +
273 pkt->u.response.stub_and_verifier.length - auth_blob.length;
274 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
276 /* pull the auth structure */
277 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
279 return NT_STATUS_NO_MEMORY;
282 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
283 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
286 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
287 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
288 return ndr_map_error2ntstatus(ndr_err);
290 status = NT_STATUS_OK;
292 /* check signature or unseal the packet */
293 switch (c->security_state.auth_info->auth_level) {
294 case DCERPC_AUTH_LEVEL_PRIVACY:
295 status = gensec_unseal_packet(c->security_state.generic_state,
297 raw_packet->data + DCERPC_REQUEST_LENGTH,
298 pkt->u.response.stub_and_verifier.length,
300 raw_packet->length - auth.credentials.length,
302 memcpy(pkt->u.response.stub_and_verifier.data,
303 raw_packet->data + DCERPC_REQUEST_LENGTH,
304 pkt->u.response.stub_and_verifier.length);
307 case DCERPC_AUTH_LEVEL_INTEGRITY:
308 status = gensec_check_packet(c->security_state.generic_state,
310 pkt->u.response.stub_and_verifier.data,
311 pkt->u.response.stub_and_verifier.length,
313 raw_packet->length - auth.credentials.length,
317 case DCERPC_AUTH_LEVEL_CONNECT:
318 status = dcerpc_check_connect_verifier(&auth.credentials);
321 case DCERPC_AUTH_LEVEL_NONE:
325 status = NT_STATUS_INVALID_LEVEL;
329 /* remove the indicated amount of paddiing */
330 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
331 return NT_STATUS_INFO_LENGTH_MISMATCH;
333 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
340 push a dcerpc request packet into a blob, possibly signing it.
342 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
343 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
344 struct ncacn_packet *pkt)
347 struct ndr_push *ndr;
349 size_t payload_length;
350 enum ndr_err_code ndr_err;
352 /* non-signed packets are simpler */
353 if (!c->security_state.auth_info ||
354 !c->security_state.generic_state) {
355 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, c->security_state.auth_info);
358 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
360 return NT_STATUS_NO_MEMORY;
363 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
364 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
367 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
368 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
371 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
372 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
373 return ndr_map_error2ntstatus(ndr_err);
375 status = NT_STATUS_OK;
377 /* pad to 16 byte multiple in the payload portion of the
378 packet. This matches what w2k3 does */
379 c->security_state.auth_info->auth_pad_length =
380 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
381 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
383 payload_length = pkt->u.request.stub_and_verifier.length +
384 c->security_state.auth_info->auth_pad_length;
386 /* sign or seal the packet */
387 switch (c->security_state.auth_info->auth_level) {
388 case DCERPC_AUTH_LEVEL_PRIVACY:
389 case DCERPC_AUTH_LEVEL_INTEGRITY:
390 /* We hope this length is accruate. If must be if the
391 * GENSEC mech does AEAD signing of the packet
393 c->security_state.auth_info->credentials
394 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
396 data_blob_clear(&c->security_state.auth_info->credentials);
399 case DCERPC_AUTH_LEVEL_CONNECT:
400 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
403 case DCERPC_AUTH_LEVEL_NONE:
404 c->security_state.auth_info->credentials = data_blob(NULL, 0);
408 status = NT_STATUS_INVALID_LEVEL;
412 if (!NT_STATUS_IS_OK(status)) {
416 /* add the auth verifier */
417 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
418 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
419 return ndr_map_error2ntstatus(ndr_err);
421 status = NT_STATUS_OK;
423 /* extract the whole packet as a blob */
424 *blob = ndr_push_blob(ndr);
426 /* fill in the fragment length and auth_length, we can't fill
427 in these earlier as we don't know the signature length (it
428 could be variable length) */
429 dcerpc_set_frag_length(blob, blob->length);
430 /* We hope this value is accruate. If must be if the GENSEC
431 * mech does AEAD signing of the packet headers */
432 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
434 /* sign or seal the packet */
435 switch (c->security_state.auth_info->auth_level) {
436 case DCERPC_AUTH_LEVEL_PRIVACY:
437 status = gensec_seal_packet(c->security_state.generic_state,
439 blob->data + DCERPC_REQUEST_LENGTH,
443 c->security_state.auth_info->credentials.length,
445 if (!NT_STATUS_IS_OK(status)) {
448 blob->length -= c->security_state.auth_info->credentials.length;
449 if (!data_blob_append(mem_ctx, blob,
450 creds2.data, creds2.length)) {
451 return NT_STATUS_NO_MEMORY;
453 dcerpc_set_auth_length(blob, creds2.length);
454 if (c->security_state.auth_info->credentials.length == 0) {
455 /* this is needed for krb5 only, to correct the total packet
457 dcerpc_set_frag_length(blob,
458 dcerpc_get_frag_length(blob)
463 case DCERPC_AUTH_LEVEL_INTEGRITY:
464 status = gensec_sign_packet(c->security_state.generic_state,
466 blob->data + DCERPC_REQUEST_LENGTH,
470 c->security_state.auth_info->credentials.length,
472 if (!NT_STATUS_IS_OK(status)) {
475 blob->length -= c->security_state.auth_info->credentials.length;
476 if (!data_blob_append(mem_ctx, blob,
477 creds2.data, creds2.length)) {
478 return NT_STATUS_NO_MEMORY;
480 dcerpc_set_auth_length(blob, creds2.length);
481 if (c->security_state.auth_info->credentials.length == 0) {
482 /* this is needed for krb5 only, to correct the total packet
484 dcerpc_set_frag_length(blob,
485 dcerpc_get_frag_length(blob)
490 case DCERPC_AUTH_LEVEL_CONNECT:
493 case DCERPC_AUTH_LEVEL_NONE:
494 c->security_state.auth_info->credentials = data_blob(NULL, 0);
498 status = NT_STATUS_INVALID_LEVEL;
502 data_blob_free(&c->security_state.auth_info->credentials);
509 fill in the fixed values in a dcerpc header
511 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
514 pkt->rpc_vers_minor = 0;
515 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
518 pkt->drep[0] = DCERPC_DREP_LE;
526 map a bind nak reason to a NTSTATUS
528 static NTSTATUS dcerpc_map_reason(uint16_t reason)
531 case DCERPC_BIND_REASON_ASYNTAX:
532 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
533 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
534 return NT_STATUS_INVALID_PARAMETER;
536 return NT_STATUS_UNSUCCESSFUL;
540 a bind or alter context has failed
542 static void dcerpc_composite_fail(struct rpc_request *req)
544 struct composite_context *c = talloc_get_type(req->async.private_data,
545 struct composite_context);
546 composite_error(c, req->status);
550 remove requests from the pending or queued queues
552 static int dcerpc_req_dequeue(struct rpc_request *req)
554 switch (req->state) {
555 case RPC_REQUEST_QUEUED:
556 DLIST_REMOVE(req->p->conn->request_queue, req);
558 case RPC_REQUEST_PENDING:
559 DLIST_REMOVE(req->p->conn->pending, req);
561 case RPC_REQUEST_DONE:
569 mark the dcerpc connection dead. All outstanding requests get an error
571 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
573 if (conn->dead) return;
577 if (conn->transport.shutdown_pipe) {
578 conn->transport.shutdown_pipe(conn, status);
581 /* all pending requests get the error */
582 while (conn->pending) {
583 struct rpc_request *req = conn->pending;
584 dcerpc_req_dequeue(req);
585 req->state = RPC_REQUEST_DONE;
586 req->status = status;
587 if (req->async.callback) {
588 req->async.callback(req);
592 talloc_set_destructor(conn, NULL);
593 if (conn->free_skipped) {
599 forward declarations of the recv_data handlers for the types of
600 packets we need to handle
602 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
603 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
606 receive a dcerpc reply from the transport. Here we work out what
607 type of reply it is (normal request, bind or alter context) and
608 dispatch to the appropriate handler
610 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
612 struct ncacn_packet pkt;
614 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
615 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
618 /* the transport may be telling us of a severe error, such as
620 if (!NT_STATUS_IS_OK(status)) {
621 data_blob_free(blob);
622 dcerpc_connection_dead(conn, status);
626 /* parse the basic packet to work out what type of response this is */
627 status = ncacn_pull(conn, blob, blob->data, &pkt);
628 if (!NT_STATUS_IS_OK(status)) {
629 data_blob_free(blob);
630 dcerpc_connection_dead(conn, status);
633 dcerpc_request_recv_data(conn, blob, &pkt);
638 Receive a bind reply from the transport
640 static void dcerpc_bind_recv_handler(struct rpc_request *req,
641 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
643 struct composite_context *c;
644 struct dcerpc_connection *conn;
646 c = talloc_get_type(req->async.private_data, struct composite_context);
648 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
649 DEBUG(2,("dcerpc: bind_nak reason %d\n",
650 pkt->u.bind_nak.reject_reason));
651 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
656 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
657 (pkt->u.bind_ack.num_results == 0) ||
658 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
659 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
665 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
666 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
668 /* the bind_ack might contain a reply set of credentials */
669 if (conn->security_state.auth_info &&
670 pkt->u.bind_ack.auth_info.length) {
671 enum ndr_err_code ndr_err;
672 ndr_err = ndr_pull_struct_blob(
673 &pkt->u.bind_ack.auth_info, conn,
675 conn->security_state.auth_info,
676 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
677 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
678 c->status = ndr_map_error2ntstatus(ndr_err);
679 if (!composite_is_ok(c)) return;
683 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
689 handle timeouts of individual dcerpc requests
691 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
692 struct timeval t, void *private)
694 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
696 if (req->ignore_timeout) {
697 dcerpc_req_dequeue(req);
698 req->state = RPC_REQUEST_DONE;
699 req->status = NT_STATUS_IO_TIMEOUT;
700 if (req->async.callback) {
701 req->async.callback(req);
706 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
710 send a async dcerpc bind request
712 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
714 const struct ndr_syntax_id *syntax,
715 const struct ndr_syntax_id *transfer_syntax)
717 struct composite_context *c;
718 struct ncacn_packet pkt;
720 struct rpc_request *req;
722 c = composite_create(mem_ctx,p->conn->event_ctx);
723 if (c == NULL) return NULL;
728 p->transfer_syntax = *transfer_syntax;
730 init_ncacn_hdr(p->conn, &pkt);
732 pkt.ptype = DCERPC_PKT_BIND;
733 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
734 pkt.call_id = p->conn->call_id;
737 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
738 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
741 pkt.u.bind.max_xmit_frag = 5840;
742 pkt.u.bind.max_recv_frag = 5840;
743 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
744 pkt.u.bind.num_contexts = 1;
745 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
746 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
747 pkt.u.bind.ctx_list[0].context_id = p->context_id;
748 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
749 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
750 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
751 pkt.u.bind.auth_info = data_blob(NULL, 0);
753 /* construct the NDR form of the packet */
754 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
755 p->conn->security_state.auth_info);
756 if (!composite_is_ok(c)) return c;
758 p->conn->transport.recv_data = dcerpc_recv_data;
761 * we allocate a dcerpc_request so we can be in the same
762 * request queue as normal requests
764 req = talloc_zero(c, struct rpc_request);
765 if (composite_nomem(req, c)) return c;
767 req->state = RPC_REQUEST_PENDING;
768 req->call_id = pkt.call_id;
769 req->async.private_data = c;
770 req->async.callback = dcerpc_composite_fail;
772 req->recv_handler = dcerpc_bind_recv_handler;
773 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
774 talloc_set_destructor(req, dcerpc_req_dequeue);
776 c->status = p->conn->transport.send_request(p->conn, &blob,
778 if (!composite_is_ok(c)) return c;
780 event_add_timed(c->event_ctx, req,
781 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
782 dcerpc_timeout_handler, req);
788 recv side of async dcerpc bind request
790 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
792 NTSTATUS result = composite_wait(ctx);
798 perform a continued bind (and auth3)
800 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
803 struct ncacn_packet pkt;
807 init_ncacn_hdr(c, &pkt);
809 pkt.ptype = DCERPC_PKT_AUTH3;
810 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
811 pkt.call_id = next_call_id(c);
813 pkt.u.auth3._pad = 0;
814 pkt.u.auth3.auth_info = data_blob(NULL, 0);
816 /* construct the NDR form of the packet */
817 status = ncacn_push_auth(&blob, mem_ctx, c->iconv_convenience, &pkt, c->security_state.auth_info);
818 if (!NT_STATUS_IS_OK(status)) {
822 /* send it on its way */
823 status = c->transport.send_request(c, &blob, false);
824 if (!NT_STATUS_IS_OK(status)) {
833 process a fragment received from the transport layer during a
836 This function frees the data
838 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
839 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
841 struct rpc_request *req;
843 NTSTATUS status = NT_STATUS_OK;
846 if this is an authenticated connection then parse and check
847 the auth info. We have to do this before finding the
848 matching packet, as the request structure might have been
849 removed due to a timeout, but if it has been we still need
850 to run the auth routines so that we don't get the sign/seal
851 info out of step with the server
853 if (c->security_state.auth_info && c->security_state.generic_state &&
854 pkt->ptype == DCERPC_PKT_RESPONSE) {
855 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
858 /* find the matching request */
859 for (req=c->pending;req;req=req->next) {
860 if (pkt->call_id == req->call_id) break;
864 /* useful for testing certain vendors RPC servers */
865 if (req == NULL && c->pending && pkt->call_id == 0) {
866 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
872 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
873 data_blob_free(raw_packet);
877 talloc_steal(req, raw_packet->data);
879 if (req->recv_handler != NULL) {
880 dcerpc_req_dequeue(req);
881 req->state = RPC_REQUEST_DONE;
882 req->recv_handler(req, raw_packet, pkt);
886 if (pkt->ptype == DCERPC_PKT_FAULT) {
887 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
888 req->fault_code = pkt->u.fault.status;
889 req->status = NT_STATUS_NET_WRITE_FAULT;
893 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
894 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
896 req->fault_code = DCERPC_FAULT_OTHER;
897 req->status = NT_STATUS_NET_WRITE_FAULT;
901 /* now check the status from the auth routines, and if it failed then fail
902 this request accordingly */
903 if (!NT_STATUS_IS_OK(status)) {
904 req->status = status;
908 length = pkt->u.response.stub_and_verifier.length;
911 req->payload.data = talloc_realloc(req,
914 req->payload.length + length);
915 if (!req->payload.data) {
916 req->status = NT_STATUS_NO_MEMORY;
919 memcpy(req->payload.data+req->payload.length,
920 pkt->u.response.stub_and_verifier.data, length);
921 req->payload.length += length;
924 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
925 c->transport.send_read(c);
929 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
930 req->flags |= DCERPC_PULL_BIGENDIAN;
932 req->flags &= ~DCERPC_PULL_BIGENDIAN;
937 /* we've got the full payload */
938 req->state = RPC_REQUEST_DONE;
939 DLIST_REMOVE(c->pending, req);
941 if (c->request_queue != NULL) {
942 /* We have to look at shipping further requests before calling
943 * the async function, that one might close the pipe */
944 dcerpc_ship_next_request(c);
947 if (req->async.callback) {
948 req->async.callback(req);
953 perform the send side of a async dcerpc request
955 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
956 const struct GUID *object,
959 DATA_BLOB *stub_data)
961 struct rpc_request *req;
963 p->conn->transport.recv_data = dcerpc_recv_data;
965 req = talloc(p, struct rpc_request);
971 req->call_id = next_call_id(p->conn);
972 req->status = NT_STATUS_OK;
973 req->state = RPC_REQUEST_QUEUED;
974 req->payload = data_blob(NULL, 0);
977 req->async_call = async;
978 req->ignore_timeout = false;
979 req->async.callback = NULL;
980 req->async.private_data = NULL;
981 req->recv_handler = NULL;
983 if (object != NULL) {
984 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
985 if (req->object == NULL) {
994 req->request_data.length = stub_data->length;
995 req->request_data.data = talloc_reference(req, stub_data->data);
996 if (req->request_data.length && req->request_data.data == NULL) {
1000 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1001 talloc_set_destructor(req, dcerpc_req_dequeue);
1003 dcerpc_ship_next_request(p->conn);
1005 if (p->request_timeout) {
1006 event_add_timed(dcerpc_event_context(p), req,
1007 timeval_current_ofs(p->request_timeout, 0),
1008 dcerpc_timeout_handler, req);
1015 Send a request using the transport
1018 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1020 struct rpc_request *req;
1021 struct dcerpc_pipe *p;
1022 DATA_BLOB *stub_data;
1023 struct ncacn_packet pkt;
1025 uint32_t remaining, chunk_size;
1026 bool first_packet = true;
1028 req = c->request_queue;
1034 stub_data = &req->request_data;
1036 if (!req->async_call && (c->pending != NULL)) {
1040 DLIST_REMOVE(c->request_queue, req);
1041 DLIST_ADD(c->pending, req);
1042 req->state = RPC_REQUEST_PENDING;
1044 init_ncacn_hdr(p->conn, &pkt);
1046 remaining = stub_data->length;
1048 /* we can write a full max_recv_frag size, minus the dcerpc
1049 request header size */
1050 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1052 pkt.ptype = DCERPC_PKT_REQUEST;
1053 pkt.call_id = req->call_id;
1054 pkt.auth_length = 0;
1056 pkt.u.request.alloc_hint = remaining;
1057 pkt.u.request.context_id = p->context_id;
1058 pkt.u.request.opnum = req->opnum;
1061 pkt.u.request.object.object = *req->object;
1062 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1063 chunk_size -= ndr_size_GUID(req->object,0);
1066 /* we send a series of pdus without waiting for a reply */
1067 while (remaining > 0 || first_packet) {
1068 uint32_t chunk = MIN(chunk_size, remaining);
1069 bool last_frag = false;
1071 first_packet = false;
1072 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1074 if (remaining == stub_data->length) {
1075 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1077 if (chunk == remaining) {
1078 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1082 pkt.u.request.stub_and_verifier.data = stub_data->data +
1083 (stub_data->length - remaining);
1084 pkt.u.request.stub_and_verifier.length = chunk;
1086 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1087 if (!NT_STATUS_IS_OK(req->status)) {
1088 req->state = RPC_REQUEST_DONE;
1089 DLIST_REMOVE(p->conn->pending, req);
1093 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1094 if (!NT_STATUS_IS_OK(req->status)) {
1095 req->state = RPC_REQUEST_DONE;
1096 DLIST_REMOVE(p->conn->pending, req);
1105 return the event context for a dcerpc pipe
1106 used by callers who wish to operate asynchronously
1108 _PUBLIC_ struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1110 return p->conn->event_ctx;
1116 perform the receive side of a async dcerpc request
1118 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1119 TALLOC_CTX *mem_ctx,
1120 DATA_BLOB *stub_data)
1124 while (req->state != RPC_REQUEST_DONE) {
1125 struct event_context *ctx = dcerpc_event_context(req->p);
1126 if (event_loop_once(ctx) != 0) {
1127 return NT_STATUS_CONNECTION_DISCONNECTED;
1130 *stub_data = req->payload;
1131 status = req->status;
1132 if (stub_data->data) {
1133 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1135 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1136 req->p->last_fault_code = req->fault_code;
1143 perform a full request/response pair on a dcerpc pipe
1145 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1146 struct GUID *object,
1149 TALLOC_CTX *mem_ctx,
1150 DATA_BLOB *stub_data_in,
1151 DATA_BLOB *stub_data_out)
1153 struct rpc_request *req;
1155 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1157 return NT_STATUS_NO_MEMORY;
1160 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1165 this is a paranoid NDR validator. For every packet we push onto the wire
1166 we pull it back again, then push it again. Then we compare the raw NDR data
1167 for that to the NDR we initially generated. If they don't match then we know
1168 we must have a bug in either the pull or push side of our code
1170 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1171 TALLOC_CTX *mem_ctx,
1174 ndr_push_flags_fn_t ndr_push,
1175 ndr_pull_flags_fn_t ndr_pull)
1178 struct ndr_pull *pull;
1179 struct ndr_push *push;
1181 enum ndr_err_code ndr_err;
1183 st = talloc_size(mem_ctx, struct_size);
1185 return NT_STATUS_NO_MEMORY;
1188 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1190 return NT_STATUS_NO_MEMORY;
1192 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1194 ndr_err = ndr_pull(pull, NDR_IN, st);
1195 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1196 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1197 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1198 "failed input validation pull - %s",
1200 return ndr_map_error2ntstatus(ndr_err);
1203 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1205 return NT_STATUS_NO_MEMORY;
1208 ndr_err = ndr_push(push, NDR_IN, st);
1209 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1210 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1211 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1212 "failed input validation push - %s",
1214 return ndr_map_error2ntstatus(ndr_err);
1217 blob2 = ndr_push_blob(push);
1219 if (data_blob_cmp(&blob, &blob2) != 0) {
1220 DEBUG(3,("original:\n"));
1221 dump_data(3, blob.data, blob.length);
1222 DEBUG(3,("secondary:\n"));
1223 dump_data(3, blob2.data, blob2.length);
1224 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1225 "failed input validation blobs doesn't match");
1226 return ndr_map_error2ntstatus(ndr_err);
1229 return NT_STATUS_OK;
1233 this is a paranoid NDR input validator. For every packet we pull
1234 from the wire we push it back again then pull and push it
1235 again. Then we compare the raw NDR data for that to the NDR we
1236 initially generated. If they don't match then we know we must have a
1237 bug in either the pull or push side of our code
1239 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1240 struct ndr_pull *pull_in,
1243 ndr_push_flags_fn_t ndr_push,
1244 ndr_pull_flags_fn_t ndr_pull,
1245 ndr_print_function_t ndr_print)
1248 struct ndr_pull *pull;
1249 struct ndr_push *push;
1250 DATA_BLOB blob, blob2;
1251 TALLOC_CTX *mem_ctx = pull_in;
1253 enum ndr_err_code ndr_err;
1255 st = talloc_size(mem_ctx, struct_size);
1257 return NT_STATUS_NO_MEMORY;
1259 memcpy(st, struct_ptr, struct_size);
1261 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1263 return NT_STATUS_NO_MEMORY;
1266 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1267 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1268 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1269 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1270 "failed output validation push - %s",
1272 return ndr_map_error2ntstatus(ndr_err);
1275 blob = ndr_push_blob(push);
1277 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1279 return NT_STATUS_NO_MEMORY;
1282 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1283 ndr_err = ndr_pull(pull, NDR_OUT, st);
1284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1285 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1286 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1287 "failed output validation pull - %s",
1289 return ndr_map_error2ntstatus(ndr_err);
1292 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1294 return NT_STATUS_NO_MEMORY;
1297 ndr_err = ndr_push(push, NDR_OUT, st);
1298 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1299 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1300 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1301 "failed output validation push2 - %s",
1303 return ndr_map_error2ntstatus(ndr_err);
1306 blob2 = ndr_push_blob(push);
1308 if (data_blob_cmp(&blob, &blob2) != 0) {
1309 DEBUG(3,("original:\n"));
1310 dump_data(3, blob.data, blob.length);
1311 DEBUG(3,("secondary:\n"));
1312 dump_data(3, blob2.data, blob2.length);
1313 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1314 "failed output validation blobs doesn't match");
1315 return ndr_map_error2ntstatus(ndr_err);
1318 /* this checks the printed forms of the two structures, which effectively
1319 tests all of the value() attributes */
1320 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1321 NDR_OUT, struct_ptr);
1322 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1324 if (strcmp(s1, s2) != 0) {
1326 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1328 /* this is sometimes useful */
1329 printf("VALIDATE ERROR\n");
1330 file_save("wire.dat", s1, strlen(s1));
1331 file_save("gen.dat", s2, strlen(s2));
1332 system("diff -u wire.dat gen.dat");
1334 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1335 "failed output validation strings doesn't match");
1336 return ndr_map_error2ntstatus(ndr_err);
1339 return NT_STATUS_OK;
1344 send a rpc request given a dcerpc_call structure
1346 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1347 const struct GUID *object,
1348 const struct ndr_interface_table *table,
1350 TALLOC_CTX *mem_ctx,
1353 const struct ndr_interface_call *call;
1354 struct ndr_push *push;
1357 struct rpc_request *req;
1358 enum ndr_err_code ndr_err;
1360 call = &table->calls[opnum];
1362 /* setup for a ndr_push_* call */
1363 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1368 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1369 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1372 /* push the structure into a blob */
1373 ndr_err = call->ndr_push(push, NDR_IN, r);
1374 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1375 status = ndr_map_error2ntstatus(ndr_err);
1376 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1377 nt_errstr(status)));
1382 /* retrieve the blob */
1383 request = ndr_push_blob(push);
1385 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1386 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1387 call->ndr_push, call->ndr_pull);
1388 if (!NT_STATUS_IS_OK(status)) {
1389 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1390 nt_errstr(status)));
1396 DEBUG(10,("rpc request data:\n"));
1397 dump_data(10, request.data, request.length);
1399 /* make the actual dcerpc request */
1400 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1404 req->ndr.table = table;
1405 req->ndr.opnum = opnum;
1406 req->ndr.struct_ptr = r;
1407 req->ndr.mem_ctx = mem_ctx;
1416 receive the answer from a dcerpc_ndr_request_send()
1418 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1420 struct dcerpc_pipe *p = req->p;
1423 struct ndr_pull *pull;
1425 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1426 void *r = req->ndr.struct_ptr;
1427 uint32_t opnum = req->ndr.opnum;
1428 const struct ndr_interface_table *table = req->ndr.table;
1429 const struct ndr_interface_call *call = &table->calls[opnum];
1430 enum ndr_err_code ndr_err;
1432 /* make sure the recv code doesn't free the request, as we
1433 need to grab the flags element before it is freed */
1434 if (talloc_reference(p, req) == NULL) {
1435 return NT_STATUS_NO_MEMORY;
1438 status = dcerpc_request_recv(req, mem_ctx, &response);
1439 if (!NT_STATUS_IS_OK(status)) {
1440 talloc_unlink(p, req);
1446 /* prepare for ndr_pull_* */
1447 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1449 talloc_unlink(p, req);
1450 return NT_STATUS_NO_MEMORY;
1454 pull->data = talloc_steal(pull, pull->data);
1456 talloc_unlink(p, req);
1458 if (flags & DCERPC_PULL_BIGENDIAN) {
1459 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1462 DEBUG(10,("rpc reply data:\n"));
1463 dump_data(10, pull->data, pull->data_size);
1465 /* pull the structure from the blob */
1466 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1467 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1468 status = ndr_map_error2ntstatus(ndr_err);
1469 dcerpc_log_packet(table, opnum, NDR_OUT,
1474 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1475 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1476 call->ndr_push, call->ndr_pull,
1478 if (!NT_STATUS_IS_OK(status)) {
1479 dcerpc_log_packet(table, opnum, NDR_OUT,
1485 if (pull->offset != pull->data_size) {
1486 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1487 pull->data_size - pull->offset));
1488 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1489 but it turns out that early versions of NT
1490 (specifically NT3.1) add junk onto the end of rpc
1491 packets, so if we want to interoperate at all with
1492 those versions then we need to ignore this error */
1495 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1497 return NT_STATUS_OK;
1502 a useful helper function for synchronous rpc requests
1504 this can be used when you have ndr push/pull functions in the
1507 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1508 const struct GUID *object,
1509 const struct ndr_interface_table *table,
1511 TALLOC_CTX *mem_ctx,
1514 struct rpc_request *req;
1516 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1518 return NT_STATUS_NO_MEMORY;
1521 return dcerpc_ndr_request_recv(req);
1526 a useful function for retrieving the server name we connected to
1528 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1530 if (!p->conn->transport.target_hostname) {
1531 if (!p->conn->transport.peer_name) {
1534 return p->conn->transport.peer_name(p->conn);
1536 return p->conn->transport.target_hostname(p->conn);
1541 get the dcerpc auth_level for a open connection
1543 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1547 if (c->flags & DCERPC_SEAL) {
1548 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1549 } else if (c->flags & DCERPC_SIGN) {
1550 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1551 } else if (c->flags & DCERPC_CONNECT) {
1552 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1554 auth_level = DCERPC_AUTH_LEVEL_NONE;
1560 Receive an alter reply from the transport
1562 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1563 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1565 struct composite_context *c;
1566 struct dcerpc_pipe *recv_pipe;
1568 c = talloc_get_type(req->async.private_data, struct composite_context);
1569 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1571 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1572 pkt->u.alter_resp.num_results == 1 &&
1573 pkt->u.alter_resp.ctx_list[0].result != 0) {
1574 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1575 pkt->u.alter_resp.ctx_list[0].reason));
1576 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1580 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1581 pkt->u.alter_resp.num_results == 0 ||
1582 pkt->u.alter_resp.ctx_list[0].result != 0) {
1583 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1587 /* the alter_resp might contain a reply set of credentials */
1588 if (recv_pipe->conn->security_state.auth_info &&
1589 pkt->u.alter_resp.auth_info.length) {
1590 enum ndr_err_code ndr_err;
1591 ndr_err = ndr_pull_struct_blob(
1592 &pkt->u.alter_resp.auth_info, recv_pipe,
1594 recv_pipe->conn->security_state.auth_info,
1595 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1596 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1597 c->status = ndr_map_error2ntstatus(ndr_err);
1598 if (!composite_is_ok(c)) return;
1606 send a dcerpc alter_context request
1608 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1609 TALLOC_CTX *mem_ctx,
1610 const struct ndr_syntax_id *syntax,
1611 const struct ndr_syntax_id *transfer_syntax)
1613 struct composite_context *c;
1614 struct ncacn_packet pkt;
1616 struct rpc_request *req;
1618 c = composite_create(mem_ctx, p->conn->event_ctx);
1619 if (c == NULL) return NULL;
1621 c->private_data = p;
1623 p->syntax = *syntax;
1624 p->transfer_syntax = *transfer_syntax;
1626 init_ncacn_hdr(p->conn, &pkt);
1628 pkt.ptype = DCERPC_PKT_ALTER;
1629 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1630 pkt.call_id = p->conn->call_id;
1631 pkt.auth_length = 0;
1633 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1634 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1637 pkt.u.alter.max_xmit_frag = 5840;
1638 pkt.u.alter.max_recv_frag = 5840;
1639 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1640 pkt.u.alter.num_contexts = 1;
1641 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1642 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1643 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1644 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1645 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1646 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1647 pkt.u.alter.auth_info = data_blob(NULL, 0);
1649 /* construct the NDR form of the packet */
1650 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1651 p->conn->security_state.auth_info);
1652 if (!composite_is_ok(c)) return c;
1654 p->conn->transport.recv_data = dcerpc_recv_data;
1657 * we allocate a dcerpc_request so we can be in the same
1658 * request queue as normal requests
1660 req = talloc_zero(c, struct rpc_request);
1661 if (composite_nomem(req, c)) return c;
1663 req->state = RPC_REQUEST_PENDING;
1664 req->call_id = pkt.call_id;
1665 req->async.private_data = c;
1666 req->async.callback = dcerpc_composite_fail;
1668 req->recv_handler = dcerpc_alter_recv_handler;
1669 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1670 talloc_set_destructor(req, dcerpc_req_dequeue);
1672 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1673 if (!composite_is_ok(c)) return c;
1675 event_add_timed(c->event_ctx, req,
1676 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1677 dcerpc_timeout_handler, req);
1682 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1684 NTSTATUS result = composite_wait(ctx);
1690 send a dcerpc alter_context request
1692 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1693 TALLOC_CTX *mem_ctx,
1694 const struct ndr_syntax_id *syntax,
1695 const struct ndr_syntax_id *transfer_syntax)
1697 struct composite_context *creq;
1698 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1699 return dcerpc_alter_context_recv(creq);