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"
52#define TAG FREERDP_TAG("core.gateway.rpc")
54static const char* PTYPE_STRINGS[] = {
"PTYPE_REQUEST",
"PTYPE_PING",
55 "PTYPE_RESPONSE",
"PTYPE_FAULT",
56 "PTYPE_WORKING",
"PTYPE_NOCALL",
57 "PTYPE_REJECT",
"PTYPE_ACK",
58 "PTYPE_CL_CANCEL",
"PTYPE_FACK",
59 "PTYPE_CANCEL_ACK",
"PTYPE_BIND",
60 "PTYPE_BIND_ACK",
"PTYPE_BIND_NAK",
61 "PTYPE_ALTER_CONTEXT",
"PTYPE_ALTER_CONTEXT_RESP",
62 "PTYPE_RPC_AUTH_3",
"PTYPE_SHUTDOWN",
63 "PTYPE_CO_CANCEL",
"PTYPE_ORPHANED",
66static const char* client_in_state_str(CLIENT_IN_CHANNEL_STATE state)
69 const char* str =
"CLIENT_IN_CHANNEL_STATE_UNKNOWN";
73 case CLIENT_IN_CHANNEL_STATE_INITIAL:
74 str =
"CLIENT_IN_CHANNEL_STATE_INITIAL";
77 case CLIENT_IN_CHANNEL_STATE_CONNECTED:
78 str =
"CLIENT_IN_CHANNEL_STATE_CONNECTED";
81 case CLIENT_IN_CHANNEL_STATE_SECURITY:
82 str =
"CLIENT_IN_CHANNEL_STATE_SECURITY";
85 case CLIENT_IN_CHANNEL_STATE_NEGOTIATED:
86 str =
"CLIENT_IN_CHANNEL_STATE_NEGOTIATED";
89 case CLIENT_IN_CHANNEL_STATE_OPENED:
90 str =
"CLIENT_IN_CHANNEL_STATE_OPENED";
93 case CLIENT_IN_CHANNEL_STATE_OPENED_A4W:
94 str =
"CLIENT_IN_CHANNEL_STATE_OPENED_A4W";
97 case CLIENT_IN_CHANNEL_STATE_FINAL:
98 str =
"CLIENT_IN_CHANNEL_STATE_FINAL";
106static const char* client_out_state_str(CLIENT_OUT_CHANNEL_STATE state)
109 const char* str =
"CLIENT_OUT_CHANNEL_STATE_UNKNOWN";
113 case CLIENT_OUT_CHANNEL_STATE_INITIAL:
114 str =
"CLIENT_OUT_CHANNEL_STATE_INITIAL";
117 case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
118 str =
"CLIENT_OUT_CHANNEL_STATE_CONNECTED";
121 case CLIENT_OUT_CHANNEL_STATE_SECURITY:
122 str =
"CLIENT_OUT_CHANNEL_STATE_SECURITY";
125 case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
126 str =
"CLIENT_OUT_CHANNEL_STATE_NEGOTIATED";
129 case CLIENT_OUT_CHANNEL_STATE_OPENED:
130 str =
"CLIENT_OUT_CHANNEL_STATE_OPENED";
133 case CLIENT_OUT_CHANNEL_STATE_OPENED_A6W:
134 str =
"CLIENT_OUT_CHANNEL_STATE_OPENED_A6W";
137 case CLIENT_OUT_CHANNEL_STATE_OPENED_A10W:
138 str =
"CLIENT_OUT_CHANNEL_STATE_OPENED_A10W";
141 case CLIENT_OUT_CHANNEL_STATE_OPENED_B3W:
142 str =
"CLIENT_OUT_CHANNEL_STATE_OPENED_B3W";
145 case CLIENT_OUT_CHANNEL_STATE_RECYCLED:
146 str =
"CLIENT_OUT_CHANNEL_STATE_RECYCLED";
149 case CLIENT_OUT_CHANNEL_STATE_FINAL:
150 str =
"CLIENT_OUT_CHANNEL_STATE_FINAL";
158const char* rpc_vc_state_str(VIRTUAL_CONNECTION_STATE state)
161 const char* str =
"VIRTUAL_CONNECTION_STATE_UNKNOWN";
165 case VIRTUAL_CONNECTION_STATE_INITIAL:
166 str =
"VIRTUAL_CONNECTION_STATE_INITIAL";
169 case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
170 str =
"VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT";
173 case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
174 str =
"VIRTUAL_CONNECTION_STATE_WAIT_A3W";
177 case VIRTUAL_CONNECTION_STATE_WAIT_C2:
178 str =
"VIRTUAL_CONNECTION_STATE_WAIT_C2";
181 case VIRTUAL_CONNECTION_STATE_OPENED:
182 str =
"VIRTUAL_CONNECTION_STATE_OPENED";
185 case VIRTUAL_CONNECTION_STATE_FINAL:
186 str =
"VIRTUAL_CONNECTION_STATE_FINAL";
221void rpc_pdu_header_print(wLog* log,
const rpcconn_hdr_t* header)
223 WINPR_ASSERT(header);
225 WLog_Print(log, WLOG_INFO,
"rpc_vers: %" PRIu8
"", header->common.rpc_vers);
226 WLog_Print(log, WLOG_INFO,
"rpc_vers_minor: %" PRIu8
"", header->common.rpc_vers_minor);
228 if (header->common.ptype > PTYPE_RTS)
229 WLog_Print(log, WLOG_INFO,
"ptype: %s (%" PRIu8
")",
"PTYPE_UNKNOWN", header->common.ptype);
231 WLog_Print(log, WLOG_INFO,
"ptype: %s (%" PRIu8
")", PTYPE_STRINGS[header->common.ptype],
232 header->common.ptype);
234 WLog_Print(log, WLOG_INFO,
"pfc_flags (0x%02" PRIX8
") = {", header->common.pfc_flags);
236 if (header->common.pfc_flags & PFC_FIRST_FRAG)
237 WLog_Print(log, WLOG_INFO,
" PFC_FIRST_FRAG");
239 if (header->common.pfc_flags & PFC_LAST_FRAG)
240 WLog_Print(log, WLOG_INFO,
" PFC_LAST_FRAG");
242 if (header->common.pfc_flags & PFC_PENDING_CANCEL)
243 WLog_Print(log, WLOG_INFO,
" PFC_PENDING_CANCEL");
245 if (header->common.pfc_flags & PFC_RESERVED_1)
246 WLog_Print(log, WLOG_INFO,
" PFC_RESERVED_1");
248 if (header->common.pfc_flags & PFC_CONC_MPX)
249 WLog_Print(log, WLOG_INFO,
" PFC_CONC_MPX");
251 if (header->common.pfc_flags & PFC_DID_NOT_EXECUTE)
252 WLog_Print(log, WLOG_INFO,
" PFC_DID_NOT_EXECUTE");
254 if (header->common.pfc_flags & PFC_OBJECT_UUID)
255 WLog_Print(log, WLOG_INFO,
" PFC_OBJECT_UUID");
257 WLog_Print(log, WLOG_INFO,
" }");
258 WLog_Print(log, WLOG_INFO,
259 "packed_drep[4]: %02" PRIX8
" %02" PRIX8
" %02" PRIX8
" %02" PRIX8
"",
260 header->common.packed_drep[0], header->common.packed_drep[1],
261 header->common.packed_drep[2], header->common.packed_drep[3]);
262 WLog_Print(log, WLOG_INFO,
"frag_length: %" PRIu16
"", header->common.frag_length);
263 WLog_Print(log, WLOG_INFO,
"auth_length: %" PRIu16
"", header->common.auth_length);
264 WLog_Print(log, WLOG_INFO,
"call_id: %" PRIu32
"", header->common.call_id);
266 if (header->common.ptype == PTYPE_RESPONSE)
268 WLog_Print(log, WLOG_INFO,
"alloc_hint: %" PRIu32
"", header->response.alloc_hint);
269 WLog_Print(log, WLOG_INFO,
"p_cont_id: %" PRIu16
"", header->response.p_cont_id);
270 WLog_Print(log, WLOG_INFO,
"cancel_count: %" PRIu8
"", header->response.cancel_count);
271 WLog_Print(log, WLOG_INFO,
"reserved: %" PRIu8
"", header->response.reserved);
280 header.rpc_vers = rpc->rpc_vers;
281 header.rpc_vers_minor = rpc->rpc_vers_minor;
282 header.packed_drep[0] = rpc->packed_drep[0];
283 header.packed_drep[1] = rpc->packed_drep[1];
284 header.packed_drep[2] = rpc->packed_drep[2];
285 header.packed_drep[3] = rpc->packed_drep[3];
289size_t rpc_offset_align(
size_t* offset,
size_t alignment)
293 *offset = (*offset + alignment - 1) & ~(alignment - 1);
298size_t rpc_offset_pad(
size_t* offset,
size_t pad)
379BOOL rpc_get_stub_data_info(rdpRpc* rpc,
const rpcconn_hdr_t* header,
size_t* poffset,
385 UINT32 frag_length = 0;
386 UINT32 auth_length = 0;
387 UINT32 auth_pad_length = 0;
388 UINT32 sec_trailer_offset = 0;
389 const rpc_sec_trailer* sec_trailer =
nullptr;
392 WINPR_ASSERT(header);
393 WINPR_ASSERT(poffset);
394 WINPR_ASSERT(length);
396 offset = RPC_COMMON_FIELDS_LENGTH;
398 switch (header->common.ptype)
402 rpc_offset_align(&offset, 8);
403 sec_trailer = &header->response.auth_verifier;
408 rpc_offset_align(&offset, 8);
409 sec_trailer = &header->request.auth_verifier;
417 WLog_Print(rpc->log, WLOG_ERROR,
"Unknown PTYPE: 0x%02" PRIX8
"", header->common.ptype);
421 frag_length = header->common.frag_length;
422 auth_length = header->common.auth_length;
428 used = offset + auth_length + 8ull;
431 auth_pad_length = sec_trailer->auth_pad_length;
432 used += sec_trailer->auth_pad_length;
435 if (frag_length < used)
441 sec_trailer_offset = frag_length - auth_length - 8;
449 if ((frag_length - (sec_trailer_offset + 8)) != auth_length)
451 WLog_Print(rpc->log, WLOG_ERROR,
452 "invalid auth_length: actual: %" PRIu32
", expected: %" PRIu32
"", auth_length,
453 (frag_length - (sec_trailer_offset + 8)));
456 *length = sec_trailer_offset - auth_pad_length - offset;
467 if (!channel || (length > INT32_MAX))
470 if (!Stream_EnsureRemainingCapacity(s, length))
474 status = BIO_read(channel->tls->bio, Stream_Pointer(s), (INT32)length);
478 Stream_Seek(s, (
size_t)status);
482 if (BIO_should_retry(channel->tls->bio))
485 WLog_Print(channel->rpc->log, WLOG_ERROR,
"rpc_channel_read: Out of retries");
489SSIZE_T rpc_channel_write_int(
RpcChannel* channel,
const BYTE* data,
size_t length,
490 const char* file,
size_t line,
const char* fkt)
492 WINPR_ASSERT(channel);
493 WINPR_ASSERT(channel->rpc);
495 const DWORD level = WLOG_TRACE;
496 if (WLog_IsLevelActive(channel->rpc->log, level))
498 WLog_PrintTextMessage(channel->rpc->log, level, line, file, fkt,
499 "Sending [%s] %" PRIuz
" bytes", fkt, length);
502 return freerdp_tls_write_all(channel->tls, data, length);
505BOOL rpc_in_channel_transition_to_state(
RpcInChannel* inChannel, CLIENT_IN_CHANNEL_STATE state)
507 WINPR_ASSERT(inChannel);
508 inChannel->State = state;
509 WLog_Print(inChannel->common.rpc->log, WLOG_DEBUG,
"%s", client_in_state_str(state));
516 HttpContext* http =
nullptr;
517 rdpSettings* settings =
nullptr;
520 if (!client || !channel || !inout || !client->context || !client->context->settings)
523 settings = client->context->settings;
524 channel->auth = credssp_auth_new(client->context);
525 if (UuidCreate(&channel->Cookie) != RPC_S_OK)
527 channel->client = client;
532 channel->http = http_context_new();
537 http = channel->http;
540 if (!http_context_set_pragma(http,
"ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729"))
545 char buffer[64] = WINPR_C_ARRAY_INIT;
546 const BOOL rc = http_context_append_pragma(http,
"SessionId=%s",
547 guid2str(guid, buffer,
sizeof(buffer)));
553 if (!http_context_append_pragma(http,
"MinConnTimeout=%" PRIu32, timeout))
557 if (!http_context_set_rdg_correlation_id(http, guid) ||
558 !http_context_set_rdg_connection_id(http, guid))
563 if (!http_context_set_method(http, inout) ||
564 !http_context_set_uri(http,
"/rpc/rpcproxy.dll?localhost:3388") ||
565 !http_context_set_accept(http,
"application/rpc") ||
566 !http_context_set_cache_control(http,
"no-cache") ||
567 !http_context_set_connection(http,
"Keep-Alive") ||
568 !http_context_set_user_agent(http,
"MSRPC") ||
569 !http_context_set_host(http, settings->GatewayHostname))
575static int rpc_in_channel_init(rdpRpc* rpc,
RpcInChannel* inChannel,
const GUID* guid)
578 WINPR_ASSERT(inChannel);
580 inChannel->common.rpc = rpc;
581 inChannel->State = CLIENT_IN_CHANNEL_STATE_INITIAL;
582 inChannel->BytesSent = 0;
583 inChannel->SenderAvailableWindow = rpc->ReceiveWindow;
584 inChannel->PingOriginator.ConnectionTimeout = 30;
585 inChannel->PingOriginator.KeepAliveInterval = 0;
587 if (rpc_channel_rpch_init(rpc->client, &inChannel->common,
"RPC_IN_DATA", guid) < 0)
593static RpcInChannel* rpc_in_channel_new(rdpRpc* rpc,
const GUID* guid)
599 rpc_in_channel_init(rpc, inChannel, guid);
610 credssp_auth_free(channel->auth);
611 http_context_free(channel->http);
612 freerdp_tls_free(channel->tls);
616BOOL rpc_out_channel_transition_to_state(
RpcOutChannel* outChannel, CLIENT_OUT_CHANNEL_STATE state)
618 WINPR_ASSERT(outChannel);
620 outChannel->State = state;
621 WLog_Print(outChannel->common.rpc->log, WLOG_DEBUG,
"%s", client_out_state_str(state));
625static int rpc_out_channel_init(rdpRpc* rpc,
RpcOutChannel* outChannel,
const GUID* guid)
628 WINPR_ASSERT(outChannel);
630 outChannel->common.rpc = rpc;
631 outChannel->State = CLIENT_OUT_CHANNEL_STATE_INITIAL;
632 outChannel->BytesReceived = 0;
633 outChannel->ReceiverAvailableWindow = rpc->ReceiveWindow;
634 outChannel->ReceiveWindow = rpc->ReceiveWindow;
635 outChannel->ReceiveWindowSize = rpc->ReceiveWindow;
636 outChannel->AvailableWindowAdvertised = rpc->ReceiveWindow;
638 if (rpc_channel_rpch_init(rpc->client, &outChannel->common,
"RPC_OUT_DATA", guid) < 0)
644RpcOutChannel* rpc_out_channel_new(rdpRpc* rpc,
const GUID* guid)
650 rpc_out_channel_init(rpc, outChannel, guid);
657 VIRTUAL_CONNECTION_STATE state)
659 WINPR_ASSERT(connection);
661 connection->State = state;
662 WLog_Print(rpc->log, WLOG_DEBUG,
"%s", rpc_vc_state_str(state));
671 if (connection->DefaultInChannel)
672 rpc_channel_free(&connection->DefaultInChannel->common);
673 if (connection->NonDefaultInChannel)
674 rpc_channel_free(&connection->NonDefaultInChannel->common);
675 if (connection->DefaultOutChannel)
676 rpc_channel_free(&connection->DefaultOutChannel->common);
677 if (connection->NonDefaultOutChannel)
678 rpc_channel_free(&connection->NonDefaultOutChannel->common);
692 if (UuidCreate(&connection->Cookie) != RPC_S_OK)
694 if (UuidCreate(&connection->AssociationGroupId) != RPC_S_OK)
696 connection->State = VIRTUAL_CONNECTION_STATE_INITIAL;
698 connection->DefaultInChannel = rpc_in_channel_new(rpc, &connection->Cookie);
700 if (!connection->DefaultInChannel)
703 connection->DefaultOutChannel = rpc_out_channel_new(rpc, &connection->Cookie);
705 if (!connection->DefaultOutChannel)
710 rpc_virtual_connection_free(connection);
714static BOOL rpc_channel_tls_connect(
RpcChannel* channel, UINT32 timeout)
716 if (!channel || !channel->client || !channel->client->context ||
717 !channel->client->context->settings)
720 rdpContext* context = channel->client->context;
721 WINPR_ASSERT(context);
723 rdpSettings* settings = context->settings;
724 WINPR_ASSERT(settings);
729 rdpTransport* transport = freerdp_get_transport(context);
731 transport_connect_layer(transport, channel->client->host, channel->client->port, timeout);
736 BIO* layerBio = BIO_new(BIO_s_transport_layer());
739 transport_layer_free(layer);
742 BIO_set_data(layerBio, layer);
744 BIO* bufferedBio = BIO_new(BIO_s_buffered_socket());
747 BIO_free_all(layerBio);
751 bufferedBio = BIO_push(bufferedBio, layerBio);
753 if (!BIO_set_nonblock(bufferedBio, TRUE))
755 BIO_free_all(bufferedBio);
759 if (channel->client->isProxy)
761 WINPR_ASSERT(settings->GatewayPort <= UINT16_MAX);
762 if (!proxy_connect(context, bufferedBio, proxyUsername, proxyPassword,
763 settings->GatewayHostname, (UINT16)settings->GatewayPort))
765 BIO_free_all(bufferedBio);
770 channel->bio = bufferedBio;
771 rdpTls* tls = channel->tls = freerdp_tls_new(context);
776 tls->hostname = settings->GatewayHostname;
777 tls->port = WINPR_ASSERTING_INT_CAST(int32_t, MIN(UINT16_MAX, settings->GatewayPort));
778 tls->isGatewayTransport = TRUE;
779 int tlsStatus = freerdp_tls_connect(tls, bufferedBio);
785 freerdp_set_last_error_if_not(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
789 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
798static int rpc_in_channel_connect(
RpcInChannel* inChannel, UINT32 timeout)
800 rdpContext* context =
nullptr;
802 if (!inChannel || !inChannel->common.client || !inChannel->common.client->context)
805 context = inChannel->common.client->context;
809 if (!rpc_channel_tls_connect(&inChannel->common, timeout))
812 rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_CONNECTED);
814 if (!rpc_ncacn_http_auth_init(context, &inChannel->common))
819 if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
821 WLog_Print(inChannel->common.rpc->log, WLOG_ERROR,
822 "rpc_ncacn_http_send_in_channel_request failure");
826 if (!rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_SECURITY))
832static int rpc_out_channel_connect(
RpcOutChannel* outChannel, UINT32 timeout)
834 rdpContext* context =
nullptr;
836 if (!outChannel || !outChannel->common.client || !outChannel->common.client->context)
839 context = outChannel->common.client->context;
843 if (!rpc_channel_tls_connect(&outChannel->common, timeout))
846 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
848 if (!rpc_ncacn_http_auth_init(context, &outChannel->common))
853 if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, FALSE))
855 WLog_Print(outChannel->common.rpc->log, WLOG_ERROR,
856 "rpc_ncacn_http_send_out_channel_request failure");
860 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
864int rpc_out_channel_replacement_connect(
RpcOutChannel* outChannel, uint32_t timeout)
866 rdpContext* context =
nullptr;
868 if (!outChannel || !outChannel->common.client || !outChannel->common.client->context)
871 context = outChannel->common.client->context;
875 if (!rpc_channel_tls_connect(&outChannel->common, timeout))
878 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
880 if (!rpc_ncacn_http_auth_init(context, (
RpcChannel*)outChannel))
885 if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, TRUE))
887 WLog_Print(outChannel->common.rpc->log, WLOG_ERROR,
888 "rpc_ncacn_http_send_out_channel_request failure");
892 rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
896BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout)
901 rpc->VirtualConnection = rpc_virtual_connection_new(rpc);
903 if (!rpc->VirtualConnection)
906 connection = rpc->VirtualConnection;
907 inChannel = connection->DefaultInChannel;
908 outChannel = connection->DefaultOutChannel;
909 rpc_virtual_connection_transition_to_state(rpc, connection, VIRTUAL_CONNECTION_STATE_INITIAL);
911 if (rpc_in_channel_connect(inChannel, timeout) < 0)
914 if (rpc_out_channel_connect(outChannel, timeout) < 0)
920rdpRpc* rpc_new(rdpTransport* transport)
922 rdpContext* context = transport_get_context(transport);
923 rdpRpc* rpc =
nullptr;
925 WINPR_ASSERT(context);
927 rpc = (rdpRpc*)calloc(1,
sizeof(rdpRpc));
932 rpc->log = WLog_Get(TAG);
933 rpc->State = RPC_CLIENT_STATE_INITIAL;
934 rpc->transport = transport;
936 rpc->auth = credssp_auth_new(context);
943 rpc->StubFragCount = 0;
945 rpc->rpc_vers_minor = 0;
947 rpc->packed_drep[0] = 0x10;
948 rpc->packed_drep[1] = 0x00;
949 rpc->packed_drep[2] = 0x00;
950 rpc->packed_drep[3] = 0x00;
951 rpc->max_xmit_frag = 0x0FF8;
952 rpc->max_recv_frag = 0x0FF8;
953 rpc->ReceiveWindow = 0x00010000;
954 rpc->ChannelLifetime = 0x40000000;
955 rpc->KeepAliveInterval = 300000;
956 rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval;
957 rpc->CurrentKeepAliveTime = 0;
959 rpc->client = rpc_client_new(context, rpc->max_recv_frag);
966 WINPR_PRAGMA_DIAG_PUSH
967 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
969 WINPR_PRAGMA_DIAG_POP
973void rpc_free(rdpRpc* rpc)
977 rpc_client_free(rpc->client);
978 credssp_auth_free(rpc->auth);
979 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.