25#include <winpr/assert.h>
26#include <winpr/cast.h>
28#include <freerdp/config.h>
30#include <freerdp/freerdp.h>
31#include <freerdp/gdi/gdi.h>
32#include <freerdp/client/cmdline.h>
34#include <freerdp/server/proxy/proxy_log.h>
35#include <freerdp/channels/drdynvc.h>
36#include <freerdp/channels/encomsp.h>
37#include <freerdp/channels/rdpdr.h>
38#include <freerdp/channels/rdpsnd.h>
39#include <freerdp/channels/cliprdr.h>
40#include <freerdp/channels/channels.h>
44#include "pf_channel.h"
45#include <freerdp/server/proxy/proxy_context.h>
48#include <freerdp/server/proxy/proxy_config.h>
49#include "proxy_modules.h"
51#include "channels/pf_channel_rdpdr.h"
52#include "channels/pf_channel_smartcard.h"
54#define TAG PROXY_TAG("client")
56static void channel_data_free(
void* obj);
59static BOOL proxy_server_reactivate(rdpContext* ps,
const rdpContext* pc)
64 if (!pf_context_copy_settings(ps->settings, pc->settings))
71 WINPR_ASSERT(ps->update);
72 return (ps->update->DesktopResize(ps));
75static void pf_client_on_error_info(
void* ctx,
const ErrorInfoEventArgs* e)
77 pClientContext* pc = (pClientContext*)ctx;
79 WINPR_ASSERT(pc->pdata);
82 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
85 if (e->code == ERRINFO_NONE)
88 PROXY_LOG_WARN(TAG, pc,
"received ErrorInfo PDU. code=0x%08" PRIu32
", message: %s", e->code,
89 freerdp_get_error_info_string(e->code));
92 freerdp_set_error_info(ps->context.rdp, e->code);
93 if (!freerdp_send_error_info(ps->context.rdp))
95 PROXY_LOG_WARN(TAG, pc,
"[fail] reply ErrorInfo PDU. code=0x%08" PRIu32
", message: %s",
96 e->code, freerdp_get_error_info_string(e->code));
100static void pf_client_on_activated(WINPR_ATTR_UNUSED
void* ctx,
101 WINPR_ATTR_UNUSED
const ActivatedEventArgs* e)
106static BOOL pf_client_load_rdpsnd(pClientContext* pc)
108 rdpContext* context = (rdpContext*)pc;
111 WINPR_ASSERT(pc->pdata);
116 if (!freerdp_static_channel_collection_find(context->settings, RDPSND_CHANNEL_NAME))
118 const char* params[2] = { RDPSND_CHANNEL_NAME,
"sys:fake" };
120 if (!freerdp_client_add_static_channel(context->settings, ARRAYSIZE(params), params))
128static BOOL pf_client_use_peer_load_balance_info(pClientContext* pc)
131 WINPR_ASSERT(pc->pdata);
133 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
135 rdpSettings* settings = pc->cctx.context.settings;
136 WINPR_ASSERT(settings);
138 DWORD lb_info_len = 0;
139 const char* lb_info = freerdp_nego_get_routing_token(&ps->context, &lb_info_len);
148static BOOL str_is_empty(
const char* str)
152 if (strlen(str) == 0)
158static BOOL pf_client_use_proxy_smartcard_auth(
const rdpSettings* settings)
167 if (str_is_empty(key))
170 if (str_is_empty(cert))
177static BOOL pf_client_pre_connect(freerdp* instance)
179 WINPR_ASSERT(instance);
180 pClientContext* pc = (pClientContext*)instance->context;
182 WINPR_ASSERT(pc->pdata);
184 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
186 WINPR_ASSERT(ps->pdata);
188 const proxyConfig* config = ps->pdata->config;
189 WINPR_ASSERT(config);
191 rdpSettings* settings = instance->context->settings;
192 WINPR_ASSERT(settings);
205 ZeroMemory(OrderSupport, 32);
207 if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, DRDYNVC_SVC_CHANNEL_NAME))
221 config->DeviceRedirection) ||
225 if (config->RemoteApp)
227 if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, RAIL_SVC_CHANNEL_NAME))
234 if (config->DeviceRedirection)
236 if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, RDPDR_SVC_CHANNEL_NAME))
247 config->DisplayControl))
250 if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, ENCOMSP_SVC_CHANNEL_NAME))
256 if (config->Clipboard)
258 if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, CLIPRDR_SVC_CHANNEL_NAME))
268 if (PubSub_SubscribeErrorInfo(instance->context->pubSub, pf_client_on_error_info) < 0)
270 if (PubSub_SubscribeActivated(instance->context->pubSub, pf_client_on_activated) < 0)
272 if (!pf_client_use_peer_load_balance_info(pc))
275 return pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_PRE_CONNECT, pc->pdata, pc);
287static BOOL updateBackIdFn(WINPR_ATTR_UNUSED
const void* key,
void* value,
void* arg)
289 pServerStaticChannelContext* current = (pServerStaticChannelContext*)value;
290 UpdateBackIdArgs* updateArgs = (UpdateBackIdArgs*)arg;
292 if (strcmp(updateArgs->name, current->channel_name) != 0)
295 current->back_channel_id = updateArgs->backId;
296 if (!HashTable_Insert(updateArgs->ps->channelsByBackId, ¤t->back_channel_id, current))
298 WLog_ERR(TAG,
"error inserting channel in channelsByBackId table");
304static BOOL pf_client_update_back_id(pServerContext* ps,
const char* name, UINT32 backId)
306 UpdateBackIdArgs res = { ps, name, backId };
308 return HashTable_Foreach(ps->channelsByFrontId, updateBackIdFn, &res) == FALSE;
312static BOOL pf_client_load_channels(freerdp* instance)
314 WINPR_ASSERT(instance);
316 pClientContext* pc = (pClientContext*)instance->context;
318 WINPR_ASSERT(pc->pdata);
320 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
322 WINPR_ASSERT(ps->pdata);
324 const proxyConfig* config = ps->pdata->config;
325 WINPR_ASSERT(config);
327 rdpSettings* settings = instance->context->settings;
328 WINPR_ASSERT(settings);
333 PROXY_LOG_INFO(TAG, pc,
"Loading addins");
335 if (!pf_client_load_rdpsnd(pc))
337 PROXY_LOG_ERR(TAG, pc,
"Failed to load rdpsnd client");
341 if (!pf_utils_is_passthrough(config))
343 if (!freerdp_client_load_addins(instance->context->channels, settings))
345 PROXY_LOG_ERR(TAG, pc,
"Failed to load addins");
351 if (!pf_channel_rdpdr_client_new(pc))
353#if defined(WITH_PROXY_EMULATE_SMARTCARD)
354 if (!pf_channel_smartcard_client_new(pc))
358 if (!freerdp_channels_from_mcs(settings, &ps->context))
364 settings, FreeRDP_ChannelDefArray, 0);
366 UINT32
id = MCS_GLOBAL_CHANNEL_ID + 1;
368 WINPR_ASSERT(channels || (size == 0));
376 dev.channel_name = cur->name;
377 dev.flags = cur->options;
380 if (!pf_modules_run_filter(pc->pdata->module,
381 FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE, pc->pdata,
384 const size_t s = size - MIN(size, x + 1);
390 if (!pf_client_update_back_id(ps, cur->name,
id++))
392 WLog_ERR(TAG,
"unable to update backid for channel %s", cur->name);
403 return pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_LOAD_CHANNELS, pc->pdata, pc);
407static BOOL pf_client_receive_channel_data_hook(freerdp* instance, UINT16 channelId,
408 const BYTE* xdata,
size_t xsize, UINT32 flags,
411 UINT64 channelId64 = channelId;
413 WINPR_ASSERT(instance);
414 WINPR_ASSERT(xdata || (xsize == 0));
416 pClientContext* pc = (pClientContext*)instance->context;
418 WINPR_ASSERT(pc->pdata);
420 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
423 proxyData* pdata = ps->pdata;
426 pServerStaticChannelContext* channel =
427 HashTable_GetItemValue(ps->channelsByBackId, &channelId64);
431 WINPR_ASSERT(channel->onBackData);
432 switch (channel->onBackData(pdata, channel, xdata, xsize, flags, totalSize))
434 case PF_CHANNEL_RESULT_PASS:
438 if (channel->front_channel_id == 0)
441 return ps->context.peer->SendChannelPacket(
442 ps->context.peer, WINPR_ASSERTING_INT_CAST(UINT16, channel->front_channel_id),
443 totalSize, flags, xdata, xsize);
444 case PF_CHANNEL_RESULT_DROP:
446 case PF_CHANNEL_RESULT_ERROR:
453static BOOL pf_client_on_server_heartbeat(freerdp* instance, BYTE period, BYTE count1, BYTE count2)
455 WINPR_ASSERT(instance);
456 pClientContext* pc = (pClientContext*)instance->context;
458 WINPR_ASSERT(pc->pdata);
460 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
463 return freerdp_heartbeat_send_heartbeat_pdu(ps->context.peer, period, count1, count2);
472 return Queue_Enqueue(pc->cached_server_channel_data, ev);
476static BOOL sendQueuedChannelData(pClientContext* pc)
486 Queue_Lock(pc->cached_server_channel_data);
487 while (rc && (ev = Queue_Dequeue(pc->cached_server_channel_data)))
489 UINT16 channelId = 0;
490 WINPR_ASSERT(pc->cctx.context.instance);
493 freerdp_channels_get_id_by_name(pc->cctx.context.instance, ev->channel_name);
495 if ((channelId == 0) || (channelId == UINT16_MAX))
499 WINPR_ASSERT(pc->cctx.context.instance->SendChannelPacket);
500 rc = pc->cctx.context.instance->SendChannelPacket(
501 pc->cctx.context.instance, channelId, ev->total_size, ev->flags, ev->data,
504 channel_data_free(ev);
507 Queue_Unlock(pc->cached_server_channel_data);
523static BOOL pf_client_post_connect(freerdp* instance)
525 WINPR_ASSERT(instance);
526 rdpContext* context = instance->context;
527 WINPR_ASSERT(context);
528 rdpUpdate* update = context->update;
529 WINPR_ASSERT(update);
530 pClientContext* pc = (pClientContext*)context;
532 WINPR_ASSERT(pc->pdata);
534 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
537 if (!pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_POST_CONNECT, pc->pdata, pc))
540 if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
545 pf_client_register_update_callbacks(update);
548 pc->client_receive_channel_data_original = instance->ReceiveChannelData;
549 instance->ReceiveChannelData = pf_client_receive_channel_data_hook;
551 instance->heartbeat->ServerHeartbeat = pf_client_on_server_heartbeat;
553 pc->connected = TRUE;
556 if (!sendQueuedChannelData(pc))
564 return proxy_server_reactivate(&ps->context, context);
570static void pf_client_post_disconnect(freerdp* instance)
572 pClientContext* pc =
nullptr;
573 proxyData* pdata =
nullptr;
578 if (!instance->context)
581 pc = (pClientContext*)instance->context;
586#if defined(WITH_PROXY_EMULATE_SMARTCARD)
587 pf_channel_smartcard_client_free(pc);
590 pf_channel_rdpdr_client_free(pc);
592 pc->connected = FALSE;
593 (void)pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_POST_DISCONNECT, pc->pdata, pc);
595 PubSub_UnsubscribeErrorInfo(instance->context->pubSub, pf_client_on_error_info);
599 if (!pc->allow_next_conn_failure)
600 proxy_data_abort_connect(pdata);
604static BOOL pf_client_redirect(freerdp* instance)
609 if (!instance->context)
612 pClientContext* pc = (pClientContext*)instance->context;
615#if defined(WITH_PROXY_EMULATE_SMARTCARD)
616 pf_channel_smartcard_client_reset(pc);
618 pf_channel_rdpdr_client_reset(pc);
620 return pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_REDIRECT, pc->pdata, pc);
630static BOOL pf_client_should_retry_without_nla(pClientContext* pc)
632 rdpSettings* settings =
nullptr;
633 const proxyConfig* config =
nullptr;
636 WINPR_ASSERT(pc->pdata);
637 settings = pc->cctx.context.settings;
638 WINPR_ASSERT(settings);
639 config = pc->pdata->config;
640 WINPR_ASSERT(config);
642 if (!config->ClientAllowFallbackToTls ||
647 return config->ClientTlsSecurity || config->ClientRdpSecurity;
651static BOOL pf_client_set_security_settings(pClientContext* pc)
654 WINPR_ASSERT(pc->pdata);
655 rdpSettings* settings = pc->cctx.context.settings;
656 WINPR_ASSERT(settings);
657 const proxyConfig* config = pc->pdata->config;
658 WINPR_ASSERT(config);
669 if (pf_client_use_proxy_smartcard_auth(settings))
686static BOOL pf_client_connect_without_nla(pClientContext* pc)
688 freerdp* instance =
nullptr;
689 rdpSettings* settings =
nullptr;
692 instance = pc->cctx.context.instance;
693 WINPR_ASSERT(instance);
695 if (!freerdp_context_reset(instance))
698 settings = pc->cctx.context.settings;
699 WINPR_ASSERT(settings);
713 pc->allow_next_conn_failure = FALSE;
714 return freerdp_connect(instance);
718static BOOL pf_client_connect(freerdp* instance)
720 pClientContext* pc =
nullptr;
721 rdpSettings* settings =
nullptr;
725 WINPR_ASSERT(instance);
726 pc = (pClientContext*)instance->context;
728 settings = instance->context->settings;
729 WINPR_ASSERT(settings);
731 if (!pf_client_set_security_settings(pc))
734 if (pf_client_should_retry_without_nla(pc))
735 retry = pc->allow_next_conn_failure = TRUE;
737 PROXY_LOG_INFO(TAG, pc,
"connecting using client info: Username: %s, Domain: %s",
740 PROXY_LOG_INFO(TAG, pc,
"connecting using security settings: rdp=%d, tls=%d, nla=%d, ext=%d",
746 if (!freerdp_connect(instance))
748 if (!pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_LOGIN_FAILURE, pc->pdata, pc))
754 PROXY_LOG_ERR(TAG, pc,
"failed to connect with NLA. retrying to connect without NLA");
755 if (!pf_client_connect_without_nla(pc))
757 PROXY_LOG_ERR(TAG, pc,
"pf_client_connect_without_nla failed!");
764 pc->allow_next_conn_failure = FALSE;
774static DWORD WINAPI pf_client_thread_proc(pClientContext* pc)
776 freerdp* instance =
nullptr;
777 proxyData* pdata =
nullptr;
780 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
784 instance = pc->cctx.context.instance;
785 WINPR_ASSERT(instance);
796 handles[nCount++] = pdata->abort_event;
798 if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_CLIENT_INIT_CONNECT, pdata, pc))
800 proxy_data_abort_connect(pdata);
804 if (!pf_client_connect(instance))
806 proxy_data_abort_connect(pdata);
809 handles[nCount++] = Queue_Event(pc->cached_server_channel_data);
811 while (!freerdp_shall_disconnect_context(instance->context))
813 UINT32 tmp = freerdp_get_event_handles(instance->context, &handles[nCount],
814 ARRAYSIZE(handles) - nCount);
818 PROXY_LOG_ERR(TAG, pc,
"freerdp_get_event_handles failed!");
822 status = WaitForMultipleObjects(nCount + tmp, handles, FALSE, INFINITE);
824 if (status == WAIT_FAILED)
826 WLog_ERR(TAG,
"WaitForMultipleObjects failed with %" PRIu32
"", status);
831 if (status == WAIT_OBJECT_0)
834 if (freerdp_shall_disconnect_context(instance->context))
837 if (proxy_data_shall_disconnect(pdata))
840 if (!freerdp_check_event_handles(instance->context))
842 if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS)
843 WLog_ERR(TAG,
"Failed to check FreeRDP event handles");
847 if (!sendQueuedChannelData(pc))
851 freerdp_disconnect(instance);
854 (void)pf_modules_run_hook(pdata->module, HOOK_TYPE_CLIENT_UNINIT_CONNECT, pdata, pc);
860static int pf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
862 const char* str_data = freerdp_get_logon_error_info_data(data);
863 const char* str_type = freerdp_get_logon_error_info_type(type);
865 if (!instance || !instance->context)
868 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
872static void pf_client_context_free(freerdp* instance, rdpContext* context)
874 pClientContext* pc = (pClientContext*)context;
875 WINPR_UNUSED(instance);
880 pc->sendChannelData =
nullptr;
881 Queue_Free(pc->cached_server_channel_data);
882 Stream_Free(pc->remote_pem, TRUE);
883 free(pc->remote_hostname);
884 free(pc->computerName.v);
885 HashTable_Free(pc->interceptContextMap);
889static BOOL pf_client_try_compare_hash(rdpCertificate* cert,
const char* hash,
890 const char* TargetCertHash, BOOL useSeparator)
893 WINPR_ASSERT(TargetCertHash);
896 char* got = freerdp_certificate_get_fingerprint_by_hash_ex(cert, hash, useSeparator);
898 rc = _stricmp(TargetCertHash, got) == 0;
904WINPR_ATTR_MALLOC(freerdp_certificate_free, 1)
905static rdpCertificate* fromPem(const
char* policy, pClientContext* pc, const
char* hostname,
906 UINT16 port, const BYTE* data,
size_t length)
908 if (!data || (length == 0))
910 PROXY_LOG_WARN(TAG, pc,
"certificate policy %s: empty PEM, deny access to %s:%" PRIu16,
911 policy, hostname, port);
914 char* copy = strndup((
const char*)data, length);
917 PROXY_LOG_WARN(TAG, pc,
918 "certificate policy %s: remote PEM clone failed, deny access to %s:%" PRIu16,
919 policy, hostname, port);
922 rdpCertificate* cert = freerdp_certificate_new_from_pem(copy);
923 winpr_znfree(copy, length);
927 TAG, pc,
"certificate policy %s: remote PEM parsing failed, deny access to %s:%" PRIu16,
928 policy, hostname, port);
934static int pf_client_verify_strict(pClientContext* pc,
const proxyConfig* config,
935 const char* hostname, UINT16 port,
const BYTE* data,
936 size_t length, BOOL hostMustMatch)
939 WINPR_ASSERT(config);
944 const size_t len = strlen(policy);
945 for (
size_t x = 0; x < len; x++)
946 policy[x] = WINPR_ASSERTING_INT_CAST(
char, toupper(policy[x]));
948 rdpCertificate* cert = fromPem(policy, pc, hostname, port, data, length);
954 BOOL rc = freerdp_certificate_verify(cert, config->CertStorePath);
955 if (rc && hostMustMatch)
959 hostlen = strlen(hostname);
960 rc = freerdp_certificate_matches_hostname(cert, hostname, hostlen);
962 PROXY_LOG_WARN(TAG, pc,
963 "certificate policy %s: hostname mismatch, deny access to %s:%" PRIu16,
964 policy, hostname, port);
967 PROXY_LOG_WARN(TAG, pc,
968 "certificate policy %s: certificate not valid, deny access to %s:%" PRIu16,
969 policy, hostname, port);
970 freerdp_certificate_free(cert);
976static int pf_client_verify_pinned(pClientContext* pc,
const char* hostname, UINT16 port,
977 const BYTE* data,
size_t length)
981 WINPR_ASSERT(pc->pdata);
983 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
985 WINPR_ASSERT(ps->pdata);
986 const proxyConfig* config = ps->pdata->config;
987 WINPR_ASSERT(config);
989 rdpCertificate* cert = fromPem(
"PINNED", pc, hostname, port, data, length);
993 if (config->TargetCertPEM && (config->TargetCertPEMLength > 0))
995 rdpCertificate* tcert = freerdp_certificate_new_from_pem(config->TargetCertPEM);
998 char* remote = freerdp_certificate_get_fingerprint_by_hash(cert,
"sha512");
999 char* target = freerdp_certificate_get_fingerprint_by_hash(tcert,
"sha512");
1000 if (remote && target)
1002 const BOOL match = strcmp(remote, target) == 0;
1006 "certificate policy PINNED: PEM mismatch, deny access to %s:%" PRIu16,
1011 "certificate policy PINNED: PEM matches, allow access to %s:%" PRIu16,
1017 PROXY_LOG_WARN(TAG, pc,
1018 "certificate policy PINNED: PEM hashing failed (remote=%p, "
1019 "target=%p), deny accessto %s:%" PRIu16,
1020 (
void*)remote, (
void*)target, hostname, port);
1022 winpr_zfree(remote);
1023 winpr_zfree(target);
1025 freerdp_certificate_free(tcert);
1031 "certificate policy PINNED: config PEM parsing failed, deny access to %s:%" PRIu16,
1036 else if (config->TargetCertHash)
1038 char* str = _strdup(config->TargetCertHash);
1041 char* hash = strchr(str,
':');
1045 BOOL success = pf_client_try_compare_hash(cert, str, hash, FALSE);
1047 success = pf_client_try_compare_hash(cert, str, hash, TRUE);
1054 PROXY_LOG_INFO(TAG, pc,
1055 "certificate policy PINNED: hash matches, allow access to %s:%" PRIu16,
1060 "certificate policy PINNED: certificate hash mismatch, deny access to %s:%" PRIu16,
1065 PROXY_LOG_WARN(TAG, pc,
1066 "certificate policy PINNED: neigter PEM nor HASH set for "
1067 "comparison, deny access to %s:%" PRIu16,
1071 freerdp_certificate_free(cert);
1076static int pf_client_verify_by_policy(pClientContext* pc,
const char* hostname, UINT16 port,
1077 const BYTE* data,
size_t length)
1080 WINPR_ASSERT(pc->pdata);
1082 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
1084 WINPR_ASSERT(ps->pdata);
1085 const proxyConfig* config = ps->pdata->config;
1086 WINPR_ASSERT(config);
1088 switch (config->TargetCertPolicy)
1090 case FREERDP_PROXY_CERT_POLICY_VERIFIED_HOST_MATCH:
1091 return pf_client_verify_strict(pc, config, hostname, port, data, length, TRUE);
1092 case FREERDP_PROXY_CERT_POLICY_VERIFIED:
1093 return pf_client_verify_strict(pc, config, hostname, port, data, length, FALSE);
1094 case FREERDP_PROXY_CERT_POLICY_PINNED:
1095 return pf_client_verify_pinned(pc, hostname, port, data, length);
1096 case FREERDP_PROXY_CERT_POLICY_ALLOW:
1097 PROXY_LOG_INFO(TAG, pc,
"certificate policy ALLOW: allow access to %s:%" PRIu16,
1100 case FREERDP_PROXY_CERT_POLICY_DENY:
1102 PROXY_LOG_WARN(TAG, pc,
"certificate policy DENY: deny access to %s:%" PRIu16, hostname,
1109static int pf_client_verify_X509_certificate(freerdp* instance,
const BYTE* data,
size_t length,
1110 const char* hostname, UINT16 port, DWORD flags)
1112 WINPR_ASSERT(instance);
1114 WINPR_ASSERT(length > 0);
1115 WINPR_ASSERT(hostname);
1117 pClientContext* pc = (pClientContext*)instance->context;
1119 Stream_ResetPosition(pc->remote_pem);
1120 if (!Stream_EnsureRemainingCapacity(pc->remote_pem, length))
1123 free(pc->remote_hostname);
1124 pc->remote_hostname =
nullptr;
1127 Stream_Write(pc->remote_pem, data, length);
1128 if (!Stream_EnsureRemainingCapacity(pc->remote_pem, 1))
1130 Stream_Zero(pc->remote_pem, 1);
1133 pc->remote_hostname = _strdup(hostname);
1134 pc->remote_port = port;
1135 pc->remote_flags = flags;
1137 Stream_SealLength(pc->remote_pem);
1140 if (pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_VERIFY_X509, pc->pdata, pc))
1142 PROXY_LOG_INFO(TAG, pc,
"certificate policy: certificate accepted by plugin hook");
1146 return pf_client_verify_by_policy(pc, hostname, port, data, length);
1150static BOOL pf_client_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
1152 WINPR_ATTR_UNUSED DWORD count, DWORD* choice,
1153 WINPR_ATTR_UNUSED BOOL gateway)
1162static BOOL pf_client_authenticate_ex(WINPR_ATTR_UNUSED freerdp* instance,
1163 WINPR_ATTR_UNUSED
char** username,
1164 WINPR_ATTR_UNUSED
char** password,
1165 WINPR_ATTR_UNUSED
char** domain, rdp_auth_reason reason)
1167 WINPR_ASSERT(instance);
1168 WINPR_ASSERT(username);
1169 WINPR_ASSERT(password);
1170 WINPR_ASSERT(domain);
1180 case AUTH_SMARTCARD_PIN:
1191static BOOL pf_client_present_gateway_message(WINPR_ATTR_UNUSED freerdp* instance,
1192 WINPR_ATTR_UNUSED UINT32 type,
1193 WINPR_ATTR_UNUSED BOOL isDisplayMandatory,
1194 WINPR_ATTR_UNUSED BOOL isConsentMandatory,
1195 WINPR_ATTR_UNUSED
size_t length,
1196 WINPR_ATTR_UNUSED
const WCHAR* message)
1198 WLog_WARN(TAG,
"TODO: Implement gateway message forwarding");
1202void channel_data_free(
void* obj)
1212 cnv.cpv = dst->data;
1215 cnv.cpv = dst->channel_name;
1221WINPR_ATTR_MALLOC(channel_data_free, 1)
1223static
void* channel_data_copy(const
void* obj)
1240 if (src->channel_name)
1242 dst->channel_name = _strdup(src->channel_name);
1243 if (!dst->channel_name)
1246 dst->data = malloc(src->data_len);
1250 cnv.cpv = dst->data;
1251 memcpy(cnv.pv, src->data, src->data_len);
1255 channel_data_free(dst);
1260static BOOL pf_client_client_new(freerdp* instance, rdpContext* context)
1263 pClientContext* pc = (pClientContext*)context;
1265 if (!instance || !context)
1268 instance->LoadChannels = pf_client_load_channels;
1269 instance->PreConnect = pf_client_pre_connect;
1270 instance->PostConnect = pf_client_post_connect;
1271 instance->PostDisconnect = pf_client_post_disconnect;
1272 instance->Redirect = pf_client_redirect;
1273 instance->LogonErrorInfo = pf_logon_error_info;
1274 instance->GetAccessToken =
nullptr;
1275 instance->RetryDialog =
nullptr;
1276 instance->VerifyCertificateEx =
nullptr;
1277 instance->VerifyChangedCertificateEx =
nullptr;
1278 instance->VerifyX509Certificate = pf_client_verify_X509_certificate;
1279 instance->AuthenticateEx = pf_client_authenticate_ex;
1280 instance->ChooseSmartcard = pf_client_choose_smartcard;
1281 instance->PresentGatewayMessage = pf_client_present_gateway_message;
1283 pc->remote_pem = Stream_New(
nullptr, 4096);
1284 if (!pc->remote_pem)
1287 pc->sendChannelData = pf_client_send_channel_data;
1288 pc->cached_server_channel_data = Queue_New(TRUE, -1, -1);
1289 if (!pc->cached_server_channel_data)
1291 obj = Queue_Object(pc->cached_server_channel_data);
1296 pc->interceptContextMap = HashTable_New(FALSE);
1297 if (!pc->interceptContextMap)
1300 if (!HashTable_SetupForStringData(pc->interceptContextMap, FALSE))
1303 obj = HashTable_ValueObject(pc->interceptContextMap);
1311static int pf_client_client_stop(rdpContext* context)
1313 pClientContext* pc = (pClientContext*)context;
1314 proxyData* pdata =
nullptr;
1318 WINPR_ASSERT(pdata);
1320 PROXY_LOG_DBG(TAG, pc,
"aborting client connection");
1321 proxy_data_abort_connect(pdata);
1322 freerdp_abort_connect_context(context);
1327int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
1329 WINPR_ASSERT(pEntryPoints);
1331 ZeroMemory(pEntryPoints,
sizeof(RDP_CLIENT_ENTRY_POINTS));
1332 pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
1333 pEntryPoints->Size =
sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
1334 pEntryPoints->ContextSize =
sizeof(pClientContext);
1336 pEntryPoints->ClientNew = pf_client_client_new;
1337 pEntryPoints->ClientFree = pf_client_context_free;
1338 pEntryPoints->ClientStop = pf_client_client_stop;
1345DWORD WINAPI pf_client_start(LPVOID arg)
1348 pClientContext* pc = (pClientContext*)arg;
1351 if (freerdp_client_start(&pc->cctx.context) == 0)
1352 rc = pf_client_thread_proc(pc);
1353 freerdp_client_stop(&pc->cctx.context);
WINPR_ATTR_NODISCARD FREERDP_API const char * pf_config_policy_to_str(FreeRDP_ProxyCertPolicy policy)
Convert a FreeRDP_ProxyCertPolicy value to a string.
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 BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API void * freerdp_settings_get_pointer_writable(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a mutable pointer settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree
WINPR_ATTR_NODISCARD OBJECT_NEW_FN fnObjectNew