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 generate a CONNECT level verifier
216 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
218 *blob = data_blob_talloc(mem_ctx, NULL, 16);
219 if (blob->data == NULL) {
220 return NT_STATUS_NO_MEMORY;
222 SIVAL(blob->data, 0, 1);
223 memset(blob->data+4, 0, 12);
228 check a CONNECT level verifier
230 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
232 if (blob->length != 16 ||
233 IVAL(blob->data, 0) != 1) {
234 return NT_STATUS_ACCESS_DENIED;
240 parse the authentication information on a dcerpc response packet
242 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
243 DATA_BLOB *raw_packet,
244 struct ncacn_packet *pkt)
246 struct ndr_pull *ndr;
248 struct dcerpc_auth auth;
250 enum ndr_err_code ndr_err;
252 if (pkt->auth_length == 0 &&
253 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
257 auth_blob.length = 8 + pkt->auth_length;
259 /* check for a valid length */
260 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
261 return NT_STATUS_INFO_LENGTH_MISMATCH;
265 pkt->u.response.stub_and_verifier.data +
266 pkt->u.response.stub_and_verifier.length - auth_blob.length;
267 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
269 /* pull the auth structure */
270 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
272 return NT_STATUS_NO_MEMORY;
275 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
276 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
279 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
280 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
281 return ndr_map_error2ntstatus(ndr_err);
283 status = NT_STATUS_OK;
285 /* check signature or unseal the packet */
286 switch (c->security_state.auth_info->auth_level) {
287 case DCERPC_AUTH_LEVEL_PRIVACY:
288 status = gensec_unseal_packet(c->security_state.generic_state,
290 raw_packet->data + DCERPC_REQUEST_LENGTH,
291 pkt->u.response.stub_and_verifier.length,
293 raw_packet->length - auth.credentials.length,
295 memcpy(pkt->u.response.stub_and_verifier.data,
296 raw_packet->data + DCERPC_REQUEST_LENGTH,
297 pkt->u.response.stub_and_verifier.length);
300 case DCERPC_AUTH_LEVEL_INTEGRITY:
301 status = gensec_check_packet(c->security_state.generic_state,
303 pkt->u.response.stub_and_verifier.data,
304 pkt->u.response.stub_and_verifier.length,
306 raw_packet->length - auth.credentials.length,
310 case DCERPC_AUTH_LEVEL_CONNECT:
311 status = dcerpc_check_connect_verifier(&auth.credentials);
314 case DCERPC_AUTH_LEVEL_NONE:
318 status = NT_STATUS_INVALID_LEVEL;
322 /* remove the indicated amount of paddiing */
323 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
324 return NT_STATUS_INFO_LENGTH_MISMATCH;
326 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
333 push a dcerpc request packet into a blob, possibly signing it.
335 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
336 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
338 struct ncacn_packet *pkt)
341 struct ndr_push *ndr;
343 size_t payload_length;
344 enum ndr_err_code ndr_err;
346 /* non-signed packets are simpler */
347 if (!c->security_state.auth_info ||
348 !c->security_state.generic_state) {
349 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, c->security_state.auth_info);
352 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
354 return NT_STATUS_NO_MEMORY;
357 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
358 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
361 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
362 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
365 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
366 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
367 return ndr_map_error2ntstatus(ndr_err);
369 status = NT_STATUS_OK;
371 /* pad to 16 byte multiple in the payload portion of the
372 packet. This matches what w2k3 does */
373 c->security_state.auth_info->auth_pad_length =
374 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
375 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
377 payload_length = pkt->u.request.stub_and_verifier.length +
378 c->security_state.auth_info->auth_pad_length;
380 /* sign or seal the packet */
381 switch (c->security_state.auth_info->auth_level) {
382 case DCERPC_AUTH_LEVEL_PRIVACY:
383 case DCERPC_AUTH_LEVEL_INTEGRITY:
384 /* We hope this length is accruate. If must be if the
385 * GENSEC mech does AEAD signing of the packet
387 c->security_state.auth_info->credentials
388 = data_blob_talloc(mem_ctx, NULL, sig_size);
389 data_blob_clear(&c->security_state.auth_info->credentials);
392 case DCERPC_AUTH_LEVEL_CONNECT:
393 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
396 case DCERPC_AUTH_LEVEL_NONE:
397 c->security_state.auth_info->credentials = data_blob(NULL, 0);
401 status = NT_STATUS_INVALID_LEVEL;
405 if (!NT_STATUS_IS_OK(status)) {
409 /* add the auth verifier */
410 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
411 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
412 return ndr_map_error2ntstatus(ndr_err);
414 status = NT_STATUS_OK;
416 /* extract the whole packet as a blob */
417 *blob = ndr_push_blob(ndr);
419 /* fill in the fragment length and auth_length, we can't fill
420 in these earlier as we don't know the signature length (it
421 could be variable length) */
422 dcerpc_set_frag_length(blob, blob->length);
423 /* We hope this value is accruate. If must be if the GENSEC
424 * mech does AEAD signing of the packet headers */
425 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
427 /* sign or seal the packet */
428 switch (c->security_state.auth_info->auth_level) {
429 case DCERPC_AUTH_LEVEL_PRIVACY:
430 status = gensec_seal_packet(c->security_state.generic_state,
432 blob->data + DCERPC_REQUEST_LENGTH,
436 c->security_state.auth_info->credentials.length,
438 if (!NT_STATUS_IS_OK(status)) {
441 blob->length -= c->security_state.auth_info->credentials.length;
442 if (!data_blob_append(mem_ctx, blob,
443 creds2.data, creds2.length)) {
444 return NT_STATUS_NO_MEMORY;
446 dcerpc_set_auth_length(blob, creds2.length);
447 if (c->security_state.auth_info->credentials.length == 0) {
448 /* this is needed for krb5 only, to correct the total packet
450 dcerpc_set_frag_length(blob,
451 dcerpc_get_frag_length(blob)
456 case DCERPC_AUTH_LEVEL_INTEGRITY:
457 status = gensec_sign_packet(c->security_state.generic_state,
459 blob->data + DCERPC_REQUEST_LENGTH,
463 c->security_state.auth_info->credentials.length,
465 if (!NT_STATUS_IS_OK(status)) {
468 blob->length -= c->security_state.auth_info->credentials.length;
469 if (!data_blob_append(mem_ctx, blob,
470 creds2.data, creds2.length)) {
471 return NT_STATUS_NO_MEMORY;
473 dcerpc_set_auth_length(blob, creds2.length);
474 if (c->security_state.auth_info->credentials.length == 0) {
475 /* this is needed for krb5 only, to correct the total packet
477 dcerpc_set_frag_length(blob,
478 dcerpc_get_frag_length(blob)
483 case DCERPC_AUTH_LEVEL_CONNECT:
486 case DCERPC_AUTH_LEVEL_NONE:
487 c->security_state.auth_info->credentials = data_blob(NULL, 0);
491 status = NT_STATUS_INVALID_LEVEL;
495 data_blob_free(&c->security_state.auth_info->credentials);
502 fill in the fixed values in a dcerpc header
504 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
507 pkt->rpc_vers_minor = 0;
508 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
511 pkt->drep[0] = DCERPC_DREP_LE;
519 map a bind nak reason to a NTSTATUS
521 static NTSTATUS dcerpc_map_reason(uint16_t reason)
524 case DCERPC_BIND_REASON_ASYNTAX:
525 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
526 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
527 return NT_STATUS_INVALID_PARAMETER;
529 return NT_STATUS_UNSUCCESSFUL;
533 a bind or alter context has failed
535 static void dcerpc_composite_fail(struct rpc_request *req)
537 struct composite_context *c = talloc_get_type(req->async.private_data,
538 struct composite_context);
539 composite_error(c, req->status);
543 remove requests from the pending or queued queues
545 static int dcerpc_req_dequeue(struct rpc_request *req)
547 switch (req->state) {
548 case RPC_REQUEST_QUEUED:
549 DLIST_REMOVE(req->p->conn->request_queue, req);
551 case RPC_REQUEST_PENDING:
552 DLIST_REMOVE(req->p->conn->pending, req);
554 case RPC_REQUEST_DONE:
562 mark the dcerpc connection dead. All outstanding requests get an error
564 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
566 if (conn->dead) return;
570 if (conn->transport.shutdown_pipe) {
571 conn->transport.shutdown_pipe(conn, status);
574 /* all pending requests get the error */
575 while (conn->pending) {
576 struct rpc_request *req = conn->pending;
577 dcerpc_req_dequeue(req);
578 req->state = RPC_REQUEST_DONE;
579 req->status = status;
580 if (req->async.callback) {
581 req->async.callback(req);
585 talloc_set_destructor(conn, NULL);
586 if (conn->free_skipped) {
592 forward declarations of the recv_data handlers for the types of
593 packets we need to handle
595 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
596 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
599 receive a dcerpc reply from the transport. Here we work out what
600 type of reply it is (normal request, bind or alter context) and
601 dispatch to the appropriate handler
603 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
605 struct ncacn_packet pkt;
607 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
608 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
611 /* the transport may be telling us of a severe error, such as
613 if (!NT_STATUS_IS_OK(status)) {
614 data_blob_free(blob);
615 dcerpc_connection_dead(conn, status);
619 /* parse the basic packet to work out what type of response this is */
620 status = ncacn_pull(conn, blob, blob->data, &pkt);
621 if (!NT_STATUS_IS_OK(status)) {
622 data_blob_free(blob);
623 dcerpc_connection_dead(conn, status);
626 dcerpc_request_recv_data(conn, blob, &pkt);
631 Receive a bind reply from the transport
633 static void dcerpc_bind_recv_handler(struct rpc_request *req,
634 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
636 struct composite_context *c;
637 struct dcerpc_connection *conn;
639 c = talloc_get_type(req->async.private_data, struct composite_context);
641 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
642 DEBUG(2,("dcerpc: bind_nak reason %d\n",
643 pkt->u.bind_nak.reject_reason));
644 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
649 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
650 (pkt->u.bind_ack.num_results == 0) ||
651 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
652 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
658 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
659 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
661 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
662 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
663 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
666 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
667 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
668 conn->flags |= DCERPC_HEADER_SIGNING;
671 /* the bind_ack might contain a reply set of credentials */
672 if (conn->security_state.auth_info &&
673 pkt->u.bind_ack.auth_info.length) {
674 enum ndr_err_code ndr_err;
675 ndr_err = ndr_pull_struct_blob(
676 &pkt->u.bind_ack.auth_info, conn,
678 conn->security_state.auth_info,
679 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
680 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
681 c->status = ndr_map_error2ntstatus(ndr_err);
682 if (!composite_is_ok(c)) return;
686 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
692 handle timeouts of individual dcerpc requests
694 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
695 struct timeval t, void *private)
697 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
699 if (req->ignore_timeout) {
700 dcerpc_req_dequeue(req);
701 req->state = RPC_REQUEST_DONE;
702 req->status = NT_STATUS_IO_TIMEOUT;
703 if (req->async.callback) {
704 req->async.callback(req);
709 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
713 send a async dcerpc bind request
715 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
717 const struct ndr_syntax_id *syntax,
718 const struct ndr_syntax_id *transfer_syntax)
720 struct composite_context *c;
721 struct ncacn_packet pkt;
723 struct rpc_request *req;
725 c = composite_create(mem_ctx,p->conn->event_ctx);
726 if (c == NULL) return NULL;
731 p->transfer_syntax = *transfer_syntax;
733 init_ncacn_hdr(p->conn, &pkt);
735 pkt.ptype = DCERPC_PKT_BIND;
736 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
737 pkt.call_id = p->conn->call_id;
740 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
741 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
744 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
745 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
748 pkt.u.bind.max_xmit_frag = 5840;
749 pkt.u.bind.max_recv_frag = 5840;
750 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
751 pkt.u.bind.num_contexts = 1;
752 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
753 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
754 pkt.u.bind.ctx_list[0].context_id = p->context_id;
755 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
756 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
757 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
758 pkt.u.bind.auth_info = data_blob(NULL, 0);
760 /* construct the NDR form of the packet */
761 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
762 p->conn->security_state.auth_info);
763 if (!composite_is_ok(c)) return c;
765 p->conn->transport.recv_data = dcerpc_recv_data;
768 * we allocate a dcerpc_request so we can be in the same
769 * request queue as normal requests
771 req = talloc_zero(c, struct rpc_request);
772 if (composite_nomem(req, c)) return c;
774 req->state = RPC_REQUEST_PENDING;
775 req->call_id = pkt.call_id;
776 req->async.private_data = c;
777 req->async.callback = dcerpc_composite_fail;
779 req->recv_handler = dcerpc_bind_recv_handler;
780 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
781 talloc_set_destructor(req, dcerpc_req_dequeue);
783 c->status = p->conn->transport.send_request(p->conn, &blob,
785 if (!composite_is_ok(c)) return c;
787 event_add_timed(c->event_ctx, req,
788 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
789 dcerpc_timeout_handler, req);
795 recv side of async dcerpc bind request
797 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
799 NTSTATUS result = composite_wait(ctx);
805 perform a continued bind (and auth3)
807 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
810 struct ncacn_packet pkt;
814 init_ncacn_hdr(p->conn, &pkt);
816 pkt.ptype = DCERPC_PKT_AUTH3;
817 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
818 pkt.call_id = next_call_id(p->conn);
820 pkt.u.auth3._pad = 0;
821 pkt.u.auth3.auth_info = data_blob(NULL, 0);
823 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
824 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
827 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
828 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
831 /* construct the NDR form of the packet */
832 status = ncacn_push_auth(&blob, mem_ctx,
833 p->conn->iconv_convenience,
835 p->conn->security_state.auth_info);
836 if (!NT_STATUS_IS_OK(status)) {
840 /* send it on its way */
841 status = p->conn->transport.send_request(p->conn, &blob, false);
842 if (!NT_STATUS_IS_OK(status)) {
851 process a fragment received from the transport layer during a
854 This function frees the data
856 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
857 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
859 struct rpc_request *req;
861 NTSTATUS status = NT_STATUS_OK;
864 if this is an authenticated connection then parse and check
865 the auth info. We have to do this before finding the
866 matching packet, as the request structure might have been
867 removed due to a timeout, but if it has been we still need
868 to run the auth routines so that we don't get the sign/seal
869 info out of step with the server
871 if (c->security_state.auth_info && c->security_state.generic_state &&
872 pkt->ptype == DCERPC_PKT_RESPONSE) {
873 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
876 /* find the matching request */
877 for (req=c->pending;req;req=req->next) {
878 if (pkt->call_id == req->call_id) break;
882 /* useful for testing certain vendors RPC servers */
883 if (req == NULL && c->pending && pkt->call_id == 0) {
884 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
890 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
891 data_blob_free(raw_packet);
895 talloc_steal(req, raw_packet->data);
897 if (req->recv_handler != NULL) {
898 dcerpc_req_dequeue(req);
899 req->state = RPC_REQUEST_DONE;
900 req->recv_handler(req, raw_packet, pkt);
904 if (pkt->ptype == DCERPC_PKT_FAULT) {
905 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
906 req->fault_code = pkt->u.fault.status;
907 req->status = NT_STATUS_NET_WRITE_FAULT;
911 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
912 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
914 req->fault_code = DCERPC_FAULT_OTHER;
915 req->status = NT_STATUS_NET_WRITE_FAULT;
919 /* now check the status from the auth routines, and if it failed then fail
920 this request accordingly */
921 if (!NT_STATUS_IS_OK(status)) {
922 req->status = status;
926 length = pkt->u.response.stub_and_verifier.length;
929 req->payload.data = talloc_realloc(req,
932 req->payload.length + length);
933 if (!req->payload.data) {
934 req->status = NT_STATUS_NO_MEMORY;
937 memcpy(req->payload.data+req->payload.length,
938 pkt->u.response.stub_and_verifier.data, length);
939 req->payload.length += length;
942 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
943 c->transport.send_read(c);
947 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
948 req->flags |= DCERPC_PULL_BIGENDIAN;
950 req->flags &= ~DCERPC_PULL_BIGENDIAN;
955 /* we've got the full payload */
956 req->state = RPC_REQUEST_DONE;
957 DLIST_REMOVE(c->pending, req);
959 if (c->request_queue != NULL) {
960 /* We have to look at shipping further requests before calling
961 * the async function, that one might close the pipe */
962 dcerpc_ship_next_request(c);
965 if (req->async.callback) {
966 req->async.callback(req);
971 perform the send side of a async dcerpc request
973 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
974 const struct GUID *object,
977 DATA_BLOB *stub_data)
979 struct rpc_request *req;
981 p->conn->transport.recv_data = dcerpc_recv_data;
983 req = talloc(p, struct rpc_request);
989 req->call_id = next_call_id(p->conn);
990 req->status = NT_STATUS_OK;
991 req->state = RPC_REQUEST_QUEUED;
992 req->payload = data_blob(NULL, 0);
995 req->async_call = async;
996 req->ignore_timeout = false;
997 req->async.callback = NULL;
998 req->async.private_data = NULL;
999 req->recv_handler = NULL;
1001 if (object != NULL) {
1002 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1003 if (req->object == NULL) {
1012 req->request_data.length = stub_data->length;
1013 req->request_data.data = talloc_reference(req, stub_data->data);
1014 if (req->request_data.length && req->request_data.data == NULL) {
1018 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1019 talloc_set_destructor(req, dcerpc_req_dequeue);
1021 dcerpc_ship_next_request(p->conn);
1023 if (p->request_timeout) {
1024 event_add_timed(dcerpc_event_context(p), req,
1025 timeval_current_ofs(p->request_timeout, 0),
1026 dcerpc_timeout_handler, req);
1033 Send a request using the transport
1036 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1038 struct rpc_request *req;
1039 struct dcerpc_pipe *p;
1040 DATA_BLOB *stub_data;
1041 struct ncacn_packet pkt;
1043 uint32_t remaining, chunk_size;
1044 bool first_packet = true;
1045 size_t sig_size = 0;
1047 req = c->request_queue;
1053 stub_data = &req->request_data;
1055 if (!req->async_call && (c->pending != NULL)) {
1059 DLIST_REMOVE(c->request_queue, req);
1060 DLIST_ADD(c->pending, req);
1061 req->state = RPC_REQUEST_PENDING;
1063 init_ncacn_hdr(p->conn, &pkt);
1065 remaining = stub_data->length;
1067 /* we can write a full max_recv_frag size, minus the dcerpc
1068 request header size */
1069 chunk_size = p->conn->srv_max_recv_frag;
1070 chunk_size -= DCERPC_REQUEST_LENGTH;
1071 if (c->security_state.generic_state) {
1072 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1073 sig_size = gensec_sig_size(c->security_state.generic_state,
1074 p->conn->srv_max_recv_frag);
1075 chunk_size -= sig_size;
1076 chunk_size -= (chunk_size % 16);
1079 pkt.ptype = DCERPC_PKT_REQUEST;
1080 pkt.call_id = req->call_id;
1081 pkt.auth_length = 0;
1083 pkt.u.request.alloc_hint = remaining;
1084 pkt.u.request.context_id = p->context_id;
1085 pkt.u.request.opnum = req->opnum;
1088 pkt.u.request.object.object = *req->object;
1089 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1090 chunk_size -= ndr_size_GUID(req->object,0);
1093 /* we send a series of pdus without waiting for a reply */
1094 while (remaining > 0 || first_packet) {
1095 uint32_t chunk = MIN(chunk_size, remaining);
1096 bool last_frag = false;
1098 first_packet = false;
1099 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1101 if (remaining == stub_data->length) {
1102 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1104 if (chunk == remaining) {
1105 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1109 pkt.u.request.stub_and_verifier.data = stub_data->data +
1110 (stub_data->length - remaining);
1111 pkt.u.request.stub_and_verifier.length = chunk;
1113 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1114 if (!NT_STATUS_IS_OK(req->status)) {
1115 req->state = RPC_REQUEST_DONE;
1116 DLIST_REMOVE(p->conn->pending, req);
1120 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1121 if (!NT_STATUS_IS_OK(req->status)) {
1122 req->state = RPC_REQUEST_DONE;
1123 DLIST_REMOVE(p->conn->pending, req);
1132 return the event context for a dcerpc pipe
1133 used by callers who wish to operate asynchronously
1135 _PUBLIC_ struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1137 return p->conn->event_ctx;
1143 perform the receive side of a async dcerpc request
1145 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1146 TALLOC_CTX *mem_ctx,
1147 DATA_BLOB *stub_data)
1151 while (req->state != RPC_REQUEST_DONE) {
1152 struct event_context *ctx = dcerpc_event_context(req->p);
1153 if (event_loop_once(ctx) != 0) {
1154 return NT_STATUS_CONNECTION_DISCONNECTED;
1157 *stub_data = req->payload;
1158 status = req->status;
1159 if (stub_data->data) {
1160 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1162 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1163 req->p->last_fault_code = req->fault_code;
1170 perform a full request/response pair on a dcerpc pipe
1172 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1173 struct GUID *object,
1176 TALLOC_CTX *mem_ctx,
1177 DATA_BLOB *stub_data_in,
1178 DATA_BLOB *stub_data_out)
1180 struct rpc_request *req;
1182 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1184 return NT_STATUS_NO_MEMORY;
1187 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1192 this is a paranoid NDR validator. For every packet we push onto the wire
1193 we pull it back again, then push it again. Then we compare the raw NDR data
1194 for that to the NDR we initially generated. If they don't match then we know
1195 we must have a bug in either the pull or push side of our code
1197 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1198 TALLOC_CTX *mem_ctx,
1201 ndr_push_flags_fn_t ndr_push,
1202 ndr_pull_flags_fn_t ndr_pull)
1205 struct ndr_pull *pull;
1206 struct ndr_push *push;
1208 enum ndr_err_code ndr_err;
1210 st = talloc_size(mem_ctx, struct_size);
1212 return NT_STATUS_NO_MEMORY;
1215 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1217 return NT_STATUS_NO_MEMORY;
1219 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1221 ndr_err = ndr_pull(pull, NDR_IN, st);
1222 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1223 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1224 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1225 "failed input validation pull - %s",
1227 return ndr_map_error2ntstatus(ndr_err);
1230 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1232 return NT_STATUS_NO_MEMORY;
1235 ndr_err = ndr_push(push, NDR_IN, st);
1236 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1237 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1238 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1239 "failed input validation push - %s",
1241 return ndr_map_error2ntstatus(ndr_err);
1244 blob2 = ndr_push_blob(push);
1246 if (data_blob_cmp(&blob, &blob2) != 0) {
1247 DEBUG(3,("original:\n"));
1248 dump_data(3, blob.data, blob.length);
1249 DEBUG(3,("secondary:\n"));
1250 dump_data(3, blob2.data, blob2.length);
1251 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1252 "failed input validation blobs doesn't match");
1253 return ndr_map_error2ntstatus(ndr_err);
1256 return NT_STATUS_OK;
1260 this is a paranoid NDR input validator. For every packet we pull
1261 from the wire we push it back again then pull and push it
1262 again. Then we compare the raw NDR data for that to the NDR we
1263 initially generated. If they don't match then we know we must have a
1264 bug in either the pull or push side of our code
1266 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1267 struct ndr_pull *pull_in,
1270 ndr_push_flags_fn_t ndr_push,
1271 ndr_pull_flags_fn_t ndr_pull,
1272 ndr_print_function_t ndr_print)
1275 struct ndr_pull *pull;
1276 struct ndr_push *push;
1277 DATA_BLOB blob, blob2;
1278 TALLOC_CTX *mem_ctx = pull_in;
1280 enum ndr_err_code ndr_err;
1282 st = talloc_size(mem_ctx, struct_size);
1284 return NT_STATUS_NO_MEMORY;
1286 memcpy(st, struct_ptr, struct_size);
1288 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1290 return NT_STATUS_NO_MEMORY;
1293 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1294 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1295 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1296 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1297 "failed output validation push - %s",
1299 return ndr_map_error2ntstatus(ndr_err);
1302 blob = ndr_push_blob(push);
1304 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1306 return NT_STATUS_NO_MEMORY;
1309 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1310 ndr_err = ndr_pull(pull, NDR_OUT, st);
1311 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1312 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1313 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1314 "failed output validation pull - %s",
1316 return ndr_map_error2ntstatus(ndr_err);
1319 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1321 return NT_STATUS_NO_MEMORY;
1324 ndr_err = ndr_push(push, NDR_OUT, st);
1325 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1326 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1327 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1328 "failed output validation push2 - %s",
1330 return ndr_map_error2ntstatus(ndr_err);
1333 blob2 = ndr_push_blob(push);
1335 if (data_blob_cmp(&blob, &blob2) != 0) {
1336 DEBUG(3,("original:\n"));
1337 dump_data(3, blob.data, blob.length);
1338 DEBUG(3,("secondary:\n"));
1339 dump_data(3, blob2.data, blob2.length);
1340 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1341 "failed output validation blobs doesn't match");
1342 return ndr_map_error2ntstatus(ndr_err);
1345 /* this checks the printed forms of the two structures, which effectively
1346 tests all of the value() attributes */
1347 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1348 NDR_OUT, struct_ptr);
1349 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1351 if (strcmp(s1, s2) != 0) {
1353 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1355 /* this is sometimes useful */
1356 printf("VALIDATE ERROR\n");
1357 file_save("wire.dat", s1, strlen(s1));
1358 file_save("gen.dat", s2, strlen(s2));
1359 system("diff -u wire.dat gen.dat");
1361 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1362 "failed output validation strings doesn't match");
1363 return ndr_map_error2ntstatus(ndr_err);
1366 return NT_STATUS_OK;
1371 send a rpc request given a dcerpc_call structure
1373 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1374 const struct GUID *object,
1375 const struct ndr_interface_table *table,
1377 TALLOC_CTX *mem_ctx,
1380 const struct ndr_interface_call *call;
1381 struct ndr_push *push;
1384 struct rpc_request *req;
1385 enum ndr_err_code ndr_err;
1387 call = &table->calls[opnum];
1389 /* setup for a ndr_push_* call */
1390 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1395 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1396 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1399 /* push the structure into a blob */
1400 ndr_err = call->ndr_push(push, NDR_IN, r);
1401 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1402 status = ndr_map_error2ntstatus(ndr_err);
1403 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1404 nt_errstr(status)));
1409 /* retrieve the blob */
1410 request = ndr_push_blob(push);
1412 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1413 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1414 call->ndr_push, call->ndr_pull);
1415 if (!NT_STATUS_IS_OK(status)) {
1416 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1417 nt_errstr(status)));
1423 DEBUG(10,("rpc request data:\n"));
1424 dump_data(10, request.data, request.length);
1426 /* make the actual dcerpc request */
1427 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1431 req->ndr.table = table;
1432 req->ndr.opnum = opnum;
1433 req->ndr.struct_ptr = r;
1434 req->ndr.mem_ctx = mem_ctx;
1443 receive the answer from a dcerpc_ndr_request_send()
1445 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1447 struct dcerpc_pipe *p = req->p;
1450 struct ndr_pull *pull;
1452 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1453 void *r = req->ndr.struct_ptr;
1454 uint32_t opnum = req->ndr.opnum;
1455 const struct ndr_interface_table *table = req->ndr.table;
1456 const struct ndr_interface_call *call = &table->calls[opnum];
1457 enum ndr_err_code ndr_err;
1459 /* make sure the recv code doesn't free the request, as we
1460 need to grab the flags element before it is freed */
1461 if (talloc_reference(p, req) == NULL) {
1462 return NT_STATUS_NO_MEMORY;
1465 status = dcerpc_request_recv(req, mem_ctx, &response);
1466 if (!NT_STATUS_IS_OK(status)) {
1467 talloc_unlink(p, req);
1473 /* prepare for ndr_pull_* */
1474 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1476 talloc_unlink(p, req);
1477 return NT_STATUS_NO_MEMORY;
1481 pull->data = talloc_steal(pull, pull->data);
1483 talloc_unlink(p, req);
1485 if (flags & DCERPC_PULL_BIGENDIAN) {
1486 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1489 DEBUG(10,("rpc reply data:\n"));
1490 dump_data(10, pull->data, pull->data_size);
1492 /* pull the structure from the blob */
1493 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1494 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1495 status = ndr_map_error2ntstatus(ndr_err);
1496 dcerpc_log_packet(table, opnum, NDR_OUT,
1501 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1502 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1503 call->ndr_push, call->ndr_pull,
1505 if (!NT_STATUS_IS_OK(status)) {
1506 dcerpc_log_packet(table, opnum, NDR_OUT,
1512 if (pull->offset != pull->data_size) {
1513 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1514 pull->data_size - pull->offset));
1515 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1516 but it turns out that early versions of NT
1517 (specifically NT3.1) add junk onto the end of rpc
1518 packets, so if we want to interoperate at all with
1519 those versions then we need to ignore this error */
1522 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1524 return NT_STATUS_OK;
1529 a useful helper function for synchronous rpc requests
1531 this can be used when you have ndr push/pull functions in the
1534 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1535 const struct GUID *object,
1536 const struct ndr_interface_table *table,
1538 TALLOC_CTX *mem_ctx,
1541 struct rpc_request *req;
1543 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1545 return NT_STATUS_NO_MEMORY;
1548 return dcerpc_ndr_request_recv(req);
1553 a useful function for retrieving the server name we connected to
1555 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1557 if (!p->conn->transport.target_hostname) {
1558 if (!p->conn->transport.peer_name) {
1561 return p->conn->transport.peer_name(p->conn);
1563 return p->conn->transport.target_hostname(p->conn);
1568 get the dcerpc auth_level for a open connection
1570 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1574 if (c->flags & DCERPC_SEAL) {
1575 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1576 } else if (c->flags & DCERPC_SIGN) {
1577 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1578 } else if (c->flags & DCERPC_CONNECT) {
1579 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1581 auth_level = DCERPC_AUTH_LEVEL_NONE;
1587 Receive an alter reply from the transport
1589 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1590 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1592 struct composite_context *c;
1593 struct dcerpc_pipe *recv_pipe;
1595 c = talloc_get_type(req->async.private_data, struct composite_context);
1596 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1598 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1599 pkt->u.alter_resp.num_results == 1 &&
1600 pkt->u.alter_resp.ctx_list[0].result != 0) {
1601 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1602 pkt->u.alter_resp.ctx_list[0].reason));
1603 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1607 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1608 pkt->u.alter_resp.num_results == 0 ||
1609 pkt->u.alter_resp.ctx_list[0].result != 0) {
1610 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1614 /* the alter_resp might contain a reply set of credentials */
1615 if (recv_pipe->conn->security_state.auth_info &&
1616 pkt->u.alter_resp.auth_info.length) {
1617 enum ndr_err_code ndr_err;
1618 ndr_err = ndr_pull_struct_blob(
1619 &pkt->u.alter_resp.auth_info, recv_pipe,
1621 recv_pipe->conn->security_state.auth_info,
1622 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1623 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1624 c->status = ndr_map_error2ntstatus(ndr_err);
1625 if (!composite_is_ok(c)) return;
1633 send a dcerpc alter_context request
1635 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1636 TALLOC_CTX *mem_ctx,
1637 const struct ndr_syntax_id *syntax,
1638 const struct ndr_syntax_id *transfer_syntax)
1640 struct composite_context *c;
1641 struct ncacn_packet pkt;
1643 struct rpc_request *req;
1645 c = composite_create(mem_ctx, p->conn->event_ctx);
1646 if (c == NULL) return NULL;
1648 c->private_data = p;
1650 p->syntax = *syntax;
1651 p->transfer_syntax = *transfer_syntax;
1653 init_ncacn_hdr(p->conn, &pkt);
1655 pkt.ptype = DCERPC_PKT_ALTER;
1656 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1657 pkt.call_id = p->conn->call_id;
1658 pkt.auth_length = 0;
1660 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1661 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1664 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1665 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1668 pkt.u.alter.max_xmit_frag = 5840;
1669 pkt.u.alter.max_recv_frag = 5840;
1670 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1671 pkt.u.alter.num_contexts = 1;
1672 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1673 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1674 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1675 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1676 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1677 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1678 pkt.u.alter.auth_info = data_blob(NULL, 0);
1680 /* construct the NDR form of the packet */
1681 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1682 p->conn->security_state.auth_info);
1683 if (!composite_is_ok(c)) return c;
1685 p->conn->transport.recv_data = dcerpc_recv_data;
1688 * we allocate a dcerpc_request so we can be in the same
1689 * request queue as normal requests
1691 req = talloc_zero(c, struct rpc_request);
1692 if (composite_nomem(req, c)) return c;
1694 req->state = RPC_REQUEST_PENDING;
1695 req->call_id = pkt.call_id;
1696 req->async.private_data = c;
1697 req->async.callback = dcerpc_composite_fail;
1699 req->recv_handler = dcerpc_alter_recv_handler;
1700 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1701 talloc_set_destructor(req, dcerpc_req_dequeue);
1703 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1704 if (!composite_is_ok(c)) return c;
1706 event_add_timed(c->event_ctx, req,
1707 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1708 dcerpc_timeout_handler, req);
1713 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1715 NTSTATUS result = composite_wait(ctx);
1721 send a dcerpc alter_context request
1723 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1724 TALLOC_CTX *mem_ctx,
1725 const struct ndr_syntax_id *syntax,
1726 const struct ndr_syntax_id *transfer_syntax)
1728 struct composite_context *creq;
1729 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1730 return dcerpc_alter_context_recv(creq);