2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
34 _PUBLIC_ NTSTATUS dcerpc_init(void)
36 gensec_init(global_loadparm);
41 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
42 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
44 /* destroy a dcerpc connection */
45 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
48 conn->free_skipped = true;
51 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
56 /* initialise a dcerpc connection.
57 the event context is optional
59 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
60 struct event_context *ev,
61 struct smb_iconv_convenience *ic)
63 struct dcerpc_connection *c;
65 c = talloc_zero(mem_ctx, struct dcerpc_connection);
70 c->iconv_convenience = talloc_reference(c, ic);
72 c->event_ctx = talloc_reference(c, ev);
74 if (c->event_ctx == NULL) {
80 c->security_state.auth_info = NULL;
81 c->security_state.session_key = dcerpc_generic_session_key;
82 c->security_state.generic_state = NULL;
83 c->binding_string = NULL;
85 c->srv_max_xmit_frag = 0;
86 c->srv_max_recv_frag = 0;
89 talloc_set_destructor(c, dcerpc_connection_destructor);
94 /* initialise a dcerpc pipe. */
95 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev,
96 struct smb_iconv_convenience *ic)
98 struct dcerpc_pipe *p;
100 p = talloc(mem_ctx, struct dcerpc_pipe);
105 p->conn = dcerpc_connection_init(p, ev, ic);
106 if (p->conn == NULL) {
111 p->last_fault_code = 0;
113 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
116 ZERO_STRUCT(p->syntax);
117 ZERO_STRUCT(p->transfer_syntax);
124 choose the next call id to use
126 static uint32_t next_call_id(struct dcerpc_connection *c)
129 if (c->call_id == 0) {
135 /* we need to be able to get/set the fragment length without doing a full
137 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
139 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
140 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
142 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
146 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
148 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
149 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
151 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
155 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
157 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
158 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
160 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
166 setup for a ndr pull, also setting up any flags from the binding string
168 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
169 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
171 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
173 if (ndr == NULL) return ndr;
175 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
176 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
179 if (c->flags & DCERPC_NDR_REF_ALLOC) {
180 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
187 parse a data blob into a ncacn_packet structure. This handles both
188 input and output packets
190 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
191 struct ncacn_packet *pkt)
193 struct ndr_pull *ndr;
194 enum ndr_err_code ndr_err;
196 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
198 return NT_STATUS_NO_MEMORY;
201 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
202 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
205 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
206 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
207 return ndr_map_error2ntstatus(ndr_err);
214 parse the authentication information on a dcerpc response packet
216 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
217 DATA_BLOB *raw_packet,
218 struct ncacn_packet *pkt)
220 struct ndr_pull *ndr;
222 struct dcerpc_auth auth;
224 enum ndr_err_code ndr_err;
226 if (!c->security_state.auth_info ||
227 !c->security_state.generic_state) {
231 switch (c->security_state.auth_info->auth_level) {
232 case DCERPC_AUTH_LEVEL_PRIVACY:
233 case DCERPC_AUTH_LEVEL_INTEGRITY:
236 case DCERPC_AUTH_LEVEL_CONNECT:
237 if (pkt->auth_length != 0) {
241 case DCERPC_AUTH_LEVEL_NONE:
242 if (pkt->auth_length != 0) {
243 return NT_STATUS_INVALID_NETWORK_RESPONSE;
248 return NT_STATUS_INVALID_LEVEL;
251 auth_blob.length = 8 + pkt->auth_length;
253 /* check for a valid length */
254 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
255 return NT_STATUS_INFO_LENGTH_MISMATCH;
259 pkt->u.response.stub_and_verifier.data +
260 pkt->u.response.stub_and_verifier.length - auth_blob.length;
261 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
263 /* pull the auth structure */
264 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
266 return NT_STATUS_NO_MEMORY;
269 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
270 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
273 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
274 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
275 return ndr_map_error2ntstatus(ndr_err);
277 status = NT_STATUS_OK;
279 /* check signature or unseal the packet */
280 switch (c->security_state.auth_info->auth_level) {
281 case DCERPC_AUTH_LEVEL_PRIVACY:
282 status = gensec_unseal_packet(c->security_state.generic_state,
284 raw_packet->data + DCERPC_REQUEST_LENGTH,
285 pkt->u.response.stub_and_verifier.length,
287 raw_packet->length - auth.credentials.length,
289 memcpy(pkt->u.response.stub_and_verifier.data,
290 raw_packet->data + DCERPC_REQUEST_LENGTH,
291 pkt->u.response.stub_and_verifier.length);
294 case DCERPC_AUTH_LEVEL_INTEGRITY:
295 status = gensec_check_packet(c->security_state.generic_state,
297 pkt->u.response.stub_and_verifier.data,
298 pkt->u.response.stub_and_verifier.length,
300 raw_packet->length - auth.credentials.length,
304 case DCERPC_AUTH_LEVEL_CONNECT:
305 /* for now we ignore possible signatures here */
306 status = NT_STATUS_OK;
310 status = NT_STATUS_INVALID_LEVEL;
314 /* remove the indicated amount of paddiing */
315 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
316 return NT_STATUS_INFO_LENGTH_MISMATCH;
318 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
325 push a dcerpc request packet into a blob, possibly signing it.
327 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
328 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
330 struct ncacn_packet *pkt)
333 struct ndr_push *ndr;
335 size_t payload_length;
336 enum ndr_err_code ndr_err;
338 /* non-signed packets are simpler */
340 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
343 switch (c->security_state.auth_info->auth_level) {
344 case DCERPC_AUTH_LEVEL_PRIVACY:
345 case DCERPC_AUTH_LEVEL_INTEGRITY:
348 case DCERPC_AUTH_LEVEL_CONNECT:
349 /* TODO: let the gensec mech decide if it wants to generate a signature */
350 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
352 case DCERPC_AUTH_LEVEL_NONE:
353 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
356 return NT_STATUS_INVALID_LEVEL;
359 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
361 return NT_STATUS_NO_MEMORY;
364 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
365 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
368 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
369 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
372 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
373 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
374 return ndr_map_error2ntstatus(ndr_err);
376 status = NT_STATUS_OK;
378 /* pad to 16 byte multiple in the payload portion of the
379 packet. This matches what w2k3 does */
380 c->security_state.auth_info->auth_pad_length =
381 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
382 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
383 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
384 return ndr_map_error2ntstatus(ndr_err);
386 status = NT_STATUS_OK;
388 payload_length = pkt->u.request.stub_and_verifier.length +
389 c->security_state.auth_info->auth_pad_length;
391 /* we start without signature, it will appended later */
392 c->security_state.auth_info->credentials = data_blob(NULL,0);
394 /* add the auth verifier */
395 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
396 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
397 return ndr_map_error2ntstatus(ndr_err);
399 status = NT_STATUS_OK;
401 /* extract the whole packet as a blob */
402 *blob = ndr_push_blob(ndr);
405 * Setup the frag and auth length in the packet buffer.
406 * This is needed if the GENSEC mech does AEAD signing
407 * of the packet headers. The signature itself will be
410 dcerpc_set_frag_length(blob, blob->length + sig_size);
411 dcerpc_set_auth_length(blob, sig_size);
413 /* sign or seal the packet */
414 switch (c->security_state.auth_info->auth_level) {
415 case DCERPC_AUTH_LEVEL_PRIVACY:
416 status = gensec_seal_packet(c->security_state.generic_state,
418 blob->data + DCERPC_REQUEST_LENGTH,
423 if (!NT_STATUS_IS_OK(status)) {
428 case DCERPC_AUTH_LEVEL_INTEGRITY:
429 status = gensec_sign_packet(c->security_state.generic_state,
431 blob->data + DCERPC_REQUEST_LENGTH,
436 if (!NT_STATUS_IS_OK(status)) {
442 status = NT_STATUS_INVALID_LEVEL;
446 if (creds2.length != sig_size) {
447 DEBUG(0,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
448 creds2.length, (uint32_t)sig_size,
449 c->security_state.auth_info->auth_pad_length,
450 pkt->u.request.stub_and_verifier.length));
451 return NT_STATUS_INTERNAL_ERROR;
454 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
455 return NT_STATUS_NO_MEMORY;
463 fill in the fixed values in a dcerpc header
465 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
468 pkt->rpc_vers_minor = 0;
469 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
472 pkt->drep[0] = DCERPC_DREP_LE;
480 map a bind nak reason to a NTSTATUS
482 static NTSTATUS dcerpc_map_reason(uint16_t reason)
485 case DCERPC_BIND_REASON_ASYNTAX:
486 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
487 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
488 return NT_STATUS_INVALID_PARAMETER;
490 return NT_STATUS_UNSUCCESSFUL;
494 a bind or alter context has failed
496 static void dcerpc_composite_fail(struct rpc_request *req)
498 struct composite_context *c = talloc_get_type(req->async.private_data,
499 struct composite_context);
500 composite_error(c, req->status);
504 remove requests from the pending or queued queues
506 static int dcerpc_req_dequeue(struct rpc_request *req)
508 switch (req->state) {
509 case RPC_REQUEST_QUEUED:
510 DLIST_REMOVE(req->p->conn->request_queue, req);
512 case RPC_REQUEST_PENDING:
513 DLIST_REMOVE(req->p->conn->pending, req);
515 case RPC_REQUEST_DONE:
523 mark the dcerpc connection dead. All outstanding requests get an error
525 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
527 if (conn->dead) return;
531 if (conn->transport.shutdown_pipe) {
532 conn->transport.shutdown_pipe(conn, status);
535 /* all pending requests get the error */
536 while (conn->pending) {
537 struct rpc_request *req = conn->pending;
538 dcerpc_req_dequeue(req);
539 req->state = RPC_REQUEST_DONE;
540 req->status = status;
541 if (req->async.callback) {
542 req->async.callback(req);
546 talloc_set_destructor(conn, NULL);
547 if (conn->free_skipped) {
553 forward declarations of the recv_data handlers for the types of
554 packets we need to handle
556 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
557 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
560 receive a dcerpc reply from the transport. Here we work out what
561 type of reply it is (normal request, bind or alter context) and
562 dispatch to the appropriate handler
564 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
566 struct ncacn_packet pkt;
568 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
569 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
572 /* the transport may be telling us of a severe error, such as
574 if (!NT_STATUS_IS_OK(status)) {
575 data_blob_free(blob);
576 dcerpc_connection_dead(conn, status);
580 /* parse the basic packet to work out what type of response this is */
581 status = ncacn_pull(conn, blob, blob->data, &pkt);
582 if (!NT_STATUS_IS_OK(status)) {
583 data_blob_free(blob);
584 dcerpc_connection_dead(conn, status);
587 dcerpc_request_recv_data(conn, blob, &pkt);
592 Receive a bind reply from the transport
594 static void dcerpc_bind_recv_handler(struct rpc_request *req,
595 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
597 struct composite_context *c;
598 struct dcerpc_connection *conn;
600 c = talloc_get_type(req->async.private_data, struct composite_context);
602 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
603 DEBUG(2,("dcerpc: bind_nak reason %d\n",
604 pkt->u.bind_nak.reject_reason));
605 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
610 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
611 (pkt->u.bind_ack.num_results == 0) ||
612 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
613 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
619 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
620 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
622 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
623 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
624 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
627 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
628 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
629 conn->flags |= DCERPC_HEADER_SIGNING;
632 /* the bind_ack might contain a reply set of credentials */
633 if (conn->security_state.auth_info &&
634 pkt->u.bind_ack.auth_info.length) {
635 enum ndr_err_code ndr_err;
636 ndr_err = ndr_pull_struct_blob(
637 &pkt->u.bind_ack.auth_info, conn,
639 conn->security_state.auth_info,
640 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
641 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
642 c->status = ndr_map_error2ntstatus(ndr_err);
643 if (!composite_is_ok(c)) return;
647 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
653 handle timeouts of individual dcerpc requests
655 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
656 struct timeval t, void *private)
658 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
660 if (req->ignore_timeout) {
661 dcerpc_req_dequeue(req);
662 req->state = RPC_REQUEST_DONE;
663 req->status = NT_STATUS_IO_TIMEOUT;
664 if (req->async.callback) {
665 req->async.callback(req);
670 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
674 send a async dcerpc bind request
676 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
678 const struct ndr_syntax_id *syntax,
679 const struct ndr_syntax_id *transfer_syntax)
681 struct composite_context *c;
682 struct ncacn_packet pkt;
684 struct rpc_request *req;
686 c = composite_create(mem_ctx,p->conn->event_ctx);
687 if (c == NULL) return NULL;
692 p->transfer_syntax = *transfer_syntax;
694 init_ncacn_hdr(p->conn, &pkt);
696 pkt.ptype = DCERPC_PKT_BIND;
697 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
698 pkt.call_id = p->conn->call_id;
701 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
702 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
705 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
706 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
709 pkt.u.bind.max_xmit_frag = 5840;
710 pkt.u.bind.max_recv_frag = 5840;
711 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
712 pkt.u.bind.num_contexts = 1;
713 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
714 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
715 pkt.u.bind.ctx_list[0].context_id = p->context_id;
716 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
717 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
718 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
719 pkt.u.bind.auth_info = data_blob(NULL, 0);
721 /* construct the NDR form of the packet */
722 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
723 p->conn->security_state.auth_info);
724 if (!composite_is_ok(c)) return c;
726 p->conn->transport.recv_data = dcerpc_recv_data;
729 * we allocate a dcerpc_request so we can be in the same
730 * request queue as normal requests
732 req = talloc_zero(c, struct rpc_request);
733 if (composite_nomem(req, c)) return c;
735 req->state = RPC_REQUEST_PENDING;
736 req->call_id = pkt.call_id;
737 req->async.private_data = c;
738 req->async.callback = dcerpc_composite_fail;
740 req->recv_handler = dcerpc_bind_recv_handler;
741 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
742 talloc_set_destructor(req, dcerpc_req_dequeue);
744 c->status = p->conn->transport.send_request(p->conn, &blob,
746 if (!composite_is_ok(c)) return c;
748 event_add_timed(c->event_ctx, req,
749 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
750 dcerpc_timeout_handler, req);
756 recv side of async dcerpc bind request
758 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
760 NTSTATUS result = composite_wait(ctx);
766 perform a continued bind (and auth3)
768 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
771 struct ncacn_packet pkt;
775 init_ncacn_hdr(p->conn, &pkt);
777 pkt.ptype = DCERPC_PKT_AUTH3;
778 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
779 pkt.call_id = next_call_id(p->conn);
781 pkt.u.auth3._pad = 0;
782 pkt.u.auth3.auth_info = data_blob(NULL, 0);
784 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
785 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
788 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
789 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
792 /* construct the NDR form of the packet */
793 status = ncacn_push_auth(&blob, mem_ctx,
794 p->conn->iconv_convenience,
796 p->conn->security_state.auth_info);
797 if (!NT_STATUS_IS_OK(status)) {
801 /* send it on its way */
802 status = p->conn->transport.send_request(p->conn, &blob, false);
803 if (!NT_STATUS_IS_OK(status)) {
812 process a fragment received from the transport layer during a
815 This function frees the data
817 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
818 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
820 struct rpc_request *req;
822 NTSTATUS status = NT_STATUS_OK;
825 if this is an authenticated connection then parse and check
826 the auth info. We have to do this before finding the
827 matching packet, as the request structure might have been
828 removed due to a timeout, but if it has been we still need
829 to run the auth routines so that we don't get the sign/seal
830 info out of step with the server
832 if (c->security_state.auth_info && c->security_state.generic_state &&
833 pkt->ptype == DCERPC_PKT_RESPONSE) {
834 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
837 /* find the matching request */
838 for (req=c->pending;req;req=req->next) {
839 if (pkt->call_id == req->call_id) break;
843 /* useful for testing certain vendors RPC servers */
844 if (req == NULL && c->pending && pkt->call_id == 0) {
845 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
851 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
852 data_blob_free(raw_packet);
856 talloc_steal(req, raw_packet->data);
858 if (req->recv_handler != NULL) {
859 dcerpc_req_dequeue(req);
860 req->state = RPC_REQUEST_DONE;
861 req->recv_handler(req, raw_packet, pkt);
865 if (pkt->ptype == DCERPC_PKT_FAULT) {
866 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
867 req->fault_code = pkt->u.fault.status;
868 req->status = NT_STATUS_NET_WRITE_FAULT;
872 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
873 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
875 req->fault_code = DCERPC_FAULT_OTHER;
876 req->status = NT_STATUS_NET_WRITE_FAULT;
880 /* now check the status from the auth routines, and if it failed then fail
881 this request accordingly */
882 if (!NT_STATUS_IS_OK(status)) {
883 req->status = status;
887 length = pkt->u.response.stub_and_verifier.length;
890 req->payload.data = talloc_realloc(req,
893 req->payload.length + length);
894 if (!req->payload.data) {
895 req->status = NT_STATUS_NO_MEMORY;
898 memcpy(req->payload.data+req->payload.length,
899 pkt->u.response.stub_and_verifier.data, length);
900 req->payload.length += length;
903 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
904 c->transport.send_read(c);
908 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
909 req->flags |= DCERPC_PULL_BIGENDIAN;
911 req->flags &= ~DCERPC_PULL_BIGENDIAN;
916 /* we've got the full payload */
917 req->state = RPC_REQUEST_DONE;
918 DLIST_REMOVE(c->pending, req);
920 if (c->request_queue != NULL) {
921 /* We have to look at shipping further requests before calling
922 * the async function, that one might close the pipe */
923 dcerpc_ship_next_request(c);
926 if (req->async.callback) {
927 req->async.callback(req);
932 perform the send side of a async dcerpc request
934 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
935 const struct GUID *object,
938 DATA_BLOB *stub_data)
940 struct rpc_request *req;
942 p->conn->transport.recv_data = dcerpc_recv_data;
944 req = talloc(p, struct rpc_request);
950 req->call_id = next_call_id(p->conn);
951 req->status = NT_STATUS_OK;
952 req->state = RPC_REQUEST_QUEUED;
953 req->payload = data_blob(NULL, 0);
956 req->async_call = async;
957 req->ignore_timeout = false;
958 req->async.callback = NULL;
959 req->async.private_data = NULL;
960 req->recv_handler = NULL;
962 if (object != NULL) {
963 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
964 if (req->object == NULL) {
973 req->request_data.length = stub_data->length;
974 req->request_data.data = talloc_reference(req, stub_data->data);
975 if (req->request_data.length && req->request_data.data == NULL) {
979 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
980 talloc_set_destructor(req, dcerpc_req_dequeue);
982 dcerpc_ship_next_request(p->conn);
984 if (p->request_timeout) {
985 event_add_timed(dcerpc_event_context(p), req,
986 timeval_current_ofs(p->request_timeout, 0),
987 dcerpc_timeout_handler, req);
994 Send a request using the transport
997 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
999 struct rpc_request *req;
1000 struct dcerpc_pipe *p;
1001 DATA_BLOB *stub_data;
1002 struct ncacn_packet pkt;
1004 uint32_t remaining, chunk_size;
1005 bool first_packet = true;
1006 size_t sig_size = 0;
1008 req = c->request_queue;
1014 stub_data = &req->request_data;
1016 if (!req->async_call && (c->pending != NULL)) {
1020 DLIST_REMOVE(c->request_queue, req);
1021 DLIST_ADD(c->pending, req);
1022 req->state = RPC_REQUEST_PENDING;
1024 init_ncacn_hdr(p->conn, &pkt);
1026 remaining = stub_data->length;
1028 /* we can write a full max_recv_frag size, minus the dcerpc
1029 request header size */
1030 chunk_size = p->conn->srv_max_recv_frag;
1031 chunk_size -= DCERPC_REQUEST_LENGTH;
1032 if (c->security_state.auth_info &&
1033 c->security_state.generic_state) {
1034 sig_size = gensec_sig_size(c->security_state.generic_state,
1035 p->conn->srv_max_recv_frag);
1037 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1038 chunk_size -= sig_size;
1041 chunk_size -= (chunk_size % 16);
1043 pkt.ptype = DCERPC_PKT_REQUEST;
1044 pkt.call_id = req->call_id;
1045 pkt.auth_length = 0;
1047 pkt.u.request.alloc_hint = remaining;
1048 pkt.u.request.context_id = p->context_id;
1049 pkt.u.request.opnum = req->opnum;
1052 pkt.u.request.object.object = *req->object;
1053 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1054 chunk_size -= ndr_size_GUID(req->object,0);
1057 /* we send a series of pdus without waiting for a reply */
1058 while (remaining > 0 || first_packet) {
1059 uint32_t chunk = MIN(chunk_size, remaining);
1060 bool last_frag = false;
1062 first_packet = false;
1063 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1065 if (remaining == stub_data->length) {
1066 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1068 if (chunk == remaining) {
1069 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1073 pkt.u.request.stub_and_verifier.data = stub_data->data +
1074 (stub_data->length - remaining);
1075 pkt.u.request.stub_and_verifier.length = chunk;
1077 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1078 if (!NT_STATUS_IS_OK(req->status)) {
1079 req->state = RPC_REQUEST_DONE;
1080 DLIST_REMOVE(p->conn->pending, req);
1084 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1085 if (!NT_STATUS_IS_OK(req->status)) {
1086 req->state = RPC_REQUEST_DONE;
1087 DLIST_REMOVE(p->conn->pending, req);
1096 return the event context for a dcerpc pipe
1097 used by callers who wish to operate asynchronously
1099 _PUBLIC_ struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1101 return p->conn->event_ctx;
1107 perform the receive side of a async dcerpc request
1109 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1110 TALLOC_CTX *mem_ctx,
1111 DATA_BLOB *stub_data)
1115 while (req->state != RPC_REQUEST_DONE) {
1116 struct event_context *ctx = dcerpc_event_context(req->p);
1117 if (event_loop_once(ctx) != 0) {
1118 return NT_STATUS_CONNECTION_DISCONNECTED;
1121 *stub_data = req->payload;
1122 status = req->status;
1123 if (stub_data->data) {
1124 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1126 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1127 req->p->last_fault_code = req->fault_code;
1134 perform a full request/response pair on a dcerpc pipe
1136 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1137 struct GUID *object,
1140 TALLOC_CTX *mem_ctx,
1141 DATA_BLOB *stub_data_in,
1142 DATA_BLOB *stub_data_out)
1144 struct rpc_request *req;
1146 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1148 return NT_STATUS_NO_MEMORY;
1151 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1156 this is a paranoid NDR validator. For every packet we push onto the wire
1157 we pull it back again, then push it again. Then we compare the raw NDR data
1158 for that to the NDR we initially generated. If they don't match then we know
1159 we must have a bug in either the pull or push side of our code
1161 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1162 TALLOC_CTX *mem_ctx,
1165 ndr_push_flags_fn_t ndr_push,
1166 ndr_pull_flags_fn_t ndr_pull)
1169 struct ndr_pull *pull;
1170 struct ndr_push *push;
1172 enum ndr_err_code ndr_err;
1174 st = talloc_size(mem_ctx, struct_size);
1176 return NT_STATUS_NO_MEMORY;
1179 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1181 return NT_STATUS_NO_MEMORY;
1183 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1185 ndr_err = ndr_pull(pull, NDR_IN, st);
1186 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1187 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1188 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1189 "failed input validation pull - %s",
1191 return ndr_map_error2ntstatus(ndr_err);
1194 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1196 return NT_STATUS_NO_MEMORY;
1199 ndr_err = ndr_push(push, NDR_IN, st);
1200 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1201 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1202 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1203 "failed input validation push - %s",
1205 return ndr_map_error2ntstatus(ndr_err);
1208 blob2 = ndr_push_blob(push);
1210 if (data_blob_cmp(&blob, &blob2) != 0) {
1211 DEBUG(3,("original:\n"));
1212 dump_data(3, blob.data, blob.length);
1213 DEBUG(3,("secondary:\n"));
1214 dump_data(3, blob2.data, blob2.length);
1215 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1216 "failed input validation blobs doesn't match");
1217 return ndr_map_error2ntstatus(ndr_err);
1220 return NT_STATUS_OK;
1224 this is a paranoid NDR input validator. For every packet we pull
1225 from the wire we push it back again then pull and push it
1226 again. Then we compare the raw NDR data for that to the NDR we
1227 initially generated. If they don't match then we know we must have a
1228 bug in either the pull or push side of our code
1230 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1231 struct ndr_pull *pull_in,
1234 ndr_push_flags_fn_t ndr_push,
1235 ndr_pull_flags_fn_t ndr_pull,
1236 ndr_print_function_t ndr_print)
1239 struct ndr_pull *pull;
1240 struct ndr_push *push;
1241 DATA_BLOB blob, blob2;
1242 TALLOC_CTX *mem_ctx = pull_in;
1244 enum ndr_err_code ndr_err;
1246 st = talloc_size(mem_ctx, struct_size);
1248 return NT_STATUS_NO_MEMORY;
1250 memcpy(st, struct_ptr, struct_size);
1252 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1254 return NT_STATUS_NO_MEMORY;
1257 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1258 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1259 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1260 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1261 "failed output validation push - %s",
1263 return ndr_map_error2ntstatus(ndr_err);
1266 blob = ndr_push_blob(push);
1268 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1270 return NT_STATUS_NO_MEMORY;
1273 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1274 ndr_err = ndr_pull(pull, NDR_OUT, st);
1275 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1276 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1277 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1278 "failed output validation pull - %s",
1280 return ndr_map_error2ntstatus(ndr_err);
1283 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1285 return NT_STATUS_NO_MEMORY;
1288 ndr_err = ndr_push(push, NDR_OUT, st);
1289 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1290 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1291 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1292 "failed output validation push2 - %s",
1294 return ndr_map_error2ntstatus(ndr_err);
1297 blob2 = ndr_push_blob(push);
1299 if (data_blob_cmp(&blob, &blob2) != 0) {
1300 DEBUG(3,("original:\n"));
1301 dump_data(3, blob.data, blob.length);
1302 DEBUG(3,("secondary:\n"));
1303 dump_data(3, blob2.data, blob2.length);
1304 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1305 "failed output validation blobs doesn't match");
1306 return ndr_map_error2ntstatus(ndr_err);
1309 /* this checks the printed forms of the two structures, which effectively
1310 tests all of the value() attributes */
1311 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1312 NDR_OUT, struct_ptr);
1313 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1315 if (strcmp(s1, s2) != 0) {
1317 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1319 /* this is sometimes useful */
1320 printf("VALIDATE ERROR\n");
1321 file_save("wire.dat", s1, strlen(s1));
1322 file_save("gen.dat", s2, strlen(s2));
1323 system("diff -u wire.dat gen.dat");
1325 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1326 "failed output validation strings doesn't match");
1327 return ndr_map_error2ntstatus(ndr_err);
1330 return NT_STATUS_OK;
1335 send a rpc request given a dcerpc_call structure
1337 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1338 const struct GUID *object,
1339 const struct ndr_interface_table *table,
1341 TALLOC_CTX *mem_ctx,
1344 const struct ndr_interface_call *call;
1345 struct ndr_push *push;
1348 struct rpc_request *req;
1349 enum ndr_err_code ndr_err;
1351 call = &table->calls[opnum];
1353 /* setup for a ndr_push_* call */
1354 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1359 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1360 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1363 /* push the structure into a blob */
1364 ndr_err = call->ndr_push(push, NDR_IN, r);
1365 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1366 status = ndr_map_error2ntstatus(ndr_err);
1367 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1368 nt_errstr(status)));
1373 /* retrieve the blob */
1374 request = ndr_push_blob(push);
1376 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1377 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1378 call->ndr_push, call->ndr_pull);
1379 if (!NT_STATUS_IS_OK(status)) {
1380 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1381 nt_errstr(status)));
1387 DEBUG(10,("rpc request data:\n"));
1388 dump_data(10, request.data, request.length);
1390 /* make the actual dcerpc request */
1391 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1395 req->ndr.table = table;
1396 req->ndr.opnum = opnum;
1397 req->ndr.struct_ptr = r;
1398 req->ndr.mem_ctx = mem_ctx;
1407 receive the answer from a dcerpc_ndr_request_send()
1409 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1411 struct dcerpc_pipe *p = req->p;
1414 struct ndr_pull *pull;
1416 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1417 void *r = req->ndr.struct_ptr;
1418 uint32_t opnum = req->ndr.opnum;
1419 const struct ndr_interface_table *table = req->ndr.table;
1420 const struct ndr_interface_call *call = &table->calls[opnum];
1421 enum ndr_err_code ndr_err;
1423 /* make sure the recv code doesn't free the request, as we
1424 need to grab the flags element before it is freed */
1425 if (talloc_reference(p, req) == NULL) {
1426 return NT_STATUS_NO_MEMORY;
1429 status = dcerpc_request_recv(req, mem_ctx, &response);
1430 if (!NT_STATUS_IS_OK(status)) {
1431 talloc_unlink(p, req);
1437 /* prepare for ndr_pull_* */
1438 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1440 talloc_unlink(p, req);
1441 return NT_STATUS_NO_MEMORY;
1445 pull->data = talloc_steal(pull, pull->data);
1447 talloc_unlink(p, req);
1449 if (flags & DCERPC_PULL_BIGENDIAN) {
1450 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1453 DEBUG(10,("rpc reply data:\n"));
1454 dump_data(10, pull->data, pull->data_size);
1456 /* pull the structure from the blob */
1457 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1458 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1459 status = ndr_map_error2ntstatus(ndr_err);
1460 dcerpc_log_packet(table, opnum, NDR_OUT,
1465 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1466 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1467 call->ndr_push, call->ndr_pull,
1469 if (!NT_STATUS_IS_OK(status)) {
1470 dcerpc_log_packet(table, opnum, NDR_OUT,
1476 if (pull->offset != pull->data_size) {
1477 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1478 pull->data_size - pull->offset));
1479 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1480 but it turns out that early versions of NT
1481 (specifically NT3.1) add junk onto the end of rpc
1482 packets, so if we want to interoperate at all with
1483 those versions then we need to ignore this error */
1486 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1488 return NT_STATUS_OK;
1493 a useful helper function for synchronous rpc requests
1495 this can be used when you have ndr push/pull functions in the
1498 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1499 const struct GUID *object,
1500 const struct ndr_interface_table *table,
1502 TALLOC_CTX *mem_ctx,
1505 struct rpc_request *req;
1507 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1509 return NT_STATUS_NO_MEMORY;
1512 return dcerpc_ndr_request_recv(req);
1517 a useful function for retrieving the server name we connected to
1519 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1521 if (!p->conn->transport.target_hostname) {
1522 if (!p->conn->transport.peer_name) {
1525 return p->conn->transport.peer_name(p->conn);
1527 return p->conn->transport.target_hostname(p->conn);
1532 get the dcerpc auth_level for a open connection
1534 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1538 if (c->flags & DCERPC_SEAL) {
1539 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1540 } else if (c->flags & DCERPC_SIGN) {
1541 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1542 } else if (c->flags & DCERPC_CONNECT) {
1543 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1545 auth_level = DCERPC_AUTH_LEVEL_NONE;
1551 Receive an alter reply from the transport
1553 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1554 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1556 struct composite_context *c;
1557 struct dcerpc_pipe *recv_pipe;
1559 c = talloc_get_type(req->async.private_data, struct composite_context);
1560 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1562 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1563 pkt->u.alter_resp.num_results == 1 &&
1564 pkt->u.alter_resp.ctx_list[0].result != 0) {
1565 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1566 pkt->u.alter_resp.ctx_list[0].reason));
1567 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1571 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1572 pkt->u.alter_resp.num_results == 0 ||
1573 pkt->u.alter_resp.ctx_list[0].result != 0) {
1574 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1578 /* the alter_resp might contain a reply set of credentials */
1579 if (recv_pipe->conn->security_state.auth_info &&
1580 pkt->u.alter_resp.auth_info.length) {
1581 enum ndr_err_code ndr_err;
1582 ndr_err = ndr_pull_struct_blob(
1583 &pkt->u.alter_resp.auth_info, recv_pipe,
1585 recv_pipe->conn->security_state.auth_info,
1586 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1587 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1588 c->status = ndr_map_error2ntstatus(ndr_err);
1589 if (!composite_is_ok(c)) return;
1597 send a dcerpc alter_context request
1599 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1600 TALLOC_CTX *mem_ctx,
1601 const struct ndr_syntax_id *syntax,
1602 const struct ndr_syntax_id *transfer_syntax)
1604 struct composite_context *c;
1605 struct ncacn_packet pkt;
1607 struct rpc_request *req;
1609 c = composite_create(mem_ctx, p->conn->event_ctx);
1610 if (c == NULL) return NULL;
1612 c->private_data = p;
1614 p->syntax = *syntax;
1615 p->transfer_syntax = *transfer_syntax;
1617 init_ncacn_hdr(p->conn, &pkt);
1619 pkt.ptype = DCERPC_PKT_ALTER;
1620 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1621 pkt.call_id = p->conn->call_id;
1622 pkt.auth_length = 0;
1624 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1625 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1628 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1629 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1632 pkt.u.alter.max_xmit_frag = 5840;
1633 pkt.u.alter.max_recv_frag = 5840;
1634 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1635 pkt.u.alter.num_contexts = 1;
1636 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1637 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1638 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1639 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1640 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1641 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1642 pkt.u.alter.auth_info = data_blob(NULL, 0);
1644 /* construct the NDR form of the packet */
1645 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1646 p->conn->security_state.auth_info);
1647 if (!composite_is_ok(c)) return c;
1649 p->conn->transport.recv_data = dcerpc_recv_data;
1652 * we allocate a dcerpc_request so we can be in the same
1653 * request queue as normal requests
1655 req = talloc_zero(c, struct rpc_request);
1656 if (composite_nomem(req, c)) return c;
1658 req->state = RPC_REQUEST_PENDING;
1659 req->call_id = pkt.call_id;
1660 req->async.private_data = c;
1661 req->async.callback = dcerpc_composite_fail;
1663 req->recv_handler = dcerpc_alter_recv_handler;
1664 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1665 talloc_set_destructor(req, dcerpc_req_dequeue);
1667 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1668 if (!composite_is_ok(c)) return c;
1670 event_add_timed(c->event_ctx, req,
1671 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1672 dcerpc_timeout_handler, req);
1677 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1679 NTSTATUS result = composite_wait(ctx);
1685 send a dcerpc alter_context request
1687 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1688 TALLOC_CTX *mem_ctx,
1689 const struct ndr_syntax_id *syntax,
1690 const struct ndr_syntax_id *transfer_syntax)
1692 struct composite_context *creq;
1693 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1694 return dcerpc_alter_context_recv(creq);