22#include <freerdp/config.h>
24#include "../settings.h"
27#include <winpr/assert.h>
28#include <winpr/cast.h>
29#include <winpr/tchar.h>
30#include <winpr/synch.h>
31#include <winpr/dsparse.h>
32#include <winpr/crypto.h>
34#include <freerdp/log.h>
36#ifdef FREERDP_HAVE_VALGRIND_MEMCHECK_H
37#include <valgrind/memcheck.h>
42#include "../credssp_auth.h"
43#include "ncacn_http.h"
46#include "rpc_client.h"
51#define TAG FREERDP_TAG("core.gateway.rpc")
53static const char* PTYPE_STRINGS[] = {
"PTYPE_REQUEST",
"PTYPE_PING",
54 "PTYPE_RESPONSE",
"PTYPE_FAULT",
55 "PTYPE_WORKING",
"PTYPE_NOCALL",
56 "PTYPE_REJECT",
"PTYPE_ACK",
57 "PTYPE_CL_CANCEL",
"PTYPE_FACK",
58 "PTYPE_CANCEL_ACK",
"PTYPE_BIND",
59 "PTYPE_BIND_ACK",
"PTYPE_BIND_NAK",
60 "PTYPE_ALTER_CONTEXT",
"PTYPE_ALTER_CONTEXT_RESP",
61 "PTYPE_RPC_AUTH_3",
"PTYPE_SHUTDOWN",
62 "PTYPE_CO_CANCEL",
"PTYPE_ORPHANED",
65static const char* client_in_state_str(CLIENT_IN_CHANNEL_STATE state)
68 const char* str =
"CLIENT_IN_CHANNEL_STATE_UNKNOWN";
72 case CLIENT_IN_CHANNEL_STATE_INITIAL:
73 str =
"CLIENT_IN_CHANNEL_STATE_INITIAL";
76 case CLIENT_IN_CHANNEL_STATE_CONNECTED:
77 str =
"CLIENT_IN_CHANNEL_STATE_CONNECTED";
80 case CLIENT_IN_CHANNEL_STATE_SECURITY:
81 str =
"CLIENT_IN_CHANNEL_STATE_SECURITY";
84 case CLIENT_IN_CHANNEL_STATE_NEGOTIATED:
85 str =
"CLIENT_IN_CHANNEL_STATE_NEGOTIATED";
88 case CLIENT_IN_CHANNEL_STATE_OPENED:
89 str =
"CLIENT_IN_CHANNEL_STATE_OPENED";
92 case CLIENT_IN_CHANNEL_STATE_OPENED_A4W:
93 str =
"CLIENT_IN_CHANNEL_STATE_OPENED_A4W";
96 case CLIENT_IN_CHANNEL_STATE_FINAL:
97 str =
"CLIENT_IN_CHANNEL_STATE_FINAL";
105static const char* client_out_state_str(CLIENT_OUT_CHANNEL_STATE state)
108 const char* str =
"CLIENT_OUT_CHANNEL_STATE_UNKNOWN";
112 case CLIENT_OUT_CHANNEL_STATE_INITIAL:
113 str =
"CLIENT_OUT_CHANNEL_STATE_INITIAL";
116 case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
117 str =
"CLIENT_OUT_CHANNEL_STATE_CONNECTED";
120 case CLIENT_OUT_CHANNEL_STATE_SECURITY:
121 str =
"CLIENT_OUT_CHANNEL_STATE_SECURITY";
124 case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
125 str =
"CLIENT_OUT_CHANNEL_STATE_NEGOTIATED";
128 case CLIENT_OUT_CHANNEL_STATE_OPENED:
129 str =
"CLIENT_OUT_CHANNEL_STATE_OPENED";
132 case CLIENT_OUT_CHANNEL_STATE_OPENED_A6W:
133 str =
"CLIENT_OUT_CHANNEL_STATE_OPENED_A6W";
136 case CLIENT_OUT_CHANNEL_STATE_OPENED_A10W:
137 str =
"CLIENT_OUT_CHANNEL_STATE_OPENED_A10W";
140 case CLIENT_OUT_CHANNEL_STATE_OPENED_B3W:
141 str =
"CLIENT_OUT_CHANNEL_STATE_OPENED_B3W";
144 case CLIENT_OUT_CHANNEL_STATE_RECYCLED:
145 str =
"CLIENT_OUT_CHANNEL_STATE_RECYCLED";
148 case CLIENT_OUT_CHANNEL_STATE_FINAL:
149 str =
"CLIENT_OUT_CHANNEL_STATE_FINAL";
157const char* rpc_vc_state_str(VIRTUAL_CONNECTION_STATE state)
160 const char* str =
"VIRTUAL_CONNECTION_STATE_UNKNOWN";
164 case VIRTUAL_CONNECTION_STATE_INITIAL:
165 str =
"VIRTUAL_CONNECTION_STATE_INITIAL";
168 case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
169 str =
"VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT";
172 case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
173 str =
"VIRTUAL_CONNECTION_STATE_WAIT_A3W";
176 case VIRTUAL_CONNECTION_STATE_WAIT_C2:
177 str =
"VIRTUAL_CONNECTION_STATE_WAIT_C2";
180 case VIRTUAL_CONNECTION_STATE_OPENED:
181 str =
"VIRTUAL_CONNECTION_STATE_OPENED";
184 case VIRTUAL_CONNECTION_STATE_FINAL:
185 str =
"VIRTUAL_CONNECTION_STATE_FINAL";
220void rpc_pdu_header_print(wLog* log,
const rpcconn_hdr_t* header)
222 WINPR_ASSERT(header);
224 WLog_Print(log, WLOG_INFO,
"rpc_vers: %" PRIu8
"", header->common.rpc_vers);
225 WLog_Print(log, WLOG_INFO,
"rpc_vers_minor: %" PRIu8
"", header->common.rpc_vers_minor);
227 if (header->common.ptype > PTYPE_RTS)
228 WLog_Print(log, WLOG_INFO,
"ptype: %s (%" PRIu8
")",
"PTYPE_UNKNOWN", header->common.ptype);
230 WLog_Print(log, WLOG_INFO,
"ptype: %s (%" PRIu8
")", PTYPE_STRINGS[header->common.ptype],
231 header->common.ptype);
233 WLog_Print(log, WLOG_INFO,
"pfc_flags (0x%02" PRIX8
") = {", header->common.pfc_flags);
235 if (header->common.pfc_flags & PFC_FIRST_FRAG)
236 WLog_Print(log, WLOG_INFO,
" PFC_FIRST_FRAG");
238 if (header->common.pfc_flags & PFC_LAST_FRAG)
239 WLog_Print(log, WLOG_INFO,
" PFC_LAST_FRAG");
241 if (header->common.pfc_flags & PFC_PENDING_CANCEL)
242 WLog_Print(log, WLOG_INFO,
" PFC_PENDING_CANCEL");
244 if (header->common.pfc_flags & PFC_RESERVED_1)
245 WLog_Print(log, WLOG_INFO,
" PFC_RESERVED_1");
247 if (header->common.pfc_flags & PFC_CONC_MPX)
248 WLog_Print(log, WLOG_INFO,
" PFC_CONC_MPX");
250 if (header->common.pfc_flags & PFC_DID_NOT_EXECUTE)
251 WLog_Print(log, WLOG_INFO,
" PFC_DID_NOT_EXECUTE");
253 if (header->common.pfc_flags & PFC_OBJECT_UUID)
254 WLog_Print(log, WLOG_INFO,
" PFC_OBJECT_UUID");
256 WLog_Print(log, WLOG_INFO,
" }");
257 WLog_Print(log, WLOG_INFO,
258 "packed_drep[4]: %02" PRIX8
" %02" PRIX8
" %02" PRIX8
" %02" PRIX8
"",
259 header->common.packed_drep[0], header->common.packed_drep[1],
260 header->common.packed_drep[2], header->common.packed_drep[3]);
261 WLog_Print(log, WLOG_INFO,
"frag_length: %" PRIu16
"", header->common.frag_length);
262 WLog_Print(log, WLOG_INFO,
"auth_length: %" PRIu16
"", header->common.auth_length);
263 WLog_Print(log, WLOG_INFO,
"call_id: %" PRIu32
"", header->common.call_id);
265 if (header->common.ptype == PTYPE_RESPONSE)
267 WLog_Print(log, WLOG_INFO,
"alloc_hint: %" PRIu32
"", header->response.alloc_hint);
268 WLog_Print(log, WLOG_INFO,
"p_cont_id: %" PRIu16
"", header->response.p_cont_id);
269 WLog_Print(log, WLOG_INFO,
"cancel_count: %" PRIu8
"", header->response.cancel_count);
270 WLog_Print(log, WLOG_INFO,
"reserved: %" PRIu8
"", header->response.reserved);
279 header.rpc_vers = rpc->rpc_vers;
280 header.rpc_vers_minor = rpc->rpc_vers_minor;
281 header.packed_drep[0] = rpc->packed_drep[0];
282 header.packed_drep[1] = rpc->packed_drep[1];
283 header.packed_drep[2] = rpc->packed_drep[2];
284 header.packed_drep[3] = rpc->packed_drep[3];
288size_t rpc_offset_align(
size_t* offset,
size_t alignment)
292 *offset = (*offset + alignment - 1) & ~(alignment - 1);
297size_t rpc_offset_pad(
size_t* offset,
size_t pad)
378BOOL rpc_get_stub_data_info(rdpRpc* rpc,
const rpcconn_hdr_t* header,
size_t* poffset,
384 UINT32 frag_length = 0;
385 UINT32 auth_length = 0;
386 UINT32 auth_pad_length = 0;
387 UINT32 sec_trailer_offset = 0;
388 const rpc_sec_trailer* sec_trailer =
nullptr;
391 WINPR_ASSERT(header);
392 WINPR_ASSERT(poffset);
393 WINPR_ASSERT(length);
395 offset = RPC_COMMON_FIELDS_LENGTH;
397 switch (header->common.ptype)
401 rpc_offset_align(&offset, 8);
402 sec_trailer = &header->response.auth_verifier;
407 rpc_offset_align(&offset, 8);
408 sec_trailer = &header->request.auth_verifier;
416 WLog_Print(rpc->log, WLOG_ERROR,
"Unknown PTYPE: 0x%02" PRIX8
"", header->common.ptype);
420 frag_length = header->common.frag_length;
421 auth_length = header->common.auth_length;
427 used = offset + auth_length + 8ull;
430 auth_pad_length = sec_trailer->auth_pad_length;
431 used += sec_trailer->auth_pad_length;
434 if (frag_length < used)
440 sec_trailer_offset = frag_length - auth_length - 8;
448 if ((frag_length - (sec_trailer_offset + 8)) != auth_length)
450 WLog_Print(rpc->log, WLOG_ERROR,
451 "invalid auth_length: actual: %" PRIu32
", expected: %" PRIu32
"", auth_length,
452 (frag_length - (sec_trailer_offset + 8)));
455 *length = sec_trailer_offset - auth_pad_length - offset;
466 if (!channel || (length > INT32_MAX))
470 status = BIO_read(channel->tls->bio, Stream_Pointer(s), (INT32)length);
474 Stream_Seek(s, (
size_t)status);
478 if (BIO_should_retry(channel->tls->bio))
481 WLog_Print(channel->rpc->log, WLOG_ERROR,
"rpc_channel_read: Out of retries");
485SSIZE_T rpc_channel_write_int(
RpcChannel* channel,
const BYTE* data,
size_t length,
486 const char* file,
size_t line,
const char* fkt)
488 WINPR_ASSERT(channel);
489 WINPR_ASSERT(channel->rpc);
491 const DWORD level = WLOG_TRACE;
492 if (WLog_IsLevelActive(channel->rpc->log, level))
494 WLog_PrintTextMessage(channel->rpc->log, level, line, file, fkt,
495 "Sending [%s] %" PRIuz
" bytes", fkt, length);
498 return freerdp_tls_write_all(channel->tls, data, length);
501BOOL rpc_in_channel_transition_to_state(
RpcInChannel* inChannel, CLIENT_IN_CHANNEL_STATE state)
503 WINPR_ASSERT(inChannel);
504 inChannel->State = state;
505 WLog_Print(inChannel->common.rpc->log, WLOG_DEBUG,
"%s", client_in_state_str(state));
512 HttpContext* http =
nullptr;
513 rdpSettings* settings =
nullptr;
516 if (!client || !channel || !inout || !client->context || !client->context->settings)
519 settings = client->context->settings;
520 channel->auth = credssp_auth_new(client->context);
521 if (!rts_generate_cookie((BYTE*)&channel->Cookie))
523 channel->client = client;
528 channel->http = http_context_new();
533 http = channel->http;
536 if (!http_context_set_pragma(http,
"ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729"))
541 RPC_CSTR strguid =
nullptr;
542 RPC_STATUS rpcStatus = UuidToStringA(guid, &strguid);
544 if (rpcStatus != RPC_S_OK)
547 const BOOL rc = http_context_append_pragma(http,
"SessionId=%s", strguid);
548 RpcStringFreeA(&strguid);
554 if (!http_context_append_pragma(http,
"MinConnTimeout=%" PRIu32, timeout))
558 if (!http_context_set_rdg_correlation_id(http, guid) ||
559 !http_context_set_rdg_connection_id(http, guid))
564 if (!http_context_set_method(http, inout) ||
565 !http_context_set_uri(http,
"/rpc/rpcproxy.dll?localhost:3388") ||
566 !http_context_set_accept(http,
"application/rpc") ||
567 !http_context_set_cache_control(http,
"no-cache") ||
568 !http_context_set_connection(http,
"Keep-Alive") ||
569 !http_context_set_user_agent(http,
"MSRPC") ||
570 !http_context_set_host(http, settings->GatewayHostname))
576static int rpc_in_channel_init(rdpRpc* rpc,
RpcInChannel* inChannel,
const GUID* guid)
579 WINPR_ASSERT(inChannel);
581 inChannel->common.rpc = rpc;
582 inChannel->State = CLIENT_IN_CHANNEL_STATE_INITIAL;
583 inChannel->BytesSent = 0;
584 inChannel->SenderAvailableWindow = rpc->ReceiveWindow;
585 inChannel->PingOriginator.ConnectionTimeout = 30;
586 inChannel->PingOriginator.KeepAliveInterval = 0;
588 if (rpc_channel_rpch_init(rpc->client, &inChannel->common,
"RPC_IN_DATA", guid) < 0)
594static RpcInChannel* rpc_in_channel_new(rdpRpc* rpc,
const GUID* guid)
600 rpc_in_channel_init(rpc, inChannel, guid);
611 credssp_auth_free(channel->auth);
612 http_context_free(channel->http);
613 freerdp_tls_free(channel->tls);
617BOOL rpc_out_channel_transition_to_state(
RpcOutChannel* outChannel, CLIENT_OUT_CHANNEL_STATE state)
619 WINPR_ASSERT(outChannel);
621 outChannel->State = state;
622 WLog_Print(outChannel->common.rpc->log, WLOG_DEBUG,
"%s", client_out_state_str(state));
626static int rpc_out_channel_init(rdpRpc* rpc,
RpcOutChannel* outChannel,
const GUID* guid)
629 WINPR_ASSERT(outChannel);
631 outChannel->common.rpc = rpc;
632 outChannel->State = CLIENT_OUT_CHANNEL_STATE_INITIAL;
633 outChannel->BytesReceived = 0;
634 outChannel->ReceiverAvailableWindow = rpc->ReceiveWindow;
635 outChannel->ReceiveWindow = rpc->ReceiveWindow;
636 outChannel->ReceiveWindowSize = rpc->ReceiveWindow;
637 outChannel->AvailableWindowAdvertised = rpc->ReceiveWindow;
639 if (rpc_channel_rpch_init(rpc->client, &outChannel->common,
"RPC_OUT_DATA", guid) < 0)
645RpcOutChannel* rpc_out_channel_new(rdpRpc* rpc,
const GUID* guid)
651 rpc_out_channel_init(rpc, outChannel, guid);
658 VIRTUAL_CONNECTION_STATE state)
660 WINPR_ASSERT(connection);
662 connection->State = state;
663 WLog_Print(rpc->log, WLOG_DEBUG,
"%s", rpc_vc_state_str(state));
672 if (connection->DefaultInChannel)
673 rpc_channel_free(&connection->DefaultInChannel->common);
674 if (connection->NonDefaultInChannel)
675 rpc_channel_free(&connection->NonDefaultInChannel->common);
676 if (connection->DefaultOutChannel)
677 rpc_channel_free(&connection->DefaultOutChannel->common);
678 if (connection->NonDefaultOutChannel)
679 rpc_channel_free(&connection->NonDefaultOutChannel->common);
693 if (!rts_generate_cookie((BYTE*)&(connection->Cookie)))
695 if (!rts_generate_cookie((BYTE*)&(connection->AssociationGroupId)))
697 connection->State = VIRTUAL_CONNECTION_STATE_INITIAL;
699 connection->DefaultInChannel = rpc_in_channel_new(rpc, &connection->Cookie);
701 if (!connection->DefaultInChannel)
704 connection->DefaultOutChannel = rpc_out_channel_new(rpc, &connection->Cookie);
706 if (!connection->DefaultOutChannel)
711 rpc_virtual_connection_free(connection);
715static BOOL rpc_channel_tls_connect(
RpcChannel* channel, UINT32 timeout)
717 if (!channel || !channel->client || !channel->client->context ||
718 !channel->client->context->settings)
721 rdpContext* context = channel->client->context;
722 WINPR_ASSERT(context);
724 rdpSettings* settings = context->settings;
725 WINPR_ASSERT(settings);
730 rdpTransport* transport = freerdp_get_transport(context);
732 transport_connect_layer(transport, channel->client->host, channel->client->port, timeout);
737 BIO* layerBio = BIO_new(BIO_s_transport_layer());
740 transport_layer_free(layer);
743 BIO_set_data(layerBio, layer);
745 BIO* bufferedBio = BIO_new(BIO_s_buffered_socket());
748 BIO_free_all(layerBio);
752 bufferedBio = BIO_push(bufferedBio, layerBio);
754 if (!BIO_set_nonblock(bufferedBio, TRUE))
756 BIO_free_all(bufferedBio);
760 if (channel->client->isProxy)
762 WINPR_ASSERT(settings->GatewayPort <= UINT16_MAX);
763 if (!proxy_connect(context, bufferedBio, proxyUsername, proxyPassword,
764 settings->GatewayHostname, (UINT16)settings->GatewayPort))
766 BIO_free_all(bufferedBio);
771 channel->bio = bufferedBio;
772 rdpTls* tls = channel->tls = freerdp_tls_new(context);
777 tls->hostname = settings->GatewayHostname;
778 tls->port = WINPR_ASSERTING_INT_CAST(int32_t, MIN(UINT16_MAX, settings->GatewayPort));
779 tls->isGatewayTransport = TRUE;
780 int tlsStatus = freerdp_tls_connect(tls, bufferedBio);
786 freerdp_set_last_error_if_not(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
790 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
799static int rpc_in_channel_connect(
RpcInChannel* inChannel, UINT32 timeout)
801 rdpContext* context =
nullptr;
803 if (!inChannel || !inChannel->common.client || !inChannel->common.client->context)
806 context = inChannel->common.client->context;
810 if (!rpc_channel_tls_connect(&inChannel->common, timeout))
813 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_CONNECTED);
815 if (!rpc_ncacn_http_auth_init(context, &inChannel->common))
820 if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
822 WLog_Print(inChannel->common.rpc->log, WLOG_ERROR,
823 "rpc_ncacn_http_send_in_channel_request failure");
827 if (!rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_SECURITY))
833static int rpc_out_channel_connect(
RpcOutChannel* outChannel, UINT32 timeout)
835 rdpContext* context =
nullptr;
837 if (!outChannel || !outChannel->common.client || !outChannel->common.client->context)
840 context = outChannel->common.client->context;
844 if (!rpc_channel_tls_connect(&outChannel->common, timeout))
847 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
849 if (!rpc_ncacn_http_auth_init(context, &outChannel->common))
854 if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, FALSE))
856 WLog_Print(outChannel->common.rpc->log, WLOG_ERROR,
857 "rpc_ncacn_http_send_out_channel_request failure");
861 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
865int rpc_out_channel_replacement_connect(
RpcOutChannel* outChannel, uint32_t timeout)
867 rdpContext* context =
nullptr;
869 if (!outChannel || !outChannel->common.client || !outChannel->common.client->context)
872 context = outChannel->common.client->context;
876 if (!rpc_channel_tls_connect(&outChannel->common, timeout))
879 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
881 if (!rpc_ncacn_http_auth_init(context, (
RpcChannel*)outChannel))
886 if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, TRUE))
888 WLog_Print(outChannel->common.rpc->log, WLOG_ERROR,
889 "rpc_ncacn_http_send_out_channel_request failure");
893 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
897BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout)
902 rpc->VirtualConnection = rpc_virtual_connection_new(rpc);
904 if (!rpc->VirtualConnection)
907 connection = rpc->VirtualConnection;
908 inChannel = connection->DefaultInChannel;
909 outChannel = connection->DefaultOutChannel;
910 rpc_virtual_connection_transition_to_state(rpc, connection, VIRTUAL_CONNECTION_STATE_INITIAL);
912 if (rpc_in_channel_connect(inChannel, timeout) < 0)
915 if (rpc_out_channel_connect(outChannel, timeout) < 0)
921rdpRpc* rpc_new(rdpTransport* transport)
923 rdpContext* context = transport_get_context(transport);
924 rdpRpc* rpc =
nullptr;
926 WINPR_ASSERT(context);
928 rpc = (rdpRpc*)calloc(1,
sizeof(rdpRpc));
933 rpc->log = WLog_Get(TAG);
934 rpc->State = RPC_CLIENT_STATE_INITIAL;
935 rpc->transport = transport;
937 rpc->auth = credssp_auth_new(context);
944 rpc->StubFragCount = 0;
946 rpc->rpc_vers_minor = 0;
948 rpc->packed_drep[0] = 0x10;
949 rpc->packed_drep[1] = 0x00;
950 rpc->packed_drep[2] = 0x00;
951 rpc->packed_drep[3] = 0x00;
952 rpc->max_xmit_frag = 0x0FF8;
953 rpc->max_recv_frag = 0x0FF8;
954 rpc->ReceiveWindow = 0x00010000;
955 rpc->ChannelLifetime = 0x40000000;
956 rpc->KeepAliveInterval = 300000;
957 rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval;
958 rpc->CurrentKeepAliveTime = 0;
960 rpc->client = rpc_client_new(context, rpc->max_recv_frag);
967 WINPR_PRAGMA_DIAG_PUSH
968 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
970 WINPR_PRAGMA_DIAG_POP
974void rpc_free(rdpRpc* rpc)
978 rpc_client_free(rpc->client);
979 credssp_auth_free(rpc->auth);
980 rpc_virtual_connection_free(rpc->VirtualConnection);
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.