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,
337 struct ncacn_packet *pkt)
340 struct ndr_push *ndr;
342 size_t payload_length;
343 enum ndr_err_code ndr_err;
345 /* non-signed packets are simpler */
346 if (!c->security_state.auth_info ||
347 !c->security_state.generic_state) {
348 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, c->security_state.auth_info);
351 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
353 return NT_STATUS_NO_MEMORY;
356 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
357 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
360 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
361 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
364 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
365 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
366 return ndr_map_error2ntstatus(ndr_err);
368 status = NT_STATUS_OK;
370 /* pad to 16 byte multiple in the payload portion of the
371 packet. This matches what w2k3 does */
372 c->security_state.auth_info->auth_pad_length =
373 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
374 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
376 payload_length = pkt->u.request.stub_and_verifier.length +
377 c->security_state.auth_info->auth_pad_length;
379 /* sign or seal the packet */
380 switch (c->security_state.auth_info->auth_level) {
381 case DCERPC_AUTH_LEVEL_PRIVACY:
382 case DCERPC_AUTH_LEVEL_INTEGRITY:
383 /* We hope this length is accruate. If must be if the
384 * GENSEC mech does AEAD signing of the packet
386 c->security_state.auth_info->credentials
387 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
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;
1046 req = c->request_queue;
1052 stub_data = &req->request_data;
1054 if (!req->async_call && (c->pending != NULL)) {
1058 DLIST_REMOVE(c->request_queue, req);
1059 DLIST_ADD(c->pending, req);
1060 req->state = RPC_REQUEST_PENDING;
1062 init_ncacn_hdr(p->conn, &pkt);
1064 remaining = stub_data->length;
1066 /* we can write a full max_recv_frag size, minus the dcerpc
1067 request header size */
1068 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1070 pkt.ptype = DCERPC_PKT_REQUEST;
1071 pkt.call_id = req->call_id;
1072 pkt.auth_length = 0;
1074 pkt.u.request.alloc_hint = remaining;
1075 pkt.u.request.context_id = p->context_id;
1076 pkt.u.request.opnum = req->opnum;
1079 pkt.u.request.object.object = *req->object;
1080 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1081 chunk_size -= ndr_size_GUID(req->object,0);
1084 /* we send a series of pdus without waiting for a reply */
1085 while (remaining > 0 || first_packet) {
1086 uint32_t chunk = MIN(chunk_size, remaining);
1087 bool last_frag = false;
1089 first_packet = false;
1090 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1092 if (remaining == stub_data->length) {
1093 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1095 if (chunk == remaining) {
1096 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1100 pkt.u.request.stub_and_verifier.data = stub_data->data +
1101 (stub_data->length - remaining);
1102 pkt.u.request.stub_and_verifier.length = chunk;
1104 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1105 if (!NT_STATUS_IS_OK(req->status)) {
1106 req->state = RPC_REQUEST_DONE;
1107 DLIST_REMOVE(p->conn->pending, req);
1111 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1112 if (!NT_STATUS_IS_OK(req->status)) {
1113 req->state = RPC_REQUEST_DONE;
1114 DLIST_REMOVE(p->conn->pending, req);
1123 return the event context for a dcerpc pipe
1124 used by callers who wish to operate asynchronously
1126 _PUBLIC_ struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1128 return p->conn->event_ctx;
1134 perform the receive side of a async dcerpc request
1136 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1137 TALLOC_CTX *mem_ctx,
1138 DATA_BLOB *stub_data)
1142 while (req->state != RPC_REQUEST_DONE) {
1143 struct event_context *ctx = dcerpc_event_context(req->p);
1144 if (event_loop_once(ctx) != 0) {
1145 return NT_STATUS_CONNECTION_DISCONNECTED;
1148 *stub_data = req->payload;
1149 status = req->status;
1150 if (stub_data->data) {
1151 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1153 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1154 req->p->last_fault_code = req->fault_code;
1161 perform a full request/response pair on a dcerpc pipe
1163 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1164 struct GUID *object,
1167 TALLOC_CTX *mem_ctx,
1168 DATA_BLOB *stub_data_in,
1169 DATA_BLOB *stub_data_out)
1171 struct rpc_request *req;
1173 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1175 return NT_STATUS_NO_MEMORY;
1178 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1183 this is a paranoid NDR validator. For every packet we push onto the wire
1184 we pull it back again, then push it again. Then we compare the raw NDR data
1185 for that to the NDR we initially generated. If they don't match then we know
1186 we must have a bug in either the pull or push side of our code
1188 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1189 TALLOC_CTX *mem_ctx,
1192 ndr_push_flags_fn_t ndr_push,
1193 ndr_pull_flags_fn_t ndr_pull)
1196 struct ndr_pull *pull;
1197 struct ndr_push *push;
1199 enum ndr_err_code ndr_err;
1201 st = talloc_size(mem_ctx, struct_size);
1203 return NT_STATUS_NO_MEMORY;
1206 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1208 return NT_STATUS_NO_MEMORY;
1210 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1212 ndr_err = ndr_pull(pull, NDR_IN, st);
1213 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1214 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1215 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1216 "failed input validation pull - %s",
1218 return ndr_map_error2ntstatus(ndr_err);
1221 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1223 return NT_STATUS_NO_MEMORY;
1226 ndr_err = ndr_push(push, NDR_IN, st);
1227 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1228 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1229 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1230 "failed input validation push - %s",
1232 return ndr_map_error2ntstatus(ndr_err);
1235 blob2 = ndr_push_blob(push);
1237 if (data_blob_cmp(&blob, &blob2) != 0) {
1238 DEBUG(3,("original:\n"));
1239 dump_data(3, blob.data, blob.length);
1240 DEBUG(3,("secondary:\n"));
1241 dump_data(3, blob2.data, blob2.length);
1242 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1243 "failed input validation blobs doesn't match");
1244 return ndr_map_error2ntstatus(ndr_err);
1247 return NT_STATUS_OK;
1251 this is a paranoid NDR input validator. For every packet we pull
1252 from the wire we push it back again then pull and push it
1253 again. Then we compare the raw NDR data for that to the NDR we
1254 initially generated. If they don't match then we know we must have a
1255 bug in either the pull or push side of our code
1257 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1258 struct ndr_pull *pull_in,
1261 ndr_push_flags_fn_t ndr_push,
1262 ndr_pull_flags_fn_t ndr_pull,
1263 ndr_print_function_t ndr_print)
1266 struct ndr_pull *pull;
1267 struct ndr_push *push;
1268 DATA_BLOB blob, blob2;
1269 TALLOC_CTX *mem_ctx = pull_in;
1271 enum ndr_err_code ndr_err;
1273 st = talloc_size(mem_ctx, struct_size);
1275 return NT_STATUS_NO_MEMORY;
1277 memcpy(st, struct_ptr, struct_size);
1279 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1281 return NT_STATUS_NO_MEMORY;
1284 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1285 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1286 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1287 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1288 "failed output validation push - %s",
1290 return ndr_map_error2ntstatus(ndr_err);
1293 blob = ndr_push_blob(push);
1295 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1297 return NT_STATUS_NO_MEMORY;
1300 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1301 ndr_err = ndr_pull(pull, NDR_OUT, st);
1302 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1303 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1304 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1305 "failed output validation pull - %s",
1307 return ndr_map_error2ntstatus(ndr_err);
1310 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1312 return NT_STATUS_NO_MEMORY;
1315 ndr_err = ndr_push(push, NDR_OUT, st);
1316 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1317 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1318 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1319 "failed output validation push2 - %s",
1321 return ndr_map_error2ntstatus(ndr_err);
1324 blob2 = ndr_push_blob(push);
1326 if (data_blob_cmp(&blob, &blob2) != 0) {
1327 DEBUG(3,("original:\n"));
1328 dump_data(3, blob.data, blob.length);
1329 DEBUG(3,("secondary:\n"));
1330 dump_data(3, blob2.data, blob2.length);
1331 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1332 "failed output validation blobs doesn't match");
1333 return ndr_map_error2ntstatus(ndr_err);
1336 /* this checks the printed forms of the two structures, which effectively
1337 tests all of the value() attributes */
1338 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1339 NDR_OUT, struct_ptr);
1340 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1342 if (strcmp(s1, s2) != 0) {
1344 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1346 /* this is sometimes useful */
1347 printf("VALIDATE ERROR\n");
1348 file_save("wire.dat", s1, strlen(s1));
1349 file_save("gen.dat", s2, strlen(s2));
1350 system("diff -u wire.dat gen.dat");
1352 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1353 "failed output validation strings doesn't match");
1354 return ndr_map_error2ntstatus(ndr_err);
1357 return NT_STATUS_OK;
1362 send a rpc request given a dcerpc_call structure
1364 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1365 const struct GUID *object,
1366 const struct ndr_interface_table *table,
1368 TALLOC_CTX *mem_ctx,
1371 const struct ndr_interface_call *call;
1372 struct ndr_push *push;
1375 struct rpc_request *req;
1376 enum ndr_err_code ndr_err;
1378 call = &table->calls[opnum];
1380 /* setup for a ndr_push_* call */
1381 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1386 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1387 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1390 /* push the structure into a blob */
1391 ndr_err = call->ndr_push(push, NDR_IN, r);
1392 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1393 status = ndr_map_error2ntstatus(ndr_err);
1394 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1395 nt_errstr(status)));
1400 /* retrieve the blob */
1401 request = ndr_push_blob(push);
1403 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1404 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1405 call->ndr_push, call->ndr_pull);
1406 if (!NT_STATUS_IS_OK(status)) {
1407 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1408 nt_errstr(status)));
1414 DEBUG(10,("rpc request data:\n"));
1415 dump_data(10, request.data, request.length);
1417 /* make the actual dcerpc request */
1418 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1422 req->ndr.table = table;
1423 req->ndr.opnum = opnum;
1424 req->ndr.struct_ptr = r;
1425 req->ndr.mem_ctx = mem_ctx;
1434 receive the answer from a dcerpc_ndr_request_send()
1436 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1438 struct dcerpc_pipe *p = req->p;
1441 struct ndr_pull *pull;
1443 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1444 void *r = req->ndr.struct_ptr;
1445 uint32_t opnum = req->ndr.opnum;
1446 const struct ndr_interface_table *table = req->ndr.table;
1447 const struct ndr_interface_call *call = &table->calls[opnum];
1448 enum ndr_err_code ndr_err;
1450 /* make sure the recv code doesn't free the request, as we
1451 need to grab the flags element before it is freed */
1452 if (talloc_reference(p, req) == NULL) {
1453 return NT_STATUS_NO_MEMORY;
1456 status = dcerpc_request_recv(req, mem_ctx, &response);
1457 if (!NT_STATUS_IS_OK(status)) {
1458 talloc_unlink(p, req);
1464 /* prepare for ndr_pull_* */
1465 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1467 talloc_unlink(p, req);
1468 return NT_STATUS_NO_MEMORY;
1472 pull->data = talloc_steal(pull, pull->data);
1474 talloc_unlink(p, req);
1476 if (flags & DCERPC_PULL_BIGENDIAN) {
1477 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1480 DEBUG(10,("rpc reply data:\n"));
1481 dump_data(10, pull->data, pull->data_size);
1483 /* pull the structure from the blob */
1484 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1485 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1486 status = ndr_map_error2ntstatus(ndr_err);
1487 dcerpc_log_packet(table, opnum, NDR_OUT,
1492 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1493 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1494 call->ndr_push, call->ndr_pull,
1496 if (!NT_STATUS_IS_OK(status)) {
1497 dcerpc_log_packet(table, opnum, NDR_OUT,
1503 if (pull->offset != pull->data_size) {
1504 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1505 pull->data_size - pull->offset));
1506 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1507 but it turns out that early versions of NT
1508 (specifically NT3.1) add junk onto the end of rpc
1509 packets, so if we want to interoperate at all with
1510 those versions then we need to ignore this error */
1513 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1515 return NT_STATUS_OK;
1520 a useful helper function for synchronous rpc requests
1522 this can be used when you have ndr push/pull functions in the
1525 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1526 const struct GUID *object,
1527 const struct ndr_interface_table *table,
1529 TALLOC_CTX *mem_ctx,
1532 struct rpc_request *req;
1534 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1536 return NT_STATUS_NO_MEMORY;
1539 return dcerpc_ndr_request_recv(req);
1544 a useful function for retrieving the server name we connected to
1546 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1548 if (!p->conn->transport.target_hostname) {
1549 if (!p->conn->transport.peer_name) {
1552 return p->conn->transport.peer_name(p->conn);
1554 return p->conn->transport.target_hostname(p->conn);
1559 get the dcerpc auth_level for a open connection
1561 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1565 if (c->flags & DCERPC_SEAL) {
1566 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1567 } else if (c->flags & DCERPC_SIGN) {
1568 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1569 } else if (c->flags & DCERPC_CONNECT) {
1570 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1572 auth_level = DCERPC_AUTH_LEVEL_NONE;
1578 Receive an alter reply from the transport
1580 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1581 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1583 struct composite_context *c;
1584 struct dcerpc_pipe *recv_pipe;
1586 c = talloc_get_type(req->async.private_data, struct composite_context);
1587 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1589 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1590 pkt->u.alter_resp.num_results == 1 &&
1591 pkt->u.alter_resp.ctx_list[0].result != 0) {
1592 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1593 pkt->u.alter_resp.ctx_list[0].reason));
1594 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1598 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1599 pkt->u.alter_resp.num_results == 0 ||
1600 pkt->u.alter_resp.ctx_list[0].result != 0) {
1601 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1605 /* the alter_resp might contain a reply set of credentials */
1606 if (recv_pipe->conn->security_state.auth_info &&
1607 pkt->u.alter_resp.auth_info.length) {
1608 enum ndr_err_code ndr_err;
1609 ndr_err = ndr_pull_struct_blob(
1610 &pkt->u.alter_resp.auth_info, recv_pipe,
1612 recv_pipe->conn->security_state.auth_info,
1613 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1614 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1615 c->status = ndr_map_error2ntstatus(ndr_err);
1616 if (!composite_is_ok(c)) return;
1624 send a dcerpc alter_context request
1626 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1627 TALLOC_CTX *mem_ctx,
1628 const struct ndr_syntax_id *syntax,
1629 const struct ndr_syntax_id *transfer_syntax)
1631 struct composite_context *c;
1632 struct ncacn_packet pkt;
1634 struct rpc_request *req;
1636 c = composite_create(mem_ctx, p->conn->event_ctx);
1637 if (c == NULL) return NULL;
1639 c->private_data = p;
1641 p->syntax = *syntax;
1642 p->transfer_syntax = *transfer_syntax;
1644 init_ncacn_hdr(p->conn, &pkt);
1646 pkt.ptype = DCERPC_PKT_ALTER;
1647 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1648 pkt.call_id = p->conn->call_id;
1649 pkt.auth_length = 0;
1651 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1652 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1655 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1656 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1659 pkt.u.alter.max_xmit_frag = 5840;
1660 pkt.u.alter.max_recv_frag = 5840;
1661 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1662 pkt.u.alter.num_contexts = 1;
1663 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1664 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1665 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1666 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1667 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1668 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1669 pkt.u.alter.auth_info = data_blob(NULL, 0);
1671 /* construct the NDR form of the packet */
1672 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1673 p->conn->security_state.auth_info);
1674 if (!composite_is_ok(c)) return c;
1676 p->conn->transport.recv_data = dcerpc_recv_data;
1679 * we allocate a dcerpc_request so we can be in the same
1680 * request queue as normal requests
1682 req = talloc_zero(c, struct rpc_request);
1683 if (composite_nomem(req, c)) return c;
1685 req->state = RPC_REQUEST_PENDING;
1686 req->call_id = pkt.call_id;
1687 req->async.private_data = c;
1688 req->async.callback = dcerpc_composite_fail;
1690 req->recv_handler = dcerpc_alter_recv_handler;
1691 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1692 talloc_set_destructor(req, dcerpc_req_dequeue);
1694 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1695 if (!composite_is_ok(c)) return c;
1697 event_add_timed(c->event_ctx, req,
1698 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1699 dcerpc_timeout_handler, req);
1704 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1706 NTSTATUS result = composite_wait(ctx);
1712 send a dcerpc alter_context request
1714 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1715 TALLOC_CTX *mem_ctx,
1716 const struct ndr_syntax_id *syntax,
1717 const struct ndr_syntax_id *transfer_syntax)
1719 struct composite_context *creq;
1720 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1721 return dcerpc_alter_context_recv(creq);