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/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "libcli/composite/composite.h"
30 #include "auth/gensec/gensec.h"
31 #include "param/param.h"
33 NTSTATUS dcerpc_init(void)
35 gensec_init(global_loadparm);
40 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
41 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
43 /* destroy a dcerpc connection */
44 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
47 conn->free_skipped = true;
50 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
55 /* initialise a dcerpc connection.
56 the event context is optional
58 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
59 struct event_context *ev,
60 struct smb_iconv_convenience *ic)
62 struct dcerpc_connection *c;
64 c = talloc_zero(mem_ctx, struct dcerpc_connection);
70 ev = event_context_init(c);
77 c->iconv_convenience = talloc_reference(c, ic);
81 if (!talloc_reference(c, ev)) {
86 c->security_state.auth_info = NULL;
87 c->security_state.session_key = dcerpc_generic_session_key;
88 c->security_state.generic_state = NULL;
89 c->binding_string = NULL;
91 c->srv_max_xmit_frag = 0;
92 c->srv_max_recv_frag = 0;
95 talloc_set_destructor(c, dcerpc_connection_destructor);
100 /* initialise a dcerpc pipe. */
101 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev,
102 struct smb_iconv_convenience *ic)
104 struct dcerpc_pipe *p;
106 p = talloc(mem_ctx, struct dcerpc_pipe);
111 p->conn = dcerpc_connection_init(p, ev, ic);
112 if (p->conn == NULL) {
117 p->last_fault_code = 0;
119 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
122 ZERO_STRUCT(p->syntax);
123 ZERO_STRUCT(p->transfer_syntax);
130 choose the next call id to use
132 static uint32_t next_call_id(struct dcerpc_connection *c)
135 if (c->call_id == 0) {
141 /* we need to be able to get/set the fragment length without doing a full
143 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
145 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
146 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
148 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
152 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
154 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
155 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
157 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
161 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
163 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
164 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
166 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
172 setup for a ndr pull, also setting up any flags from the binding string
174 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
175 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
177 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
179 if (ndr == NULL) return ndr;
181 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
182 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
185 if (c->flags & DCERPC_NDR_REF_ALLOC) {
186 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
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 generate a CONNECT level verifier
222 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
224 *blob = data_blob_talloc(mem_ctx, NULL, 16);
225 if (blob->data == NULL) {
226 return NT_STATUS_NO_MEMORY;
228 SIVAL(blob->data, 0, 1);
229 memset(blob->data+4, 0, 12);
234 check a CONNECT level verifier
236 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
238 if (blob->length != 16 ||
239 IVAL(blob->data, 0) != 1) {
240 return NT_STATUS_ACCESS_DENIED;
246 parse the authentication information on a dcerpc response packet
248 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
249 DATA_BLOB *raw_packet,
250 struct ncacn_packet *pkt)
252 struct ndr_pull *ndr;
254 struct dcerpc_auth auth;
256 enum ndr_err_code ndr_err;
258 if (pkt->auth_length == 0 &&
259 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
263 auth_blob.length = 8 + pkt->auth_length;
265 /* check for a valid length */
266 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
267 return NT_STATUS_INFO_LENGTH_MISMATCH;
271 pkt->u.response.stub_and_verifier.data +
272 pkt->u.response.stub_and_verifier.length - auth_blob.length;
273 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
275 /* pull the auth structure */
276 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
278 return NT_STATUS_NO_MEMORY;
281 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
282 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
285 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
286 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
287 return ndr_map_error2ntstatus(ndr_err);
289 status = NT_STATUS_OK;
291 /* check signature or unseal the packet */
292 switch (c->security_state.auth_info->auth_level) {
293 case DCERPC_AUTH_LEVEL_PRIVACY:
294 status = gensec_unseal_packet(c->security_state.generic_state,
296 raw_packet->data + DCERPC_REQUEST_LENGTH,
297 pkt->u.response.stub_and_verifier.length,
299 raw_packet->length - auth.credentials.length,
301 memcpy(pkt->u.response.stub_and_verifier.data,
302 raw_packet->data + DCERPC_REQUEST_LENGTH,
303 pkt->u.response.stub_and_verifier.length);
306 case DCERPC_AUTH_LEVEL_INTEGRITY:
307 status = gensec_check_packet(c->security_state.generic_state,
309 pkt->u.response.stub_and_verifier.data,
310 pkt->u.response.stub_and_verifier.length,
312 raw_packet->length - auth.credentials.length,
316 case DCERPC_AUTH_LEVEL_CONNECT:
317 status = dcerpc_check_connect_verifier(&auth.credentials);
320 case DCERPC_AUTH_LEVEL_NONE:
324 status = NT_STATUS_INVALID_LEVEL;
328 /* remove the indicated amount of paddiing */
329 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
330 return NT_STATUS_INFO_LENGTH_MISMATCH;
332 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
339 push a dcerpc request packet into a blob, possibly signing it.
341 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
342 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
343 struct ncacn_packet *pkt)
346 struct ndr_push *ndr;
348 size_t payload_length;
349 enum ndr_err_code ndr_err;
351 /* non-signed packets are simpler */
352 if (!c->security_state.auth_info ||
353 !c->security_state.generic_state) {
354 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, c->security_state.auth_info);
357 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
359 return NT_STATUS_NO_MEMORY;
362 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
363 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
366 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
367 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
370 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
371 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
372 return ndr_map_error2ntstatus(ndr_err);
374 status = NT_STATUS_OK;
376 /* pad to 16 byte multiple in the payload portion of the
377 packet. This matches what w2k3 does */
378 c->security_state.auth_info->auth_pad_length =
379 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
380 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
382 payload_length = pkt->u.request.stub_and_verifier.length +
383 c->security_state.auth_info->auth_pad_length;
385 /* sign or seal the packet */
386 switch (c->security_state.auth_info->auth_level) {
387 case DCERPC_AUTH_LEVEL_PRIVACY:
388 case DCERPC_AUTH_LEVEL_INTEGRITY:
389 /* We hope this length is accruate. If must be if the
390 * GENSEC mech does AEAD signing of the packet
392 c->security_state.auth_info->credentials
393 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
395 data_blob_clear(&c->security_state.auth_info->credentials);
398 case DCERPC_AUTH_LEVEL_CONNECT:
399 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
402 case DCERPC_AUTH_LEVEL_NONE:
403 c->security_state.auth_info->credentials = data_blob(NULL, 0);
407 status = NT_STATUS_INVALID_LEVEL;
411 if (!NT_STATUS_IS_OK(status)) {
415 /* add the auth verifier */
416 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
417 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
418 return ndr_map_error2ntstatus(ndr_err);
420 status = NT_STATUS_OK;
422 /* extract the whole packet as a blob */
423 *blob = ndr_push_blob(ndr);
425 /* fill in the fragment length and auth_length, we can't fill
426 in these earlier as we don't know the signature length (it
427 could be variable length) */
428 dcerpc_set_frag_length(blob, blob->length);
429 /* We hope this value is accruate. If must be if the GENSEC
430 * mech does AEAD signing of the packet headers */
431 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
433 /* sign or seal the packet */
434 switch (c->security_state.auth_info->auth_level) {
435 case DCERPC_AUTH_LEVEL_PRIVACY:
436 status = gensec_seal_packet(c->security_state.generic_state,
438 blob->data + DCERPC_REQUEST_LENGTH,
442 c->security_state.auth_info->credentials.length,
444 if (!NT_STATUS_IS_OK(status)) {
447 blob->length -= c->security_state.auth_info->credentials.length;
448 if (!data_blob_append(mem_ctx, blob,
449 creds2.data, creds2.length)) {
450 return NT_STATUS_NO_MEMORY;
452 dcerpc_set_auth_length(blob, creds2.length);
453 if (c->security_state.auth_info->credentials.length == 0) {
454 /* this is needed for krb5 only, to correct the total packet
456 dcerpc_set_frag_length(blob,
457 dcerpc_get_frag_length(blob)
462 case DCERPC_AUTH_LEVEL_INTEGRITY:
463 status = gensec_sign_packet(c->security_state.generic_state,
465 blob->data + DCERPC_REQUEST_LENGTH,
469 c->security_state.auth_info->credentials.length,
471 if (!NT_STATUS_IS_OK(status)) {
474 blob->length -= c->security_state.auth_info->credentials.length;
475 if (!data_blob_append(mem_ctx, blob,
476 creds2.data, creds2.length)) {
477 return NT_STATUS_NO_MEMORY;
479 dcerpc_set_auth_length(blob, creds2.length);
480 if (c->security_state.auth_info->credentials.length == 0) {
481 /* this is needed for krb5 only, to correct the total packet
483 dcerpc_set_frag_length(blob,
484 dcerpc_get_frag_length(blob)
489 case DCERPC_AUTH_LEVEL_CONNECT:
492 case DCERPC_AUTH_LEVEL_NONE:
493 c->security_state.auth_info->credentials = data_blob(NULL, 0);
497 status = NT_STATUS_INVALID_LEVEL;
501 data_blob_free(&c->security_state.auth_info->credentials);
508 fill in the fixed values in a dcerpc header
510 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
513 pkt->rpc_vers_minor = 0;
514 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
517 pkt->drep[0] = DCERPC_DREP_LE;
525 map a bind nak reason to a NTSTATUS
527 static NTSTATUS dcerpc_map_reason(uint16_t reason)
530 case DCERPC_BIND_REASON_ASYNTAX:
531 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
532 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
533 return NT_STATUS_INVALID_PARAMETER;
535 return NT_STATUS_UNSUCCESSFUL;
539 a bind or alter context has failed
541 static void dcerpc_composite_fail(struct rpc_request *req)
543 struct composite_context *c = talloc_get_type(req->async.private_data,
544 struct composite_context);
545 composite_error(c, req->status);
549 remove requests from the pending or queued queues
551 static int dcerpc_req_dequeue(struct rpc_request *req)
553 switch (req->state) {
554 case RPC_REQUEST_QUEUED:
555 DLIST_REMOVE(req->p->conn->request_queue, req);
557 case RPC_REQUEST_PENDING:
558 DLIST_REMOVE(req->p->conn->pending, req);
560 case RPC_REQUEST_DONE:
568 mark the dcerpc connection dead. All outstanding requests get an error
570 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
572 if (conn->dead) return;
576 if (conn->transport.shutdown_pipe) {
577 conn->transport.shutdown_pipe(conn, status);
580 /* all pending requests get the error */
581 while (conn->pending) {
582 struct rpc_request *req = conn->pending;
583 dcerpc_req_dequeue(req);
584 req->state = RPC_REQUEST_DONE;
585 req->status = status;
586 if (req->async.callback) {
587 req->async.callback(req);
591 talloc_set_destructor(conn, NULL);
592 if (conn->free_skipped) {
598 forward declarations of the recv_data handlers for the types of
599 packets we need to handle
601 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
602 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
605 receive a dcerpc reply from the transport. Here we work out what
606 type of reply it is (normal request, bind or alter context) and
607 dispatch to the appropriate handler
609 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
611 struct ncacn_packet pkt;
613 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
614 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
617 /* the transport may be telling us of a severe error, such as
619 if (!NT_STATUS_IS_OK(status)) {
620 data_blob_free(blob);
621 dcerpc_connection_dead(conn, status);
625 /* parse the basic packet to work out what type of response this is */
626 status = ncacn_pull(conn, blob, blob->data, &pkt);
627 if (!NT_STATUS_IS_OK(status)) {
628 data_blob_free(blob);
629 dcerpc_connection_dead(conn, status);
632 dcerpc_request_recv_data(conn, blob, &pkt);
637 Receive a bind reply from the transport
639 static void dcerpc_bind_recv_handler(struct rpc_request *req,
640 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
642 struct composite_context *c;
643 struct dcerpc_connection *conn;
645 c = talloc_get_type(req->async.private_data, struct composite_context);
647 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
648 DEBUG(2,("dcerpc: bind_nak reason %d\n",
649 pkt->u.bind_nak.reject_reason));
650 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
655 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
656 (pkt->u.bind_ack.num_results == 0) ||
657 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
658 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
664 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
665 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
667 /* the bind_ack might contain a reply set of credentials */
668 if (conn->security_state.auth_info &&
669 pkt->u.bind_ack.auth_info.length) {
670 enum ndr_err_code ndr_err;
671 ndr_err = ndr_pull_struct_blob(
672 &pkt->u.bind_ack.auth_info, conn,
674 conn->security_state.auth_info,
675 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
676 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
677 c->status = ndr_map_error2ntstatus(ndr_err);
678 if (!composite_is_ok(c)) return;
682 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
688 handle timeouts of individual dcerpc requests
690 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
691 struct timeval t, void *private)
693 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
695 if (req->ignore_timeout) {
696 dcerpc_req_dequeue(req);
697 req->state = RPC_REQUEST_DONE;
698 req->status = NT_STATUS_IO_TIMEOUT;
699 if (req->async.callback) {
700 req->async.callback(req);
705 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
709 send a async dcerpc bind request
711 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
713 const struct ndr_syntax_id *syntax,
714 const struct ndr_syntax_id *transfer_syntax)
716 struct composite_context *c;
717 struct ncacn_packet pkt;
719 struct rpc_request *req;
721 c = composite_create(mem_ctx,p->conn->event_ctx);
722 if (c == NULL) return NULL;
727 p->transfer_syntax = *transfer_syntax;
729 init_ncacn_hdr(p->conn, &pkt);
731 pkt.ptype = DCERPC_PKT_BIND;
732 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
733 pkt.call_id = p->conn->call_id;
736 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
737 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
740 pkt.u.bind.max_xmit_frag = 5840;
741 pkt.u.bind.max_recv_frag = 5840;
742 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
743 pkt.u.bind.num_contexts = 1;
744 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
745 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
746 pkt.u.bind.ctx_list[0].context_id = p->context_id;
747 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
748 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
749 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
750 pkt.u.bind.auth_info = data_blob(NULL, 0);
752 /* construct the NDR form of the packet */
753 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
754 p->conn->security_state.auth_info);
755 if (!composite_is_ok(c)) return c;
757 p->conn->transport.recv_data = dcerpc_recv_data;
760 * we allocate a dcerpc_request so we can be in the same
761 * request queue as normal requests
763 req = talloc_zero(c, struct rpc_request);
764 if (composite_nomem(req, c)) return c;
766 req->state = RPC_REQUEST_PENDING;
767 req->call_id = pkt.call_id;
768 req->async.private_data = c;
769 req->async.callback = dcerpc_composite_fail;
771 req->recv_handler = dcerpc_bind_recv_handler;
772 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
773 talloc_set_destructor(req, dcerpc_req_dequeue);
775 c->status = p->conn->transport.send_request(p->conn, &blob,
777 if (!composite_is_ok(c)) return c;
779 event_add_timed(c->event_ctx, req,
780 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
781 dcerpc_timeout_handler, req);
787 recv side of async dcerpc bind request
789 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
791 NTSTATUS result = composite_wait(ctx);
797 perform a continued bind (and auth3)
799 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
802 struct ncacn_packet pkt;
806 init_ncacn_hdr(c, &pkt);
808 pkt.ptype = DCERPC_PKT_AUTH3;
809 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
810 pkt.call_id = next_call_id(c);
812 pkt.u.auth3._pad = 0;
813 pkt.u.auth3.auth_info = data_blob(NULL, 0);
815 /* construct the NDR form of the packet */
816 status = ncacn_push_auth(&blob, mem_ctx, c->iconv_convenience, &pkt, c->security_state.auth_info);
817 if (!NT_STATUS_IS_OK(status)) {
821 /* send it on its way */
822 status = c->transport.send_request(c, &blob, false);
823 if (!NT_STATUS_IS_OK(status)) {
832 process a fragment received from the transport layer during a
835 This function frees the data
837 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
838 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
840 struct rpc_request *req;
842 NTSTATUS status = NT_STATUS_OK;
845 if this is an authenticated connection then parse and check
846 the auth info. We have to do this before finding the
847 matching packet, as the request structure might have been
848 removed due to a timeout, but if it has been we still need
849 to run the auth routines so that we don't get the sign/seal
850 info out of step with the server
852 if (c->security_state.auth_info && c->security_state.generic_state &&
853 pkt->ptype == DCERPC_PKT_RESPONSE) {
854 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
857 /* find the matching request */
858 for (req=c->pending;req;req=req->next) {
859 if (pkt->call_id == req->call_id) break;
863 /* useful for testing certain vendors RPC servers */
864 if (req == NULL && c->pending && pkt->call_id == 0) {
865 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
871 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
872 data_blob_free(raw_packet);
876 talloc_steal(req, raw_packet->data);
878 if (req->recv_handler != NULL) {
879 dcerpc_req_dequeue(req);
880 req->state = RPC_REQUEST_DONE;
881 req->recv_handler(req, raw_packet, pkt);
885 if (pkt->ptype == DCERPC_PKT_FAULT) {
886 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
887 req->fault_code = pkt->u.fault.status;
888 req->status = NT_STATUS_NET_WRITE_FAULT;
892 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
893 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
895 req->fault_code = DCERPC_FAULT_OTHER;
896 req->status = NT_STATUS_NET_WRITE_FAULT;
900 /* now check the status from the auth routines, and if it failed then fail
901 this request accordingly */
902 if (!NT_STATUS_IS_OK(status)) {
903 req->status = status;
907 length = pkt->u.response.stub_and_verifier.length;
910 req->payload.data = talloc_realloc(req,
913 req->payload.length + length);
914 if (!req->payload.data) {
915 req->status = NT_STATUS_NO_MEMORY;
918 memcpy(req->payload.data+req->payload.length,
919 pkt->u.response.stub_and_verifier.data, length);
920 req->payload.length += length;
923 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
924 c->transport.send_read(c);
928 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
929 req->flags |= DCERPC_PULL_BIGENDIAN;
931 req->flags &= ~DCERPC_PULL_BIGENDIAN;
936 /* we've got the full payload */
937 req->state = RPC_REQUEST_DONE;
938 DLIST_REMOVE(c->pending, req);
940 if (c->request_queue != NULL) {
941 /* We have to look at shipping further requests before calling
942 * the async function, that one might close the pipe */
943 dcerpc_ship_next_request(c);
946 if (req->async.callback) {
947 req->async.callback(req);
952 perform the send side of a async dcerpc request
954 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
955 const struct GUID *object,
958 DATA_BLOB *stub_data)
960 struct rpc_request *req;
962 p->conn->transport.recv_data = dcerpc_recv_data;
964 req = talloc(p, struct rpc_request);
970 req->call_id = next_call_id(p->conn);
971 req->status = NT_STATUS_OK;
972 req->state = RPC_REQUEST_QUEUED;
973 req->payload = data_blob(NULL, 0);
976 req->async_call = async;
977 req->ignore_timeout = false;
978 req->async.callback = NULL;
979 req->async.private_data = NULL;
980 req->recv_handler = NULL;
982 if (object != NULL) {
983 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
984 if (req->object == NULL) {
993 req->request_data.length = stub_data->length;
994 req->request_data.data = talloc_reference(req, stub_data->data);
995 if (req->request_data.length && req->request_data.data == NULL) {
999 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1000 talloc_set_destructor(req, dcerpc_req_dequeue);
1002 dcerpc_ship_next_request(p->conn);
1004 if (p->request_timeout) {
1005 event_add_timed(dcerpc_event_context(p), req,
1006 timeval_current_ofs(p->request_timeout, 0),
1007 dcerpc_timeout_handler, req);
1014 Send a request using the transport
1017 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1019 struct rpc_request *req;
1020 struct dcerpc_pipe *p;
1021 DATA_BLOB *stub_data;
1022 struct ncacn_packet pkt;
1024 uint32_t remaining, chunk_size;
1025 bool first_packet = true;
1027 req = c->request_queue;
1033 stub_data = &req->request_data;
1035 if (!req->async_call && (c->pending != NULL)) {
1039 DLIST_REMOVE(c->request_queue, req);
1040 DLIST_ADD(c->pending, req);
1041 req->state = RPC_REQUEST_PENDING;
1043 init_ncacn_hdr(p->conn, &pkt);
1045 remaining = stub_data->length;
1047 /* we can write a full max_recv_frag size, minus the dcerpc
1048 request header size */
1049 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1051 pkt.ptype = DCERPC_PKT_REQUEST;
1052 pkt.call_id = req->call_id;
1053 pkt.auth_length = 0;
1055 pkt.u.request.alloc_hint = remaining;
1056 pkt.u.request.context_id = p->context_id;
1057 pkt.u.request.opnum = req->opnum;
1060 pkt.u.request.object.object = *req->object;
1061 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1062 chunk_size -= ndr_size_GUID(req->object,0);
1065 /* we send a series of pdus without waiting for a reply */
1066 while (remaining > 0 || first_packet) {
1067 uint32_t chunk = MIN(chunk_size, remaining);
1068 bool last_frag = false;
1070 first_packet = false;
1071 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1073 if (remaining == stub_data->length) {
1074 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1076 if (chunk == remaining) {
1077 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1081 pkt.u.request.stub_and_verifier.data = stub_data->data +
1082 (stub_data->length - remaining);
1083 pkt.u.request.stub_and_verifier.length = chunk;
1085 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1086 if (!NT_STATUS_IS_OK(req->status)) {
1087 req->state = RPC_REQUEST_DONE;
1088 DLIST_REMOVE(p->conn->pending, req);
1092 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1093 if (!NT_STATUS_IS_OK(req->status)) {
1094 req->state = RPC_REQUEST_DONE;
1095 DLIST_REMOVE(p->conn->pending, req);
1104 return the event context for a dcerpc pipe
1105 used by callers who wish to operate asynchronously
1107 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1109 return p->conn->event_ctx;
1115 perform the receive side of a async dcerpc request
1117 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1118 TALLOC_CTX *mem_ctx,
1119 DATA_BLOB *stub_data)
1123 while (req->state != RPC_REQUEST_DONE) {
1124 struct event_context *ctx = dcerpc_event_context(req->p);
1125 if (event_loop_once(ctx) != 0) {
1126 return NT_STATUS_CONNECTION_DISCONNECTED;
1129 *stub_data = req->payload;
1130 status = req->status;
1131 if (stub_data->data) {
1132 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1134 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1135 req->p->last_fault_code = req->fault_code;
1142 perform a full request/response pair on a dcerpc pipe
1144 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1145 struct GUID *object,
1148 TALLOC_CTX *mem_ctx,
1149 DATA_BLOB *stub_data_in,
1150 DATA_BLOB *stub_data_out)
1152 struct rpc_request *req;
1154 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1156 return NT_STATUS_NO_MEMORY;
1159 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1164 this is a paranoid NDR validator. For every packet we push onto the wire
1165 we pull it back again, then push it again. Then we compare the raw NDR data
1166 for that to the NDR we initially generated. If they don't match then we know
1167 we must have a bug in either the pull or push side of our code
1169 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1170 TALLOC_CTX *mem_ctx,
1173 ndr_push_flags_fn_t ndr_push,
1174 ndr_pull_flags_fn_t ndr_pull)
1177 struct ndr_pull *pull;
1178 struct ndr_push *push;
1180 enum ndr_err_code ndr_err;
1182 st = talloc_size(mem_ctx, struct_size);
1184 return NT_STATUS_NO_MEMORY;
1187 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1189 return NT_STATUS_NO_MEMORY;
1191 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1193 ndr_err = ndr_pull(pull, NDR_IN, st);
1194 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1195 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1196 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1197 "failed input validation pull - %s",
1199 return ndr_map_error2ntstatus(ndr_err);
1202 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1204 return NT_STATUS_NO_MEMORY;
1207 ndr_err = ndr_push(push, NDR_IN, st);
1208 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1209 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1210 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1211 "failed input validation push - %s",
1213 return ndr_map_error2ntstatus(ndr_err);
1216 blob2 = ndr_push_blob(push);
1218 if (data_blob_cmp(&blob, &blob2) != 0) {
1219 DEBUG(3,("original:\n"));
1220 dump_data(3, blob.data, blob.length);
1221 DEBUG(3,("secondary:\n"));
1222 dump_data(3, blob2.data, blob2.length);
1223 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1224 "failed input validation blobs doesn't match");
1225 return ndr_map_error2ntstatus(ndr_err);
1228 return NT_STATUS_OK;
1232 this is a paranoid NDR input validator. For every packet we pull
1233 from the wire we push it back again then pull and push it
1234 again. Then we compare the raw NDR data for that to the NDR we
1235 initially generated. If they don't match then we know we must have a
1236 bug in either the pull or push side of our code
1238 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1239 struct ndr_pull *pull_in,
1242 ndr_push_flags_fn_t ndr_push,
1243 ndr_pull_flags_fn_t ndr_pull,
1244 ndr_print_function_t ndr_print)
1247 struct ndr_pull *pull;
1248 struct ndr_push *push;
1249 DATA_BLOB blob, blob2;
1250 TALLOC_CTX *mem_ctx = pull_in;
1252 enum ndr_err_code ndr_err;
1254 st = talloc_size(mem_ctx, struct_size);
1256 return NT_STATUS_NO_MEMORY;
1258 memcpy(st, struct_ptr, struct_size);
1260 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1262 return NT_STATUS_NO_MEMORY;
1265 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1266 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1267 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1268 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1269 "failed output validation push - %s",
1271 return ndr_map_error2ntstatus(ndr_err);
1274 blob = ndr_push_blob(push);
1276 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1278 return NT_STATUS_NO_MEMORY;
1281 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1282 ndr_err = ndr_pull(pull, NDR_OUT, st);
1283 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1284 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1285 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1286 "failed output validation pull - %s",
1288 return ndr_map_error2ntstatus(ndr_err);
1291 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1293 return NT_STATUS_NO_MEMORY;
1296 ndr_err = ndr_push(push, NDR_OUT, st);
1297 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1298 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1299 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1300 "failed output validation push2 - %s",
1302 return ndr_map_error2ntstatus(ndr_err);
1305 blob2 = ndr_push_blob(push);
1307 if (data_blob_cmp(&blob, &blob2) != 0) {
1308 DEBUG(3,("original:\n"));
1309 dump_data(3, blob.data, blob.length);
1310 DEBUG(3,("secondary:\n"));
1311 dump_data(3, blob2.data, blob2.length);
1312 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1313 "failed output validation blobs doesn't match");
1314 return ndr_map_error2ntstatus(ndr_err);
1317 /* this checks the printed forms of the two structures, which effectively
1318 tests all of the value() attributes */
1319 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1320 NDR_OUT, struct_ptr);
1321 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1323 if (strcmp(s1, s2) != 0) {
1325 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1327 /* this is sometimes useful */
1328 printf("VALIDATE ERROR\n");
1329 file_save("wire.dat", s1, strlen(s1));
1330 file_save("gen.dat", s2, strlen(s2));
1331 system("diff -u wire.dat gen.dat");
1333 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1334 "failed output validation strings doesn't match");
1335 return ndr_map_error2ntstatus(ndr_err);
1338 return NT_STATUS_OK;
1343 send a rpc request given a dcerpc_call structure
1345 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1346 const struct GUID *object,
1347 const struct ndr_interface_table *table,
1349 TALLOC_CTX *mem_ctx,
1352 const struct ndr_interface_call *call;
1353 struct ndr_push *push;
1356 struct rpc_request *req;
1357 enum ndr_err_code ndr_err;
1359 call = &table->calls[opnum];
1361 /* setup for a ndr_push_* call */
1362 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1367 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1368 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1371 /* push the structure into a blob */
1372 ndr_err = call->ndr_push(push, NDR_IN, r);
1373 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1374 status = ndr_map_error2ntstatus(ndr_err);
1375 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1376 nt_errstr(status)));
1381 /* retrieve the blob */
1382 request = ndr_push_blob(push);
1384 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1385 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1386 call->ndr_push, call->ndr_pull);
1387 if (!NT_STATUS_IS_OK(status)) {
1388 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1389 nt_errstr(status)));
1395 DEBUG(10,("rpc request data:\n"));
1396 dump_data(10, request.data, request.length);
1398 /* make the actual dcerpc request */
1399 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1403 req->ndr.table = table;
1404 req->ndr.opnum = opnum;
1405 req->ndr.struct_ptr = r;
1406 req->ndr.mem_ctx = mem_ctx;
1415 receive the answer from a dcerpc_ndr_request_send()
1417 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1419 struct dcerpc_pipe *p = req->p;
1422 struct ndr_pull *pull;
1424 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1425 void *r = req->ndr.struct_ptr;
1426 uint32_t opnum = req->ndr.opnum;
1427 const struct ndr_interface_table *table = req->ndr.table;
1428 const struct ndr_interface_call *call = &table->calls[opnum];
1429 enum ndr_err_code ndr_err;
1431 /* make sure the recv code doesn't free the request, as we
1432 need to grab the flags element before it is freed */
1433 if (talloc_reference(p, req) == NULL) {
1434 return NT_STATUS_NO_MEMORY;
1437 status = dcerpc_request_recv(req, mem_ctx, &response);
1438 if (!NT_STATUS_IS_OK(status)) {
1439 talloc_unlink(p, req);
1445 /* prepare for ndr_pull_* */
1446 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1448 talloc_unlink(p, req);
1449 return NT_STATUS_NO_MEMORY;
1453 pull->data = talloc_steal(pull, pull->data);
1455 talloc_unlink(p, req);
1457 if (flags & DCERPC_PULL_BIGENDIAN) {
1458 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1461 DEBUG(10,("rpc reply data:\n"));
1462 dump_data(10, pull->data, pull->data_size);
1464 /* pull the structure from the blob */
1465 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1466 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1467 status = ndr_map_error2ntstatus(ndr_err);
1468 dcerpc_log_packet(table, opnum, NDR_OUT,
1473 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1474 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1475 call->ndr_push, call->ndr_pull,
1477 if (!NT_STATUS_IS_OK(status)) {
1478 dcerpc_log_packet(table, opnum, NDR_OUT,
1484 if (pull->offset != pull->data_size) {
1485 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1486 pull->data_size - pull->offset));
1487 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1488 but it turns out that early versions of NT
1489 (specifically NT3.1) add junk onto the end of rpc
1490 packets, so if we want to interoperate at all with
1491 those versions then we need to ignore this error */
1494 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1496 return NT_STATUS_OK;
1501 a useful helper function for synchronous rpc requests
1503 this can be used when you have ndr push/pull functions in the
1506 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1507 const struct GUID *object,
1508 const struct ndr_interface_table *table,
1510 TALLOC_CTX *mem_ctx,
1513 struct rpc_request *req;
1515 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1517 return NT_STATUS_NO_MEMORY;
1520 return dcerpc_ndr_request_recv(req);
1525 a useful function for retrieving the server name we connected to
1527 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1529 if (!p->conn->transport.target_hostname) {
1530 if (!p->conn->transport.peer_name) {
1533 return p->conn->transport.peer_name(p->conn);
1535 return p->conn->transport.target_hostname(p->conn);
1540 get the dcerpc auth_level for a open connection
1542 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1546 if (c->flags & DCERPC_SEAL) {
1547 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1548 } else if (c->flags & DCERPC_SIGN) {
1549 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1550 } else if (c->flags & DCERPC_CONNECT) {
1551 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1553 auth_level = DCERPC_AUTH_LEVEL_NONE;
1559 Receive an alter reply from the transport
1561 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1562 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1564 struct composite_context *c;
1565 struct dcerpc_pipe *recv_pipe;
1567 c = talloc_get_type(req->async.private_data, struct composite_context);
1568 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1570 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1571 pkt->u.alter_resp.num_results == 1 &&
1572 pkt->u.alter_resp.ctx_list[0].result != 0) {
1573 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1574 pkt->u.alter_resp.ctx_list[0].reason));
1575 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1579 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1580 pkt->u.alter_resp.num_results == 0 ||
1581 pkt->u.alter_resp.ctx_list[0].result != 0) {
1582 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1586 /* the alter_resp might contain a reply set of credentials */
1587 if (recv_pipe->conn->security_state.auth_info &&
1588 pkt->u.alter_resp.auth_info.length) {
1589 enum ndr_err_code ndr_err;
1590 ndr_err = ndr_pull_struct_blob(
1591 &pkt->u.alter_resp.auth_info, recv_pipe,
1593 recv_pipe->conn->security_state.auth_info,
1594 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1595 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1596 c->status = ndr_map_error2ntstatus(ndr_err);
1597 if (!composite_is_ok(c)) return;
1605 send a dcerpc alter_context request
1607 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1608 TALLOC_CTX *mem_ctx,
1609 const struct ndr_syntax_id *syntax,
1610 const struct ndr_syntax_id *transfer_syntax)
1612 struct composite_context *c;
1613 struct ncacn_packet pkt;
1615 struct rpc_request *req;
1617 c = composite_create(mem_ctx, p->conn->event_ctx);
1618 if (c == NULL) return NULL;
1620 c->private_data = p;
1622 p->syntax = *syntax;
1623 p->transfer_syntax = *transfer_syntax;
1625 init_ncacn_hdr(p->conn, &pkt);
1627 pkt.ptype = DCERPC_PKT_ALTER;
1628 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1629 pkt.call_id = p->conn->call_id;
1630 pkt.auth_length = 0;
1632 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1633 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1636 pkt.u.alter.max_xmit_frag = 5840;
1637 pkt.u.alter.max_recv_frag = 5840;
1638 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1639 pkt.u.alter.num_contexts = 1;
1640 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1641 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1642 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1643 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1644 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1645 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1646 pkt.u.alter.auth_info = data_blob(NULL, 0);
1648 /* construct the NDR form of the packet */
1649 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1650 p->conn->security_state.auth_info);
1651 if (!composite_is_ok(c)) return c;
1653 p->conn->transport.recv_data = dcerpc_recv_data;
1656 * we allocate a dcerpc_request so we can be in the same
1657 * request queue as normal requests
1659 req = talloc_zero(c, struct rpc_request);
1660 if (composite_nomem(req, c)) return c;
1662 req->state = RPC_REQUEST_PENDING;
1663 req->call_id = pkt.call_id;
1664 req->async.private_data = c;
1665 req->async.callback = dcerpc_composite_fail;
1667 req->recv_handler = dcerpc_alter_recv_handler;
1668 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1669 talloc_set_destructor(req, dcerpc_req_dequeue);
1671 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1672 if (!composite_is_ok(c)) return c;
1674 event_add_timed(c->event_ctx, req,
1675 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1676 dcerpc_timeout_handler, req);
1681 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1683 NTSTATUS result = composite_wait(ctx);
1689 send a dcerpc alter_context request
1691 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1692 TALLOC_CTX *mem_ctx,
1693 const struct ndr_syntax_id *syntax,
1694 const struct ndr_syntax_id *transfer_syntax)
1696 struct composite_context *creq;
1697 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1698 return dcerpc_alter_context_recv(creq);