2 * Unix SMB/CIFS implementation.
3 * DCERPC client routines
5 * Copyright (C) Stefan Metzmacher 2011
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "system/network.h"
24 #include "lib/util/tevent_ntstatus.h"
25 #include "lib/tsocket/tsocket.h"
26 #include "librpc/gen_ndr/ndr_dcerpc.h"
27 #include "source3/librpc/rpc/dcerpc.h"
28 #include "source4/librpc/rpc/dcerpc.h"
29 #include "auth/gensec/gensec.h"
30 #include "librpc/rpc/dcerpc_connection.h"
31 #include "../lib/util/dlinklist.h"
33 struct dcerpc_association;
34 struct dcerpc_connection;
35 struct dcerpc_security;
36 struct dcerpc_presentation;
39 struct dcerpc_association {
40 uint32_t assoc_group_id;
41 uint16_t client_features;
44 uint32_t next_call_id;
47 struct dcerpc_connection {
48 struct dcerpc_association *assoc;
51 struct tstream_context *stream;
52 dcerpc_connection_use_trans_fn use_trans_fn;
53 struct tevent_queue *write_queue;
57 uint16_t max_xmit_frag;
58 uint16_t max_recv_frag;
59 bool concurrent_multiplex;
63 uint32_t next_sec_context_id;
64 uint16_t next_pres_context_id;
67 struct tevent_queue *out_queue;
68 struct dcerpc_call *list;
69 struct dcerpc_call *active;
73 struct tevent_context *ev;
74 struct tevent_req *subreq;
78 struct dcerpc_security {
80 enum dcerpc_AuthType auth_type;
81 enum dcerpc_AuthLevel auth_level;
82 struct gensec_security *gensec;
85 struct dcerpc_presentation {
87 const struct ndr_interface_table *table;
88 struct ndr_syntax_id transfer;
90 struct dcerpc_ctx_list req;
91 struct dcerpc_ack_ctx ack;
96 struct dcerpc_call *prev, *next;
99 struct dcerpc_security *sec;
100 struct dcerpc_presentation *pres;
104 NTSTATUS (*handler)(void *private_data,
105 struct ncacn_packet *pkt,
110 struct dcerpc_association *dcerpc_association_create(TALLOC_CTX *mem_ctx,
111 uint16_t client_features)
113 struct dcerpc_association *assoc;
115 assoc = talloc_zero(mem_ctx, struct dcerpc_association);
120 assoc->next_call_id = 1;
122 assoc->client_features = client_features;
127 struct dcerpc_connection *dcerpc_connection_create(TALLOC_CTX *mem_ctx,
128 struct dcerpc_association *assoc,
129 struct tstream_context **stream)
131 struct dcerpc_connection *conn;
133 conn = talloc_zero(mem_ctx, struct dcerpc_connection);
139 conn->transport.stream = talloc_move(conn, stream);
140 conn->transport.write_queue = tevent_queue_create(conn, "write_queue");
141 if (conn->transport.write_queue == NULL) {
146 conn->features.max_xmit_frag = 4280;
147 conn->features.max_recv_frag = 4280;
149 conn->calls.out_queue = tevent_queue_create(conn, "out_queue");
150 if (conn->calls.out_queue == NULL) {
158 void dcerpc_connection_set_use_trans_fn(struct dcerpc_connection *conn,
159 dcerpc_connection_use_trans_fn fn)
161 conn->transport.use_trans_fn = fn;
164 struct dcerpc_security *dcerpc_security_allocate(
166 struct dcerpc_connection *conn,
167 enum dcerpc_AuthType auth_type,
168 enum dcerpc_AuthLevel auth_level,
169 struct gensec_security **gensec)
171 struct dcerpc_security *sec;
173 sec = talloc_zero(mem_ctx, struct dcerpc_security);
178 sec->context_id = conn->next_sec_context_id++;
179 sec->auth_type = auth_type;
180 sec->auth_level = auth_level;
182 if (gensec != NULL) {
183 sec->gensec = talloc_move(sec, gensec);
189 struct dcerpc_presentation *dcerpc_presentation_allocate(
191 struct dcerpc_connection *conn,
192 const struct ndr_interface_table *table,
193 const struct ndr_syntax_id *transfer)
195 struct dcerpc_presentation *pres;
197 pres = talloc_zero(mem_ctx, struct dcerpc_presentation);
202 pres->context_id = conn->next_pres_context_id++;
204 pres->transfer = *transfer;
206 pres->negotiate.req.abstract_syntax = table->syntax_id;
207 pres->negotiate.req.context_id = pres->context_id;
208 pres->negotiate.req.num_transfer_syntaxes = 1;
209 pres->negotiate.req.transfer_syntaxes = &pres->transfer;
211 pres->negotiate.ack.result = DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION;
212 pres->negotiate.ack.reason.value =
213 DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED;
218 struct dcerpc_call *dcerpc_call_allocate(TALLOC_CTX *mem_ctx,
219 struct dcerpc_association *assoc,
220 struct dcerpc_security *sec,
221 struct dcerpc_presentation *pres)
223 struct dcerpc_call *call;
225 call = talloc_zero(mem_ctx, struct dcerpc_call);
230 call->call_id = assoc->next_call_id++;
238 static NTSTATUS dcerpc_guess_pdu_sizes(struct dcerpc_security *sec,
241 size_t max_xmit_frag,
242 size_t pad_alignment,
243 size_t *data_to_send,
251 /* no auth token cases first */
252 switch (sec->auth_level) {
253 case DCERPC_AUTH_LEVEL_NONE:
254 case DCERPC_AUTH_LEVEL_CONNECT:
255 case DCERPC_AUTH_LEVEL_PACKET:
256 max_len = max_xmit_frag - header_len;
257 *data_to_send = MIN(max_len, data_left);
260 *frag_len = header_len + *data_to_send;
263 case DCERPC_AUTH_LEVEL_PRIVACY:
264 case DCERPC_AUTH_LEVEL_INTEGRITY:
265 if (sec->auth_type == DCERPC_AUTH_TYPE_NONE) {
266 return NT_STATUS_INVALID_PARAMETER_MIX;
268 if (sec->gensec == NULL) {
269 return NT_STATUS_INVALID_PARAMETER_MIX;
274 return NT_STATUS_INVALID_PARAMETER;
278 /* Sign/seal case, calculate auth and pad lengths */
280 max_len = max_xmit_frag - header_len - DCERPC_AUTH_TRAILER_LENGTH;
282 *auth_len = gensec_sig_size(sec->gensec, max_len);
284 max_len -= *auth_len;
286 *data_to_send = MIN(max_len, data_left);
288 mod_len = (header_len + *data_to_send) % pad_alignment;
290 *pad_len = pad_alignment - mod_len;
295 if (*data_to_send + *pad_len > max_len) {
296 *data_to_send -= pad_alignment;
299 *frag_len = header_len + *data_to_send + *pad_len
300 + DCERPC_AUTH_TRAILER_LENGTH + *auth_len;
305 static NTSTATUS dcerpc_ncacn_push_auth(DATA_BLOB *blob,
307 struct ncacn_packet *pkt,
308 struct dcerpc_auth *auth_info)
310 struct ndr_push *ndr;
311 enum ndr_err_code ndr_err;
313 ndr = ndr_push_init_ctx(mem_ctx);
315 return NT_STATUS_NO_MEMORY;
318 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
319 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
322 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
323 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
327 pkt->auth_length = auth_info->credentials.length;
329 pkt->auth_length = 0;
332 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
333 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
334 return ndr_map_error2ntstatus(ndr_err);
339 /* the s3 rpc server doesn't handle auth padding in
340 bind requests. Use zero auth padding to keep us
341 working with old servers */
342 uint32_t offset = ndr->offset;
343 ndr_err = ndr_push_align(ndr, 16);
344 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
345 return ndr_map_error2ntstatus(ndr_err);
347 auth_info->auth_pad_length = ndr->offset - offset;
349 auth_info->auth_pad_length = 0;
351 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info);
352 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
353 return ndr_map_error2ntstatus(ndr_err);
357 *blob = ndr_push_blob(ndr);
359 /* fill in the frag length */
360 dcerpc_set_frag_length(blob, blob->length);
365 static NTSTATUS dcerpc_ncacn_packet_blob(TALLOC_CTX *mem_ctx,
366 enum dcerpc_pkt_type ptype,
368 uint16_t auth_length,
370 union dcerpc_payload *u,
373 struct ncacn_packet r;
377 r.rpc_vers_minor = 0;
379 r.pfc_flags = pfc_flags;
380 r.drep[0] = DCERPC_DREP_LE;
384 r.auth_length = auth_length;
388 status = dcerpc_ncacn_push_auth(blob, mem_ctx, &r, NULL);
389 if (!NT_STATUS_IS_OK(status)) {
393 if (DEBUGLEVEL >= 10) {
394 /* set frag len for print function */
395 r.frag_length = blob->length;
396 NDR_PRINT_DEBUG(ncacn_packet, &r);
402 #define DCERPC_PAYLOAD_PADDING_SIZE 16 //TODO???
404 static NTSTATUS dcerpc_auth_blob(TALLOC_CTX *mem_ctx,
405 enum dcerpc_AuthType auth_type,
406 enum dcerpc_AuthLevel auth_level,
407 uint8_t auth_pad_length,
408 uint32_t auth_context_id,
409 const DATA_BLOB *credentials,
412 struct dcerpc_auth r;
413 enum ndr_err_code ndr_err;
415 r.auth_type = auth_type;
416 r.auth_level = auth_level;
417 r.auth_pad_length = auth_pad_length;
419 r.auth_context_id = auth_context_id;
420 r.credentials = *credentials;
422 ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
423 (ndr_push_flags_fn_t)ndr_push_dcerpc_auth);
424 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
425 return ndr_map_error2ntstatus(ndr_err);
428 if (DEBUGLEVEL >= 10) {
429 NDR_PRINT_DEBUG(dcerpc_auth, &r);
435 static NTSTATUS dcerpc_response_auth_blob(struct dcerpc_security *sec,
439 char pad[DCERPC_PAYLOAD_PADDING_SIZE] = { 0, };
442 uint16_t data_and_pad_len = 0;
445 if (rpc_out->length < DCERPC_RESPONSE_LENGTH) {
446 return NT_STATUS_INVALID_PARAMETER_MIX;
449 if (sec->auth_type == DCERPC_AUTH_TYPE_NONE ||
450 sec->auth_type == DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM) {
454 if (sec->gensec == NULL) {
455 return NT_STATUS_INVALID_PARAMETER_MIX;
459 /* Copy the sign/seal padding data. */
460 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
461 return NT_STATUS_NO_MEMORY;
465 data_and_pad_len = rpc_out->length - DCERPC_RESPONSE_LENGTH;
467 /* marshall the dcerpc_auth with an actually empty auth_blob.
468 * This is needed because the ntmlssp signature includes the
469 * auth header. We will append the actual blob later. */
470 auth_blob = data_blob_null;
471 status = dcerpc_auth_blob(rpc_out->data,
478 if (!NT_STATUS_IS_OK(status)) {
482 /* append the header */
483 if (!data_blob_append(NULL, rpc_out,
484 auth_info.data, auth_info.length)) {
485 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
486 (unsigned int)auth_info.length));
487 return NT_STATUS_NO_MEMORY;
489 data_blob_free(&auth_info);
491 switch (sec->auth_level) {
492 case DCERPC_AUTH_LEVEL_PRIVACY:
493 /* Data portion is encrypted. */
494 status = gensec_seal_packet(sec->gensec,
497 + DCERPC_RESPONSE_LENGTH,
502 if (!NT_STATUS_IS_OK(status)) {
507 case DCERPC_AUTH_LEVEL_INTEGRITY:
508 /* Data is signed. */
509 status = gensec_sign_packet(sec->gensec,
512 + DCERPC_RESPONSE_LENGTH,
517 if (!NT_STATUS_IS_OK(status)) {
524 smb_panic("bad auth level");
526 return NT_STATUS_INVALID_PARAMETER;
529 /* Finally attach the blob. */
530 if (!data_blob_append(NULL, rpc_out,
531 auth_blob.data, auth_blob.length)) {
532 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
533 (unsigned int)auth_blob.length));
534 return NT_STATUS_NO_MEMORY;
536 data_blob_free(&auth_blob);
541 static NTSTATUS dcerpc_check_pdu_auth(struct dcerpc_security *sec,
542 struct ncacn_packet *pkt,
543 DATA_BLOB *pkt_trailer,
549 struct dcerpc_auth auth_info;
550 uint32_t auth_length;
554 switch (sec->auth_level) {
555 case DCERPC_AUTH_LEVEL_PRIVACY:
556 DEBUG(10, ("Requested Privacy.\n"));
559 case DCERPC_AUTH_LEVEL_INTEGRITY:
560 DEBUG(10, ("Requested Integrity.\n"));
563 case DCERPC_AUTH_LEVEL_CONNECT:
564 if (pkt->auth_length != 0) {
570 case DCERPC_AUTH_LEVEL_NONE:
571 if (pkt->auth_length != 0) {
572 DEBUG(3, ("Got non-zero auth len on non "
573 "authenticated connection!\n"));
574 return NT_STATUS_INVALID_PARAMETER;
580 DEBUG(3, ("Unimplemented Auth Level %d",
582 return NT_STATUS_INVALID_PARAMETER;
585 /* Paranioa checks for auth_length. */
586 if (pkt->auth_length > pkt->frag_length) {
587 return NT_STATUS_INFO_LENGTH_MISMATCH;
589 if (((unsigned int)pkt->auth_length
590 + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) ||
591 ((unsigned int)pkt->auth_length
592 + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
593 /* Integer wrap attempt. */
594 return NT_STATUS_INFO_LENGTH_MISMATCH;
597 status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
598 &auth_info, &auth_length, false);
599 if (!NT_STATUS_IS_OK(status)) {
603 data = data_blob_const(raw_pkt->data + header_size,
604 pkt_trailer->length - auth_length);
605 full_pkt = data_blob_const(raw_pkt->data,
606 raw_pkt->length - auth_info.credentials.length);
608 switch (sec->auth_type) {
609 case DCERPC_AUTH_TYPE_NONE:
610 case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
616 switch (sec->auth_level) {
617 case DCERPC_AUTH_LEVEL_PRIVACY:
618 /* Data portion is encrypted. */
619 status = gensec_unseal_packet(sec->gensec,
624 &auth_info.credentials);
627 case DCERPC_AUTH_LEVEL_INTEGRITY:
628 /* Data is signed. */
629 status = gensec_check_packet(sec->gensec,
634 &auth_info.credentials);
637 return NT_STATUS_INVALID_PARAMETER;
639 /* TODO: remove later
640 * this is still needed because in the server code the
641 * pkt_trailer actually has a copy of the raw data, and they
642 * are still both used in later calls */
643 if (sec->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
644 memcpy(pkt_trailer->data, data.data, data.length);
647 *pad_len = auth_info.auth_pad_length;
648 data_blob_free(&auth_info.credentials);
652 static void dcerpc_connection_loop(struct tevent_req *subreq);
654 static NTSTATUS dcerpc_connection_loop_restart(struct dcerpc_connection *conn,
655 struct tevent_context *ev)
658 return NT_STATUS_INVALID_PARAMETER; // TODO...
661 if (conn->loop.subreq) {
662 if (conn->loop.ev != ev) {
663 return NT_STATUS_INVALID_PARAMETER; // TODO...
668 if (conn->calls.list == NULL) {
669 conn->loop.ev = NULL;
673 conn->loop.subreq = dcerpc_read_ncacn_packet_send(conn,
675 conn->transport.stream);
676 if (conn->loop.subreq == NULL) {
677 return NT_STATUS_NO_MEMORY;
679 tevent_req_set_callback(conn->loop.subreq, dcerpc_connection_loop, conn);
684 static void dcerpc_connection_loop(struct tevent_req *subreq)
686 struct dcerpc_connection *conn =
687 tevent_req_callback_data(subreq,
688 struct dcerpc_connection);
690 struct ncacn_packet *pkt;
692 struct dcerpc_call *call;
693 bool valid_type = false;
695 conn->loop.subreq = NULL;
697 error = dcerpc_read_ncacn_packet_recv(subreq, subreq, &pkt, &pdu);
698 if (!NT_STATUS_IS_OK(error)) {
700 // disconnect and notify pending calls
704 if (DEBUGLEVEL >= 10) {
705 NDR_PRINT_DEBUG(ncacn_packet, pkt);
708 switch (pkt->ptype) {
709 case DCERPC_PKT_REQUEST:
710 /* Ordinary request. */
714 case DCERPC_PKT_PING:
715 /* Connectionless is server alive ? */
718 case DCERPC_PKT_RESPONSE:
719 /* Ordinary reply. */
723 case DCERPC_PKT_FAULT:
724 /* Fault in processing of call. */
728 case DCERPC_PKT_WORKING:
729 /* Connectionless reply to a ping when server busy. */
732 case DCERPC_PKT_NOCALL:
733 /* Connectionless reply to a ping when server has lost part of clients call. */
736 case DCERPC_PKT_REJECT:
737 /* Refuse a request with a code. */
743 case DCERPC_PKT_CL_CANCEL:
746 case DCERPC_PKT_FACK:
749 case DCERPC_PKT_CANCEL_ACK:
750 /* Server ACK to client cancel request. */
753 case DCERPC_PKT_BIND:
754 /* Bind to interface. */
758 case DCERPC_PKT_BIND_ACK:
759 /* Server ack of bind. */
763 case DCERPC_PKT_BIND_NAK:
764 /* Server nack of bind. */
768 case DCERPC_PKT_ALTER:
773 case DCERPC_PKT_ALTER_RESP:
774 /* Reply to alter auth. */
778 case DCERPC_PKT_AUTH3:
779 /* not the real name! this is undocumented! */
783 case DCERPC_PKT_SHUTDOWN:
784 /* Server to client request to shutdown. */
788 case DCERPC_PKT_CO_CANCEL:
789 /* Connection-oriented cancel request. */
793 case DCERPC_PKT_ORPHANED:
794 /* Client telling server it's aborting a partially sent request or telling server to stop sending replies. */
799 /* RTS packets used in ncacn_http */
805 // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
809 for (call = conn->calls.list; call; call = call->next) {
810 if (call->call_id == pkt->call_id) {
817 // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
821 if (call->incoming.handler == NULL) {
823 // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
827 error = call->incoming.handler(call->incoming.private_data, pkt, pdu);
829 if (!NT_STATUS_IS_OK(error)) {
830 // disconnect and notify pending calls
834 error = dcerpc_connection_loop_restart(conn, conn->loop.ev);
835 if (!NT_STATUS_IS_OK(error)) {
836 // disconnect and notify pending calls
841 struct dcerpc_do_bind_out_frag;
843 struct dcerpc_do_bind_state {
844 struct tevent_context *ev;
845 struct dcerpc_connection *conn;
846 struct dcerpc_call *call;
847 struct dcerpc_security *sec;
851 struct dcerpc_do_bind_out_frag *out_frag;
853 struct dcerpc_presentation **pres;
854 uint32_t remaining_pres;
857 struct dcerpc_ctx_list *ctx_list;
858 struct ndr_syntax_id features;
861 struct dcerpc_do_bind_out_frag {
862 struct tevent_context *ev;
863 struct dcerpc_connection *conn;
864 struct tevent_req *req;
865 enum dcerpc_pkt_type ptype;
868 struct tevent_req *subreq_wait1;
869 struct tevent_req *subreq_wait2;
872 static void dcerpc_do_bind_cleanup(struct tevent_req *req,
873 enum tevent_req_state req_state);
875 static void dcerpc_do_bind_out_frag_next(struct tevent_req *req,
877 static void dcerpc_do_bind_sec_next(struct tevent_req *subreq);
879 static NTSTATUS dcerpc_do_bind_handle_in_frag(void *private_data,
880 struct ncacn_packet *pkt,
883 struct tevent_req *dcerpc_do_bind_send(TALLOC_CTX *mem_ctx,
884 struct tevent_context *ev,
885 struct dcerpc_connection *conn,
886 struct dcerpc_call *call,
887 struct dcerpc_security *sec,
889 struct dcerpc_presentation **pres)
891 struct tevent_req *req;
892 struct dcerpc_do_bind_state *state;
895 req = tevent_req_create(mem_ctx, &state,
896 struct dcerpc_do_bind_state);
904 state->num_pres = num_pres;
907 state->call->incoming.private_data = req;
908 state->call->incoming.handler = dcerpc_do_bind_handle_in_frag;
909 DLIST_ADD_END(state->conn->calls.list, state->call, NULL);
911 tevent_req_set_cleanup_fn(req, dcerpc_do_bind_cleanup);
913 if (state->sec != NULL && state->sec->gensec != NULL) {
914 struct tevent_req *subreq;
916 subreq = gensec_update_send(state, ev,
919 if (tevent_req_nomem(subreq, req)) {
920 return tevent_req_post(req, ev);
922 tevent_req_set_callback(subreq, dcerpc_do_bind_sec_next, req);
927 state->sec_status = NT_STATUS_OK;
928 ok = tevent_queue_add(state->conn->calls.out_queue,
931 dcerpc_do_bind_out_frag_next,
934 tevent_req_nomem(NULL, req);
935 return tevent_req_post(req, ev);
941 static void dcerpc_do_bind_cleanup(struct tevent_req *req,
942 enum tevent_req_state req_state)
944 struct dcerpc_do_bind_state *state =
946 struct dcerpc_do_bind_state);
948 if (state->out_frag != NULL) {
949 state->out_frag->req = NULL;
950 state->out_frag = NULL;
953 if (state->call != NULL) {
954 ZERO_STRUCT(state->call->incoming);
955 DLIST_REMOVE(state->conn->calls.list, state->call);
960 static void dcerpc_do_bind_sec_next(struct tevent_req *subreq)
962 struct tevent_req *req =
963 tevent_req_callback_data(subreq,
965 struct dcerpc_do_bind_state *state =
967 struct dcerpc_do_bind_state);
971 data_blob_free(&state->sec_out);
972 status = gensec_update_recv(subreq, state, &state->sec_out);
974 data_blob_free(&state->sec_in);
975 state->sec_status = status;
976 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
977 status = NT_STATUS_OK;
979 if (!NT_STATUS_IS_OK(status)) {
980 tevent_req_nterror(req, status);
984 ok = tevent_queue_add(state->conn->calls.out_queue,
987 dcerpc_do_bind_out_frag_next,
990 tevent_req_nomem(NULL, req);
995 static void dcerpc_do_bind_out_frag_trans_wait1(struct tevent_req *subreq);
996 static void dcerpc_do_bind_out_frag_done(struct tevent_req *subreq);
997 static void dcerpc_do_bind_out_frag_trans_wait2(struct tevent_req *subreq);
999 static void dcerpc_do_bind_out_frag_next(struct tevent_req *req,
1002 struct dcerpc_do_bind_state *state =
1003 tevent_req_data(req,
1004 struct dcerpc_do_bind_state);
1005 struct dcerpc_do_bind_out_frag *frag;
1006 size_t auth_len = 0;
1008 DATA_BLOB auth_info = data_blob_null;
1009 union dcerpc_payload u;
1010 struct tevent_req *subreq;
1012 bool use_trans = true;
1015 * the fragment belongs to the connection instead of the request
1016 * because it has to remain in case the request is canceled
1018 frag = talloc_zero(state->conn, struct dcerpc_do_bind_out_frag);
1019 if (tevent_req_nomem(frag, req)) {
1022 frag->ev = state->ev;
1023 frag->conn = state->conn;
1025 state->out_frag = frag;
1027 if (!state->conn->features.bind_done) {
1028 frag->ptype = DCERPC_PKT_BIND;
1029 } else if (state->remaining_pres > 0) {
1030 frag->ptype = DCERPC_PKT_ALTER;
1031 } else if (!NT_STATUS_IS_OK(state->sec_status)) {
1032 frag->ptype = DCERPC_PKT_ALTER;
1033 } else if (state->sec_out.length > 0) {
1034 frag->ptype = DCERPC_PKT_AUTH3;
1038 status = dcerpc_auth_blob(frag,
1039 state->sec->auth_type,
1040 state->sec->auth_level,
1041 0, /* auth_pad_length */
1042 state->sec->context_id, /* auth_context_id */
1045 if (!NT_STATUS_IS_OK(status)) {
1046 tevent_req_nterror(req, status);
1050 auth_len = auth_info.length;
1053 auth_len -= DCERPC_AUTH_TRAILER_LENGTH;
1057 state->num_ctx = state->num_pres;
1058 if (!state->conn->assoc->negotiate_done) {
1059 state->num_ctx += 1;
1062 state->ctx_list = talloc_zero_array(frag,
1063 struct dcerpc_ctx_list,
1065 if (tevent_req_nomem(state->ctx_list, req)) {
1069 for (i=0; i < state->num_pres; i++) {
1070 state->ctx_list[i] = state->pres[i]->negotiate.req;
1073 if (!state->conn->assoc->negotiate_done) {
1074 state->features = dcerpc_construct_bind_time_features(
1075 state->conn->assoc->client_features);
1077 state->ctx_list[i].context_id = state->conn->next_pres_context_id;
1079 state->ctx_list[i].abstract_syntax =
1080 state->ctx_list[i-1].abstract_syntax;
1082 state->ctx_list[i].num_transfer_syntaxes = 1;
1083 state->ctx_list[i].transfer_syntaxes = &state->features;
1086 switch (frag->ptype) {
1087 case DCERPC_PKT_BIND:
1088 case DCERPC_PKT_ALTER:
1089 u.bind.max_xmit_frag = state->conn->features.max_xmit_frag;
1090 u.bind.max_recv_frag = state->conn->features.max_recv_frag;
1091 u.bind.assoc_group_id = state->conn->assoc->assoc_group_id;
1092 u.bind.num_contexts = state->num_ctx;
1093 u.bind.ctx_list = state->ctx_list;
1094 u.bind.auth_info = auth_info;
1097 case DCERPC_PKT_AUTH3:
1099 u.auth3.auth_info = auth_info;
1102 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1106 status = dcerpc_ncacn_packet_blob(frag,
1108 DCERPC_PFC_FLAG_FIRST |
1109 DCERPC_PFC_FLAG_LAST,
1111 state->call->call_id,
1114 if (!NT_STATUS_IS_OK(status)) {
1115 DEBUG(0, ("Failed to marshall bind/alter ncacn_packet.\n"));
1116 tevent_req_nterror(req, status);
1120 if (frag->ptype == DCERPC_PKT_AUTH3) {
1124 if (frag->conn->transport.use_trans_fn == NULL) {
1128 if (frag->conn->loop.subreq != NULL) {
1132 if (frag->conn->features.concurrent_multiplex) {
1136 if (tevent_queue_length(frag->conn->calls.out_queue) > 1) {
1141 frag->subreq_wait1 = tevent_queue_wait_send(frag,
1143 frag->conn->transport.write_queue);
1144 if (tevent_req_nomem(req, frag->subreq_wait1)) {
1147 tevent_req_set_callback(frag->subreq_wait1,
1148 dcerpc_do_bind_out_frag_trans_wait1,
1151 * we need to block reads until our write is
1152 * the next in the write queue.
1154 frag->conn->loop.subreq = frag->subreq_wait1;
1155 frag->conn->loop.ev = frag->ev;
1159 * We need to add a dcerpc_write_fragment_queue_send/recv()
1162 frag->vector.iov_base = frag->blob.data;
1163 frag->vector.iov_len = frag->blob.length;
1164 subreq = tstream_writev_queue_send(frag, frag->ev,
1165 frag->conn->transport.stream,
1166 frag->conn->transport.write_queue,
1168 if (tevent_req_nomem(subreq, req)) {
1171 tevent_req_set_callback(subreq,
1172 dcerpc_do_bind_out_frag_done,
1176 frag->subreq_wait2 = tevent_queue_wait_send(frag,
1178 frag->conn->transport.write_queue);
1179 if (tevent_req_nomem(req, frag->subreq_wait2)) {
1182 tevent_req_set_callback(frag->subreq_wait2,
1183 dcerpc_do_bind_out_frag_trans_wait2,
1187 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1188 if (tevent_req_nterror(req, status)) {
1193 static void dcerpc_do_bind_out_frag_trans_wait1(struct tevent_req *subreq)
1195 struct dcerpc_do_bind_out_frag *frag =
1196 tevent_req_callback_data(subreq,
1197 struct dcerpc_do_bind_out_frag);
1198 struct tevent_req *req = frag->req;
1203 * TODO; what if the caller has been free'ed?
1206 frag->subreq_wait1 = NULL;
1207 frag->conn->loop.subreq = NULL;
1209 ok = tevent_queue_wait_recv(subreq);
1211 status = NT_STATUS_INTERNAL_ERROR;
1214 tevent_req_nterror(req, status);
1216 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1220 if (tevent_queue_length(frag->conn->transport.write_queue) > 3) {
1222 * We added 3 entries into the queue,
1223 * wait1, writev and wait2.
1225 * There's more to write, we should not block
1226 * further writev calls for a trans call.
1228 * The wait2 stage will trigger the read.
1230 TALLOC_FREE(subreq);
1235 * we don't need wait2 anymore, we're sure that
1236 * we'll do a trans call.
1238 TALLOC_FREE(frag->subreq_wait2);
1240 status = frag->conn->transport.use_trans_fn(frag->conn->transport.stream);
1241 if (!NT_STATUS_IS_OK(status)) {
1244 tevent_req_nterror(req, status);
1246 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1250 /* we free subreq after tstream_cli_np_use_trans */
1251 TALLOC_FREE(subreq);
1253 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1254 if (!NT_STATUS_IS_OK(status)) {
1257 tevent_req_nterror(req, status);
1259 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1264 static void dcerpc_do_bind_out_frag_done(struct tevent_req *subreq)
1266 struct dcerpc_do_bind_out_frag *frag =
1267 tevent_req_callback_data(subreq,
1268 struct dcerpc_do_bind_out_frag);
1269 struct tevent_req *req = frag->req;
1275 * If the caller has been free'ed, we have should
1276 * ignore any errors and just free 'frag'
1279 struct dcerpc_do_bind_state *state =
1280 tevent_req_data(req,
1281 struct dcerpc_do_bind_state);
1283 state->out_frag = NULL;
1286 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1287 TALLOC_FREE(subreq);
1290 status = map_nt_error_from_unix_common(sys_errno);
1292 tevent_req_nterror(req, status);
1297 if (frag->ptype == DCERPC_PKT_AUTH3) {
1302 tevent_req_done(req);
1306 if (frag->subreq_wait2 != NULL) {
1312 /* we need to wait for incoming pdus */
1315 static void dcerpc_do_bind_out_frag_trans_wait2(struct tevent_req *subreq)
1317 struct dcerpc_do_bind_out_frag *frag =
1318 tevent_req_callback_data(subreq,
1319 struct dcerpc_do_bind_out_frag);
1320 struct tevent_req *req = frag->req;
1324 frag->subreq_wait2 = NULL;
1326 ok = tevent_queue_wait_recv(subreq);
1328 status = NT_STATUS_INTERNAL_ERROR;
1331 tevent_req_nterror(req, status);
1333 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1337 TALLOC_FREE(subreq);
1339 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1340 if (!NT_STATUS_IS_OK(status)) {
1343 tevent_req_nterror(req, status);
1345 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1351 /* we need to wait for incoming pdus */
1354 static NTSTATUS dcerpc_do_bind_handle_in_frag(void *private_data,
1355 struct ncacn_packet *pkt,
1358 struct tevent_req *req =
1359 talloc_get_type_abort(private_data,
1361 struct dcerpc_do_bind_state *state =
1362 tevent_req_data(req,
1363 struct dcerpc_do_bind_state);
1367 DLIST_REMOVE(state->conn->calls.list, state->call);
1369 /* Ensure we have the correct type. */
1370 switch (pkt->ptype) {
1371 case DCERPC_PKT_BIND_ACK:
1372 case DCERPC_PKT_ALTER_RESP:
1373 if (pkt->auth_length != 0) {
1374 return NT_STATUS_NOT_IMPLEMENTED;
1377 if (!state->conn->features.bind_done) {
1378 if (pkt->u.bind_ack.max_recv_frag < 1234) {
1379 return NT_STATUS_RPC_PROTOCOL_ERROR;
1381 if (pkt->u.bind_ack.max_xmit_frag < 1234) {
1382 return NT_STATUS_RPC_PROTOCOL_ERROR;
1384 state->conn->features.max_recv_frag =
1385 pkt->u.bind_ack.max_recv_frag;
1386 state->conn->features.max_xmit_frag =
1387 pkt->u.bind_ack.max_xmit_frag;
1389 if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1390 state->conn->features.concurrent_multiplex = true;
1393 state->conn->features.bind_done = true;
1396 if (!state->conn->assoc->negotiate_done) {
1397 state->conn->assoc->negotiate_done = true;
1398 state->conn->assoc->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1401 if (pkt->u.bind_ack.assoc_group_id != state->conn->assoc->assoc_group_id) {
1402 return NT_STATUS_RPC_PROTOCOL_ERROR;
1405 if (pkt->u.bind_ack.num_results > state->num_ctx) {
1406 return NT_STATUS_RPC_PROTOCOL_ERROR;
1409 for (i = 0; i < pkt->u.bind_ack.num_results; i++) {
1410 struct dcerpc_ack_ctx *ack = &pkt->u.bind_ack.ctx_list[i];
1412 if (i < state->num_pres) {
1413 state->pres[i]->negotiate.ack = *ack;
1417 if (ack->result != DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1421 state->conn->assoc->features = state->conn->assoc->client_features;
1422 state->conn->assoc->features &= ack->reason.negotiate;
1425 for (i = 0; i < state->num_pres; i++) {
1426 struct dcerpc_ack_ctx *ack = &state->pres[i]->negotiate.ack;
1429 if (ack->result != DCERPC_BIND_ACK_RESULT_ACCEPTANCE) {
1433 ok = ndr_syntax_id_equal(&state->pres[i]->transfer,
1436 return NT_STATUS_RPC_PROTOCOL_ERROR;
1440 tevent_req_done(req);
1441 return NT_STATUS_OK;
1443 //case DCERPC_PKT_ALTER_RESP:
1444 if (pkt->auth_length != 0) {
1445 return NT_STATUS_NOT_IMPLEMENTED;
1448 return NT_STATUS_NOT_IMPLEMENTED;
1451 /* Point the return values at the NDR data. */
1452 payload.data = frag.data + DCERPC_RESPONSE_LENGTH;
1454 if (pkt->auth_length) {
1455 /* We've already done integer wrap tests in
1456 * dcerpc_check_auth(). */
1457 payload.length = frag.length
1458 - DCERPC_RESPONSE_LENGTH
1460 - DCERPC_AUTH_TRAILER_LENGTH
1463 payload.length = frag.length - DCERPC_RESPONSE_LENGTH;
1466 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
1467 if (pkt->drep[0] & DCERPC_DREP_LE) {
1468 state->response.bigendian = false;
1470 state->response.bigendian = true;
1474 DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
1475 (long unsigned int)frag.length,
1476 (long unsigned int)payload.length,
1477 (unsigned int)pad_len));
1480 * If this is the first reply, and the allocation hint is
1481 * reasonable, try and set up the reply_pdu DATA_BLOB to the
1485 if ((state->response.blob.length == 0) &&
1486 pkt->u.response.alloc_hint &&
1487 (pkt->u.response.alloc_hint < 15*1024*1024)) {
1488 ok = data_blob_realloc(state, &state->response.blob,
1489 pkt->u.response.alloc_hint);
1491 DEBUG(0, ("reply alloc hint %d too "
1492 "large to allocate\n",
1493 (int)pkt->u.response.alloc_hint));
1494 return NT_STATUS_NO_MEMORY;
1498 new_total = state->response.ofs + payload.length;
1500 if (new_total > 15 * 1024 *1024) {
1501 return NT_STATUS_RPC_PROTOCOL_ERROR;//TODO
1504 missing = new_total - state->response.blob.length;
1507 ok = data_blob_realloc(state, &state->response.blob,
1510 DEBUG(0, ("reply alloc hint %d too "
1511 "large to allocate\n",
1512 (int)pkt->u.response.alloc_hint));
1513 return NT_STATUS_NO_MEMORY;
1517 memcpy(state->response.blob.data + state->response.ofs,
1518 payload.data, payload.length);
1519 state->response.ofs += payload.length;
1521 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
1522 tevent_req_done(req);//TODO
1523 return NT_STATUS_OK;
1525 return NT_STATUS_OK;
1527 return NT_STATUS_NOT_IMPLEMENTED;
1529 case DCERPC_PKT_FAULT:
1531 DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault "
1532 "code %s received from %s!\n",
1533 dcerpc_errstr(talloc_tos(),
1534 pkt->u.fault.status),
1537 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1538 if (NT_STATUS_IS_OK(status)) {
1539 status = NT_STATUS_RPC_PROTOCOL_ERROR;
1542 tevent_req_nterror(req, status);//TODO
1543 return NT_STATUS_OK;
1545 DEBUG(0, ("Unknown packet type %u received from %s!\n",
1546 (unsigned int)pkt->ptype,
1548 return NT_STATUS_RPC_PROTOCOL_ERROR;
1551 return NT_STATUS_RPC_PROTOCOL_ERROR;
1554 NTSTATUS dcerpc_do_bind_recv(struct tevent_req *req)
1556 struct dcerpc_do_bind_state *state =
1557 tevent_req_data(req,
1558 struct dcerpc_do_bind_state);
1561 if (tevent_req_is_nterror(req, &status)) {
1562 tevent_req_received(req);
1566 if (!NT_STATUS_IS_OK(state->sec_status)) {
1567 status = state->sec_status;
1568 tevent_req_received(req);
1572 tevent_req_received(req);
1573 return NT_STATUS_OK;
1576 struct dcerpc_do_request_out_frag;
1578 struct dcerpc_do_request_state {
1579 struct tevent_context *ev;
1580 struct dcerpc_connection *conn;
1581 struct dcerpc_call *call;
1582 const struct GUID *object;
1585 const DATA_BLOB *blob;
1589 struct dcerpc_do_request_out_frag *out_frag;
1597 struct dcerpc_do_request_out_frag {
1598 struct tevent_context *ev;
1599 struct dcerpc_connection *conn;
1600 struct tevent_req *req;
1603 struct iovec vector;
1604 struct tevent_req *subreq_wait1;
1605 struct tevent_req *subreq_wait2;
1608 static void dcerpc_do_request_cleanup(struct tevent_req *req,
1609 enum tevent_req_state req_state);
1611 static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
1612 void *private_data);
1614 static NTSTATUS dcerpc_do_request_handle_in_frag(void *private_data,
1615 struct ncacn_packet *pkt,
1618 struct tevent_req *dcerpc_do_request_send(TALLOC_CTX *mem_ctx,
1619 struct tevent_context *ev,
1620 struct dcerpc_connection *conn,
1621 struct dcerpc_call *call,
1622 const struct GUID *object,
1624 const DATA_BLOB *request,
1627 struct tevent_req *req;
1628 struct dcerpc_do_request_state *state;
1631 req = tevent_req_create(mem_ctx, &state,
1632 struct dcerpc_do_request_state);
1639 state->object = object;
1640 state->opnum = opnum;
1641 state->request.blob = request;
1642 state->request.bigendian = bigendian;
1644 state->call->incoming.private_data = req;
1645 state->call->incoming.handler = dcerpc_do_request_handle_in_frag;
1646 DLIST_ADD_END(state->conn->calls.list, state->call, NULL);
1648 tevent_req_set_cleanup_fn(req, dcerpc_do_request_cleanup);
1650 ok = tevent_queue_add(state->conn->calls.out_queue,
1653 dcerpc_do_request_out_frag_next,
1656 tevent_req_nomem(NULL, req);
1657 return tevent_req_post(req, ev);
1663 static void dcerpc_do_request_cleanup(struct tevent_req *req,
1664 enum tevent_req_state req_state)
1666 struct dcerpc_do_request_state *state =
1667 tevent_req_data(req,
1668 struct dcerpc_do_request_state);
1670 if (state->out_frag != NULL) {
1671 state->out_frag->req = NULL;
1672 state->out_frag = NULL;
1675 if (state->call != NULL) {
1676 ZERO_STRUCT(state->call->incoming);
1677 DLIST_REMOVE(state->conn->calls.list, state->call);
1682 static void dcerpc_do_request_out_frag_trans_wait1(struct tevent_req *subreq);
1683 static void dcerpc_do_request_out_frag_done(struct tevent_req *subreq);
1684 static void dcerpc_do_request_out_frag_trans_wait2(struct tevent_req *subreq);
1686 static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
1689 struct dcerpc_do_request_state *state =
1690 tevent_req_data(req,
1691 struct dcerpc_do_request_state);
1692 struct dcerpc_do_request_out_frag *frag;
1693 size_t data_sent_thistime;
1694 size_t hdr_len = DCERPC_REQUEST_LENGTH;
1701 union dcerpc_payload u;
1704 struct tevent_req *subreq;
1705 bool use_trans = true;
1707 if (state->object) {
1708 flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1713 * the fragment belongs to the connection instead of the request
1714 * because it has to remain in case the request is canceled
1716 frag = talloc_zero(state->conn, struct dcerpc_do_request_out_frag);
1717 if (tevent_req_nomem(frag, req)) {
1720 frag->ev = state->ev;
1721 frag->conn = state->conn;
1723 state->out_frag = frag;
1725 data_left = state->request.blob->length - state->request.ofs;
1727 status = dcerpc_guess_pdu_sizes(state->call->sec,
1729 state->conn->features.max_xmit_frag,
1731 &data_sent_thistime,
1732 &frag_len, &auth_len, &pad_len);
1733 if (!NT_STATUS_IS_OK(status)) {
1734 tevent_req_nterror(req, status);
1738 if (state->request.ofs == 0) {
1739 flags |= DCERPC_PFC_FLAG_FIRST;
1742 payload.data = state->request.blob->data + state->request.ofs;
1743 payload.length = data_sent_thistime;
1745 state->request.ofs += data_sent_thistime;
1747 if (state->request.blob->length == state->request.ofs) {
1748 flags |= DCERPC_PFC_FLAG_LAST;
1751 ZERO_STRUCT(u.request);
1753 u.request.alloc_hint = state->request.blob->length -
1755 u.request.context_id = state->call->pres->context_id;
1756 u.request.opnum = state->opnum;
1757 if (state->object) {
1758 u.request.object.object = *state->object;
1760 //TODO pass state->request.bigendian
1761 status = dcerpc_ncacn_packet_blob(frag,
1765 state->call->call_id,
1768 if (!NT_STATUS_IS_OK(status)) {
1769 tevent_req_nterror(req, status);
1773 /* explicitly set frag_len here as dcerpc_push_ncacn_packet() can't
1774 * compute it right for requests because the auth trailer is missing
1776 dcerpc_set_frag_length(&frag->blob, frag_len);
1778 /* Copy in the data. */
1779 ok = data_blob_append(frag, &frag->blob,
1780 payload.data, payload.length);
1782 tevent_req_nomem(NULL, req);
1786 switch (state->call->sec->auth_level) {
1787 case DCERPC_AUTH_LEVEL_NONE:
1788 case DCERPC_AUTH_LEVEL_CONNECT:
1789 case DCERPC_AUTH_LEVEL_PACKET:
1791 case DCERPC_AUTH_LEVEL_INTEGRITY:
1792 case DCERPC_AUTH_LEVEL_PRIVACY:
1793 status = dcerpc_response_auth_blob(state->call->sec,
1796 if (!NT_STATUS_IS_OK(status)) {
1797 tevent_req_nterror(req, status);
1802 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1806 frag->is_last = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
1808 if (!frag->is_last) {
1812 if (frag->conn->transport.use_trans_fn == NULL) {
1816 if (frag->conn->loop.subreq != NULL) {
1820 if (frag->conn->features.concurrent_multiplex) {
1824 if (tevent_queue_length(frag->conn->calls.out_queue) > 1) {
1829 frag->subreq_wait1 = tevent_queue_wait_send(frag,
1831 frag->conn->transport.write_queue);
1832 if (tevent_req_nomem(req, frag->subreq_wait1)) {
1835 tevent_req_set_callback(frag->subreq_wait1,
1836 dcerpc_do_request_out_frag_trans_wait1,
1839 * we need to block reads until our write is
1840 * the next in the write queue.
1842 frag->conn->loop.subreq = frag->subreq_wait1;
1843 frag->conn->loop.ev = frag->ev;
1847 * We need to add a dcerpc_write_fragment_queue_send/recv()
1850 frag->vector.iov_base = frag->blob.data;
1851 frag->vector.iov_len = frag->blob.length;
1852 subreq = tstream_writev_queue_send(frag, frag->ev,
1853 frag->conn->transport.stream,
1854 frag->conn->transport.write_queue,
1856 if (tevent_req_nomem(subreq, req)) {
1859 tevent_req_set_callback(subreq,
1860 dcerpc_do_request_out_frag_done,
1864 frag->subreq_wait2 = tevent_queue_wait_send(frag,
1866 frag->conn->transport.write_queue);
1867 if (tevent_req_nomem(req, frag->subreq_wait2)) {
1870 tevent_req_set_callback(frag->subreq_wait2,
1871 dcerpc_do_request_out_frag_trans_wait2,
1875 if (!frag->is_last) {
1879 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1880 if (tevent_req_nterror(req, status)) {
1885 static void dcerpc_do_request_out_frag_trans_wait1(struct tevent_req *subreq)
1887 struct dcerpc_do_request_out_frag *frag =
1888 tevent_req_callback_data(subreq,
1889 struct dcerpc_do_request_out_frag);
1890 struct tevent_req *req = frag->req;
1895 * TODO; what if the caller has been free'ed?
1898 frag->subreq_wait1 = NULL;
1899 frag->conn->loop.subreq = NULL;
1901 ok = tevent_queue_wait_recv(subreq);
1903 status = NT_STATUS_INTERNAL_ERROR;
1906 tevent_req_nterror(req, status);
1908 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1912 if (tevent_queue_length(frag->conn->transport.write_queue) > 3) {
1914 * We added 3 entries into the queue,
1915 * wait1, writev and wait2.
1917 * There's more to write, we should not block
1918 * further writev calls for a trans call.
1920 * The wait2 stage will trigger the read.
1922 TALLOC_FREE(subreq);
1927 * we don't need wait2 anymore, we're sure that
1928 * we'll do a trans call.
1930 TALLOC_FREE(frag->subreq_wait2);
1932 status = frag->conn->transport.use_trans_fn(frag->conn->transport.stream);
1933 if (!NT_STATUS_IS_OK(status)) {
1936 tevent_req_nterror(req, status);
1938 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1942 /* we free subreq after tstream_cli_np_use_trans */
1943 TALLOC_FREE(subreq);
1945 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1946 if (!NT_STATUS_IS_OK(status)) {
1949 tevent_req_nterror(req, status);
1951 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1956 static void dcerpc_do_request_out_frag_done(struct tevent_req *subreq)
1958 struct dcerpc_do_request_out_frag *frag =
1959 tevent_req_callback_data(subreq,
1960 struct dcerpc_do_request_out_frag);
1961 struct tevent_req *req = frag->req;
1967 * If the caller has been free'ed, we have should
1968 * ignore any errors and just free 'frag'
1971 struct dcerpc_do_request_state *state =
1972 tevent_req_data(req,
1973 struct dcerpc_do_request_state);
1975 state->out_frag = NULL;
1978 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1979 TALLOC_FREE(subreq);
1982 status = map_nt_error_from_unix_common(sys_errno);
1984 tevent_req_nterror(req, status);
1989 if (frag->subreq_wait2 != NULL) {
1993 if (frag->is_last) {
2003 dcerpc_do_request_out_frag_next(req, NULL);
2006 static void dcerpc_do_request_out_frag_trans_wait2(struct tevent_req *subreq)
2008 struct dcerpc_do_request_out_frag *frag =
2009 tevent_req_callback_data(subreq,
2010 struct dcerpc_do_request_out_frag);
2011 struct tevent_req *req = frag->req;
2015 frag->subreq_wait2 = NULL;
2017 ok = tevent_queue_wait_recv(subreq);
2019 status = NT_STATUS_INTERNAL_ERROR;
2022 tevent_req_nterror(req, status);
2024 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2028 TALLOC_FREE(subreq);
2030 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
2031 if (!NT_STATUS_IS_OK(status)) {
2034 tevent_req_nterror(req, status);
2036 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2042 /* we need to wait for incoming pdus */
2045 static NTSTATUS dcerpc_do_request_handle_in_frag(void *private_data,
2046 struct ncacn_packet *pkt,
2049 struct tevent_req *req =
2050 talloc_get_type_abort(private_data,
2052 struct dcerpc_do_request_state *state =
2053 tevent_req_data(req,
2054 struct dcerpc_do_request_state);
2063 /* Ensure we have the correct type. */
2064 switch (pkt->ptype) {
2065 case DCERPC_PKT_RESPONSE:
2067 /* Here's where we deal with incoming sign/seal. */
2068 error = dcerpc_check_pdu_auth(state->call->sec,
2070 &pkt->u.response.stub_and_verifier,
2071 DCERPC_RESPONSE_LENGTH,
2073 if (!NT_STATUS_IS_OK(error)) {
2077 if (frag.length < DCERPC_RESPONSE_LENGTH + pad_len) {
2078 return NT_STATUS_RPC_PROTOCOL_ERROR;
2081 /* Point the return values at the NDR data. */
2082 payload.data = frag.data + DCERPC_RESPONSE_LENGTH;
2084 if (pkt->auth_length) {
2085 /* We've already done integer wrap tests in
2086 * dcerpc_check_auth(). */
2087 payload.length = frag.length
2088 - DCERPC_RESPONSE_LENGTH
2090 - DCERPC_AUTH_TRAILER_LENGTH
2093 payload.length = frag.length - DCERPC_RESPONSE_LENGTH;
2096 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
2097 if (pkt->drep[0] & DCERPC_DREP_LE) {
2098 state->response.bigendian = false;
2100 state->response.bigendian = true;
2104 DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
2105 (long unsigned int)frag.length,
2106 (long unsigned int)payload.length,
2107 (unsigned int)pad_len));
2110 * If this is the first reply, and the allocation hint is
2111 * reasonable, try and set up the reply_pdu DATA_BLOB to the
2115 if ((state->response.blob.length == 0) &&
2116 pkt->u.response.alloc_hint &&
2117 (pkt->u.response.alloc_hint < 15*1024*1024)) {
2118 ok = data_blob_realloc(state, &state->response.blob,
2119 pkt->u.response.alloc_hint);
2121 DEBUG(0, ("reply alloc hint %d too "
2122 "large to allocate\n",
2123 (int)pkt->u.response.alloc_hint));
2124 return NT_STATUS_NO_MEMORY;
2128 new_total = state->response.ofs + payload.length;
2130 if (new_total > 15 * 1024 *1024) {
2131 return NT_STATUS_RPC_PROTOCOL_ERROR;//TODO
2134 missing = new_total - state->response.blob.length;
2137 ok = data_blob_realloc(state, &state->response.blob,
2140 DEBUG(0, ("reply alloc hint %d too "
2141 "large to allocate\n",
2142 (int)pkt->u.response.alloc_hint));
2143 return NT_STATUS_NO_MEMORY;
2147 memcpy(state->response.blob.data + state->response.ofs,
2148 payload.data, payload.length);
2149 state->response.ofs += payload.length;
2151 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
2152 tevent_req_done(req);//TODO
2153 return NT_STATUS_OK;
2155 return NT_STATUS_OK;
2157 case DCERPC_PKT_FAULT:
2159 DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault "
2160 "code %s received from %s!\n",
2161 dcerpc_errstr(talloc_tos(),
2162 pkt->u.fault.status),
2165 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2166 if (NT_STATUS_IS_OK(status)) {
2167 status = NT_STATUS_RPC_PROTOCOL_ERROR;
2170 tevent_req_nterror(req, status);//TODO
2171 return NT_STATUS_OK;
2173 DEBUG(0, ("Unknown packet type %u received from %s!\n",
2174 (unsigned int)pkt->ptype,
2176 return NT_STATUS_RPC_PROTOCOL_ERROR;
2180 NTSTATUS dcerpc_do_request_recv(struct tevent_req *req,
2181 TALLOC_CTX *mem_ctx,
2182 DATA_BLOB *response,
2185 struct dcerpc_do_request_state *state =
2186 tevent_req_data(req,
2187 struct dcerpc_do_request_state);
2190 if (tevent_req_is_nterror(req, &status)) {
2191 tevent_req_received(req);
2195 /* return data to caller and assign it ownership of memory */
2196 response->data = talloc_move(mem_ctx, &state->response.blob.data);
2197 response->length = state->response.blob.length;
2198 *bigendian = state->response.bigendian;
2200 tevent_req_received(req);
2201 return NT_STATUS_OK;