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;
70 struct dcerpc_call *new_call;
74 struct tevent_context *ev;
75 struct tevent_req *subreq;
79 struct dcerpc_security {
81 enum dcerpc_AuthType auth_type;
82 enum dcerpc_AuthLevel auth_level;
83 struct gensec_security *gensec;
86 struct dcerpc_presentation {
88 const struct ndr_interface_table *table;
89 struct ndr_syntax_id transfer;
91 struct dcerpc_ctx_list req;
92 struct dcerpc_ack_ctx ack;
97 struct dcerpc_call *prev, *next;
100 struct dcerpc_security *sec;
101 struct dcerpc_presentation *pres;
105 NTSTATUS (*handler)(void *private_data,
106 struct ncacn_packet *pkt,
111 struct dcerpc_association *dcerpc_association_create(TALLOC_CTX *mem_ctx,
112 uint16_t client_features)
114 struct dcerpc_association *assoc;
116 assoc = talloc_zero(mem_ctx, struct dcerpc_association);
121 assoc->next_call_id = 1;
123 assoc->client_features = client_features;
128 struct dcerpc_connection *dcerpc_connection_create(TALLOC_CTX *mem_ctx,
129 struct dcerpc_association *assoc,
130 struct tstream_context **stream)
132 struct dcerpc_connection *conn;
134 conn = talloc_zero(mem_ctx, struct dcerpc_connection);
140 conn->transport.stream = talloc_move(conn, stream);
141 conn->transport.write_queue = tevent_queue_create(conn, "write_queue");
142 if (conn->transport.write_queue == NULL) {
147 conn->features.max_xmit_frag = 4280;
148 conn->features.max_recv_frag = 4280;
150 conn->calls.out_queue = tevent_queue_create(conn, "out_queue");
151 if (conn->calls.out_queue == NULL) {
159 void dcerpc_connection_set_use_trans_fn(struct dcerpc_connection *conn,
160 dcerpc_connection_use_trans_fn fn)
162 conn->transport.use_trans_fn = fn;
165 struct dcerpc_security *dcerpc_security_allocate(
167 struct dcerpc_connection *conn,
168 enum dcerpc_AuthType auth_type,
169 enum dcerpc_AuthLevel auth_level,
170 struct gensec_security **gensec)
172 struct dcerpc_security *sec;
174 sec = talloc_zero(mem_ctx, struct dcerpc_security);
179 sec->context_id = conn->next_sec_context_id++;
180 sec->auth_type = auth_type;
181 sec->auth_level = auth_level;
183 if (gensec != NULL) {
184 sec->gensec = talloc_move(sec, gensec);
190 struct dcerpc_presentation *dcerpc_presentation_allocate(
192 struct dcerpc_connection *conn,
193 const struct ndr_interface_table *table,
194 const struct ndr_syntax_id *transfer)
196 struct dcerpc_presentation *pres;
198 pres = talloc_zero(mem_ctx, struct dcerpc_presentation);
203 pres->context_id = conn->next_pres_context_id++;
205 pres->transfer = *transfer;
207 pres->negotiate.req.abstract_syntax = table->syntax_id;
208 pres->negotiate.req.context_id = pres->context_id;
209 pres->negotiate.req.num_transfer_syntaxes = 1;
210 pres->negotiate.req.transfer_syntaxes = &pres->transfer;
212 pres->negotiate.ack.result = DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION;
213 pres->negotiate.ack.reason.value =
214 DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED;
219 struct dcerpc_call *dcerpc_call_allocate(TALLOC_CTX *mem_ctx,
220 struct dcerpc_association *assoc,
221 struct dcerpc_security *sec,
222 struct dcerpc_presentation *pres)
224 struct dcerpc_call *call;
226 call = talloc_zero(mem_ctx, struct dcerpc_call);
231 call->call_id = assoc->next_call_id++;
239 static NTSTATUS dcerpc_guess_pdu_sizes(struct dcerpc_security *sec,
242 size_t max_xmit_frag,
243 size_t pad_alignment,
244 size_t *data_to_send,
252 /* no auth token cases first */
253 switch (sec->auth_level) {
254 case DCERPC_AUTH_LEVEL_NONE:
255 case DCERPC_AUTH_LEVEL_CONNECT:
256 case DCERPC_AUTH_LEVEL_PACKET:
257 max_len = max_xmit_frag - header_len;
258 *data_to_send = MIN(max_len, data_left);
261 *frag_len = header_len + *data_to_send;
264 case DCERPC_AUTH_LEVEL_PRIVACY:
265 case DCERPC_AUTH_LEVEL_INTEGRITY:
266 if (sec->auth_type == DCERPC_AUTH_TYPE_NONE) {
267 return NT_STATUS_INVALID_PARAMETER_MIX;
269 if (sec->gensec == NULL) {
270 return NT_STATUS_INVALID_PARAMETER_MIX;
275 return NT_STATUS_INVALID_PARAMETER;
279 /* Sign/seal case, calculate auth and pad lengths */
281 max_len = max_xmit_frag - header_len - DCERPC_AUTH_TRAILER_LENGTH;
283 *auth_len = gensec_sig_size(sec->gensec, max_len);
285 max_len -= *auth_len;
287 *data_to_send = MIN(max_len, data_left);
289 mod_len = (header_len + *data_to_send) % pad_alignment;
291 *pad_len = pad_alignment - mod_len;
296 if (*data_to_send + *pad_len > max_len) {
297 *data_to_send -= pad_alignment;
300 *frag_len = header_len + *data_to_send + *pad_len
301 + DCERPC_AUTH_TRAILER_LENGTH + *auth_len;
306 static NTSTATUS dcerpc_ncacn_push_auth(DATA_BLOB *blob,
308 struct ncacn_packet *pkt,
309 struct dcerpc_auth *auth_info)
311 struct ndr_push *ndr;
312 enum ndr_err_code ndr_err;
314 ndr = ndr_push_init_ctx(mem_ctx);
316 return NT_STATUS_NO_MEMORY;
319 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
320 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
323 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
324 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
328 pkt->auth_length = auth_info->credentials.length;
330 // pkt->auth_length = 0;
333 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
334 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
335 return ndr_map_error2ntstatus(ndr_err);
340 /* the s3 rpc server doesn't handle auth padding in
341 bind requests. Use zero auth padding to keep us
342 working with old servers */
343 uint32_t offset = ndr->offset;
344 ndr_err = ndr_push_align(ndr, 16);
345 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
346 return ndr_map_error2ntstatus(ndr_err);
348 auth_info->auth_pad_length = ndr->offset - offset;
350 auth_info->auth_pad_length = 0;
352 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info);
353 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
354 return ndr_map_error2ntstatus(ndr_err);
358 *blob = ndr_push_blob(ndr);
360 /* fill in the frag length */
361 dcerpc_set_frag_length(blob, blob->length);
366 static NTSTATUS dcerpc_ncacn_packet_blob(TALLOC_CTX *mem_ctx,
367 enum dcerpc_pkt_type ptype,
369 uint16_t auth_length,
371 union dcerpc_payload *u,
374 struct ncacn_packet r;
378 r.rpc_vers_minor = 0;
380 r.pfc_flags = pfc_flags;
381 r.drep[0] = DCERPC_DREP_LE;
385 r.auth_length = auth_length;
389 status = dcerpc_ncacn_push_auth(blob, mem_ctx, &r, NULL);
390 if (!NT_STATUS_IS_OK(status)) {
394 if (DEBUGLEVEL >= 10) {
395 /* set frag len for print function */
396 r.frag_length = blob->length;
397 NDR_PRINT_DEBUG(ncacn_packet, &r);
403 #define DCERPC_PAYLOAD_PADDING_SIZE 16 //TODO???
405 static NTSTATUS dcerpc_auth_blob(TALLOC_CTX *mem_ctx,
406 enum dcerpc_AuthType auth_type,
407 enum dcerpc_AuthLevel auth_level,
408 uint8_t auth_pad_length,
409 uint32_t auth_context_id,
410 const DATA_BLOB *credentials,
413 struct dcerpc_auth r;
414 enum ndr_err_code ndr_err;
416 r.auth_type = auth_type;
417 r.auth_level = auth_level;
418 r.auth_pad_length = auth_pad_length;
420 r.auth_context_id = auth_context_id;
421 r.credentials = *credentials;
423 ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
424 (ndr_push_flags_fn_t)ndr_push_dcerpc_auth);
425 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
426 return ndr_map_error2ntstatus(ndr_err);
429 if (DEBUGLEVEL >= 10) {
430 NDR_PRINT_DEBUG(dcerpc_auth, &r);
436 static NTSTATUS dcerpc_response_auth_blob(struct dcerpc_security *sec,
440 char pad[DCERPC_PAYLOAD_PADDING_SIZE] = { 0, };
443 uint16_t data_and_pad_len = 0;
446 if (rpc_out->length < DCERPC_RESPONSE_LENGTH) {
447 return NT_STATUS_INVALID_PARAMETER_MIX;
450 if (sec->auth_type == DCERPC_AUTH_TYPE_NONE ||
451 sec->auth_type == DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM) {
455 if (sec->gensec == NULL) {
456 return NT_STATUS_INVALID_PARAMETER_MIX;
460 /* Copy the sign/seal padding data. */
461 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
462 return NT_STATUS_NO_MEMORY;
466 data_and_pad_len = rpc_out->length - DCERPC_RESPONSE_LENGTH;
468 /* marshall the dcerpc_auth with an actually empty auth_blob.
469 * This is needed because the ntmlssp signature includes the
470 * auth header. We will append the actual blob later. */
471 auth_blob = data_blob_null;
472 status = dcerpc_auth_blob(rpc_out->data,
479 if (!NT_STATUS_IS_OK(status)) {
483 /* append the header */
484 if (!data_blob_append(NULL, rpc_out,
485 auth_info.data, auth_info.length)) {
486 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
487 (unsigned int)auth_info.length));
488 return NT_STATUS_NO_MEMORY;
490 data_blob_free(&auth_info);
492 switch (sec->auth_level) {
493 case DCERPC_AUTH_LEVEL_PRIVACY:
494 /* Data portion is encrypted. */
495 status = gensec_seal_packet(sec->gensec,
498 + DCERPC_RESPONSE_LENGTH,
503 if (!NT_STATUS_IS_OK(status)) {
508 case DCERPC_AUTH_LEVEL_INTEGRITY:
509 /* Data is signed. */
510 status = gensec_sign_packet(sec->gensec,
513 + DCERPC_RESPONSE_LENGTH,
518 if (!NT_STATUS_IS_OK(status)) {
525 smb_panic("bad auth level");
527 return NT_STATUS_INVALID_PARAMETER;
530 /* Finally attach the blob. */
531 if (!data_blob_append(NULL, rpc_out,
532 auth_blob.data, auth_blob.length)) {
533 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
534 (unsigned int)auth_blob.length));
535 return NT_STATUS_NO_MEMORY;
537 data_blob_free(&auth_blob);
542 static NTSTATUS dcerpc_check_pdu_auth(struct dcerpc_security *sec,
543 struct ncacn_packet *pkt,
544 DATA_BLOB *pkt_trailer,
550 struct dcerpc_auth auth_info;
551 uint32_t auth_length;
555 switch (sec->auth_level) {
556 case DCERPC_AUTH_LEVEL_PRIVACY:
557 DEBUG(10, ("Requested Privacy.\n"));
560 case DCERPC_AUTH_LEVEL_INTEGRITY:
561 DEBUG(10, ("Requested Integrity.\n"));
564 case DCERPC_AUTH_LEVEL_CONNECT:
565 if (pkt->auth_length != 0) {
571 case DCERPC_AUTH_LEVEL_NONE:
572 if (pkt->auth_length != 0) {
573 DEBUG(3, ("Got non-zero auth len on non "
574 "authenticated connection!\n"));
575 return NT_STATUS_INVALID_PARAMETER;
581 DEBUG(3, ("Unimplemented Auth Level %d",
583 return NT_STATUS_INVALID_PARAMETER;
586 /* Paranioa checks for auth_length. */
587 if (pkt->auth_length > pkt->frag_length) {
588 return NT_STATUS_INFO_LENGTH_MISMATCH;
590 if (((unsigned int)pkt->auth_length
591 + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) ||
592 ((unsigned int)pkt->auth_length
593 + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
594 /* Integer wrap attempt. */
595 return NT_STATUS_INFO_LENGTH_MISMATCH;
598 status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
599 &auth_info, &auth_length, false);
600 if (!NT_STATUS_IS_OK(status)) {
604 data = data_blob_const(raw_pkt->data + header_size,
605 pkt_trailer->length - auth_length);
606 full_pkt = data_blob_const(raw_pkt->data,
607 raw_pkt->length - auth_info.credentials.length);
609 switch (sec->auth_type) {
610 case DCERPC_AUTH_TYPE_NONE:
611 case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
617 switch (sec->auth_level) {
618 case DCERPC_AUTH_LEVEL_PRIVACY:
619 /* Data portion is encrypted. */
620 status = gensec_unseal_packet(sec->gensec,
625 &auth_info.credentials);
628 case DCERPC_AUTH_LEVEL_INTEGRITY:
629 /* Data is signed. */
630 status = gensec_check_packet(sec->gensec,
635 &auth_info.credentials);
638 return NT_STATUS_INVALID_PARAMETER;
640 /* TODO: remove later
641 * this is still needed because in the server code the
642 * pkt_trailer actually has a copy of the raw data, and they
643 * are still both used in later calls */
644 if (sec->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
645 memcpy(pkt_trailer->data, data.data, data.length);
648 *pad_len = auth_info.auth_pad_length;
649 data_blob_free(&auth_info.credentials);
653 static void dcerpc_connection_loop(struct tevent_req *subreq);
655 static NTSTATUS dcerpc_connection_loop_restart(struct dcerpc_connection *conn,
656 struct tevent_context *ev)
659 return NT_STATUS_INVALID_PARAMETER; // TODO...
662 if (conn->loop.subreq) {
663 if (conn->loop.ev != ev) {
664 return NT_STATUS_INVALID_PARAMETER; // TODO...
669 if (conn->calls.list == NULL) {
670 conn->loop.ev = NULL;
674 conn->loop.subreq = dcerpc_read_ncacn_packet_send(conn,
676 conn->transport.stream);
677 if (conn->loop.subreq == NULL) {
678 return NT_STATUS_NO_MEMORY;
680 tevent_req_set_callback(conn->loop.subreq, dcerpc_connection_loop, conn);
685 static void dcerpc_connection_loop(struct tevent_req *subreq)
687 struct dcerpc_connection *conn =
688 tevent_req_callback_data(subreq,
689 struct dcerpc_connection);
691 struct ncacn_packet *pkt;
693 struct dcerpc_call *call;
694 bool valid_type = false;
696 conn->loop.subreq = NULL;
698 error = dcerpc_read_ncacn_packet_recv(subreq, subreq, &pkt, &pdu);
699 if (!NT_STATUS_IS_OK(error)) {
701 // disconnect and notify pending calls
705 if (DEBUGLEVEL >= 10) {
706 NDR_PRINT_DEBUG(ncacn_packet, pkt);
709 switch (pkt->ptype) {
710 case DCERPC_PKT_REQUEST:
711 /* Ordinary request. */
715 case DCERPC_PKT_PING:
716 /* Connectionless is server alive ? */
719 case DCERPC_PKT_RESPONSE:
720 /* Ordinary reply. */
724 case DCERPC_PKT_FAULT:
725 /* Fault in processing of call. */
729 case DCERPC_PKT_WORKING:
730 /* Connectionless reply to a ping when server busy. */
733 case DCERPC_PKT_NOCALL:
734 /* Connectionless reply to a ping when server has lost part of clients call. */
737 case DCERPC_PKT_REJECT:
738 /* Refuse a request with a code. */
744 case DCERPC_PKT_CL_CANCEL:
747 case DCERPC_PKT_FACK:
750 case DCERPC_PKT_CANCEL_ACK:
751 /* Server ACK to client cancel request. */
754 case DCERPC_PKT_BIND:
755 /* Bind to interface. */
759 case DCERPC_PKT_BIND_ACK:
760 /* Server ack of bind. */
764 case DCERPC_PKT_BIND_NAK:
765 /* Server nack of bind. */
769 case DCERPC_PKT_ALTER:
774 case DCERPC_PKT_ALTER_RESP:
775 /* Reply to alter auth. */
779 case DCERPC_PKT_AUTH3:
780 /* not the real name! this is undocumented! */
784 case DCERPC_PKT_SHUTDOWN:
785 /* Server to client request to shutdown. */
789 case DCERPC_PKT_CO_CANCEL:
790 /* Connection-oriented cancel request. */
794 case DCERPC_PKT_ORPHANED:
795 /* Client telling server it's aborting a partially sent request or telling server to stop sending replies. */
800 /* RTS packets used in ncacn_http */
806 // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
810 if (conn->calls.active != NULL) {
811 if (pkt->call_id != conn->calls.active->call_id) {
813 // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
816 call = conn->calls.active;
818 call = conn->calls.list;
821 for (call = conn->calls.list; call; call = call->next) {
822 if (call->call_id == pkt->call_id) {
828 call = conn->calls.new_call;
833 // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
837 if (call->incoming.handler == NULL) {
839 // disconnect and notify pending calls NT_STATUS_RPC_PROTOCOL_ERROR;
843 error = call->incoming.handler(call->incoming.private_data, pkt, pdu);
845 if (!NT_STATUS_IS_OK(error)) {
846 // disconnect and notify pending calls
850 if (conn->calls.new_call == NULL) {
851 conn->loop.ev = NULL;
855 error = dcerpc_connection_loop_restart(conn, conn->loop.ev);
856 if (!NT_STATUS_IS_OK(error)) {
857 // disconnect and notify pending calls
862 struct dcerpc_do_bind_out_frag;
864 struct dcerpc_do_bind_state {
865 struct tevent_context *ev;
866 struct dcerpc_connection *conn;
867 struct dcerpc_call *call;
868 struct dcerpc_security *sec;
872 struct dcerpc_do_bind_out_frag *out_frag;
874 struct dcerpc_presentation **pres;
875 uint32_t remaining_pres;
878 struct dcerpc_ctx_list *ctx_list;
879 struct ndr_syntax_id features;
882 struct dcerpc_do_bind_out_frag {
883 struct tevent_context *ev;
884 struct dcerpc_connection *conn;
885 struct tevent_req *req;
886 enum dcerpc_pkt_type ptype;
889 struct tevent_req *subreq_wait1;
890 struct tevent_req *subreq_wait2;
893 static void dcerpc_do_bind_cleanup(struct tevent_req *req,
894 enum tevent_req_state req_state);
896 static void dcerpc_do_bind_sec_next(struct tevent_req *subreq);
897 static void dcerpc_do_bind_out_frag_next(struct tevent_req *subreq);
899 static NTSTATUS dcerpc_do_bind_handle_in_frag(void *private_data,
900 struct ncacn_packet *pkt,
903 struct tevent_req *dcerpc_do_bind_send(TALLOC_CTX *mem_ctx,
904 struct tevent_context *ev,
905 struct dcerpc_connection *conn,
906 struct dcerpc_call *call,
907 struct dcerpc_security *sec,
909 struct dcerpc_presentation **pres)
911 struct tevent_req *req;
912 struct dcerpc_do_bind_state *state;
913 struct tevent_req *subreq;
915 req = tevent_req_create(mem_ctx, &state,
916 struct dcerpc_do_bind_state);
924 state->num_pres = num_pres;
927 state->call->incoming.private_data = req;
928 state->call->incoming.handler = dcerpc_do_bind_handle_in_frag;
929 DLIST_ADD_END(state->conn->calls.list, state->call, NULL);
931 tevent_req_set_cleanup_fn(req, dcerpc_do_bind_cleanup);
932 tevent_req_defer_callback(req, ev);
934 if (state->sec != NULL && state->sec->gensec != NULL) {
935 subreq = gensec_update_send(state, ev,
938 if (tevent_req_nomem(subreq, req)) {
939 return tevent_req_post(req, ev);
941 tevent_req_set_callback(subreq, dcerpc_do_bind_sec_next, req);
946 state->sec_status = NT_STATUS_OK;
948 subreq = tevent_queue_wait_send(state, state->ev,
949 state->conn->calls.out_queue);
950 if (tevent_req_nomem(subreq, req)) {
951 return tevent_req_post(req, ev);
953 tevent_req_set_callback(subreq, dcerpc_do_bind_out_frag_next, req);
958 static void dcerpc_do_bind_cleanup(struct tevent_req *req,
959 enum tevent_req_state req_state)
961 struct dcerpc_do_bind_state *state =
963 struct dcerpc_do_bind_state);
965 if (state->out_frag != NULL) {
966 state->out_frag->req = NULL;
967 state->out_frag = NULL;
970 if (state->call != NULL) {
971 ZERO_STRUCT(state->call->incoming);
972 DLIST_REMOVE(state->conn->calls.list, state->call);
977 static void dcerpc_do_bind_sec_next(struct tevent_req *subreq)
979 struct tevent_req *req =
980 tevent_req_callback_data(subreq,
982 struct dcerpc_do_bind_state *state =
984 struct dcerpc_do_bind_state);
987 data_blob_free(&state->sec_out);
988 status = gensec_update_recv(subreq, state, &state->sec_out);
990 data_blob_free(&state->sec_in);
991 state->sec_status = status;
992 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
993 status = NT_STATUS_OK;
995 if (!NT_STATUS_IS_OK(status)) {
996 tevent_req_nterror(req, status);
1000 if (NT_STATUS_IS_OK(state->sec_status) &&
1001 state->sec_out.length == 0)
1003 tevent_req_done(req);
1007 subreq = tevent_queue_wait_send(state, state->ev,
1008 state->conn->calls.out_queue);
1009 if (tevent_req_nomem(subreq, req)) {
1012 tevent_req_set_callback(subreq, dcerpc_do_bind_out_frag_next, req);
1015 static void dcerpc_do_bind_out_frag_trans_wait1(struct tevent_req *subreq);
1016 static void dcerpc_do_bind_out_frag_done(struct tevent_req *subreq);
1017 static void dcerpc_do_bind_out_frag_trans_wait2(struct tevent_req *subreq);
1019 static void dcerpc_do_bind_out_frag_next(struct tevent_req *subreq)
1021 struct tevent_req *req =
1022 tevent_req_callback_data(subreq,
1024 struct dcerpc_do_bind_state *state =
1025 tevent_req_data(req,
1026 struct dcerpc_do_bind_state);
1027 struct dcerpc_do_bind_out_frag *frag;
1028 size_t auth_len = 0;
1030 DATA_BLOB auth_info = data_blob_null;
1031 union dcerpc_payload u;
1033 bool use_trans = true;
1036 ok = tevent_queue_wait_recv(subreq);
1040 TALLOC_FREE(subreq);
1043 * the fragment belongs to the connection instead of the request
1044 * because it has to remain in case the request is canceled
1046 frag = talloc_zero(state->conn, struct dcerpc_do_bind_out_frag);
1047 if (tevent_req_nomem(frag, req)) {
1050 frag->ev = state->ev;
1051 frag->conn = state->conn;
1053 state->out_frag = frag;
1055 if (!state->conn->features.bind_done) {
1056 frag->ptype = DCERPC_PKT_BIND;
1057 } else if (state->remaining_pres > 0) {
1058 frag->ptype = DCERPC_PKT_ALTER;
1059 } else if (!NT_STATUS_IS_OK(state->sec_status)) {
1060 frag->ptype = DCERPC_PKT_ALTER;
1061 } else if (state->sec_out.length > 0) {
1062 frag->ptype = DCERPC_PKT_AUTH3;
1066 status = dcerpc_auth_blob(frag,
1067 state->sec->auth_type,
1068 state->sec->auth_level,
1069 0, /* auth_pad_length */
1070 state->sec->context_id, /* auth_context_id */
1073 if (!NT_STATUS_IS_OK(status)) {
1074 tevent_req_nterror(req, status);
1078 auth_len = auth_info.length;
1081 auth_len -= DCERPC_AUTH_TRAILER_LENGTH;
1085 state->num_ctx = state->num_pres;
1086 if (!state->conn->assoc->negotiate_done) {
1087 state->num_ctx += 1;
1090 state->ctx_list = talloc_zero_array(frag,
1091 struct dcerpc_ctx_list,
1093 if (tevent_req_nomem(state->ctx_list, req)) {
1097 for (i=0; i < state->num_pres; i++) {
1098 state->ctx_list[i] = state->pres[i]->negotiate.req;
1101 if (!state->conn->assoc->negotiate_done) {
1102 state->features = dcerpc_construct_bind_time_features(
1103 state->conn->assoc->client_features);
1105 state->ctx_list[i].context_id = state->conn->next_pres_context_id;
1107 state->ctx_list[i].abstract_syntax =
1108 state->ctx_list[i-1].abstract_syntax;
1110 state->ctx_list[i].num_transfer_syntaxes = 1;
1111 state->ctx_list[i].transfer_syntaxes = &state->features;
1114 switch (frag->ptype) {
1115 case DCERPC_PKT_BIND:
1116 case DCERPC_PKT_ALTER:
1117 u.bind.max_xmit_frag = state->conn->features.max_xmit_frag;
1118 u.bind.max_recv_frag = state->conn->features.max_recv_frag;
1119 u.bind.assoc_group_id = state->conn->assoc->assoc_group_id;
1120 u.bind.num_contexts = state->num_ctx;
1121 u.bind.ctx_list = state->ctx_list;
1122 u.bind.auth_info = auth_info;
1125 case DCERPC_PKT_AUTH3:
1127 u.auth3.auth_info = auth_info;
1130 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1134 status = dcerpc_ncacn_packet_blob(frag,
1136 DCERPC_PFC_FLAG_FIRST |
1137 DCERPC_PFC_FLAG_LAST,
1139 state->call->call_id,
1142 if (!NT_STATUS_IS_OK(status)) {
1143 DEBUG(0, ("Failed to marshall bind/alter ncacn_packet.\n"));
1144 tevent_req_nterror(req, status);
1148 if (frag->ptype == DCERPC_PKT_AUTH3) {
1152 if (frag->conn->transport.use_trans_fn == NULL) {
1156 if (frag->conn->loop.subreq != NULL) {
1160 if (frag->conn->features.concurrent_multiplex) {
1164 if (tevent_queue_length(frag->conn->calls.out_queue) > 1) {
1169 frag->subreq_wait1 = tevent_queue_wait_send(frag,
1171 frag->conn->transport.write_queue);
1172 if (tevent_req_nomem(req, frag->subreq_wait1)) {
1175 tevent_req_set_callback(frag->subreq_wait1,
1176 dcerpc_do_bind_out_frag_trans_wait1,
1179 * we need to block reads until our write is
1180 * the next in the write queue.
1182 frag->conn->loop.subreq = frag->subreq_wait1;
1183 frag->conn->loop.ev = frag->ev;
1187 * We need to add a dcerpc_write_fragment_queue_send/recv()
1190 frag->vector.iov_base = frag->blob.data;
1191 frag->vector.iov_len = frag->blob.length;
1192 subreq = tstream_writev_queue_send(frag, frag->ev,
1193 frag->conn->transport.stream,
1194 frag->conn->transport.write_queue,
1196 if (tevent_req_nomem(subreq, req)) {
1199 tevent_req_set_callback(subreq,
1200 dcerpc_do_bind_out_frag_done,
1204 frag->subreq_wait2 = tevent_queue_wait_send(frag,
1206 frag->conn->transport.write_queue);
1207 if (tevent_req_nomem(req, frag->subreq_wait2)) {
1210 tevent_req_set_callback(frag->subreq_wait2,
1211 dcerpc_do_bind_out_frag_trans_wait2,
1215 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1216 if (tevent_req_nterror(req, status)) {
1221 static void dcerpc_do_bind_out_frag_trans_wait1(struct tevent_req *subreq)
1223 struct dcerpc_do_bind_out_frag *frag =
1224 tevent_req_callback_data(subreq,
1225 struct dcerpc_do_bind_out_frag);
1226 struct tevent_req *req = frag->req;
1231 * TODO; what if the caller has been free'ed?
1234 frag->subreq_wait1 = NULL;
1235 frag->conn->loop.subreq = NULL;
1237 ok = tevent_queue_wait_recv(subreq);
1239 status = NT_STATUS_INTERNAL_ERROR;
1242 tevent_req_nterror(req, status);
1244 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1248 if (tevent_queue_length(frag->conn->transport.write_queue) > 3) {
1250 * We added 3 entries into the queue,
1251 * wait1, writev and wait2.
1253 * There's more to write, we should not block
1254 * further writev calls for a trans call.
1256 * The wait2 stage will trigger the read.
1258 TALLOC_FREE(subreq);
1263 * we don't need wait2 anymore, we're sure that
1264 * we'll do a trans call.
1266 TALLOC_FREE(frag->subreq_wait2);
1268 status = frag->conn->transport.use_trans_fn(frag->conn->transport.stream);
1269 if (!NT_STATUS_IS_OK(status)) {
1272 tevent_req_nterror(req, status);
1274 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1278 /* we free subreq after tstream_cli_np_use_trans */
1279 TALLOC_FREE(subreq);
1281 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1282 if (!NT_STATUS_IS_OK(status)) {
1285 tevent_req_nterror(req, status);
1287 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1292 static void dcerpc_do_bind_out_frag_done(struct tevent_req *subreq)
1294 struct dcerpc_do_bind_out_frag *frag =
1295 tevent_req_callback_data(subreq,
1296 struct dcerpc_do_bind_out_frag);
1297 struct tevent_req *req = frag->req;
1303 * If the caller has been free'ed, we have should
1304 * ignore any errors and just free 'frag'
1307 struct dcerpc_do_bind_state *state =
1308 tevent_req_data(req,
1309 struct dcerpc_do_bind_state);
1311 state->out_frag = NULL;
1314 ret = tstream_writev_queue_recv(subreq, &sys_errno);
1315 TALLOC_FREE(subreq);
1318 status = map_nt_error_from_unix_common(sys_errno);
1320 tevent_req_nterror(req, status);
1325 if (frag->ptype == DCERPC_PKT_AUTH3) {
1330 tevent_req_done(req);
1334 if (frag->subreq_wait2 != NULL) {
1340 /* we need to wait for incoming pdus */
1343 static void dcerpc_do_bind_out_frag_trans_wait2(struct tevent_req *subreq)
1345 struct dcerpc_do_bind_out_frag *frag =
1346 tevent_req_callback_data(subreq,
1347 struct dcerpc_do_bind_out_frag);
1348 struct tevent_req *req = frag->req;
1352 frag->subreq_wait2 = NULL;
1354 ok = tevent_queue_wait_recv(subreq);
1356 status = NT_STATUS_INTERNAL_ERROR;
1359 tevent_req_nterror(req, status);
1361 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1365 TALLOC_FREE(subreq);
1367 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1368 if (!NT_STATUS_IS_OK(status)) {
1371 tevent_req_nterror(req, status);
1373 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1379 /* we need to wait for incoming pdus */
1382 static NTSTATUS dcerpc_do_bind_handle_in_frag(void *private_data,
1383 struct ncacn_packet *pkt,
1386 struct tevent_req *req =
1387 talloc_get_type_abort(private_data,
1389 struct dcerpc_do_bind_state *state =
1390 tevent_req_data(req,
1391 struct dcerpc_do_bind_state);
1395 /* Ensure we have the correct type. */
1396 switch (pkt->ptype) {
1397 case DCERPC_PKT_BIND_ACK:
1398 case DCERPC_PKT_ALTER_RESP:
1399 if (pkt->auth_length != 0) {
1400 // return NT_STATUS_NOT_IMPLEMENTED;
1403 if (!state->conn->features.bind_done) {
1404 if (pkt->u.bind_ack.max_recv_frag < 1234) {
1405 return NT_STATUS_RPC_PROTOCOL_ERROR;
1407 if (pkt->u.bind_ack.max_xmit_frag < 1234) {
1408 return NT_STATUS_RPC_PROTOCOL_ERROR;
1410 state->conn->features.max_recv_frag =
1411 pkt->u.bind_ack.max_recv_frag;
1412 state->conn->features.max_xmit_frag =
1413 pkt->u.bind_ack.max_xmit_frag;
1415 if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1416 state->conn->features.concurrent_multiplex = true;
1419 state->conn->features.bind_done = true;
1422 if (!state->conn->assoc->negotiate_done) {
1423 state->conn->assoc->negotiate_done = true;
1424 state->conn->assoc->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1427 if (pkt->u.bind_ack.assoc_group_id != state->conn->assoc->assoc_group_id) {
1428 return NT_STATUS_RPC_PROTOCOL_ERROR;
1431 if (pkt->u.bind_ack.num_results > state->num_ctx) {
1432 return NT_STATUS_RPC_PROTOCOL_ERROR;
1435 for (i = 0; i < pkt->u.bind_ack.num_results; i++) {
1436 struct dcerpc_ack_ctx *ack = &pkt->u.bind_ack.ctx_list[i];
1438 if (i < state->num_pres) {
1439 state->pres[i]->negotiate.ack = *ack;
1443 if (ack->result != DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1447 state->conn->assoc->features = state->conn->assoc->client_features;
1448 state->conn->assoc->features &= ack->reason.negotiate;
1451 for (i = 0; i < state->num_pres; i++) {
1452 struct dcerpc_ack_ctx *ack = &state->pres[i]->negotiate.ack;
1455 if (ack->result != DCERPC_BIND_ACK_RESULT_ACCEPTANCE) {
1459 ok = ndr_syntax_id_equal(&state->pres[i]->transfer,
1462 return NT_STATUS_RPC_PROTOCOL_ERROR;
1466 if (pkt->auth_length >= 8) {
1467 struct tevent_req *subreq;
1469 state->sec_in = data_blob_talloc(state,
1470 pkt->u.bind_ack.auth_info.data + 8,
1471 pkt->u.bind_ack.auth_info.length - 8);
1473 subreq = gensec_update_send(state, state->ev,
1476 if (tevent_req_nomem(subreq, req)) {
1477 return NT_STATUS_OK;
1479 tevent_req_set_callback(subreq, dcerpc_do_bind_sec_next, req);
1480 return NT_STATUS_OK;
1483 tevent_req_done(req);
1484 return NT_STATUS_OK;
1486 //case DCERPC_PKT_ALTER_RESP:
1487 if (pkt->auth_length != 0) {
1488 return NT_STATUS_NOT_IMPLEMENTED;
1491 return NT_STATUS_NOT_IMPLEMENTED;
1494 /* Point the return values at the NDR data. */
1495 payload.data = frag.data + DCERPC_RESPONSE_LENGTH;
1497 if (pkt->auth_length) {
1498 /* We've already done integer wrap tests in
1499 * dcerpc_check_auth(). */
1500 payload.length = frag.length
1501 - DCERPC_RESPONSE_LENGTH
1503 - DCERPC_AUTH_TRAILER_LENGTH
1506 payload.length = frag.length - DCERPC_RESPONSE_LENGTH;
1509 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
1510 if (pkt->drep[0] & DCERPC_DREP_LE) {
1511 state->response.bigendian = false;
1513 state->response.bigendian = true;
1517 DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
1518 (long unsigned int)frag.length,
1519 (long unsigned int)payload.length,
1520 (unsigned int)pad_len));
1523 * If this is the first reply, and the allocation hint is
1524 * reasonable, try and set up the reply_pdu DATA_BLOB to the
1528 if ((state->response.blob.length == 0) &&
1529 pkt->u.response.alloc_hint &&
1530 (pkt->u.response.alloc_hint < 15*1024*1024)) {
1531 ok = data_blob_realloc(state, &state->response.blob,
1532 pkt->u.response.alloc_hint);
1534 DEBUG(0, ("reply alloc hint %d too "
1535 "large to allocate\n",
1536 (int)pkt->u.response.alloc_hint));
1537 return NT_STATUS_NO_MEMORY;
1541 new_total = state->response.ofs + payload.length;
1543 if (new_total > 15 * 1024 *1024) {
1544 return NT_STATUS_RPC_PROTOCOL_ERROR;//TODO
1547 missing = new_total - state->response.blob.length;
1550 ok = data_blob_realloc(state, &state->response.blob,
1553 DEBUG(0, ("reply alloc hint %d too "
1554 "large to allocate\n",
1555 (int)pkt->u.response.alloc_hint));
1556 return NT_STATUS_NO_MEMORY;
1560 memcpy(state->response.blob.data + state->response.ofs,
1561 payload.data, payload.length);
1562 state->response.ofs += payload.length;
1564 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
1565 tevent_req_done(req);//TODO
1566 return NT_STATUS_OK;
1568 return NT_STATUS_OK;
1570 return NT_STATUS_NOT_IMPLEMENTED;
1572 case DCERPC_PKT_FAULT:
1574 DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault "
1575 "code %s received from %s!\n",
1576 dcerpc_errstr(talloc_tos(),
1577 pkt->u.fault.status),
1580 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1581 if (NT_STATUS_IS_OK(status)) {
1582 status = NT_STATUS_RPC_PROTOCOL_ERROR;
1585 tevent_req_nterror(req, status);//TODO
1586 return NT_STATUS_OK;
1588 DEBUG(0, ("Unknown packet type %u received from %s!\n",
1589 (unsigned int)pkt->ptype,
1591 return NT_STATUS_RPC_PROTOCOL_ERROR;
1594 return NT_STATUS_RPC_PROTOCOL_ERROR;
1597 NTSTATUS dcerpc_do_bind_recv(struct tevent_req *req)
1599 struct dcerpc_do_bind_state *state =
1600 tevent_req_data(req,
1601 struct dcerpc_do_bind_state);
1604 if (tevent_req_is_nterror(req, &status)) {
1605 tevent_req_received(req);
1609 if (!NT_STATUS_IS_OK(state->sec_status)) {
1610 status = state->sec_status;
1611 tevent_req_received(req);
1615 tevent_req_received(req);
1616 return NT_STATUS_OK;
1619 struct dcerpc_do_request_out_frag;
1621 struct dcerpc_do_request_state {
1622 struct tevent_context *ev;
1623 struct dcerpc_connection *conn;
1624 struct dcerpc_call *call;
1625 const struct GUID *object;
1628 const DATA_BLOB *blob;
1632 struct dcerpc_do_request_out_frag *out_frag;
1640 struct dcerpc_do_request_out_frag {
1641 struct tevent_context *ev;
1642 struct dcerpc_connection *conn;
1643 struct tevent_req *req;
1646 struct iovec vector;
1647 struct tevent_req *subreq_wait1;
1648 struct tevent_req *subreq_wait2;
1651 static void dcerpc_do_request_cleanup(struct tevent_req *req,
1652 enum tevent_req_state req_state);
1654 static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
1655 void *private_data);
1657 static NTSTATUS dcerpc_do_request_handle_in_frag(void *private_data,
1658 struct ncacn_packet *pkt,
1661 struct tevent_req *dcerpc_do_request_send(TALLOC_CTX *mem_ctx,
1662 struct tevent_context *ev,
1663 struct dcerpc_connection *conn,
1664 struct dcerpc_call *call,
1665 const struct GUID *object,
1667 const DATA_BLOB *request,
1670 struct tevent_req *req;
1671 struct dcerpc_do_request_state *state;
1674 req = tevent_req_create(mem_ctx, &state,
1675 struct dcerpc_do_request_state);
1682 state->object = object;
1683 state->opnum = opnum;
1684 state->request.blob = request;
1685 state->request.bigendian = bigendian;
1687 state->call->incoming.private_data = req;
1688 state->call->incoming.handler = dcerpc_do_request_handle_in_frag;
1689 DLIST_ADD_END(state->conn->calls.list, state->call, NULL);
1691 tevent_req_set_cleanup_fn(req, dcerpc_do_request_cleanup);
1692 tevent_req_defer_callback(req, ev);
1694 ok = tevent_queue_add(state->conn->calls.out_queue,
1697 dcerpc_do_request_out_frag_next,
1700 tevent_req_nomem(NULL, req);
1701 return tevent_req_post(req, ev);
1707 static void dcerpc_do_request_cleanup(struct tevent_req *req,
1708 enum tevent_req_state req_state)
1710 struct dcerpc_do_request_state *state =
1711 tevent_req_data(req,
1712 struct dcerpc_do_request_state);
1714 if (state->out_frag != NULL) {
1715 state->out_frag->req = NULL;
1716 state->out_frag = NULL;
1719 if (state->call != NULL) {
1720 ZERO_STRUCT(state->call->incoming);
1721 DLIST_REMOVE(state->conn->calls.list, state->call);
1726 static void dcerpc_do_request_out_frag_trans_wait1(struct tevent_req *subreq);
1727 static void dcerpc_do_request_out_frag_done(struct tevent_req *subreq);
1728 static void dcerpc_do_request_out_frag_trans_wait2(struct tevent_req *subreq);
1730 static void dcerpc_do_request_out_frag_next(struct tevent_req *req,
1733 struct dcerpc_do_request_state *state =
1734 tevent_req_data(req,
1735 struct dcerpc_do_request_state);
1736 struct dcerpc_do_request_out_frag *frag;
1737 size_t data_sent_thistime;
1738 size_t hdr_len = DCERPC_REQUEST_LENGTH;
1745 union dcerpc_payload u;
1748 struct tevent_req *subreq;
1749 bool use_trans = true;
1751 if (state->object) {
1752 flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1757 * the fragment belongs to the connection instead of the request
1758 * because it has to remain in case the request is canceled
1760 frag = talloc_zero(state->conn, struct dcerpc_do_request_out_frag);
1761 if (tevent_req_nomem(frag, req)) {
1764 frag->ev = state->ev;
1765 frag->conn = state->conn;
1767 state->out_frag = frag;
1769 data_left = state->request.blob->length - state->request.ofs;
1771 status = dcerpc_guess_pdu_sizes(state->call->sec,
1773 state->conn->features.max_xmit_frag,
1775 &data_sent_thistime,
1776 &frag_len, &auth_len, &pad_len);
1777 if (!NT_STATUS_IS_OK(status)) {
1778 tevent_req_nterror(req, status);
1782 if (state->request.ofs == 0) {
1783 flags |= DCERPC_PFC_FLAG_FIRST;
1786 payload.data = state->request.blob->data + state->request.ofs;
1787 payload.length = data_sent_thistime;
1789 state->request.ofs += data_sent_thistime;
1791 if (state->request.blob->length == state->request.ofs) {
1792 flags |= DCERPC_PFC_FLAG_LAST;
1795 ZERO_STRUCT(u.request);
1797 u.request.alloc_hint = state->request.blob->length -
1799 u.request.context_id = state->call->pres->context_id;
1800 u.request.opnum = state->opnum;
1801 if (state->object) {
1802 u.request.object.object = *state->object;
1804 //TODO pass state->request.bigendian
1805 status = dcerpc_ncacn_packet_blob(frag,
1809 state->call->call_id,
1812 if (!NT_STATUS_IS_OK(status)) {
1813 tevent_req_nterror(req, status);
1817 /* explicitly set frag_len here as dcerpc_push_ncacn_packet() can't
1818 * compute it right for requests because the auth trailer is missing
1820 dcerpc_set_frag_length(&frag->blob, frag_len);
1822 /* Copy in the data. */
1823 ok = data_blob_append(frag, &frag->blob,
1824 payload.data, payload.length);
1826 tevent_req_nomem(NULL, req);
1830 switch (state->call->sec->auth_level) {
1831 case DCERPC_AUTH_LEVEL_NONE:
1832 case DCERPC_AUTH_LEVEL_CONNECT:
1833 case DCERPC_AUTH_LEVEL_PACKET:
1835 case DCERPC_AUTH_LEVEL_INTEGRITY:
1836 case DCERPC_AUTH_LEVEL_PRIVACY:
1837 status = dcerpc_response_auth_blob(state->call->sec,
1840 if (!NT_STATUS_IS_OK(status)) {
1841 tevent_req_nterror(req, status);
1846 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1850 frag->is_last = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
1852 if (!frag->is_last) {
1856 if (frag->conn->transport.use_trans_fn == NULL) {
1860 if (frag->conn->loop.subreq != NULL) {
1864 if (frag->conn->features.concurrent_multiplex) {
1868 if (tevent_queue_length(frag->conn->calls.out_queue) > 1) {
1873 frag->subreq_wait1 = tevent_queue_wait_send(frag,
1875 frag->conn->transport.write_queue);
1876 if (tevent_req_nomem(req, frag->subreq_wait1)) {
1879 tevent_req_set_callback(frag->subreq_wait1,
1880 dcerpc_do_request_out_frag_trans_wait1,
1883 * we need to block reads until our write is
1884 * the next in the write queue.
1886 frag->conn->loop.subreq = frag->subreq_wait1;
1887 frag->conn->loop.ev = frag->ev;
1891 * We need to add a dcerpc_write_fragment_queue_send/recv()
1894 frag->vector.iov_base = frag->blob.data;
1895 frag->vector.iov_len = frag->blob.length;
1896 subreq = tstream_writev_queue_send(frag, frag->ev,
1897 frag->conn->transport.stream,
1898 frag->conn->transport.write_queue,
1900 if (tevent_req_nomem(subreq, req)) {
1903 tevent_req_set_callback(subreq,
1904 dcerpc_do_request_out_frag_done,
1908 frag->subreq_wait2 = tevent_queue_wait_send(frag,
1910 frag->conn->transport.write_queue);
1911 if (tevent_req_nomem(req, frag->subreq_wait2)) {
1914 tevent_req_set_callback(frag->subreq_wait2,
1915 dcerpc_do_request_out_frag_trans_wait2,
1919 if (!frag->is_last) {
1923 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1924 if (tevent_req_nterror(req, status)) {
1929 static void dcerpc_do_request_out_frag_trans_wait1(struct tevent_req *subreq)
1931 struct dcerpc_do_request_out_frag *frag =
1932 tevent_req_callback_data(subreq,
1933 struct dcerpc_do_request_out_frag);
1934 struct tevent_req *req = frag->req;
1939 * TODO; what if the caller has been free'ed?
1942 frag->subreq_wait1 = NULL;
1943 frag->conn->loop.subreq = NULL;
1945 ok = tevent_queue_wait_recv(subreq);
1947 status = NT_STATUS_INTERNAL_ERROR;
1950 tevent_req_nterror(req, status);
1952 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1956 if (tevent_queue_length(frag->conn->transport.write_queue) > 3) {
1958 * We added 3 entries into the queue,
1959 * wait1, writev and wait2.
1961 * There's more to write, we should not block
1962 * further writev calls for a trans call.
1964 * The wait2 stage will trigger the read.
1966 TALLOC_FREE(subreq);
1971 * we don't need wait2 anymore, we're sure that
1972 * we'll do a trans call.
1974 TALLOC_FREE(frag->subreq_wait2);
1976 status = frag->conn->transport.use_trans_fn(frag->conn->transport.stream);
1977 if (!NT_STATUS_IS_OK(status)) {
1980 tevent_req_nterror(req, status);
1982 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
1986 /* we free subreq after tstream_cli_np_use_trans */
1987 TALLOC_FREE(subreq);
1989 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
1990 if (!NT_STATUS_IS_OK(status)) {
1993 tevent_req_nterror(req, status);
1995 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2000 static void dcerpc_do_request_out_frag_done(struct tevent_req *subreq)
2002 struct dcerpc_do_request_out_frag *frag =
2003 tevent_req_callback_data(subreq,
2004 struct dcerpc_do_request_out_frag);
2005 struct tevent_req *req = frag->req;
2011 * If the caller has been free'ed, we have should
2012 * ignore any errors and just free 'frag'
2015 struct dcerpc_do_request_state *state =
2016 tevent_req_data(req,
2017 struct dcerpc_do_request_state);
2019 state->out_frag = NULL;
2022 ret = tstream_writev_queue_recv(subreq, &sys_errno);
2023 TALLOC_FREE(subreq);
2026 status = map_nt_error_from_unix_common(sys_errno);
2028 tevent_req_nterror(req, status);
2033 if (frag->subreq_wait2 != NULL) {
2037 if (frag->is_last) {
2047 dcerpc_do_request_out_frag_next(req, NULL);
2050 static void dcerpc_do_request_out_frag_trans_wait2(struct tevent_req *subreq)
2052 struct dcerpc_do_request_out_frag *frag =
2053 tevent_req_callback_data(subreq,
2054 struct dcerpc_do_request_out_frag);
2055 struct tevent_req *req = frag->req;
2059 frag->subreq_wait2 = NULL;
2061 ok = tevent_queue_wait_recv(subreq);
2063 status = NT_STATUS_INTERNAL_ERROR;
2066 tevent_req_nterror(req, status);
2068 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2072 TALLOC_FREE(subreq);
2074 status = dcerpc_connection_loop_restart(frag->conn, frag->ev);
2075 if (!NT_STATUS_IS_OK(status)) {
2078 tevent_req_nterror(req, status);
2080 //dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2086 /* we need to wait for incoming pdus */
2089 static NTSTATUS dcerpc_do_request_handle_in_frag(void *private_data,
2090 struct ncacn_packet *pkt,
2093 struct tevent_req *req =
2094 talloc_get_type_abort(private_data,
2096 struct dcerpc_do_request_state *state =
2097 tevent_req_data(req,
2098 struct dcerpc_do_request_state);
2107 /* Ensure we have the correct type. */
2108 switch (pkt->ptype) {
2109 case DCERPC_PKT_RESPONSE:
2111 /* Here's where we deal with incoming sign/seal. */
2112 error = dcerpc_check_pdu_auth(state->call->sec,
2114 &pkt->u.response.stub_and_verifier,
2115 DCERPC_RESPONSE_LENGTH,
2117 if (!NT_STATUS_IS_OK(error)) {
2121 if (frag.length < DCERPC_RESPONSE_LENGTH + pad_len) {
2122 return NT_STATUS_RPC_PROTOCOL_ERROR;
2125 /* Point the return values at the NDR data. */
2126 payload.data = frag.data + DCERPC_RESPONSE_LENGTH;
2128 if (pkt->auth_length) {
2129 /* We've already done integer wrap tests in
2130 * dcerpc_check_auth(). */
2131 payload.length = frag.length
2132 - DCERPC_RESPONSE_LENGTH
2134 - DCERPC_AUTH_TRAILER_LENGTH
2137 payload.length = frag.length - DCERPC_RESPONSE_LENGTH;
2140 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
2141 if (pkt->drep[0] & DCERPC_DREP_LE) {
2142 state->response.bigendian = false;
2144 state->response.bigendian = true;
2148 DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
2149 (long unsigned int)frag.length,
2150 (long unsigned int)payload.length,
2151 (unsigned int)pad_len));
2154 * If this is the first reply, and the allocation hint is
2155 * reasonable, try and set up the reply_pdu DATA_BLOB to the
2159 if ((state->response.blob.length == 0) &&
2160 pkt->u.response.alloc_hint &&
2161 (pkt->u.response.alloc_hint < 15*1024*1024)) {
2162 ok = data_blob_realloc(state, &state->response.blob,
2163 pkt->u.response.alloc_hint);
2165 DEBUG(0, ("reply alloc hint %d too "
2166 "large to allocate\n",
2167 (int)pkt->u.response.alloc_hint));
2168 return NT_STATUS_NO_MEMORY;
2172 new_total = state->response.ofs + payload.length;
2174 if (new_total > 15 * 1024 *1024) {
2175 return NT_STATUS_RPC_PROTOCOL_ERROR;//TODO
2178 missing = new_total - state->response.blob.length;
2181 ok = data_blob_realloc(state, &state->response.blob,
2184 DEBUG(0, ("reply alloc hint %d too "
2185 "large to allocate\n",
2186 (int)pkt->u.response.alloc_hint));
2187 return NT_STATUS_NO_MEMORY;
2191 memcpy(state->response.blob.data + state->response.ofs,
2192 payload.data, payload.length);
2193 state->response.ofs += payload.length;
2195 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
2196 tevent_req_done(req);//TODO
2197 return NT_STATUS_OK;
2199 return NT_STATUS_OK;
2201 case DCERPC_PKT_FAULT:
2203 DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault "
2204 "code %s received from %s!\n",
2205 dcerpc_errstr(talloc_tos(),
2206 pkt->u.fault.status),
2209 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2210 if (NT_STATUS_IS_OK(status)) {
2211 status = NT_STATUS_RPC_PROTOCOL_ERROR;
2214 tevent_req_nterror(req, status);//TODO
2215 return NT_STATUS_OK;
2217 DEBUG(0, ("Unknown packet type %u received from %s!\n",
2218 (unsigned int)pkt->ptype,
2220 return NT_STATUS_RPC_PROTOCOL_ERROR;
2224 NTSTATUS dcerpc_do_request_recv(struct tevent_req *req,
2225 TALLOC_CTX *mem_ctx,
2226 DATA_BLOB *response,
2229 struct dcerpc_do_request_state *state =
2230 tevent_req_data(req,
2231 struct dcerpc_do_request_state);
2234 if (tevent_req_is_nterror(req, &status)) {
2235 tevent_req_received(req);
2239 /* return data to caller and assign it ownership of memory */
2240 response->data = talloc_move(mem_ctx, &state->response.blob.data);
2241 response->length = state->response.blob.length;
2242 *bigendian = state->response.bigendian;
2244 tevent_req_received(req);
2245 return NT_STATUS_OK;