20#include <freerdp/config.h>
22#include <freerdp/log.h>
25#include <winpr/wtypes.h>
26#include <winpr/assert.h>
27#include <winpr/cast.h>
28#include <winpr/print.h>
29#include <winpr/synch.h>
30#include <winpr/thread.h>
31#include <winpr/stream.h>
34#include "ncacn_http.h"
38#include "rpc_client.h"
39#include "rts_signature.h"
45#define TAG FREERDP_TAG("core.gateway.rpc")
48static const char* rpc_client_state_str(RPC_CLIENT_STATE state)
51 const char* str =
"RPC_CLIENT_STATE_UNKNOWN";
55 case RPC_CLIENT_STATE_INITIAL:
56 str =
"RPC_CLIENT_STATE_INITIAL";
59 case RPC_CLIENT_STATE_ESTABLISHED:
60 str =
"RPC_CLIENT_STATE_ESTABLISHED";
63 case RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK:
64 str =
"RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK";
67 case RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK:
68 str =
"RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK";
71 case RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE:
72 str =
"RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE";
75 case RPC_CLIENT_STATE_CONTEXT_NEGOTIATED:
76 str =
"RPC_CLIENT_STATE_CONTEXT_NEGOTIATED";
79 case RPC_CLIENT_STATE_WAIT_RESPONSE:
80 str =
"RPC_CLIENT_STATE_WAIT_RESPONSE";
83 case RPC_CLIENT_STATE_FINAL:
84 str =
"RPC_CLIENT_STATE_FINAL";
93static BOOL rpc_pdu_reset(
RPC_PDU* pdu)
99 Stream_ResetPosition(pdu->s);
100 return Stream_SetLength(pdu->s, 0);
103static void rpc_pdu_free(
RPC_PDU* pdu)
108 Stream_Free(pdu->s, TRUE);
112WINPR_ATTR_MALLOC(rpc_pdu_free, 1)
113static
RPC_PDU* rpc_pdu_new(
void)
120 pdu->s = Stream_New(
nullptr, 4096);
125 if (!rpc_pdu_reset(pdu))
136static int rpc_client_receive_pipe_write(
RpcClient* client,
const BYTE* buffer,
size_t length)
140 if (!client || !buffer)
143 EnterCriticalSection(&(client->PipeLock));
145 if (ringbuffer_write(&(client->ReceivePipe), buffer, length))
146 status += (int)length;
148 if (ringbuffer_used(&(client->ReceivePipe)) > 0)
149 (
void)SetEvent(client->PipeEvent);
151 LeaveCriticalSection(&(client->PipeLock));
155int rpc_client_receive_pipe_read(
RpcClient* client, BYTE* buffer,
size_t length)
161 if (!client || !buffer)
164 EnterCriticalSection(&(client->PipeLock));
165 nchunks = ringbuffer_peek(&(client->ReceivePipe), chunks, length);
167 for (
int index = 0; index < nchunks; index++)
169 CopyMemory(&buffer[status], chunks[index].data, chunks[index].size);
170 status += chunks[index].size;
174 ringbuffer_commit_read_bytes(&(client->ReceivePipe), status);
176 if (ringbuffer_used(&(client->ReceivePipe)) < 1)
177 (void)ResetEvent(client->PipeEvent);
179 LeaveCriticalSection(&(client->PipeLock));
181 if (status > INT_MAX)
186static int rpc_client_transition_to_state(rdpRpc* rpc, RPC_CLIENT_STATE state)
192 WLog_Print(rpc->log, WLOG_DEBUG,
"%s", rpc_client_state_str(state));
197static int rpc_client_recv_pdu_int(rdpRpc* rpc,
RPC_PDU* pdu)
205 rdpTsg* tsg = transport_get_tsg(rpc->transport);
207 WLog_Print(rpc->log, WLOG_TRACE,
"client state %s, vc state %s",
208 rpc_client_state_str(rpc->State), rpc_vc_state_str(rpc->VirtualConnection->State));
211 rts_match_pdu_signature_ex(&RTS_PDU_PING_SIGNATURE, pdu->s,
nullptr, &found, TRUE);
212 rts_print_pdu_signature(rpc->log, WLOG_TRACE, &found);
214 return rts_recv_ping_pdu(rpc, pdu->s);
216 if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
218 switch (rpc->VirtualConnection->State)
220 case VIRTUAL_CONNECTION_STATE_INITIAL:
223 case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
226 case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
227 if (memcmp(&found, &RTS_PDU_CONN_A3_SIGNATURE,
sizeof(found)) != 0)
229 WLog_Print(rpc->log, WLOG_ERROR,
"unexpected RTS PDU: Expected CONN/A3");
230 rts_print_pdu_signature(rpc->log, WLOG_ERROR, &found);
234 if (!rts_recv_CONN_A3_pdu(rpc, pdu->s))
236 WLog_Print(rpc->log, WLOG_ERROR,
"rts_recv_CONN_A3_pdu failure");
240 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
241 VIRTUAL_CONNECTION_STATE_WAIT_C2);
245 case VIRTUAL_CONNECTION_STATE_WAIT_C2:
246 if (memcmp(&found, &RTS_PDU_CONN_C2_SIGNATURE,
sizeof(found)) != 0)
248 WLog_Print(rpc->log, WLOG_ERROR,
"unexpected RTS PDU: Expected CONN/C2");
249 rts_print_pdu_signature(rpc->log, WLOG_ERROR, &found);
253 if (!rts_recv_CONN_C2_pdu(rpc, pdu->s))
255 WLog_Print(rpc->log, WLOG_ERROR,
"rts_recv_CONN_C2_pdu failure");
259 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
260 VIRTUAL_CONNECTION_STATE_OPENED);
261 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_ESTABLISHED);
263 if (rpc_send_bind_pdu(rpc, TRUE) < 0)
265 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_send_bind_pdu failure");
269 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK);
273 case VIRTUAL_CONNECTION_STATE_OPENED:
276 case VIRTUAL_CONNECTION_STATE_FINAL:
282 else if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
284 if (rpc->State == RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK)
286 if (pdu->Type == PTYPE_BIND_ACK || pdu->Type == PTYPE_ALTER_CONTEXT_RESP)
288 if (!rpc_recv_bind_ack_pdu(rpc, pdu->s))
290 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_recv_bind_ack_pdu failure");
296 WLog_Print(rpc->log, WLOG_ERROR,
297 "RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK unexpected pdu type: 0x%08" PRIX32
303 switch (rpc_bind_state(rpc))
305 case RPC_BIND_STATE_INCOMPLETE:
306 if (rpc_send_bind_pdu(rpc, FALSE) < 0)
308 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_send_bind_pdu failure");
312 case RPC_BIND_STATE_LAST_LEG:
313 if (rpc_send_rpc_auth_3_pdu(rpc) < 0)
315 WLog_Print(rpc->log, WLOG_ERROR,
316 "rpc_secure_bind: error sending rpc_auth_3 pdu!");
321 case RPC_BIND_STATE_COMPLETE:
322 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_CONTEXT_NEGOTIATED);
324 if (!tsg_proxy_begin(tsg))
326 WLog_Print(rpc->log, WLOG_ERROR,
"tsg_proxy_begin failure");
338 WLog_Print(rpc->log, WLOG_ERROR,
"invalid rpc->State: %u", rpc->State);
341 else if (rpc->State >= RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
343 if (!tsg_recv_pdu(tsg, pdu))
353static int rpc_client_recv_pdu(rdpRpc* rpc,
RPC_PDU* pdu)
358 Stream_SealLength(pdu->s);
359 Stream_ResetPosition(pdu->s);
361 const size_t before = Stream_GetRemainingLength(pdu->s);
362 WLog_Print(rpc->log, WLOG_TRACE,
"RPC PDU parsing %" PRIuz
" bytes", before);
363 const int rc = rpc_client_recv_pdu_int(rpc, pdu);
366 const size_t after = Stream_GetRemainingLength(pdu->s);
370 WLog_Print(rpc->log, WLOG_WARN,
"Incompletely parsed RPC PDU (%" PRIuz
" bytes remain)",
378static int rpc_client_recv_fragment(rdpRpc* rpc,
wStream* fragment)
381 size_t StubOffset = 0;
382 size_t StubLength = 0;
387 WINPR_ASSERT(rpc->client);
388 WINPR_ASSERT(fragment);
390 RPC_PDU* pdu = rpc->client->pdu;
393 Stream_SealLength(fragment);
394 Stream_ResetPosition(fragment);
396 if (!rts_read_pdu_header(fragment, &header))
399 if (header.common.ptype == PTYPE_RESPONSE)
401 rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header.common.frag_length;
402 rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -=
403 header.common.frag_length;
405 if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow <
406 (rpc->ReceiveWindow / 2))
408 if (!rts_send_flow_control_ack_pdu(rpc))
412 if (!rpc_get_stub_data_info(rpc, &header, &StubOffset, &StubLength))
414 WLog_Print(rpc->log, WLOG_ERROR,
"expected stub");
420 if ((header.common.call_id == rpc->PipeCallId) &&
421 (header.common.pfc_flags & PFC_LAST_FRAG))
424 TerminateEventArgs e;
425 rdpContext* context = transport_get_context(rpc->transport);
426 rdpTsg* tsg = transport_get_tsg(rpc->transport);
428 WINPR_ASSERT(context);
430 if (Stream_Length(fragment) < StubOffset + 4)
432 if (!Stream_SetPosition(fragment, StubOffset))
434 Stream_Read_UINT32(fragment, rpc->result);
436 utils_abort_connect(context->rdp);
437 tsg_set_state(tsg, TSG_STATE_TUNNEL_CLOSE_PENDING);
438 EventArgsInit(&e,
"freerdp");
440 rc = PubSub_OnTerminate(context->rdp->pubSub, context, &e) >= 0 ? 0 : -1;
444 if (header.common.call_id != rpc->PipeCallId)
452 if (rpc->StubFragCount == 0)
453 rpc->StubCallId = header.common.call_id;
455 if (rpc->StubCallId != header.common.call_id)
457 WLog_Print(rpc->log, WLOG_ERROR,
458 "invalid call_id: actual: %" PRIu32
", expected: %" PRIu32
459 ", frag_count: %" PRIu32
"",
460 rpc->StubCallId, header.common.call_id, rpc->StubFragCount);
463 call = rpc_client_call_find_by_id(rpc->log, rpc->client, rpc->StubCallId);
468 if (call->OpNum != TsProxySetupReceivePipeOpnum)
472 if (!Stream_EnsureRemainingCapacity(pdu->s, StubLength))
475 if (Stream_Length(fragment) < StubOffset + StubLength)
478 if (!Stream_SetPosition(fragment, StubOffset))
481 Stream_Write(pdu->s, Stream_ConstPointer(fragment), StubLength);
482 rpc->StubFragCount++;
484 if (response->alloc_hint == StubLength)
486 pdu->Flags = RPC_PDU_FLAG_STUB;
487 pdu->Type = PTYPE_RESPONSE;
488 pdu->CallId = rpc->StubCallId;
490 if (rpc_client_recv_pdu(rpc, pdu) < 0)
492 if (!rpc_pdu_reset(pdu))
494 rpc->StubFragCount = 0;
501 if (Stream_Length(fragment) < StubOffset + StubLength)
503 if (!Stream_SetPosition(fragment, StubOffset))
505 if (rpc_client_receive_pipe_write(rpc->client, Stream_ConstPointer(fragment),
508 rpc->StubFragCount++;
510 if (response->alloc_hint == StubLength)
512 rpc->StubFragCount = 0;
519 else if (header.common.ptype == PTYPE_RTS)
521 if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
524 pdu->Type = header.common.ptype;
525 pdu->CallId = header.common.call_id;
527 const size_t len = Stream_Length(fragment);
528 if (!Stream_EnsureRemainingCapacity(pdu->s, len))
531 Stream_Write(pdu->s, Stream_Buffer(fragment), len);
533 if (rpc_client_recv_pdu(rpc, pdu) < 0)
536 if (!rpc_pdu_reset(pdu))
541 if (!rts_recv_out_of_sequence_pdu(rpc, fragment, &header))
547 else if (header.common.ptype == PTYPE_BIND_ACK ||
548 header.common.ptype == PTYPE_ALTER_CONTEXT_RESP)
551 pdu->Type = header.common.ptype;
552 pdu->CallId = header.common.call_id;
554 const size_t len = Stream_Length(fragment);
555 if (!Stream_EnsureRemainingCapacity(pdu->s, len))
558 Stream_Write(pdu->s, Stream_Buffer(fragment), len);
560 if (rpc_client_recv_pdu(rpc, pdu) < 0)
563 if (!rpc_pdu_reset(pdu))
567 else if (header.common.ptype == PTYPE_FAULT)
570 rpc_recv_fault_pdu(fault->status);
575 WLog_Print(rpc->log, WLOG_ERROR,
"unexpected RPC PDU type 0x%02" PRIX8
"",
576 header.common.ptype);
581 rc = (rc < 0) ? 1 : 0;
585 rpc_client_call_discard(rpc->log, rpc->client, header.common.call_id);
586 rts_free_pdu_header(&header, FALSE);
591static SSIZE_T rpc_client_default_out_channel_recv(rdpRpc* rpc)
594 HttpResponse* response =
nullptr;
597 HANDLE outChannelEvent =
nullptr;
599 inChannel = connection->DefaultInChannel;
600 outChannel = connection->DefaultOutChannel;
601 BIO_get_event(outChannel->common.tls->bio, &outChannelEvent);
603 if (outChannel->State < CLIENT_OUT_CHANNEL_STATE_OPENED)
605 if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
608 response = http_response_recv(outChannel->common.tls, TRUE);
613 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_SECURITY)
616 if (!rpc_ncacn_http_recv_out_channel_response(&outChannel->common, response))
618 http_response_free(response);
619 WLog_Print(rpc->log, WLOG_ERROR,
620 "rpc_ncacn_http_recv_out_channel_response failure");
626 if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, FALSE))
628 http_response_free(response);
629 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_ncacn_http_send_out_channel_request failure");
633 if (rpc_ncacn_http_is_final_request(&outChannel->common))
635 rpc_ncacn_http_auth_uninit(&outChannel->common);
636 rpc_out_channel_transition_to_state(outChannel,
637 CLIENT_OUT_CHANNEL_STATE_NEGOTIATED);
641 if (!rts_send_CONN_A1_pdu(rpc))
643 http_response_free(response);
644 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_send_CONN_A1_pdu error!");
648 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_OPENED);
650 if (inChannel->State == CLIENT_IN_CHANNEL_STATE_OPENED)
652 rpc_virtual_connection_transition_to_state(
653 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
660 http_response_free(response);
662 else if (connection->State == VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT)
665 if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
668 response = http_response_recv(outChannel->common.tls, FALSE);
673 const UINT16 statusCode = http_response_get_status_code(response);
674 if (statusCode != HTTP_STATUS_OK)
676 http_response_log_error_status(rpc->log, WLOG_ERROR, response);
678 if (statusCode == HTTP_STATUS_DENIED)
680 rdpContext* context = transport_get_context(rpc->transport);
681 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
684 http_response_free(response);
688 http_response_free(response);
689 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
690 VIRTUAL_CONNECTION_STATE_WAIT_A3W);
695 wStream* fragment = rpc->client->ReceiveFragment;
702 while (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
704 status = rpc_channel_read(&outChannel->common, fragment,
705 RPC_COMMON_FIELDS_LENGTH - Stream_GetPosition(fragment));
710 if (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
714 pos = Stream_GetPosition(fragment);
715 Stream_ResetPosition(fragment);
718 const rts_pdu_status_t rc = rts_read_common_pdu_header(fragment, &header, TRUE);
719 if (rc == RTS_PDU_FAIL)
722 if (!Stream_SetPosition(fragment, pos))
725 if (header.frag_length >= rpc->max_recv_frag)
727 WLog_Print(rpc->log, WLOG_ERROR,
728 "rpc_client_recv: invalid fragment size: %" PRIu16
" (max: %" PRIu16
")",
729 header.frag_length, rpc->max_recv_frag);
730 winpr_HexDump(TAG, WLOG_ERROR, Stream_Buffer(fragment),
731 Stream_GetPosition(fragment));
735 while (Stream_GetPosition(fragment) < header.frag_length)
737 status = rpc_channel_read(&outChannel->common, fragment,
738 header.frag_length - Stream_GetPosition(fragment));
742 WLog_Print(rpc->log, WLOG_ERROR,
"error reading fragment body");
746 if (Stream_GetPosition(fragment) < header.frag_length)
752 status = rpc_client_recv_fragment(rpc, fragment);
758 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_RECYCLED &&
759 connection->NonDefaultOutChannel)
761 rpc_channel_free(&connection->DefaultOutChannel->common);
762 connection->DefaultOutChannel = connection->NonDefaultOutChannel;
763 connection->NonDefaultOutChannel =
nullptr;
764 rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
765 CLIENT_OUT_CHANNEL_STATE_OPENED);
766 rpc_virtual_connection_transition_to_state(
767 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
771 Stream_ResetPosition(fragment);
780static SSIZE_T rpc_client_nondefault_out_channel_recv(rdpRpc* rpc)
783 HttpResponse* response =
nullptr;
785 HANDLE nextOutChannelEvent =
nullptr;
786 nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
787 BIO_get_event(nextOutChannel->common.tls->bio, &nextOutChannelEvent);
789 if (WaitForSingleObject(nextOutChannelEvent, 0) != WAIT_OBJECT_0)
792 response = http_response_recv(nextOutChannel->common.tls, TRUE);
796 switch (nextOutChannel->State)
798 case CLIENT_OUT_CHANNEL_STATE_SECURITY:
799 if (rpc_ncacn_http_recv_out_channel_response(&nextOutChannel->common, response))
801 if (rpc_ncacn_http_send_out_channel_request(&nextOutChannel->common, TRUE))
803 if (rpc_ncacn_http_is_final_request(&nextOutChannel->common))
805 rpc_ncacn_http_auth_uninit(&nextOutChannel->common);
807 if (rts_send_OUT_R1_A3_pdu(rpc))
810 rpc_out_channel_transition_to_state(
811 nextOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
815 WLog_Print(rpc->log, WLOG_ERROR,
"rts_send_OUT_R1/A3_pdu failure");
825 WLog_Print(rpc->log, WLOG_ERROR,
826 "rpc_ncacn_http_send_out_channel_request failure");
831 WLog_Print(rpc->log, WLOG_ERROR,
832 "rpc_ncacn_http_recv_out_channel_response failure");
837 case CLIENT_OUT_CHANNEL_STATE_INITIAL:
838 case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
839 case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
841 WLog_Print(rpc->log, WLOG_ERROR,
842 "rpc_client_nondefault_out_channel_recv: Unexpected message %08" PRIx32,
843 nextOutChannel->State);
847 http_response_free(response);
853int rpc_client_out_channel_recv(rdpRpc* rpc)
858 if (connection->DefaultOutChannel)
860 status = rpc_client_default_out_channel_recv(rpc);
866 if (connection->NonDefaultOutChannel)
868 status = rpc_client_nondefault_out_channel_recv(rpc);
877int rpc_client_in_channel_recv(rdpRpc* rpc)
880 HttpResponse* response =
nullptr;
883 HANDLE InChannelEvent =
nullptr;
885 inChannel = connection->DefaultInChannel;
886 outChannel = connection->DefaultOutChannel;
887 BIO_get_event(inChannel->common.tls->bio, &InChannelEvent);
889 if (WaitForSingleObject(InChannelEvent, 0) != WAIT_OBJECT_0)
892 if (inChannel->State < CLIENT_IN_CHANNEL_STATE_OPENED)
894 response = http_response_recv(inChannel->common.tls, TRUE);
899 if (inChannel->State == CLIENT_IN_CHANNEL_STATE_SECURITY)
901 if (!rpc_ncacn_http_recv_in_channel_response(&inChannel->common, response))
903 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_ncacn_http_recv_in_channel_response failure");
904 http_response_free(response);
910 if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
912 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_ncacn_http_send_in_channel_request failure");
913 http_response_free(response);
917 if (rpc_ncacn_http_is_final_request(&inChannel->common))
919 rpc_ncacn_http_auth_uninit(&inChannel->common);
920 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_NEGOTIATED);
924 if (!rts_send_CONN_B1_pdu(rpc))
926 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_send_CONN_B1_pdu error!");
927 http_response_free(response);
931 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_OPENED);
933 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED)
935 rpc_virtual_connection_transition_to_state(
936 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
943 http_response_free(response);
947 response = http_response_recv(inChannel->common.tls, TRUE);
953 http_response_free(response);
969 RpcClientCall* val = HashTable_GetItemValue(client->ClientCallList, &CallId);
970 WLog_Print(log, WLOG_TRACE,
"search 0x%08" PRIx32
": %p {%" PRIuz
"}", CallId, (
void*)val,
971 HashTable_Count(client->ClientCallList));
977 WINPR_ASSERT(client);
981 const BOOL rc = HashTable_Insert(client->ClientCallList, &call->CallId, call);
982 WLog_Print(log, WLOG_TRACE,
"adding 0x%08" PRIx32
": %s {%" PRIuz
"}", call->CallId,
983 rc ?
"success" :
"failed", HashTable_Count(client->ClientCallList));
987void rpc_client_call_discard(wLog* log,
RpcClient* client, UINT32 CallId)
989 WINPR_ASSERT(client);
991 const BOOL rc = HashTable_Remove(client->ClientCallList, &CallId);
992 WLog_Print(log, WLOG_TRACE,
"discard 0x%08" PRIx32
": %s {%" PRIuz
"}", CallId,
993 rc ?
"success" :
"failed", HashTable_Count(client->ClientCallList));
997static RPC_CLIENT_CALL_STATE next(RPC_CLIENT_CALL_STATE state)
1001 case RPC_CLIENT_CALL_STATE_INITIAL:
1002 return RPC_CLIENT_CALL_STATE_SEND_PDUS;
1003 case RPC_CLIENT_CALL_STATE_SEND_PDUS:
1004 return RPC_CLIENT_CALL_STATE_DISPATCHED;
1005 case RPC_CLIENT_CALL_STATE_DISPATCHED:
1006 return RPC_CLIENT_CALL_STATE_RECEIVE_PDU;
1007 case RPC_CLIENT_CALL_STATE_RECEIVE_PDU:
1008 return RPC_CLIENT_CALL_STATE_COMPLETE;
1009 case RPC_CLIENT_CALL_STATE_COMPLETE:
1010 return RPC_CLIENT_CALL_STATE_FINAL;
1011 case RPC_CLIENT_CALL_STATE_FINAL:
1012 return RPC_CLIENT_CALL_STATE_FINAL;
1014 case RPC_CLIENT_CALL_STATE_FAULT:
1016 return RPC_CLIENT_CALL_STATE_FAULT;
1020void rpc_client_call_advance(wLog* log,
RpcClient* client, UINT32 CallId,
1021 RPC_CLIENT_CALL_STATE expected, BOOL success)
1023 WINPR_ASSERT(client);
1024 HashTable_Lock(client->ClientCallList);
1025 RpcClientCall* call = rpc_client_call_find_by_id(log, client, CallId);
1029 call->State = next(call->State);
1031 call->State = RPC_CLIENT_CALL_STATE_FAULT;
1034 HashTable_Unlock(client->ClientCallList);
1037RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum)
1044 clientCall->CallId = CallId;
1045 clientCall->OpNum = OpNum;
1046 clientCall->State = RPC_CLIENT_CALL_STATE_INITIAL;
1055static void rpc_array_client_call_free(
void* call)
1060int rpc_in_channel_send_pdu(
RpcInChannel* inChannel,
const BYTE* buffer,
size_t length)
1065 WINPR_ASSERT(inChannel);
1067 SSIZE_T status = rpc_channel_write(&inChannel->common, buffer, length);
1072 Stream_StaticConstInit(&s, buffer, length);
1073 const rts_pdu_status_t rc = rts_read_common_pdu_header(&s, &header, FALSE);
1074 if (rc != RTS_PDU_VALID)
1087 if (header.ptype == PTYPE_REQUEST)
1089 const uint32_t ustatus = WINPR_ASSERTING_INT_CAST(uint32_t, status);
1090 inChannel->BytesSent += ustatus;
1091 inChannel->SenderAvailableWindow -= ustatus;
1094 if (status > INT32_MAX)
1098 rpc_client_call_advance(inChannel->common.rpc->log, inChannel->common.client, header.call_id,
1099 RPC_CLIENT_CALL_STATE_DISPATCHED, status > 0);
1103BOOL rpc_client_write_call(rdpRpc* rpc,
wStream* s, UINT16 opnum)
1109 BYTE* buffer =
nullptr;
1110 size_t stub_data_pad = 0;
1112 SecBuffer ciphertext = WINPR_C_ARRAY_INIT;
1114 rdpCredsspAuth* auth =
nullptr;
1124 connection = rpc->VirtualConnection;
1128 WLog_Print(rpc->log, WLOG_ERROR,
"invalid auth context");
1135 inChannel = connection->DefaultInChannel;
1140 Stream_SealLength(s);
1143 const size_t length = Stream_Length(s);
1144 if (length > UINT32_MAX)
1148 const size_t asize = credssp_auth_trailer_size(auth);
1149 request_pdu.header = rpc_pdu_header_init(rpc);
1150 request_pdu.header.ptype = PTYPE_REQUEST;
1151 request_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
1152 request_pdu.header.auth_length = (UINT16)asize;
1154 request_pdu.header.call_id = rpc->CallId++;
1155 request_pdu.alloc_hint = (UINT32)length;
1156 request_pdu.p_cont_id = 0x0000;
1157 request_pdu.opnum = opnum;
1158 clientCall = rpc_client_call_new(request_pdu.header.call_id, request_pdu.opnum);
1163 if (!rpc_client_call_add(rpc->log, rpc->client, clientCall))
1165 rpc_client_call_free(clientCall);
1170 if (request_pdu.opnum == TsProxySetupReceivePipeOpnum)
1171 rpc->PipeCallId = request_pdu.header.call_id;
1173 request_pdu.stub_data = Stream_Buffer(s);
1175 stub_data_pad = rpc_offset_align(&offset, 8);
1179 const size_t alg = rpc_offset_align(&offset, 4);
1180 WINPR_ASSERT(alg <= UINT8_MAX);
1181 request_pdu.auth_verifier.auth_pad_length = (UINT8)alg;
1183 request_pdu.auth_verifier.auth_type =
1184 rpc_auth_pkg_to_security_provider(credssp_auth_pkg_name(rpc->auth));
1185 request_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
1186 request_pdu.auth_verifier.auth_reserved = 0x00;
1187 request_pdu.auth_verifier.auth_context_id = 0x00000000;
1188 offset += (8 + request_pdu.header.auth_length);
1190 if (offset > UINT16_MAX)
1192 request_pdu.header.frag_length = (UINT16)offset;
1193 buffer = (BYTE*)calloc(1, request_pdu.header.frag_length);
1198 CopyMemory(buffer, &request_pdu, 24);
1200 rpc_offset_pad(&offset, stub_data_pad);
1201 CopyMemory(&buffer[offset], request_pdu.stub_data, length);
1205 rpc_offset_pad(&offset, request_pdu.auth_verifier.auth_pad_length);
1206 CopyMemory(&buffer[offset], &request_pdu.auth_verifier.auth_type, 8);
1209 if (offset > request_pdu.header.frag_length)
1212 plaintext.pvBuffer = buffer;
1213 plaintext.cbBuffer = (UINT32)offset;
1214 plaintext.BufferType = SECBUFFER_READONLY;
1218 if (!credssp_auth_encrypt(auth, &plaintext, &ciphertext, &size, rpc->SendSeqNum++))
1221 if (offset + size > request_pdu.header.frag_length)
1223 sspi_SecBufferFree(&ciphertext);
1227 CopyMemory(&buffer[offset], ciphertext.pvBuffer, size);
1231 sspi_SecBufferFree(&ciphertext);
1233 if (rpc_in_channel_send_pdu(inChannel, buffer, request_pdu.header.frag_length) < 0)
1239 rpc_client_call_discard(rpc->log, rpc->client, request_pdu.header.call_id);
1242 Stream_Free(s, TRUE);
1247static BOOL rpc_client_resolve_gateway(rdpSettings* settings,
char** host, UINT16* port,
1250 struct addrinfo* result =
nullptr;
1252 if (!settings || !host || !port || !isProxy)
1260 *isProxy = proxy_prepare(settings, &peerHostname, port, &proxyUsername, &proxyPassword);
1261 result = freerdp_tcp_resolve_host(peerHostname, *port, 0);
1266 *host = freerdp_tcp_address_to_string(
1267 WINPR_PACKED_ALIGN_CAST(
const struct sockaddr_storage*, result->ai_addr),
nullptr);
1268 freeaddrinfo(result);
1274static BOOL compare_uint32(
const void* objA,
const void* objB)
1279 const UINT32* a = objA;
1280 const UINT32* b = objB;
1285static UINT32 hash_uint32(
const void* key)
1289 const UINT32* k = key;
1293RpcClient* rpc_client_new(rdpContext* context, UINT32 max_recv_frag)
1301 if (!rpc_client_resolve_gateway(context->settings, &client->host, &client->port,
1305 client->context = context;
1307 if (!client->context)
1310 client->pdu = rpc_pdu_new();
1315 client->ReceiveFragment = Stream_New(
nullptr, max_recv_frag);
1317 if (!client->ReceiveFragment)
1320 client->PipeEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
1322 if (!client->PipeEvent)
1325 if (!ringbuffer_init(&(client->ReceivePipe), 4096))
1328 if (!InitializeCriticalSectionAndSpinCount(&(client->PipeLock), 4000))
1331 client->ClientCallList = HashTable_New(TRUE);
1333 if (!client->ClientCallList)
1336 if (!HashTable_SetHashFunction(client->ClientCallList, hash_uint32))
1339 obj = HashTable_KeyObject(client->ClientCallList);
1341 obj = HashTable_ValueObject(client->ClientCallList);
1345 WINPR_PRAGMA_DIAG_PUSH
1346 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1347 rpc_client_free(client);
1348 WINPR_PRAGMA_DIAG_POP
1359 if (client->ReceiveFragment)
1360 Stream_Free(client->ReceiveFragment, TRUE);
1362 if (client->PipeEvent)
1363 (void)CloseHandle(client->PipeEvent);
1365 ringbuffer_destroy(&(client->ReceivePipe));
1366 DeleteCriticalSection(&(client->PipeLock));
1369 rpc_pdu_free(client->pdu);
1371 HashTable_Free(client->ClientCallList);
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
a piece of data in the ring buffer, exactly like a glibc iovec
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree
WINPR_ATTR_NODISCARD OBJECT_EQUALS_FN fnObjectEquals