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")
47static const char* rpc_client_state_str(RPC_CLIENT_STATE state)
50 const char* str =
"RPC_CLIENT_STATE_UNKNOWN";
54 case RPC_CLIENT_STATE_INITIAL:
55 str =
"RPC_CLIENT_STATE_INITIAL";
58 case RPC_CLIENT_STATE_ESTABLISHED:
59 str =
"RPC_CLIENT_STATE_ESTABLISHED";
62 case RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK:
63 str =
"RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK";
66 case RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK:
67 str =
"RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK";
70 case RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE:
71 str =
"RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE";
74 case RPC_CLIENT_STATE_CONTEXT_NEGOTIATED:
75 str =
"RPC_CLIENT_STATE_CONTEXT_NEGOTIATED";
78 case RPC_CLIENT_STATE_WAIT_RESPONSE:
79 str =
"RPC_CLIENT_STATE_WAIT_RESPONSE";
82 case RPC_CLIENT_STATE_FINAL:
83 str =
"RPC_CLIENT_STATE_FINAL";
92static BOOL rpc_pdu_reset(
RPC_PDU* pdu)
98 Stream_ResetPosition(pdu->s);
99 return Stream_SetLength(pdu->s, 0);
102static void rpc_pdu_free(
RPC_PDU* pdu)
107 Stream_Free(pdu->s, TRUE);
111WINPR_ATTR_MALLOC(rpc_pdu_free, 1)
112static
RPC_PDU* rpc_pdu_new(
void)
119 pdu->s = Stream_New(
nullptr, 4096);
124 if (!rpc_pdu_reset(pdu))
134static int rpc_client_receive_pipe_write(
RpcClient* client,
const BYTE* buffer,
size_t length)
138 if (!client || !buffer)
141 EnterCriticalSection(&(client->PipeLock));
143 if (ringbuffer_write(&(client->ReceivePipe), buffer, length))
144 status += (int)length;
146 if (ringbuffer_used(&(client->ReceivePipe)) > 0)
147 (
void)SetEvent(client->PipeEvent);
149 LeaveCriticalSection(&(client->PipeLock));
153int rpc_client_receive_pipe_read(
RpcClient* client, BYTE* buffer,
size_t length)
159 if (!client || !buffer)
162 EnterCriticalSection(&(client->PipeLock));
163 nchunks = ringbuffer_peek(&(client->ReceivePipe), chunks, length);
165 for (
int index = 0; index < nchunks; index++)
167 CopyMemory(&buffer[status], chunks[index].data, chunks[index].size);
168 status += chunks[index].size;
172 ringbuffer_commit_read_bytes(&(client->ReceivePipe), status);
174 if (ringbuffer_used(&(client->ReceivePipe)) < 1)
175 (void)ResetEvent(client->PipeEvent);
177 LeaveCriticalSection(&(client->PipeLock));
179 if (status > INT_MAX)
184static int rpc_client_transition_to_state(rdpRpc* rpc, RPC_CLIENT_STATE state)
189 WLog_DBG(TAG,
"%s", rpc_client_state_str(state));
193static int rpc_client_recv_pdu_int(rdpRpc* rpc,
RPC_PDU* pdu)
201 rdpTsg* tsg = transport_get_tsg(rpc->transport);
203 WLog_Print(rpc->log, WLOG_TRACE,
"client state %s, vc state %s",
204 rpc_client_state_str(rpc->State), rpc_vc_state_str(rpc->VirtualConnection->State));
207 rts_match_pdu_signature_ex(&RTS_PDU_PING_SIGNATURE, pdu->s,
nullptr, &found, TRUE);
208 rts_print_pdu_signature(rpc->log, WLOG_TRACE, &found);
210 return rts_recv_ping_pdu(rpc, pdu->s);
212 if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
214 switch (rpc->VirtualConnection->State)
216 case VIRTUAL_CONNECTION_STATE_INITIAL:
219 case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
222 case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
223 if (memcmp(&found, &RTS_PDU_CONN_A3_SIGNATURE,
sizeof(found)) != 0)
225 WLog_Print(rpc->log, WLOG_ERROR,
"unexpected RTS PDU: Expected CONN/A3");
226 rts_print_pdu_signature(rpc->log, WLOG_ERROR, &found);
230 if (!rts_recv_CONN_A3_pdu(rpc, pdu->s))
232 WLog_Print(rpc->log, WLOG_ERROR,
"rts_recv_CONN_A3_pdu failure");
236 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
237 VIRTUAL_CONNECTION_STATE_WAIT_C2);
241 case VIRTUAL_CONNECTION_STATE_WAIT_C2:
242 if (memcmp(&found, &RTS_PDU_CONN_C2_SIGNATURE,
sizeof(found)) != 0)
244 WLog_Print(rpc->log, WLOG_ERROR,
"unexpected RTS PDU: Expected CONN/C2");
245 rts_print_pdu_signature(rpc->log, WLOG_ERROR, &found);
249 if (!rts_recv_CONN_C2_pdu(rpc, pdu->s))
251 WLog_Print(rpc->log, WLOG_ERROR,
"rts_recv_CONN_C2_pdu failure");
255 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
256 VIRTUAL_CONNECTION_STATE_OPENED);
257 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_ESTABLISHED);
259 if (rpc_send_bind_pdu(rpc, TRUE) < 0)
261 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_send_bind_pdu failure");
265 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK);
269 case VIRTUAL_CONNECTION_STATE_OPENED:
272 case VIRTUAL_CONNECTION_STATE_FINAL:
278 else if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
280 if (rpc->State == RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK)
282 if (pdu->Type == PTYPE_BIND_ACK || pdu->Type == PTYPE_ALTER_CONTEXT_RESP)
284 if (!rpc_recv_bind_ack_pdu(rpc, pdu->s))
286 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_recv_bind_ack_pdu failure");
292 WLog_Print(rpc->log, WLOG_ERROR,
293 "RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK unexpected pdu type: 0x%08" PRIX32
299 switch (rpc_bind_state(rpc))
301 case RPC_BIND_STATE_INCOMPLETE:
302 if (rpc_send_bind_pdu(rpc, FALSE) < 0)
304 WLog_Print(rpc->log, WLOG_ERROR,
"rpc_send_bind_pdu failure");
308 case RPC_BIND_STATE_LAST_LEG:
309 if (rpc_send_rpc_auth_3_pdu(rpc) < 0)
311 WLog_Print(rpc->log, WLOG_ERROR,
312 "rpc_secure_bind: error sending rpc_auth_3 pdu!");
317 case RPC_BIND_STATE_COMPLETE:
318 rpc_client_transition_to_state(rpc, RPC_CLIENT_STATE_CONTEXT_NEGOTIATED);
320 if (!tsg_proxy_begin(tsg))
322 WLog_Print(rpc->log, WLOG_ERROR,
"tsg_proxy_begin failure");
334 WLog_Print(rpc->log, WLOG_ERROR,
"invalid rpc->State: %u", rpc->State);
337 else if (rpc->State >= RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
339 if (!tsg_recv_pdu(tsg, pdu))
348static int rpc_client_recv_pdu(rdpRpc* rpc,
RPC_PDU* pdu)
353 Stream_SealLength(pdu->s);
354 Stream_ResetPosition(pdu->s);
356 const size_t before = Stream_GetRemainingLength(pdu->s);
357 WLog_Print(rpc->log, WLOG_TRACE,
"RPC PDU parsing %" PRIuz
" bytes", before);
358 const int rc = rpc_client_recv_pdu_int(rpc, pdu);
361 const size_t after = Stream_GetRemainingLength(pdu->s);
365 WLog_Print(rpc->log, WLOG_WARN,
"Incompletely parsed RPC PDU (%" PRIuz
" bytes remain)",
372static int rpc_client_recv_fragment(rdpRpc* rpc,
wStream* fragment)
376 size_t StubOffset = 0;
377 size_t StubLength = 0;
382 WINPR_ASSERT(rpc->client);
383 WINPR_ASSERT(fragment);
385 pdu = rpc->client->pdu;
388 Stream_SealLength(fragment);
389 Stream_ResetPosition(fragment);
391 if (!rts_read_pdu_header(fragment, &header))
394 if (header.common.ptype == PTYPE_RESPONSE)
396 rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header.common.frag_length;
397 rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -=
398 header.common.frag_length;
400 if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow <
401 (rpc->ReceiveWindow / 2))
403 if (!rts_send_flow_control_ack_pdu(rpc))
407 if (!rpc_get_stub_data_info(rpc, &header, &StubOffset, &StubLength))
409 WLog_ERR(TAG,
"expected stub");
415 if ((header.common.call_id == rpc->PipeCallId) &&
416 (header.common.pfc_flags & PFC_LAST_FRAG))
419 TerminateEventArgs e;
420 rdpContext* context = transport_get_context(rpc->transport);
421 rdpTsg* tsg = transport_get_tsg(rpc->transport);
423 WINPR_ASSERT(context);
425 if (Stream_Length(fragment) < StubOffset + 4)
427 if (!Stream_SetPosition(fragment, StubOffset))
429 Stream_Read_UINT32(fragment, rpc->result);
431 utils_abort_connect(context->rdp);
432 tsg_set_state(tsg, TSG_STATE_TUNNEL_CLOSE_PENDING);
433 EventArgsInit(&e,
"freerdp");
435 rc = PubSub_OnTerminate(context->rdp->pubSub, context, &e) >= 0 ? 0 : -1;
439 if (header.common.call_id != rpc->PipeCallId)
447 if (rpc->StubFragCount == 0)
448 rpc->StubCallId = header.common.call_id;
450 if (rpc->StubCallId != header.common.call_id)
453 "invalid call_id: actual: %" PRIu32
", expected: %" PRIu32
454 ", frag_count: %" PRIu32
"",
455 rpc->StubCallId, header.common.call_id, rpc->StubFragCount);
458 call = rpc_client_call_find_by_id(rpc->client, rpc->StubCallId);
463 if (call->OpNum != TsProxySetupReceivePipeOpnum)
467 if (!Stream_EnsureCapacity(pdu->s, response->alloc_hint))
470 if (Stream_Length(fragment) < StubOffset + StubLength)
473 if (!Stream_SetPosition(fragment, StubOffset))
475 Stream_Write(pdu->s, Stream_ConstPointer(fragment), StubLength);
476 rpc->StubFragCount++;
478 if (response->alloc_hint == StubLength)
480 pdu->Flags = RPC_PDU_FLAG_STUB;
481 pdu->Type = PTYPE_RESPONSE;
482 pdu->CallId = rpc->StubCallId;
484 if (rpc_client_recv_pdu(rpc, pdu) < 0)
486 if (!rpc_pdu_reset(pdu))
488 rpc->StubFragCount = 0;
495 if (Stream_Length(fragment) < StubOffset + StubLength)
497 if (!Stream_SetPosition(fragment, StubOffset))
499 rpc_client_receive_pipe_write(rpc->client, Stream_ConstPointer(fragment), StubLength);
500 rpc->StubFragCount++;
502 if (response->alloc_hint == StubLength)
504 rpc->StubFragCount = 0;
511 else if (header.common.ptype == PTYPE_RTS)
513 if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
516 pdu->Type = header.common.ptype;
517 pdu->CallId = header.common.call_id;
519 const size_t len = Stream_Length(fragment);
520 if (!Stream_EnsureCapacity(pdu->s, len))
523 Stream_Write(pdu->s, Stream_Buffer(fragment), len);
525 if (rpc_client_recv_pdu(rpc, pdu) < 0)
528 if (!rpc_pdu_reset(pdu))
533 if (!rts_recv_out_of_sequence_pdu(rpc, fragment, &header))
539 else if (header.common.ptype == PTYPE_BIND_ACK ||
540 header.common.ptype == PTYPE_ALTER_CONTEXT_RESP)
543 pdu->Type = header.common.ptype;
544 pdu->CallId = header.common.call_id;
546 const size_t len = Stream_Length(fragment);
547 if (!Stream_EnsureCapacity(pdu->s, len))
550 Stream_Write(pdu->s, Stream_Buffer(fragment), len);
552 if (rpc_client_recv_pdu(rpc, pdu) < 0)
555 if (!rpc_pdu_reset(pdu))
559 else if (header.common.ptype == PTYPE_FAULT)
562 rpc_recv_fault_pdu(fault->status);
567 WLog_ERR(TAG,
"unexpected RPC PDU type 0x%02" PRIX8
"", header.common.ptype);
572 rc = (rc < 0) ? 1 : 0;
575 rts_free_pdu_header(&header, FALSE);
579static SSIZE_T rpc_client_default_out_channel_recv(rdpRpc* rpc)
582 HttpResponse* response =
nullptr;
585 HANDLE outChannelEvent =
nullptr;
587 inChannel = connection->DefaultInChannel;
588 outChannel = connection->DefaultOutChannel;
589 BIO_get_event(outChannel->common.tls->bio, &outChannelEvent);
591 if (outChannel->State < CLIENT_OUT_CHANNEL_STATE_OPENED)
593 if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
596 response = http_response_recv(outChannel->common.tls, TRUE);
601 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_SECURITY)
604 if (!rpc_ncacn_http_recv_out_channel_response(&outChannel->common, response))
606 http_response_free(response);
607 WLog_ERR(TAG,
"rpc_ncacn_http_recv_out_channel_response failure");
613 if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, FALSE))
615 http_response_free(response);
616 WLog_ERR(TAG,
"rpc_ncacn_http_send_out_channel_request failure");
620 if (rpc_ncacn_http_is_final_request(&outChannel->common))
622 rpc_ncacn_http_auth_uninit(&outChannel->common);
623 rpc_out_channel_transition_to_state(outChannel,
624 CLIENT_OUT_CHANNEL_STATE_NEGOTIATED);
628 if (!rts_send_CONN_A1_pdu(rpc))
630 http_response_free(response);
631 WLog_ERR(TAG,
"rpc_send_CONN_A1_pdu error!");
635 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_OPENED);
637 if (inChannel->State == CLIENT_IN_CHANNEL_STATE_OPENED)
639 rpc_virtual_connection_transition_to_state(
640 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
647 http_response_free(response);
649 else if (connection->State == VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT)
652 if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
655 response = http_response_recv(outChannel->common.tls, FALSE);
660 const UINT16 statusCode = http_response_get_status_code(response);
661 if (statusCode != HTTP_STATUS_OK)
663 http_response_log_error_status(WLog_Get(TAG), WLOG_ERROR, response);
665 if (statusCode == HTTP_STATUS_DENIED)
667 rdpContext* context = transport_get_context(rpc->transport);
668 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
671 http_response_free(response);
675 http_response_free(response);
676 rpc_virtual_connection_transition_to_state(rpc, rpc->VirtualConnection,
677 VIRTUAL_CONNECTION_STATE_WAIT_A3W);
682 wStream* fragment = rpc->client->ReceiveFragment;
689 while (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
691 status = rpc_channel_read(&outChannel->common, fragment,
692 RPC_COMMON_FIELDS_LENGTH - Stream_GetPosition(fragment));
697 if (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH)
701 pos = Stream_GetPosition(fragment);
702 Stream_ResetPosition(fragment);
705 const rts_pdu_status_t rc = rts_read_common_pdu_header(fragment, &header, TRUE);
706 if (rc == RTS_PDU_FAIL)
709 if (!Stream_SetPosition(fragment, pos))
712 if (header.frag_length > rpc->max_recv_frag)
715 "rpc_client_recv: invalid fragment size: %" PRIu16
" (max: %" PRIu16
")",
716 header.frag_length, rpc->max_recv_frag);
717 winpr_HexDump(TAG, WLOG_ERROR, Stream_Buffer(fragment),
718 Stream_GetPosition(fragment));
722 while (Stream_GetPosition(fragment) < header.frag_length)
724 status = rpc_channel_read(&outChannel->common, fragment,
725 header.frag_length - Stream_GetPosition(fragment));
729 WLog_ERR(TAG,
"error reading fragment body");
733 if (Stream_GetPosition(fragment) < header.frag_length)
739 status = rpc_client_recv_fragment(rpc, fragment);
745 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_RECYCLED &&
746 connection->NonDefaultOutChannel)
748 rpc_channel_free(&connection->DefaultOutChannel->common);
749 connection->DefaultOutChannel = connection->NonDefaultOutChannel;
750 connection->NonDefaultOutChannel =
nullptr;
751 rpc_out_channel_transition_to_state(connection->DefaultOutChannel,
752 CLIENT_OUT_CHANNEL_STATE_OPENED);
753 rpc_virtual_connection_transition_to_state(
754 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
758 Stream_ResetPosition(fragment);
766static SSIZE_T rpc_client_nondefault_out_channel_recv(rdpRpc* rpc)
769 HttpResponse* response =
nullptr;
771 HANDLE nextOutChannelEvent =
nullptr;
772 nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
773 BIO_get_event(nextOutChannel->common.tls->bio, &nextOutChannelEvent);
775 if (WaitForSingleObject(nextOutChannelEvent, 0) != WAIT_OBJECT_0)
778 response = http_response_recv(nextOutChannel->common.tls, TRUE);
782 switch (nextOutChannel->State)
784 case CLIENT_OUT_CHANNEL_STATE_SECURITY:
785 if (rpc_ncacn_http_recv_out_channel_response(&nextOutChannel->common, response))
787 if (rpc_ncacn_http_send_out_channel_request(&nextOutChannel->common, TRUE))
789 if (rpc_ncacn_http_is_final_request(&nextOutChannel->common))
791 rpc_ncacn_http_auth_uninit(&nextOutChannel->common);
793 if (rts_send_OUT_R1_A3_pdu(rpc))
796 rpc_out_channel_transition_to_state(
797 nextOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
801 WLog_ERR(TAG,
"rts_send_OUT_R1/A3_pdu failure");
811 WLog_ERR(TAG,
"rpc_ncacn_http_send_out_channel_request failure");
816 WLog_ERR(TAG,
"rpc_ncacn_http_recv_out_channel_response failure");
821 case CLIENT_OUT_CHANNEL_STATE_INITIAL:
822 case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
823 case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
826 "rpc_client_nondefault_out_channel_recv: Unexpected message %08" PRIx32,
827 nextOutChannel->State);
831 http_response_free(response);
837int rpc_client_out_channel_recv(rdpRpc* rpc)
842 if (connection->DefaultOutChannel)
844 status = rpc_client_default_out_channel_recv(rpc);
850 if (connection->NonDefaultOutChannel)
852 status = rpc_client_nondefault_out_channel_recv(rpc);
861int rpc_client_in_channel_recv(rdpRpc* rpc)
864 HttpResponse* response =
nullptr;
867 HANDLE InChannelEvent =
nullptr;
869 inChannel = connection->DefaultInChannel;
870 outChannel = connection->DefaultOutChannel;
871 BIO_get_event(inChannel->common.tls->bio, &InChannelEvent);
873 if (WaitForSingleObject(InChannelEvent, 0) != WAIT_OBJECT_0)
876 if (inChannel->State < CLIENT_IN_CHANNEL_STATE_OPENED)
878 response = http_response_recv(inChannel->common.tls, TRUE);
883 if (inChannel->State == CLIENT_IN_CHANNEL_STATE_SECURITY)
885 if (!rpc_ncacn_http_recv_in_channel_response(&inChannel->common, response))
887 WLog_ERR(TAG,
"rpc_ncacn_http_recv_in_channel_response failure");
888 http_response_free(response);
894 if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
896 WLog_ERR(TAG,
"rpc_ncacn_http_send_in_channel_request failure");
897 http_response_free(response);
901 if (rpc_ncacn_http_is_final_request(&inChannel->common))
903 rpc_ncacn_http_auth_uninit(&inChannel->common);
904 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_NEGOTIATED);
908 if (!rts_send_CONN_B1_pdu(rpc))
910 WLog_ERR(TAG,
"rpc_send_CONN_B1_pdu error!");
911 http_response_free(response);
915 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_OPENED);
917 if (outChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED)
919 rpc_virtual_connection_transition_to_state(
920 rpc, connection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
927 http_response_free(response);
931 response = http_response_recv(inChannel->common.tls, TRUE);
937 http_response_free(response);
955 ArrayList_Lock(client->ClientCallList);
956 const size_t count = ArrayList_Count(client->ClientCallList);
958 for (
size_t index = 0; index < count; index++)
960 clientCall = (
RpcClientCall*)ArrayList_GetItem(client->ClientCallList, index);
962 if (clientCall->CallId == CallId)
966 ArrayList_Unlock(client->ClientCallList);
970RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum)
978 clientCall->CallId = CallId;
979 clientCall->OpNum = OpNum;
980 clientCall->State = RPC_CLIENT_CALL_STATE_SEND_PDUS;
989static void rpc_array_client_call_free(
void* call)
994int rpc_in_channel_send_pdu(
RpcInChannel* inChannel,
const BYTE* buffer,
size_t length)
1000 SSIZE_T status = rpc_channel_write(&inChannel->common, buffer, length);
1005 Stream_StaticConstInit(&s, buffer, length);
1006 const rts_pdu_status_t rc = rts_read_common_pdu_header(&s, &header, FALSE);
1007 if (rc != RTS_PDU_VALID)
1010 clientCall = rpc_client_call_find_by_id(inChannel->common.client, header.call_id);
1014 clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED;
1023 if (header.ptype == PTYPE_REQUEST)
1025 const uint32_t ustatus = WINPR_ASSERTING_INT_CAST(uint32_t, status);
1026 inChannel->BytesSent += ustatus;
1027 inChannel->SenderAvailableWindow -= ustatus;
1030 if (status > INT32_MAX)
1035BOOL rpc_client_write_call(rdpRpc* rpc,
wStream* s, UINT16 opnum)
1038 BYTE* buffer =
nullptr;
1039 size_t stub_data_pad = 0;
1041 SecBuffer ciphertext = WINPR_C_ARRAY_INIT;
1043 rdpCredsspAuth* auth =
nullptr;
1056 connection = rpc->VirtualConnection;
1060 WLog_ERR(TAG,
"invalid auth context");
1067 inChannel = connection->DefaultInChannel;
1072 Stream_SealLength(s);
1075 const size_t length = Stream_Length(s);
1076 if (length > UINT32_MAX)
1080 const size_t asize = credssp_auth_trailer_size(auth);
1081 request_pdu.header = rpc_pdu_header_init(rpc);
1082 request_pdu.header.ptype = PTYPE_REQUEST;
1083 request_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
1084 request_pdu.header.auth_length = (UINT16)asize;
1086 request_pdu.header.call_id = rpc->CallId++;
1087 request_pdu.alloc_hint = (UINT32)length;
1088 request_pdu.p_cont_id = 0x0000;
1089 request_pdu.opnum = opnum;
1090 clientCall = rpc_client_call_new(request_pdu.header.call_id, request_pdu.opnum);
1095 if (!ArrayList_Append(rpc->client->ClientCallList, clientCall))
1097 rpc_client_call_free(clientCall);
1102 if (request_pdu.opnum == TsProxySetupReceivePipeOpnum)
1103 rpc->PipeCallId = request_pdu.header.call_id;
1105 request_pdu.stub_data = Stream_Buffer(s);
1107 stub_data_pad = rpc_offset_align(&offset, 8);
1111 const size_t alg = rpc_offset_align(&offset, 4);
1112 WINPR_ASSERT(alg <= UINT8_MAX);
1113 request_pdu.auth_verifier.auth_pad_length = (UINT8)alg;
1115 request_pdu.auth_verifier.auth_type =
1116 rpc_auth_pkg_to_security_provider(credssp_auth_pkg_name(rpc->auth));
1117 request_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
1118 request_pdu.auth_verifier.auth_reserved = 0x00;
1119 request_pdu.auth_verifier.auth_context_id = 0x00000000;
1120 offset += (8 + request_pdu.header.auth_length);
1122 if (offset > UINT16_MAX)
1124 request_pdu.header.frag_length = (UINT16)offset;
1125 buffer = (BYTE*)calloc(1, request_pdu.header.frag_length);
1130 CopyMemory(buffer, &request_pdu, 24);
1132 rpc_offset_pad(&offset, stub_data_pad);
1133 CopyMemory(&buffer[offset], request_pdu.stub_data, length);
1137 rpc_offset_pad(&offset, request_pdu.auth_verifier.auth_pad_length);
1138 CopyMemory(&buffer[offset], &request_pdu.auth_verifier.auth_type, 8);
1141 if (offset > request_pdu.header.frag_length)
1144 plaintext.pvBuffer = buffer;
1145 plaintext.cbBuffer = (UINT32)offset;
1146 plaintext.BufferType = SECBUFFER_READONLY;
1150 if (!credssp_auth_encrypt(auth, &plaintext, &ciphertext, &size, rpc->SendSeqNum++))
1153 if (offset + size > request_pdu.header.frag_length)
1155 sspi_SecBufferFree(&ciphertext);
1159 CopyMemory(&buffer[offset], ciphertext.pvBuffer, size);
1163 sspi_SecBufferFree(&ciphertext);
1165 if (rpc_in_channel_send_pdu(inChannel, buffer, request_pdu.header.frag_length) < 0)
1171 Stream_Free(s, TRUE);
1175static BOOL rpc_client_resolve_gateway(rdpSettings* settings,
char** host, UINT16* port,
1178 struct addrinfo* result =
nullptr;
1180 if (!settings || !host || !port || !isProxy)
1188 *isProxy = proxy_prepare(settings, &peerHostname, port, &proxyUsername, &proxyPassword);
1189 result = freerdp_tcp_resolve_host(peerHostname, *port, 0);
1195 freerdp_tcp_address_to_string((
const struct sockaddr_storage*)result->ai_addr,
nullptr);
1196 freeaddrinfo(result);
1201RpcClient* rpc_client_new(rdpContext* context, UINT32 max_recv_frag)
1209 if (!rpc_client_resolve_gateway(context->settings, &client->host, &client->port,
1213 client->context = context;
1215 if (!client->context)
1218 client->pdu = rpc_pdu_new();
1223 client->ReceiveFragment = Stream_New(
nullptr, max_recv_frag);
1225 if (!client->ReceiveFragment)
1228 client->PipeEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
1230 if (!client->PipeEvent)
1233 if (!ringbuffer_init(&(client->ReceivePipe), 4096))
1236 if (!InitializeCriticalSectionAndSpinCount(&(client->PipeLock), 4000))
1239 client->ClientCallList = ArrayList_New(TRUE);
1241 if (!client->ClientCallList)
1244 obj = ArrayList_Object(client->ClientCallList);
1248 WINPR_PRAGMA_DIAG_PUSH
1249 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1250 rpc_client_free(client);
1251 WINPR_PRAGMA_DIAG_POP
1262 if (client->ReceiveFragment)
1263 Stream_Free(client->ReceiveFragment, TRUE);
1265 if (client->PipeEvent)
1266 (void)CloseHandle(client->PipeEvent);
1268 ringbuffer_destroy(&(client->ReceivePipe));
1269 DeleteCriticalSection(&(client->PipeLock));
1272 rpc_pdu_free(client->pdu);
1274 if (client->ClientCallList)
1275 ArrayList_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